乐固壳分析

Posted 人怜直节生来瘦,自许高材老更刚。

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了乐固壳分析相关的知识,希望对你有一定的参考价值。

本文以乐固2.8.1(后面还有2.10.3.1)为例,介绍乐固壳的分析和脱壳过程。

一、绕过反调试
首先,使用ida加载libshella-2.8.1.so后,出现以下section错误提示,点“OK”后仍然可以加载成功:

 

这说明“乐固”在section做了一些手脚。要解决这个问题,我们需要明白关于section和segment的一些不同:
1. ELF中的section主要提供给Linker使用, 而segment提供给Loader用,Linker需要关心.text, .rel,.text, .data, .rodata等等,关键是Linker需要做relocation。而Loader只需要知道Read/Write/Execute的属性。
2.一个executable的ELF文件可以没有section,但必须有segment。ELF文件中间部分是共用的(也就是代码段、数据段等)
由第2点可知,既然ELF可以没有section,我们就将section_header_table的数据全部清0,然后再用ida打开,发现没有这个错误提示了。
在修复的libshella-2.8.1.so的Exports表中找到JNI_OnLoad函数,发现该函数是加密的:

我们知道so 文件加载时首先会查看 .init 或 .init_array 段是否存在,如果存在那么就先运行这段的内容,如果不存在的话那么就检查是否存在JNI_OnLoad,存在则执行。所以JNI_OnLoad的解密就应该是在 .init 或 .init_array 段中。
因为 .init 或者 .init_array 在 IDA 动态调试的时候是不会显示出来的,所以需要静态分析出这两段的偏移量然后动态调试的时候计算出绝对位置,然后在 make code(快捷键:c),这样才可以看到该段内的代码内容。
那么,如何定位到执行so文件的init或init_array函数呢?
方法1:
1)从手机或虚拟机中pull出来linker
2)搜索字符串“[ Calling %s @ %p for \'%s\' ]”,见下图:

3)查找引用此字符串的地址:

4)到sub_271C处,见下图 :


方法2:使用 IDA 加载 .so 文件,按ctrl+s快捷键查看 “Segments” 视图,这里会列出不同类型的代码段信息,如下图所示。

方法3:readelf -a查看init_array的偏移地址:

我尝试了前两种方法都没成功,不知为什么。使用第三种方法,如上图,得到init_array地址:0x9e20。通过ida定位到该地址,发现调用了两个函数tencent1115357682105733551029和sub_14D4

第一个函数tencent1115357682105733551029为空函数,可以直接忽略:

主要看第二个函数

 1 int sub_B6F084D4()
 2 {
 3   unsigned int v0; // ST44_4
 4   unsigned int v1; // ST40_4
 5   unsigned __int64 v2; // kr00_8
 6   char v3; // ST27_1
 7   int j; // [sp+14h] [bp-44h]
 8   int v6; // [sp+18h] [bp-40h]
 9   int v7; // [sp+1Ch] [bp-3Ch]
10   char v8; // [sp+2Eh] [bp-2Ah]
11   char v9; // [sp+2Fh] [bp-29h]
12   char v10; // [sp+30h] [bp-28h]
13   char v11; // [sp+33h] [bp-25h]
14   unsigned int v12; // [sp+34h] [bp-24h]
15   _DWORD *v13; // [sp+38h] [bp-20h]
16   unsigned int v14; // [sp+48h] [bp-10h]
17   unsigned int i; // [sp+4Ch] [bp-Ch]
18 
19   for ( i = (unsigned int)sub_B6F084D4 & 0xFFFFF000; *(_DWORD *)i != 1179403647; i -= 4096 )
20     ;
21   v14 = 0;
22   v13 = (_DWORD *)(i + *(_DWORD *)(i + 28));
23   v12 = 0;
24   while ( v12 < *(unsigned __int16 *)(i + 44) )
25   {
26     if ( *v13 != 1 || v13[6] != 5 )
27     {
28       if ( *v13 == 1 && v13[6] == 6 )
29       {
30         v0 = v13[2] & 0xFFFFF000;
31         v1 = (v13[2] + v13[4] + 4095) & 0xFFFFF000;
32         break;
33       }
34     }
35     else
36     {
37       v14 = (v13[2] + v13[4] + 4095) & 0xFFFFF000;
38     }
39     ++v12;
40     v13 += 8;
41   }
42   v11 = 43;
43   v10 = -103;
44   v9 = 32;
45   v8 = 21;
46   v2 = (unsigned __int64)word_B6F11010[0] << 16;
47   v7 = LOWORD(word_B6F11010[0]);
48   v6 = LOWORD(word_B6F11010[0]) - (word_B6F11010[0] >> 16);
49   mprotect_0(i + HIDWORD(v2), (v6 + 4095) & 0xFFFFF000, 3);
50   for ( j = HIDWORD(v2); j <= v7; ++j )
51   {
52     v3 = *(_BYTE *)(i + j);
53     *(_BYTE *)(i + j) ^= (unsigned __int8)((j ^ (v10 - v9)) + v8) ^ v11;
54     *(_BYTE *)(i + j) += v10 ^ v9 & v8;
55     v11 += v3 & (v10 + v9 - v8) & j;
56     v10 += v3 ^ (v11 + j);
57     v9 ^= (unsigned __int8)(v3 - v11) ^ (unsigned __int8)j;
58     v8 -= v3 + v11 - j;
59   }
60   mprotect_0(i + HIDWORD(v2), (v6 + 4095) & 0xFFFFF000, 5);
61   sub_B6F083DC(i + HIDWORD(v2), v6);
62   word_B6F11010[0] = i;
63   dword_B6F11380 = i;
64   unk_B6F11384 = v14;
65   return sub_B6F0F630();
66 }

我们看到这个函数主要进行了一些字节变换,然后调用了mprotect,sub_B6F083DC和sub_B6F0F630三个函数。sub_B6F083DC函数就是做了 cacheflush和syscall操作,不管它。

 

我们来看看sub_B6F0F630函数,发现该函数调用pthread_create创建了一个线程,第三个参数是线程运行函数的起始地址。

通过ida定位这个地址,查看pthread_create创建的线程调用的函数如下:

  1 int __fastcall sub_B6F0EBD0(int a1)
  2 {
  3   int v2; // r0
  4   int v3; // r0
  5   char *v4; // r3
  6   int *v5; // r1
  7   int *v6; // r3
  8   int v7; // r2
  9   unsigned int v8; // r0
 10   char *v9; // r3
 11   char v10; // [sp-10h] [bp-490h]
 12   char v11; // [sp-Fh] [bp-48Fh]
 13   char v12; // [sp-Eh] [bp-48Eh]
 14   char v13; // [sp-Dh] [bp-48Dh]
 15   char v14; // [sp-Ch] [bp-48Ch]
 16   char v15; // [sp-Bh] [bp-48Bh]
 17   char v16; // [sp-Ah] [bp-48Ah]
 18   char v17; // [sp-9h] [bp-489h]
 19   char v18; // [sp-8h] [bp-488h]
 20   char v19; // [sp-7h] [bp-487h]
 21   char v20; // [sp-6h] [bp-486h]
 22   char v21; // [sp-5h] [bp-485h]
 23   char v22; // [sp-4h] [bp-484h]
 24   char v23; // [sp-3h] [bp-483h]
 25   char v24; // [sp-2h] [bp-482h]
 26   int v25; // [sp+0h] [bp-480h]
 27   int v26; // [sp+4h] [bp-47Ch]
 28   int v27; // [sp+8h] [bp-478h]
 29   int v28; // [sp+Ch] [bp-474h]
 30   int v29; // [sp+10h] [bp-470h]
 31   int v30; // [sp+14h] [bp-46Ch]
 32   int v31; // [sp+18h] [bp-468h]
 33   int v32; // [sp+1Ch] [bp-464h]
 34   int v33; // [sp+20h] [bp-460h]
 35   int v34; // [sp+24h] [bp-45Ch]
 36   int v35; // [sp+28h] [bp-458h]
 37   int v36; // [sp+2Ch] [bp-454h]
 38   int v37; // [sp+30h] [bp-450h]
 39   int v38; // [sp+34h] [bp-44Ch]
 40   int v39; // [sp+38h] [bp-448h]
 41   int v40; // [sp+3Ch] [bp-444h]
 42   void *v41; // [sp+40h] [bp-440h]
 43   char *v42; // [sp+44h] [bp-43Ch]
 44   void *v43; // [sp+48h] [bp-438h]
 45   char v44; // [sp+4Ch] [bp-434h]
 46   char v45; // [sp+4Dh] [bp-433h]
 47   char v46; // [sp+4Eh] [bp-432h]
 48   char v47; // [sp+4Fh] [bp-431h]
 49   char v48; // [sp+50h] [bp-430h]
 50   char v49; // [sp+51h] [bp-42Fh]
 51   char v50; // [sp+52h] [bp-42Eh]
 52   char v51; // [sp+53h] [bp-42Dh]
 53   char v52; // [sp+54h] [bp-42Ch]
 54   char v53; // [sp+55h] [bp-42Bh]
 55   char v54; // [sp+56h] [bp-42Ah]
 56   char v55; // [sp+57h] [bp-429h]
 57   char v56; // [sp+58h] [bp-428h]
 58   char v57; // [sp+59h] [bp-427h]
 59   char v58; // [sp+5Ah] [bp-426h]
 60   char v59; // [sp+5Bh] [bp-425h]
 61   int watch_fd; // [sp+5Ch] [bp-424h]
 62   char v61; // [sp+60h] [bp-420h]
 63   int v62; // [sp+460h] [bp-20h]
 64   int v63; // [sp+464h] [bp-1Ch]
 65   int v64; // [sp+468h] [bp-18h]
 66   int v65; // [sp+46Ch] [bp-14h]
 67 
 68   v65 = a1;
 69   ++dword_B6F11378;
 70   v43 = &loc_B6F10F44;
 71   v42 = &v44;
 72   v41 = &loc_B6F10F44;
 73   unk_B6F11388 = sub_B6F08218(1024);            // malloc
 74   v40 = sub_B6F0DDEC();
 75   unk_B6F1138C = sub_B6F0DEE0(0, v65, unk_B6F11384);
 76   v64 = getppid_0();
 77   v50 = unk_B6F112B7 ^ 0x96;
 78   v49 = unk_B6F112B6 ^ 0xF7;
 79   v58 = unk_B6F112BF ^ 0xE1;
 80   v51 = unk_B6F112B8 ^ 0x9E;
 81   v46 = unk_B6F112B3 ^ 0x85;
 82   v53 = unk_B6F112BA ^ 0x98;
 83   v59 = unk_B6F112C0;
 84   v44 = unk_B6F112B1 ^ 0xE9;
 85   v47 = unk_B6F112B4 ^ 0x95;
 86   v56 = unk_B6F112BD ^ 0xCA;
 87   v54 = unk_B6F112BB ^ 0xEE;
 88   v48 = unk_B6F112B5 ^ 0xEA;
 89   v45 = unk_B6F112B2 ^ 0x97;
 90   v57 = unk_B6F112BE ^ 0xD3;
 91   v55 = unk_B6F112BC ^ 0xA5;
 92   v52 = unk_B6F112B9 ^ 0xFB;
 93   v63 = sub_B6F082D8((int)&v44);                // opendir
 94   if ( v63 )
 95   {
 96     v39 = 4095;
 97     watch_fd = init();
 98     v38 = watch_fd;
 99     sub_B6F08338();                             // fcntl
100     v2 = sub_B6F08338();
101     v22 = byte_B6F112CD ^ 0x8D;
102     v10 = unk_B6F112C1 ^ 0x91;
103     v19 = byte_B6F112CA ^ 0xC5;
104     v21 = byte_B6F112CC ^ 0x80;
105     v13 = byte_B6F112C4 ^ 0xD3;
106     v15 = byte_B6F112C6 ^ 0xE1;
107     v17 = byte_B6F112C8 ^ 0xCA;
108     v18 = byte_B6F112C9 ^ 0xE1;
109     v24 = byte_B6F112CF;
110     v23 = byte_B6F112CE ^ 0xC8;
111     v11 = byte_B6F112C2 ^ 0x87;
112     v12 = byte_B6F112C3 ^ 0x96;
113     v20 = byte_B6F112CB ^ 0xDA;
114     v14 = byte_B6F112C5 ^ 0xD7;
115     v16 = byte_B6F112C7 ^ 0xE2;
116     v37 = v2;
117     v36 = add_watch(watch_fd, &v10, 4095);
118     while ( 1 )
119     {
120       v62 = sub_B6F082E4(v63);                  // readdir
121       if ( !v62 )
122         break;
123       if ( *(_BYTE *)(v62 + 18) & 4 && &word_2E != (__int16 *)*(unsigned __int8 *)(v62 + 19) )
124       {
125         *(&v10 - 11) = byte_B6F112DD ^ 0x8D;
126         *(&v10 - 22) = byte_B6F112D2 ^ 0x9E;
127         *(&v10 - 12) = byte_B6F112DC ^ 0xAD;
128         *(&v10 - 5) = byte_B6F112E3 ^ 0x86;
129         *(&v10 - 14) = byte_B6F112DA ^ 0xE1;
130         *(&v10 - 8) = byte_B6F112E0 ^ 0xB1;
131         *(&v10 - 10) = byte_B6F112DE ^ 0xCF;
132         *(&v10 - 15) = byte_B6F112D9 ^ 0xB1;
133         *(&v10 - 24) = unk_B6F112D0 ^ 0xA7;
134         *(&v10 - 13) = byte_B6F112DB ^ 0xE0;
135         *(&v10 - 7) = byte_B6F112E1 ^ 0xA2;
136         *(&v10 - 3) = byte_B6F112E5 ^ 0xAB;
137         *(&v10 - 17) = byte_B6F112D7 ^ 0x8B;
138         *(&v10 - 2) = byte_B6F112E6;
139         *(&v10 - 23) = byte_B6F112D1 ^ 0xBD;
140         *(&v10 - 19) = byte_B6F112D5 ^ 0xCC;
141         *(&v10 - 9) = byte_B6F112DF ^ 0xA7;
142         *(&v10 - 6) = byte_B6F112E2 ^ 0xE6;
143         *(&v10 - 16) = byte_B6F112D8 ^ 0xA0;
144         *(&v10 - 18) = byte_B6F112D6 ^ 0x83;
145         *(&v10 - 21) = byte_B6F112D3 ^ 0x98;
146         *(&v10 - 20) = byte_B6F112D4 ^ 0xD2;
147         *(&v10 - 4) = byte_B6F112E4 ^ 0xC2;
148         v35 = sub_B6F082F0();                   // sprintf
149         v34 = add_watch(watch_fd, &v61, 4095);
150       }
151     }
152     v33 = sub_B6F08314(v63);                    // closedir
153     while ( 1 )
154     {
155       *(&v10 - 12) = byte_B6F112FC ^ 0x8D;
156       *(&v10 - 7) = byte_B6F11301;
157       *(&v10 - 10) = byte_B6F112FE ^ 0xD9;
158       *(&v10 - 14) = byte_B6F112FA ^ 0xD2;
159       *(&v10 - 17) = byte_B6F112F7 ^ 0xD5;
160       *(&v10 - 19) = byte_B6F112F5 ^ 0x81;
161       *(&v10 - 22) = byte_B6F112F2 ^ 0xB8;
162       *(&v10 - 13) = byte_B6F112FB ^ 0xC7;
163       *(&v10 - 15) = byte_B6F112F9 ^ 0xB2;
164       *(&v10 - 18) = byte_B6F112F6 ^ 0x81;
165       *(&v10 - 24) = unk_B6F112F0 ^ 0x9C;
166       *(&v10 - 9) = byte_B6F112FF ^ 0x95;
167       *(&v10 - 20) = byte_B6F112F4 ^ 0x82;
168       *(&v10 - 23) = byte_B6F112F1 ^ 0x81;
169       *(&v10 - 16) = byte_B6F112F8 ^ 0x88;
170       *(&v10 - 8) = byte_B6F11300 ^ 0xC;
171       *(&v10 - 11) = byte_B6F112FD ^ 0xC8;
172       *(&v10 - 21) = byte_B6F112F3 ^ 0x8B;
173       v3 = sub_B6F0DFA0((int)(&v10 - 24));
174       if ( v3 != v64 )
175       {
176         *(&v10 - 16) = byte_B6F112F8 ^ 0x88;
177         *(&v10 - 11) = byte_B6F112FD ^ 0xC8;
178         *(&v10 - 24) = unk_B6F112F0 ^ 0x9C;
179         *(&v10 - 9) = byte_B6F112FF ^ 0x95;
180         *(&v10 - 8) = byte_B6F11300 ^ 0xC;
181         *(&v10 - 10) = byte_B6F112FE ^ 0xD9;
182         *(&v10 - 20) = byte_B6F112F4 ^ 0x82;
183         *(&v10 - 18) = byte_B6F112F6 ^ 0x81;
184         *(&v10 - 7) = byte_B6F11301;
185         *(&v10 - 23) = byte_B6F112F1 ^ 0x81;
186         *(&v10 - 19) = byte_B6F112F5 ^ 0x81;
187         *(&v10 - 14) = byte_B6F112FA ^ 0xD2;
188         *(&v10 - 21) = byte_B6F112F3 ^ 0x8B;
189         *(&v10 - 12) = byte_B6F112FC ^ 0x8D;
190         *(&v10 - 13) = byte_B6F112FB ^ 0xC7;
191         *(&v10 - 22) = byte_B6F112F2 ^ 0xB8;
192         *(&v10 - 15) = byte_B6F112F9 ^ 0xB2;
193         *(&v10 - 17) = byte_B6F112F7 ^ 0xD5;
194         if ( sub_B6F0DFA0((int)(&v10 - 24)) )
195         {
196           *(&v10 - 6) = byte_B6F11304 ^ 0xAF;
197           *(&v10 - 8) = unk_B6F11302 ^ 0x8B;
198           *(&v10 - 5) = byte_B6F11305 ^ 0xF3;
199           *(&v10 - 7) = byte_B6F11303 ^ 0xCB;
200           *(&v10 - 4) = byte_B6F11306;
201           *(&v10 - 13) = byte_B6F1130A ^ 0xA7;
202           *(&v10 - 5) = byte_B6F11312 ^ 0xDF;
203           *(&v10 - 9) = byte_B6F1130E ^ 0xB5;
204           *(&v10 - 14) = byte_B6F11309 ^ 0xAC;
205           *(&v10 - 4) = byte_B6F11313 ^ 0x80;
206           *(&v10 - 8) = byte_B6F1130F ^ 0xFD;
207           *(&v10 - 12) = byte_B6F1130B ^ 0xC4;
208           *(&v10 - 7) = byte_B6F11310 ^ 0xE7;
209           *(&v10 - 15) = byte_B6F11308 ^ 0xC5;
210           *(&v10 - 16) = unk_B6F11307 ^ 0xA9;
211           *(&v10 - 3) = byte_B6F11314;
212           *(&v10 - 6) = byte_B6F11311 ^ 0x9E;
213           *(&v10 - 10) = byte_B6F1130D ^ 0x93;
214           *(&v10 - 11) = byte_B6F1130C ^ 0xE3;
215           v32 = sub_B6F081C4(6, (int)(&v10 - 8), (int)(&v10 - 16));// _android_log_print
216           v31 = sub_B6F0826C(9);                // raise
217         }
218       }
219       if ( read_0(watch_fd, &v61, &dword_354[43]) > 0 )
220       {
221         *(&v10 - 5) = byte_B6F11305 ^ 0xF3;
222         *(&v10 - 4) = byte_B6F11306;
223         *(&v10 - 6) = byte_B6F11304 ^ 0xAF;
224         *(&v10 - 8) = unk_B6F11302 ^ 0x8B;
225         *(&v10 - 7) = byte_B6F11303 ^ 0xCB;
226         v4 = &v10 - 16;
227         *v4 = unk_B6F11315 ^ 0xB2;
228         *(&v10 - 14) = byte_B6F11317 ^ 0xA6;
229         *(&v10 - 11) = byte_B6F1131A ^ 0xBF;
230         *(&v10 - 13) = byte_B6F11318 ^ 0xBA;
231         *(&v10 - walle多渠道打包+Tinker(bugly)热更新集成+360加固(乐固)

Android 逆向整体加固脱壳 ( DEX 优化流程分析 | DexPrepare.cpp 中 dvmOptimizeDexFile() 方法分析 | /bin/dexopt 源码分析 )(代码片段

Android 事件分发事件分发源码分析 ( Activity 中各层级的事件传递 | Activity -> PhoneWindow -> DecorView -> ViewGroup )(代码片段

Android 插件化VirtualApp 源码分析 ( 目前的 API 现状 | 安装应用源码分析 | 安装按钮执行的操作 | 返回到 HomeActivity 执行的操作 )(代码片段

腾讯应用宝上传应用步骤

CPNtools协议建模安全分析---实例变迁标记