Frida特征对抗案例2

警告
本文最后更新于 2023-08-19,文中内容可能已过时。
  • com.jingdong.app.mall 12.1.0
  • pixel2 android10.0
  • frida 14.2.2

使用frida以spawn模式启动,可以发现进程直接崩溃,说明存在反调试

1
2
3
Spawned `com.jingdong.app.mall`. Resuming main thread!                  
[Pixel 2::com.jingdong.app.mall]-> Process terminated
[Pixel 2::com.jingdong.app.mall]->

通常检测逻辑是放在native层的,因此进一步判断是哪个so导致的

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
function hook_dlopen() {
    Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"),
        {
            onEnter: function (args) {
                var pathptr = args[0];
                if (pathptr !== undefined && pathptr != null) {
                    var path = ptr(pathptr).readCString();
                    console.log("load " + path);
                }
            }
        }
    );
}

由so的加载流程可知,so都是是顺序加载,从命令行中当加载libJDMobileSec之后,进程就崩溃了,可以猜测反调试点在libJDMobileSec中

1
2
3
4
5
Spawned `com.jingdong.app.mall`. Resuming main thread!                  
[Pixel 2::com.jingdong.app.mall]-> load /system/framework/oat/arm/org.apache.http.legacy.odex
load /data/app/com.jingdong.app.mall-OXNoca8Sb7xq1IC0YJW2PA==/oat/arm/base.odex
load /data/app/com.jingdong.app.mall-OXNoca8Sb7xq1IC0YJW2PA==/lib/arm/libJDMobileSec.so
Process terminated

同样需要判断具体检测的函数在哪个部分,优先确定JNI_OnLoad的偏移是0x56BC

 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
function hook_dlopen(soName = '') {
    Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"),
        {
            onEnter: function (args) {
                var pathptr = args[0];
                if (pathptr !== undefined && pathptr != null) {
                    var path = ptr(pathptr).readCString();
                    if (path.indexOf(soName) >= 0) {
                        this.is_can_hook = true;
                    }
                }
            },
            onLeave: function (retval) {
                if (this.is_can_hook) {
                    hook_JNI_OnLoad()
                }
            }
        }
    );
}
 
function hook_JNI_OnLoad(){
    let module = Process.findModuleByName("libJDMobileSec.so")
    Interceptor.attach(module.base.add(0x56BC + 1), {
        onEnter(args){
            console.log("call JNI_OnLoad")
        }
    })
}

setImmediate(hook_dlopen,"libJDMobileSec.so")

看到是在JNI_OnLoad之后进程崩溃的,说明检测逻辑应该是JNI_OnLoad里面

1
2
3
Spawned `com.jingdong.app.mall`. Resuming main thread!                  
[Pixel 2::com.jingdong.app.mall]-> call JNI_OnLoad
Process terminated

测试下是否有新起线程检测

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function hook_pthread_create(){
    var base = Process.findModuleByName("libJDMobileSec.so").base
    console.log("libJDMobileSec.so --- " + base)
    Interceptor.attach(Module.findExportByName("libc.so", "pthread_create"),{
        onEnter(args){
            let func_addr = args[2]
            console.log("The thread function address is " + func_addr + " offset:" + (func_addr-base).toString(16))
        }
    })
}

可以看到有个新起的线程

1
2
3
4
5
Spawned `com.jingdong.app.mall`. Resuming main thread!                  
[Pixel 2::com.jingdong.app.mall]-> call JNI_OnLoad
libJDMobileSec.so --- 0xce055000
The thread function address is 0xce06151d offset:c51d
Process terminated

优先nop掉看是否该点是检测点,追溯到JNI_OnLoad方法里面偏移0x688A上

1
2
3
4
function bypass(){
    let module = Process.findModuleByName("libJDMobileSec.so")
    nop(module.base.add(0x688A))
}

nop掉之后还是崩溃,看来检测点可能不是这里或者不止一个,继续尝试其他hook点

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
function replace_str() {
    var pt_strstr = Module.findExportByName("libc.so", 'strstr');
 
    Interceptor.attach(pt_strstr, {
        onEnter: function (args) {
            var str1 = args[0].readCString();
            var str2 = args[1].readCString();
            console.log("strstr-->", str1, str2);
            // console.log('strstr called from:\\n' + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\\n') + '\\n');
            // console.log('strstr called from:\\n' + Thread.backtrace(this.context, Backtracer.FUZZY).map(DebugSymbol.fromAddress).join('\\n') + '\\n');
        }
    }); 
}

看看字符比较会不会有发现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
strstr--> bb123000-bb222000 r--p 00000000 103:1d 2720259                           /data/app/com.jingdong.app.mall-OXNoca8Sb7xq1IC0YJW2PA==/oat/arm/base.odex
 com.saurik.substrate
strstr called from:\n0xcdf5dbfb libJDMobileSec.so!0xabfb\n0xcdf6e5a1 libJDMobileSec.so!0x1b5a1\n
strstr--> bb222000-bb272000 r--p 00000000 103:06 1437                              /system/framework/oat/arm/org.apache.http.legacy.odex
 re.frida.server/frida-agent-32.so
strstr called from:\n0xcdf5da3f libJDMobileSec.so!0xaa3f\n0xcdf6e5a1 libJDMobileSec.so!0x1b5a1\n
strstr--> bb222000-bb272000 r--p 00000000 103:06 1437                              /system/framework/oat/arm/org.apache.http.legacy.odex
 re.frida.server/frida-agent-64.so
strstr called from:\n0xcdf5da85 libJDMobileSec.so!0xaa85\n0xcdf6e5a1 libJDMobileSec.so!0x1b5a1\n
strstr--> bb222000-bb272000 r--p 00000000 103:06 1437                              /system/framework/oat/arm/org.apache.http.legacy.odex
 com.saurik.substrate
strstr called from:\n0xcdf5dbfb libJDMobileSec.so!0xabfb\n0xcdf6e5a1 libJDMobileSec.so!0x1b5a1\n
strstr--> bb272000-bc06a000 r--p 00000000 103:1d 1032201                           /data/local/tmp/re.frida.server/frida-agent-32.so
 re.frida.server/frida-agent-32.so
strstr called from:\

从日志中看出来应该是比较了maps中是否包含frida-agent、substrate等特征,根据堆栈确定调用点大致是在0xaa85、0xabfb这几个偏移上,从ida上看都集中在sub_A934这个函数里面,看看交叉引用的地方 ,在JNI_OnLoad中有两处,nop掉看看效果

1
2
3
4
5
6
function bypass(){
    let module = Process.findModuleByName("libJDMobileSec.so")
    nop(module.base.add(0x688A))
    nop(module.base.add(0x623A))
    nop(module.base.add(0x634A))
}

nop掉两处后就可以正常调试了,说明sub_A934这个函数就是反调试检测的函数,看看具体sub_A934的函数逻辑是什么

  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
 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
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
int sub_A934()
{
  ......
  v0 = -1072311660;
  v1 = 1723222422;
  v47 = dword_24ED8;
  v2 = -1703318409;
  do
  {
    while ( 1 )
    {
      while ( 1 )
      {
        while ( 1 )
        {
          while ( 1 )
          {
            while ( 1 )
            {
              while ( 1 )
              {
                while ( 1 )
                {
                  while ( 1 )
                  {
                    while ( 1 )
                    {
                      while ( 1 )
                      {
                        while ( 1 )
                        {
                          while ( 1 )
                          {
                            while ( 1 )
                            {
                              while ( 1 )
                              {
                                while ( 1 )
                                {
                                  while ( 1 )
                                  {
                                    while ( v2 <= -1401839159 )
                                    {
                                      if ( v2 == -1703318409 )
                                      {
                                        v2 = 775535239;
                                        if ( !v47 )
                                          v2 = -419580537;
                                      }
                                    }
                                    if ( v2 <= 1993647575 )
                                      break;
                                    if ( v2 == 1993647576 )
                                    {
                                      if ( !s )
                                        goto LABEL_73;
                                      v3 = sub_97C4((float *)&unk_21C24, 33);
                                      v4 = v1;
                                      v5 = v0;
                                      v6 = strstr(s, v3);
                                      free(v3);
                                      v2 = 509119054;
                                      v7 = v6 == 0;
                                      v0 = v5;
                                      v1 = v4;
                                      if ( v7 )
                                      {
                                        v8 = v0;
                                        v9 = sub_97C4((float *)&unk_21CA8, 33);
                                        v10 = strstr(s, v9);
                                        v11 = (char *)v9;
                                        v0 = v8;
                                        v1 = v4;
                                        free(v11);
                                        v2 = 509119054;
                                        if ( !v10 )
LABEL_73:
                                          v2 = 1287785172;
                                      }
                                    }
                                  }
                                  if ( v2 <= 1723222421 )
                                    break;
                                  if ( v2 == v1 )
LABEL_108:
                                    v2 = -370315561;
                                }
                                if ( v2 > -1282738887 )
                                  break;
                                if ( v2 == -1401839158 )
                                {
                                  v2 = 3915268;
                                  if ( v49 )
                                    v2 = -1282738886;
                                }
                              }
                              if ( v2 > v0 )
                                break;
                              if ( v2 == -1282738886 )
                              {
                                s = &v51;
                                v7 = fgets(&v51, 256, stream) == 0;
                                v2 = -104947837;
                                if ( !v7 )
                                  v2 = 1993647576;
                              }
                            }
                            if ( v2 <= 1389383840 )
                              break;
                            if ( v2 == 1389383841 )
                            {
                              fclose(stream);
                              sub_113FC();
                              v12 = 0;
                              v13 = x * ~-x & (x * ~-x ^ 0xFFFFFFFE);
                              v14 = 0;
                              if ( !v13 )
                                v14 = 1;
                              if ( y < 10 )
                                v12 = 1;
                              v15 = v13 != 0;
                              v16 = 0;
                              v17 = v14 ^ v12;
                              if ( y > 9 )
                                v16 = 1;
                              v7 = ((v15 | v16) ^ 1 | v17) == 0;
                              v2 = -1072311659;
                              if ( !v7 )
                                v2 = 327108677;
                            }
                          }
                          if ( v2 <= 1287785171 )
                            break;
                          if ( v2 == 1287785172 )
                          {
                            if ( !s )
                              goto LABEL_87;
                            v18 = v1;
                            v19 = v0;
                            v20 = sub_97C4((float *)&unk_21BD4, 20);
                            v21 = strstr(s, v20);
                            v22 = (char *)v20;
                            v0 = v19;
                            v1 = v18;
                            free(v22);
                            v2 = -1046283837;
                            if ( !v21 )
LABEL_87:
                              v2 = -1282738886;
                          }
                        }
                        if ( v2 <= 775535238 )
                          break;
                        if ( v2 == 775535239 )
                        {
                          v23 = 0;
                          v24 = ~(x * (x - 1)) | 0xFFFFFFFE;
                          v25 = 0;
                          if ( v24 == -1 )
                            v25 = 1;
                          if ( y < 10 )
                            v23 = 1;
                          v7 = v24 == -1;
                          v26 = 0;
                          if ( !v7 )
                            v26 = 1;
                          v27 = 0;
                          v28 = v25 ^ v23;
                          if ( y > 9 )
                            v27 = 1;
                          v7 = ((v26 | v27) ^ 1 | v28) == 0;
                          v2 = -909066482;
                          if ( !v7 )
                            v2 = 129779082;
                        }
                      }
                      if ( v2 <= 509119053 )
                        break;
                      if ( v2 == 509119054 )
                      {
                        v29 = 0;
                        v30 = x * ~-x & (x * ~-x ^ 0xFFFFFFFE);
                        v31 = 0;
                        if ( !v30 )
                          v31 = 1;
                        if ( y < 10 )
                          v29 = 1;
                        v32 = v30 != 0;
                        v33 = 0;
                        v34 = v31 ^ v29;
                        if ( y > 9 )
                          v33 = 1;
                        v7 = ((v32 | v33) ^ 1 | v34) == 0;
                        v2 = -1072311659;
                        if ( !v7 )
                          v2 = 1389383841;
                      }
                    }
                    if ( v2 <= 327108676 )
                      break;
                    if ( v2 == 327108677 )
                      goto LABEL_73;
                  }
                  if ( v2 <= 129779081 )
                    break;
                  if ( v2 == 129779082 )
                  {
                    v35 = sub_97C4((float *)&unk_21BA0, 13);
                    v36 = getpid();
                    sprintf(&v52, v35, v36);
                    free(v35);
                    v0 = -1072311660;
                    v37 = fopen(&v52, (const char *)&unk_1B5A1);
                    stream = v37;
                    if ( v37 )
                      LOBYTE(v37) = 1;
                    v49 = (char)v37;
                    v38 = 0;
                    if ( (~(x * (x - 1)) | 0xFFFFFFFE) != -1 )
                      v38 = 1;
                    v39 = 0;
                    if ( y > 9 )
                      v39 = 1;
                    v7 = ((v38 | v39) ^ 1 | v39 ^ v38) == 0;
                    v2 = -909066482;
                    if ( !v7 )
                      v2 = -1401839158;
                  }
                }
                if ( v2 > -1046283838 )
                  break;
                if ( v2 == -1072311659 )
                {
                  fclose(stream);
                  sub_113FC();
                  v2 = 1389383841;
                }
              }
              if ( v2 > -909066483 )
                break;
              if ( v2 == -1046283837 )
              {
                fclose(stream);
                sub_113FC();
                goto LABEL_87;
              }
            }
            if ( v2 > -813385351 )
              break;
            if ( v2 == -909066482 )
            {
              v40 = sub_97C4((float *)&unk_21BA0, 13);
              v41 = getpid();
              sprintf(&v52, v40, v41);
              free(v40);
              v0 = -1072311660;
              fopen(&v52, (const char *)&unk_1B5A1);
              v2 = 129779082;
            }
          }
          if ( v2 > -419580538 )
            break;
          if ( v2 == -813385350 )
            v2 = 4185867;
        }
        if ( v2 > -370315562 )
          break;
        if ( v2 == -419580537 )
        {
          v42 = 0;
          if ( !((x * ~-x ^ 0xFFFFFFFE) & x * ~-x) )
            v42 = 1;
          v43 = 0;
          if ( y < 10 )
            v43 = 1;
          v7 = (v42 & v43 | v43 ^ v42) == 0;
          v2 = -813385350;
          if ( !v7 )
            v2 = 4185867;
        }
      }
      if ( v2 <= -104947838 )
        break;
      switch ( v2 )
      {
        case -104947837:
          fclose(stream);
          v2 = 3915268;
          break;
        case 3915268:
          goto LABEL_108;
        case 4185867:
          v44 = 0;
          if ( !((x * ~-x ^ 0xFFFFFFFE) & x * ~-x) )
            v44 = 1;
          v45 = 0;
          if ( y < 10 )
            v45 = 1;
          v7 = (v44 & v45 | v45 ^ v44) == 0;
          v2 = -813385350;
          if ( !v7 )
            v2 = 1723222422;
          break;
      }
    }
  }
  while ( v2 != -370315561 );
  return _stack_chk_guard - v53;
}

代码量不长,检测点应该都收敛在maps中,两个需要注意的函数

  • sub_97C4 负责字符动态解密的,有多处调用
     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
    
    _BYTE *__fastcall sub_97C4(float *a1, signed int a2)
    {
    signed int v2; // r4
    float *v3; // r5
    _BYTE *result; // r0
    _BYTE *v5; // r1
    signed int v6; // r2
    float v7; // s0
    
    v2 = a2;
    v3 = a1;
    result = malloc(a2 + 1);
    if ( v2 >= 1 )
    {
        v5 = result;
        v6 = v2;
        do
        {
        v7 = *v3;
        ++v3;
        --v6;
        *v5++ = ((signed int)(float)(v7 + v7) ^ 0xDE) + 34;
        }
        while ( v6 );
    }
    result[v2] = 0;
    return result;
    }
    
  • sub_113FC syscall执行系统编号37的功能,就是kill,等待1秒后杀死当前进程
    1
    2
    3
    4
    5
    6
    7
    8
    
    int sub_113FC()
    {
    __pid_t v0; // r0
    
    sleep(1u);
    v0 = getpid();
    return syscall(37, v0, 9);
    }
    

完整代码看这里libJDMobileSec.js

相关内容