吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2755|回复: 0
收起左侧

[Android CTF] 《攻防世界》MOBILE--easy-dex

[复制链接]
HNHuangJingYU 发表于 2021-9-29 21:44
本帖最后由 HNHuangJingYU 于 2021-9-29 21:48 编辑

1. 嗯,拿到easy-dex.apk拖入jeb分析好家伙直接没有dex文件,嗯明白了,小型的脱壳题目,果断进入libnative.so,逆向前不知道什么是NativeActivity通过这里进行了简单了解下:https://medium.com/androiddevelopers/getting-started-with-c-and-android-native-activities-2213b402ffff,了解到了两个重要函数ANativeActivity_onCreate、android_main大概就是页面的入口函数,通过IDA分析主要的核心代码在android_main里面
[C++] 纯文本查看 复制代码
int __fastcall android_main(_DWORD *application)
{
 
  application_1 = application;
  destLen = 0x100000;
  dest = malloc(0x100000u);
  v2 = dword_43A18;
  v3 = malloc(dword_43A18);
  _aeabi_memcpy(v3, &loc_7004, v2);
  filename = -1651995194;

  LOBYTE(filename) = 47;                        //  //将47赋值给filename中检索低位字节
  do
    *(&filename + v4++) ^= 0xE9u;               // //给filename填充数据
  while ( v4 != 53 );                           //  //长度为52
  v5 = 1;
  LOBYTE(name) = 47;                            // //将47赋值给name中检索低位字节。
  do
    *(&name + v5++) ^= 0xE9u;
  while ( v5 != 47 );                           // //长度47
  j_app_dummy();
  _aeabi_memclr8(&application_2, 52);
  *application_1 = &application_2;              //  //取application_2地址赋值给application_1[0]
  application_1[1] = sub_29B8;
  application_1[2] = sub_2B90;                  // func2
  application_2 = application_1;
  v27 = ASensorManager_getInstance();           //  //application_2 取得 application_1 地址
  v28 = ASensorManager_getDefaultSensor();      // //管理传感器实例对象
  v6 = 0;
  v29 = ASensorManager_createEventQueue(v27, application_1[7], 3, 0, 0);
  v7 = application_1[5];
  if ( v7 )                                     // application_1[5]是否存在
  {
    v8 = *(v7 + 4);
    v9 = *(v7 + 8);
    v31 = *v7;
    v32 = v8;
    v33 = v9;
  }
  _android_log_print(4, "FindMyDex", "Can you shake your phone 100 times in 10 seconds?");
  v10 = 0;
  do
  {
    while ( 1 )
    {
      v12 = 0;
      if ( !v30 )
        v12 = -1;
      v13 = ALooper_pollAll(v12, 0, &v25, &v24);// 执行所有挂起的回调
      if ( v13 >= 0 )
        break;
      if ( v30 )
      {
        v11 = v31 + 0.01;
        if ( (v31 + 0.01) > 1.0 )
          v11 = 0.0;
        v31 = v11;
        sub_2C14(&application_2);
      }
    }
    if ( v24 )
      (*(v24 + 8))(application_1);
    if ( v13 == 3 && v28 )
    {
      while ( 1 )
      {
        do
        {
          if ( ASensorEventQueue_getEvents(v29, &v35, 1) < 1 )
            goto LABEL_51;
        }
        while ( v36 != 1 );
        if ( v10 & 1 )
        {
          if ( v37 >= -15.0 )
          {
LABEL_30:
            v14 = v10;
            goto LABEL_31;
          }
          if ( v10 == 1 )
            v6 = time(0);
          v14 = v10 + 1;
        }
        else
        {
          if ( v37 <= 15.0 )
            goto LABEL_30;
          v14 = v10 + 1;
          if ( v10 >= 0 )
            _android_log_print(4, "FindMyDex", "Oh yeah~ You Got it~ %d times to go~", 99 - v10);
        }
LABEL_31:
        v10 = v14;
        if ( (v14 - 1) <= 0x58 )                // 解密文件
        {
          v10 = v14;
          v15 = v14 / 10;
          if ( v14 % 10 == 9 )
          {
            v16 = dword_43A18;
            v17 = dword_43A18 / 10;
            v18 = (v15 + 1) * (dword_43A18 / 10);
            if ( dword_43A18 / 10 * v15 < v18 )
            {
              v19 = &v3[v17 * v15];
              do
              {
                --v17;
                *v19++ ^= v14;
              }
              while ( v17 );
            }
            if ( v14 == 89 )
            {
              while ( v18 < v16 )
                v3[v18++] ^= 0x59u;
            }
            v10 = v14 + 1;
          }
        }
        if ( v14 == 100 )
        {
          if ( (time(0) - v6) > 9 )
          {
            _android_log_print(4, "FindMyDex", "OH~ You are too slow. Please try again");
            _aeabi_memcpy(v3, &loc_7004, dword_43A18);
            v10 = 0;
          }
          else
          {
            v20 = v6;
            if ( uncompress(dest, &destLen, v3, dword_43A18) )// 解压缩文件
              _android_log_print(5, "FindMyDex", "Dangerous operation detected.");
            v21 = open(&filename, 577, 511);
            if ( !v21 )
              _android_log_print(5, "FindMyDex", "Something wrong with the permission.");
            write(v21, dest, destLen);          // 写入数据
            close(v21);
            free(dest);
            free(v3);
            if ( access(&name, 0) && mkdir(&name, 0x1FFu) )
              _android_log_print(5, "FindMyDex", "Something wrong with the permission..");
            sub_2368(application_1);
            remove(&filename);                  // 删除文件
            _android_log_print(4, "FindMyDex", "Congratulations!! You made it!");
            sub_2250(application_1);
            v10 = 2147483648;
            v6 = v20;
          }
        }
      }
    }
LABEL_51:
    ;
  }
  while ( !application_1[15] );
  sub_2BDA(&application_2);
  return _stack_chk_guard - v65;
}
2. 主要分为创建文件对传感器进行实例化和监听、对数据进行dex解密、解压缩、写数据、删除文件。
3. 分析解密文件处可知都是对dword_43A18数据段进行操作,所以先将这个段dump下来试试看,查看ida view得知dword_43A18位于.data里面,如图:

1

1

4. 通过0x43A18 - 0x3CA10 = 0x7008 定位到0x7008处,那么数据段就是从0x7004开始的那么就得到了dump需要的条件,那么运行脚本:
[Asm] 纯文本查看 复制代码
static main()
{
auto i,fp;
fp = fopen("d:\\dump","wb");
auto start = 0x7004;
auto size = 0x3CA10;
for(i=start;i<start+size;i++)
{
fputc(Byte(i),fp);
}
fp.close();
}
5. 在D盘找到demp文件,那么现在再进行解密。解密操作核心部分:

2

2

6. Java复现脚本(到了这里实在是卡住了第一次接触这种题,搜了下大佬思路,引用了大神的脚本,并对脚本进行了难理解的注释,算是做一丢丢贡献把,我也是第一次接触CTF,就当作一次学习的旅程吧)这里加了一个jar文件、注意下如图:

3

3

[Java] 纯文本查看 复制代码
@Test
public void demo() {
    try {
        FileInputStream fis = new FileInputStream("D://dump");
        int length = 0x3ca10;   //文件大小
        byte[] b = new byte[length];
        int tempchar;
        int index = 0;
        while ((tempchar = fis.read()) != -1) {     //读取每个字节的数据存入 byte[] b
            b[index] = (byte) tempchar;
            index++;
        }
        int v15, v16, v17, v18, v19;
        for (int v14 = 0; v14 < 90; v14++) {        //这里是对应着C++中的 LABEL_31 那块部分解密逻辑
            v15 = v14 / 10;                          //因为LABEL_31处于一个while ( 1 )的大逻辑死循环里面
            if (v14 % 10 == 9) {                     //当v37满足-15<=v37<=15的时候 则v14 = v10 +1(V10的初始值为0)
                v16 = length;                        //所以就可以得出这个for循环
                v17 = length / 10;
                v18 = (v15 + 1) * (length / 10);
                if (length / 10 * v15 < v18) {
                    v19 = v17 * v15;        //这里进行了变换 原句:v19 = &v3[v17 * v15];
                    do {                    //因为v3是一个占内存控件大小为0x3ca10的空数据地址 这里v19则是地址
                        --v17;
                        b[v19++] ^= v14;    //原句 : *v19++ ^= v14;  可理解为: *v3[v17 * v15]取这块内存地址下的数据
                    }
                    while (v17 > 0);
                }
                if (v14 == 89) {
                    while (v18 < v16) {         //到达这里解密算法就结束了
                        b[v18++] ^= 89;
                    }
                }
            }
        }

        fis.close();

        FileOutputStream fos = new FileOutputStream("D://class.dex");   //进行文件写出
        for (byte ch : unjzlib(b)) {
            fos.write(ch);
        }
        fos.flush();
        fos.close();

    } catch (IOException e) {
        e.printStackTrace();
    }

}



public static byte[] unjzlib(byte[] object) {
    byte[] data = null;
    try {
        ByteArrayInputStream in = new ByteArrayInputStream(object);
        ZInputStream zIn = new ZInputStream(in); // qwb{TH3y_lo<e_EACh_OTH3r_FOrEUER}
        byte[] buf = new byte[1024];
        int num;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        while ((num = zIn.read(buf, 0, buf.length)) != -1) {
            baos.write(buf, 0, num);
        }
        data = baos.toByteArray();
        baos.flush();
        baos.close();
        zIn.close();
        in.close();

    } catch (IOException e) {
        e.printStackTrace();
    }
    return data;
}
7. 运行后就得到了完整的dex文件了路径在你写出文件的目录下,用jeb打开dex文件(jadx不行)一看b类好家伙这种算法逆向直接就给了我一大重击拳,求助大神的帖子后发现是一个第三方算法。先将MainActivity中的m转换为Base64因为twofish算法解密后是Base64。8.转换为Base64结果:iE3y2hEF1izgbVUfGKWQrUCtgFQFop7iEkbmRwWdwsZ1HdQGcPxRVAkWzV/eDC9N,去到网页在线twofish解密得到flag:qwb{TH3y_Io<e_EACh_OTh3r_FOrEUER}

免费评分

参与人数 1威望 +1 吾爱币 +20 热心值 +1 收起 理由
qtfreet00 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-29 15:11

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表