乐固壳分析
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 执行的操作 )(代码片段