这次我们来调试dex,题目是GCTF 2017中的一道安卓水题,算法一望而知,但我们换一种方法做做看。
题目附件:com.example.crackme.apk
你大概需要:
1.一部手机,已root,有ro.debuggable=1,安卓4.4.4(非必须),cpu架构32位(非必须,但这题我在64位机子上调试失败)
2.IDA
3.JEB2(此处非必须)
参照前一篇文章,手机连电脑,adb连shell以root启动android_server,adb再转发端口,这里不再多说。
apk文件拖到IDA里,选择dex文件。
根据JEB2中的反汇编结果,我们找到关键的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public void onCreate(Bundle arg3) { super.onCreate(arg3); this.setContentView(2130968601); this.setTitle(2131099677); this.edit_userName = "Tenshine"; this.edit_sn = this.findViewById(2131492945); this.btn_register = this.findViewById(2131492946); this.btn_register.setOnClickListener(new View$OnClickListener() { public void onClick(View arg5) { if(!MainActivity.this.checkSN(MainActivity.this.edit_userName.trim(), MainActivity.this.edit_sn.getText().toString().trim())) { Toast.makeText(MainActivity.this, 2131099678, 0).show(); } else { Toast.makeText(MainActivity.this, 2131099675, 0).show(); MainActivity.this.btn_register.setEnabled(false); MainActivity.this.setTitle(2131099673); } } }); }
|
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
| private boolean checkSN(String name, String sn) { boolean v7 = false; if(name != null) { try { if(name.length() == 0) { return v7; }
if(sn == null) { return v7; }
if(sn.length() != 22) { return v7; }
MessageDigest v1 = MessageDigest.getInstance("MD5"); v1.reset(); v1.update(name.getBytes()); String enc1 = MainActivity.toHexString(v1.digest(), ""); StringBuilder ecn2 = new StringBuilder(); int v4; for(v4 = 0; v4 < enc1.length(); v4 += 2) { ecn2.append(enc1.charAt(v4)); }
if(!"flag{" + ecn2.toString() + "}".equalsIgnoreCase(sn)) { return v7; } } catch(NoSuchAlgorithmException v2) { goto label_40; }
v7 = true; }
return v7; label_40: v2.printStackTrace(); return v7; }
|
如果是静态分析的话,这样也就分析出来了,很简单,但现在我们假设中间是一坨很复杂的算法,那么动态分析就方便的多了。
IDA中找到关键代码下好断点。
手机端打开crackme到主界面,IDA选择attach to process
成功后会显示如下,点一下运行。
输入长度22位的假flag后成功断下
打开local窗口
单步f8,
切换到local窗口
可以看到,flag直接通过动态跟踪的方式出来了。