Crackme1

Android stdio 第一个程序 Crackme1

安装Android Studio。

Crackme1

创建app

File->New Project[Application name: Crackme1,Project Location : ..;Company domain: ese.example.com]->Phone and Tablet[API 19…]->Empty Activity->Finish[默认就好]

布局框架

activit_main_xml编辑如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<ScrollView
android:layout_width="368dp"
android:layout_height="495dp"
tools:layout_editor_absoluteY="8dp"
tools:layout_editor_absoluteX="8dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:layout_width="400dp"
android:layout_height="60dp"
android:inputType="textPersonName"
android:id="@+id/login_edit_account"
android:drawableLeft="@android:drawable/ic_menu_myplaces"
android:hint="请输入您的用户名"
android:layout_marginTop="20dp"
android:layout_below="@+id/logo"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<EditText
android:layout_width="400dp"
android:layout_height="60dp"
android:inputType="textPassword"
android:ems="10"
android:id="@+id/login_edit_pwd"
android:drawableLeft="@android:drawable/ic_lock_idle_lock"
android:hint="请输入您的密码"
android:layout_below="@+id/login_edit_account"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="登录"
android:id="@+id/login_btn_login"
android:onClick="finish_login"
android:background="#545bcb"
android:textSize="20dp"
android:textColor="#ffffff"
android:layout_below="@+id/login_edit_pwd"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="52dp" />
</RelativeLayout>
</ScrollView>

如图

填加需要的字符res->values->strings.xml

1
2
3
4
5
<resources>
<string name="app_name">Crackme1</string>
<string name="success">success!!!!</string>
<string name="fail">Fail!!!!</string>
</resources>

代码

接着编写MainActivity类的代码,添加一个checkSN()方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
private boolean checkSN(String userName, String sn) { //确认验证,len(sn)==16
try {
if ((userName == null) || (userName.length() == 0))
return false;
if ((sn == null) || (sn.length() != 16))
return false;
MessageDigest digest = null;
digest = MessageDigest.getInstance("MD5");
digest.reset();
digest.update(userName.getBytes());
byte[] bytes = digest.digest(); //采用MD5对用户名进行Hash
String hexstr = toHexString(bytes, ""); //将计算结果转化成字符串
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hexstr.length(); i += 2) {
sb.append(hexstr.charAt(i));
}
String userSN = sb.toString(); //计算出的SN
//Log.d("len(sn)==16", "-------sn==16----------------------------------");
//Log.d("name_md5_hex", hexstr);
//Log.d("sn", userSN);
if (!userSN.equalsIgnoreCase(sn)) //比较注册码是否正确
return false;
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
private static String toHexString(byte[] bytes, String separator) { //转为十六进制
StringBuilder hexString = new StringBuilder();
for (byte b : bytes) {
String hex = Integer.toHexString(0xFF & b);
if(hex.length() == 1){
hexString.append('0');
}
hexString.append(hex).append(separator);
}
return hexString.toString();
}

onCreate方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle(R.string.app_name);
final EditText et_username = (EditText) findViewById(R.id.login_edit_account);
final EditText et_sn = (EditText) findViewById(R.id.login_edit_pwd);
final Button bt_login = (Button) findViewById(R.id.login_btn_login);
bt_login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(!checkSN(et_username.getText().toString().trim(),
et_sn.getText().toString().trim())){
Toast.makeText(MainActivity.this, R.string.fail, Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(MainActivity.this, R.string.success, Toast.LENGTH_SHORT).show();
bt_login.setEnabled(false);
}
}
});
}

运行结果:

技巧

调试信息: atl+6可以查看log.d()的调试结果.
修改保存路径: Create new project -> Select Project Location
生成apk的位置: 存储路径下app/build/outputs/apk
Terminal窗口: 可以查看当前文件的位置
生成版本: Build->Edit Build Types->release
生成: Build->Build Apk

破解Crackme1

破解Android程序通常的方法是将apk文件利用ApkTool反编译或者Apkdb反编译,生成Smali格式的返汇编代码,然后阅读Smali文件的代码来理解程序运行的机制,找到程序的突破口进行修改。最后使用ApkTool重新编译生成apk文件并签名,最后进行测试是否破解成功。
在实际的分析过程中,还可以使用ida直接分析apk,或者dex2jar与jd-gui配合来进行java源码级的分析等。

方法1

使用jd-gui查看Crackme1


这里就是返回结果为true则成功。接着我们使用apkdb[这是一键编译,方便点]反编译apk,并找到MainActvity.smali代码

1
java -jar apktool.jar d demo.apk

调用checkSN方法,参数是传递两个string[p1,p2],返回值是Z[boolean]布尔型

1
2
3
4
5
6
7
8
9
10
11
12
.locals 1
.param p0, "x0" # Lcom/example/ese/crackme1/MainActivity;
.param p1, "x1" # Ljava/lang/String;
.param p2, "x2" # Ljava/lang/String;
.prologue
.line 13
invoke-direct {p0, p1, p2}, Lcom/example/ese/crackme1/MainActivity;->checkSN(Ljava/lang/String;Ljava/lang/String;)Z
move-result v0 //返回结果
return v0

这里将返回结果修改为1,

1
2
3
4
5
move-result v0 //返回结果
const/4 v0, 0x1
return v0

在进行打包和签名。安装,成功绕过。这里有反编译打包回来,签名的方法。

方法2

使用ddms动态调试,在程序算出sn的时候,我们将sn打印出来。

1
2
3
4
5
6
7
8
.line 60
:cond_2
invoke-virtual {v5}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v6
.line 64
.local v6, "userSN":Ljava/lang/String;

修改

1
2
3
4
5
6
7
8
9
10
11
.line 60
:cond_2
invoke-virtual {v5}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v6
const-string v3,"TEST"
invoke-static{v3,v6},Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
.line 64
.local v6, "userSN":Ljava/lang/String;

这是添加log.d(“TEST”,v6),v6就是算出来序列号的值。然后在反编译回去,签名。运行结果:

输入,显示成功

Donate
-------------本文结束感谢您的阅读-------------