吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3374|回复: 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++] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
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里面,如图:

4. 通过0x43A18 - 0x3CA10 = 0x7008 定位到0x7008处,那么数据段就是从0x7004开始的那么就得到了dump需要的条件,那么运行脚本:
[Asm] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
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文件,那么现在再进行解密。解密操作核心部分:

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

[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
@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, 2025-6-8 13:03

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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