题目

CSDN免积分下载

查壳

先查壳(PKiD等),有壳脱壳,没壳用AndroidKiller等反编译工具打开查看JAVA代码
无壳APK

Java Decompiler - MainActivity-onClick

  1. public void onClick(View paramAnonymousView)
  2. {
  3. if (!MainActivity.this.checkSN(MainActivity.this.edit_userName.getText().toString().trim(), MainActivity.this.edit_sn.getText().toString().trim()))
  4. {
  5. Toast.makeText(MainActivity.this, 2131034123, 0).show();
  6. }
  7. for (;;)
  8. {
  9. return;
  10. Toast.makeText(MainActivity.this, 2131034120, 0).show();
  11. MainActivity.this.btn_register.setEnabled(false);
  12. MainActivity.this.setTitle(2131034118);
  13. }
  14. }

答案

YOU_KNOW_ANDROID

Writeup

image.png

解题

文件下载后是一个压缩包,其中有一个无壳APK,一个doc文档:

⚠⚠⚠危险危险危险⚠⚠⚠

image.png
这个文件不是没用的,答案最后揭晓

运行

image.png
image.png

解题思路

搜索字符串

使用反编译工具的字符串搜索功能,搜索点击“注册”按钮后的提示字符串“md5:”:
image.png
值来自资源文件“string.xml”,搜索值的字段后获取资源id,再搜索资源id即可定位到资源id在java中被调用的位置:
image.png
资源id:
image.png
此时已经能知道,成功的逻辑就是弹出吐司信息“md5:b3241668ecbeb19921fdac5ac1aafa69”,但是这并不像FLAG,并且输入框是两个,可能后续还有代码是需要成功输入后才能出现的,所以还是继续分析了JAVA代码。
——虽然最后会发现并不需要分析。

MainActivity

搜不出来或者没有思路时,应该先看Android程序的入口——一般来说是MainActivity函数,为了保险可以从“AndroidManifest.xml”查找入口点,根据页面布局的按钮可知主要代码在“onClick”函数中:
image.png

代码

MainActivity

  1. public void onCreate(Bundle paramBundle)
  2. {
  3. …………………………省略…………………………
  4. this.edit_userName = ((EditText)findViewById(2131230721));
  5. this.edit_sn = ((EditText)findViewById(2131230722));
  6. …………………………省略…………………………
  7. {
  8. public void onClick(View paramAnonymousView)
  9. {
  10. if (!MainActivity.this.checkSN(MainActivity.this.edit_userName.getText().toString().trim(), MainActivity.this.edit_sn.getText().toString().trim()))
  11. { //不成功字符串
  12. Toast.makeText(MainActivity.this, 2131034123, 0).show();
  13. }
  14. for (;;)
  15. {
  16. return;
  17. //成功字符串
  18. 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

  1. 判断输入的UserName和SN,均不为空而且SN长度为16;

(实际上因为出题者粗心,都为空时进入成功逻辑)

  1. MD5加密UserName的值输出为十六进制;
  2. 对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) ```

💯破解注册码💯

image.png
这不就是一开始不输入按注册的吐司消息吗😳😳😳

MD5

MD5密码算法是不可逆的。 可以将一个单词加密为MD5,但不可能创建反向函数将MD5哈希解密为纯文本。MD5算法有一个可以利用的弱点,每次创建一个单词的MD5散列时,都会得到相同的结果。 由于这个算法在几十年前是世界上最主要的算法之一,许多数据库都有对应于他们所知道的每一个MD5的单词。

因此,MD5没有解密算法,但是有一个解决方案。 通过现有的数据库进行MD5值查询匹配

通过得到的MD5“b3241668ecbeb19921fdac5ac1aafa69”查询到匹配的字符串为“YOUKNOW”:
image.png

😑脑筋急转弯😑

  1. 代码中还原的注册码算法,只是用于验证注册码
  2. 验证成功后弹出字符串的MD5值
  3. 将MD5匹配原为字符串后需要再根据提示猜出Flag:

image.png