题目
查壳
先查壳(PKiD等),有壳脱壳,没壳用AndroidKiller等反编译工具打开查看JAVA代码
无壳APK
Java Decompiler - MainActivity-onClick
public void onClick(View paramAnonymousView){if (!MainActivity.this.checkSN(MainActivity.this.edit_userName.getText().toString().trim(), MainActivity.this.edit_sn.getText().toString().trim())){Toast.makeText(MainActivity.this, 2131034123, 0).show();}for (;;){return;Toast.makeText(MainActivity.this, 2131034120, 0).show();MainActivity.this.btn_register.setEnabled(false);MainActivity.this.setTitle(2131034118);}}
答案
Writeup
解题
文件下载后是一个压缩包,其中有一个无壳APK,一个doc文档:
⚠⚠⚠危险危险危险⚠⚠⚠
运行
解题思路
搜索字符串
使用反编译工具的字符串搜索功能,搜索点击“注册”按钮后的提示字符串“md5:”:
值来自资源文件“string.xml”,搜索值的字段后获取资源id,再搜索资源id即可定位到资源id在java中被调用的位置:
资源id:
此时已经能知道,成功的逻辑就是弹出吐司信息“md5:b3241668ecbeb19921fdac5ac1aafa69”,但是这并不像FLAG,并且输入框是两个,可能后续还有代码是需要成功输入后才能出现的,所以还是继续分析了JAVA代码。
——虽然最后会发现并不需要分析。
MainActivity
搜不出来或者没有思路时,应该先看Android程序的入口——一般来说是MainActivity函数,为了保险可以从“AndroidManifest.xml”查找入口点,根据页面布局的按钮可知主要代码在“onClick”函数中:
代码
MainActivity
public void onCreate(Bundle paramBundle){…………………………省略…………………………this.edit_userName = ((EditText)findViewById(2131230721));this.edit_sn = ((EditText)findViewById(2131230722));…………………………省略…………………………{public void onClick(View paramAnonymousView){if (!MainActivity.this.checkSN(MainActivity.this.edit_userName.getText().toString().trim(), MainActivity.this.edit_sn.getText().toString().trim())){ //不成功字符串Toast.makeText(MainActivity.this, 2131034123, 0).show();}for (;;){return;//成功字符串Toast.makeText(MainActivity.this, 2131034120, 0).show();
成功的成立条件为“checkSN(userName, sn) !=0 ”:
MainActivity.this.checkSN(MainActivity.this.edit_userName.getText().toString().trim(), MainActivity.this.edit_sn.getText().toString().trim())
简化为伪代码:checkSN(userName, sn)
checkSN
- 判断输入的UserName和SN,均不为空而且SN长度为16;
(实际上因为出题者粗心,都为空时进入成功逻辑)
- MD5加密UserName的值输出为十六进制;
- 对MD5的值步长为2取值保存和SN对比是否相等
checkSN(String inputUserName, String inputSN) { if ((inputSN == null) || (inputSN.length() != 16)) { //inputSN长度为16 bool1 = false; } else { Object localObject = MessageDigest.getInstance("MD5"); localObject = toHexString(((MessageDigest)localObject).digest(), ""); for (int i = 0; i < ((String)localObject).length(); i += 2) { inputUserName.append(((String)localObject).charAt(i)); } //忽略大小写比较 boolean bool2 = inputUserName.toString().equalsIgnoreCase(inputSN);🐍Python🐍MD5加密后步长为2取值
```python import hashlib md5 = hashlib.md5()
inputUserName = “十三陵陈飞宇”
MD5
md5.update(inputUserName.encode(‘utf8’)) md5UserName = md5.hexdigest()
步长为2切片
inputSN = md5UserName[::2].upper() print(inputSN) ```
💯破解注册码💯
MD5
MD5密码算法是不可逆的。 可以将一个单词加密为MD5,但不可能创建反向函数将MD5哈希解密为纯文本。MD5算法有一个可以利用的弱点,每次创建一个单词的MD5散列时,都会得到相同的结果。 由于这个算法在几十年前是世界上最主要的算法之一,许多数据库都有对应于他们所知道的每一个MD5的单词。
因此,MD5没有解密算法,但是有一个解决方案。 通过现有的数据库进行MD5值查询匹配。
通过得到的MD5“b3241668ecbeb19921fdac5ac1aafa69”查询到匹配的字符串为“YOUKNOW”:
😑脑筋急转弯😑
- 代码中还原的注册码算法,只是用于验证注册码
- 验证成功后弹出字符串的MD5值
- 将MD5匹配原为字符串后需要再根据提示猜出Flag:




