尝试hook
可以看到frida启动后一会就被kill了,手机上的app也退出了
现在需要找到检测点,首先通过hook dlopen看看是在哪一个so中退出的
libmsaoaidsec.so中,那么具体的检测函数如何定位呢,frida的检测函数很有可能会调用pthread_create来创建检测线程,那么我们可以尝试去hook一下这个函数
但是hook的时机很重要,linker在加载so时会按顺序执行:.init,.init_array,JNI_OnLoad
.init,.init_array是在do_dlopen中执行的,find_library函数会根据命名空间ns,库名translate_name,加载标志flags,拓展信息extinfo和调用者caller来查找库,si指向找到的库。call_constructors函数负责调用库中的.init段和.init_array段中的函数。
1 2 3 soinfo* si = find_library(ns, translated_name, flags, extinfo, caller); ... si->call_constructors();
先看看在不在JNI_OnLoad中,
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 function hook_dlopen(){ Java.perform(function(){ var dlopen = Module.findExportByName(null, "dlopen"); var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext"); Interceptor.attach(dlopen, { onEnter: function (args) { var path_ptr = args[0]; var path = ptr(path_ptr).readCString(); console.log("[dlopen:]", path); }, onLeave: function (retval) { } }); Interceptor.attach(android_dlopen_ext, { onEnter: function (args) { var path_ptr = args[0]; var path = ptr(path_ptr).readCString(); console.log("[dlopen_ext:]", path); }, onLeave: function (retval) { if(this.fileName!=null && this.fileName.indexOf("libmsaoaidsec.so")>=0){ let JNI_OnLoad = Module.findExportByName(this.fileName, "JNI_OnLoad") console.log("[*] JNI_Onload " + JNI_OnLoad); } } }); }) }
hook后发现并没有JNI_OnLoad字眼,那么检测就在JNI_OnLoad之前,hook的时机选择上面提到的call_constructors,hook thread_create。
1 2 3 4 //获取call_constructors的偏移 C:\Users\n1ng>adb shell cepheus:/ $ readelf -sW /apex/com.android.runtime/bin/linker64 | grep call_constructors 715: 000000000004b140 556 FUNC LOCAL HIDDEN 11 __dl__ZN6soinfo17call_constructorsEv
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 function hook_linker_call_constructors() { let linker64_base_addr = Module.getBaseAddress('linker64') let offset = 0x4b140 // __dl__ZN6soinfo17call_constructorsEv let call_constructors = linker64_base_addr.add(offset) let listener = Interceptor.attach(call_constructors,{ onEnter:function(args){ console.log('hook_linker_call_constructors onEnter') let secmodule = Process.findModuleByName("libmsaoaidsec.so") if (secmodule != null){ // do something hook_pthred_create(); } } }) } function hook_pthred_create(){ console.log("[*] libmaoaidsec.so "+ Process.findModuleByName("libmsaoaidsec.so").base) Interceptor.attach(Module.findExportByName('libc.so','pthread_create'),{ onEnter(args){ let func_addr = args[2] console.log(`The thread Called function address is: ${func_addr}`) } }) }
hook结果
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 hook_linker_call_constructors onEnter [*] libmaoaidsec.so 0x6ed6140000 The thread Called function address is: 0x6ed615c544 The thread Called function address is: 0x6ed615c544 The thread Called function address is: 0x6ed615c544 The thread Called function address is: 0x6ed615c544 The thread Called function address is: 0x6ed615c544 The thread Called function address is: 0x6ed615c544 The thread Called function address is: 0x6ed615c544 The thread Called function address is: 0x6ed615c544 The thread Called function address is: 0x6ed615b8d4 The thread Called function address is: 0x6ed615b8d4 The thread Called function address is: 0x6ed615b8d4 The thread Called function address is: 0x6ed615b8d4 The thread Called function address is: 0x6ed615b8d4 The thread Called function address is: 0x6ed615b8d4 The thread Called function address is: 0x6ed615b8d4 The thread Called function address is: 0x6ed615b8d4 hook_linker_call_constructors onEnter [*] libmaoaidsec.so 0x6ed6140000 The thread Called function address is: 0x6ed6166e5c The thread Called function address is: 0x6ed6166e5c The thread Called function address is: 0x6ed6166e5c The thread Called function address is: 0x6ed6166e5c The thread Called function address is: 0x6ed6166e5c The thread Called function address is: 0x6ed6166e5c The thread Called function address is: 0x6ed6166e5c The thread Called function address is: 0x6ed6166e5c The thread Called function address is: 0x6ed6166e5c Process terminated [MI 9::com.shizhuang.duapp ]->
计算一下偏移
1 2 3 4 5 6 >>> data = [0x6ed615c544,0x6ed615b8d4,0x6ed6166e5c] >>> k = 0x6ed6140000 >>> for i in data: ... print(hex(i - k),end = ',') ... 0x1c544,0x1b8d4,0x26e5c
sub_1c544 ida中跳到1c544看看
byte_49030,byte_4904A,byte_49056并不是有意思的字符,并且前面有一些异或的操作,猜测就是对字符做了加密
hook然后dump一下看
1 2 3 4 5 6 function hook_so(){ var base_addr = Module.findBaseAddress("libmsaoaidsec.so"); var dump_addr = base_addr.add(0x49020); console.log(hexdump(dump_addr, {length: 0x8f})); }
1 2 3 4 5 6 7 8 9 10 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 6ec2d91020 2f 70 72 6f 63 2f 73 65 6c 66 2f 74 61 73 6b 00 /proc/self/task. 6ec2d91030 2f 70 72 6f 63 2f 73 65 6c 66 2f 74 61 73 6b 2f /proc/self/task/ 6ec2d91040 25 73 2f 73 74 61 74 75 73 00 67 75 6d 2d 6a 73 %s/status.gum-js 6ec2d91050 2d 6c 6f 6f 70 00 67 6d 61 69 6e 00 2f 70 72 6f -loop.gmain./pro 6ec2d91060 63 2f 73 65 6c 66 2f 66 64 00 6c 69 6e 6a 65 63 c/self/fd.linjec 6ec2d91070 74 6f 72 00 2f 70 72 6f 63 2f 73 65 6c 66 2f 6d tor./proc/self/m 6ec2d91080 61 70 73 00 2f 64 61 74 61 2f 6c 6f 63 61 6c 2f aps./data/local/ 6ec2d91090 74 6d 70 00 5f 41 47 45 4e 54 5f 31 2e 30 00 66 tmp._AGENT_1.0.f 6ec2d910a0 72 69 64 61 2d 61 67 65 6e 74 00 00 00 00 00 rida-agent.....
可以看到就是对一些常见检测中会用到的字符
/proc/self/task,查看线程信息,frida注入后会多出几个线程
gum-js-loop,特征字符
gmain,特征字符
/proc/self/fd,检测文件描述符信息
injector,特征字符
/proc/self/maps,frida注入后会在maps中显示一些包含特征字符的信息
/data/local/tmp,比较敏感的一个路径
_AGENT_1.0,特征字符
frida-agent,特征字符
但这里还没有做具体的检测。看到了几个可疑函数,跟过去看看
sub_1bfac 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 DIR *sub_1BFAC() { DIR *result; // x0 DIR *v1; // x19 struct dirent *v2; // x0 struct dirent *v3; // x25 const char *d_name; // x25 int v5; // w0 unsigned int v6; // w25 unsigned __int64 i; // x29 char v8[4]; // [xsp+14h] [xbp-46Ch] BYREF char haystack[512]; // [xsp+18h] [xbp-468h] BYREF char s[520]; // [xsp+218h] [xbp-268h] BYREF _ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)); result = opendir(byte_49020); if ( result ) { v1 = result; v2 = readdir(result); if ( v2 ) { v3 = v2; do { memset(s, 0, 0x200u); d_name = v3->d_name; if ( strcmp(d_name, byte_305E5) ) { if ( strcmp(d_name, &byte_305E4) ) { _snprintf_chk(s, 512LL, 0LL, 512LL, byte_49030, d_name); v5 = openat(-100, s, 0x80000, 0LL); if ( v5 ) { v6 = v5; memset(haystack, 0, sizeof(haystack)); for ( i = 0LL; i < 0x1FF; ++i ) { if ( _read_chk(v6, v8, 1LL, 1LL) != 1 ) break; if ( v8[0] == 10 ) break; haystack[i] = v8[0]; } if ( strstr(haystack, byte_4904A) || strstr(haystack, byte_49056) ) exit(0); close(v6); } } } v3 = readdir(v1); } while ( v3 ); } return (DIR *)closedir(v1); } return result; }
,继续往下跟到sub_1BFAC
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 DIR *sub_1BFAC() { DIR *result; // x0 DIR *v1; // x19 struct dirent *v2; // x0 struct dirent *v3; // x25 const char *d_name; // x25 int v5; // w0 unsigned int v6; // w25 unsigned __int64 i; // x29 char v8[4]; // [xsp+14h] [xbp-46Ch] BYREF char haystack[512]; // [xsp+18h] [xbp-468h] BYREF char s[520]; // [xsp+218h] [xbp-268h] BYREF _ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)); result = opendir(byte_49020); if ( result ) { v1 = result; v2 = readdir(result); if ( v2 ) { v3 = v2; do { memset(s, 0, 0x200u); d_name = v3->d_name; if ( strcmp(d_name, byte_305E5) ) { if ( strcmp(d_name, &byte_305E4) ) { _snprintf_chk(s, 512LL, 0LL, 512LL, byte_49030, d_name); v5 = openat(-100, s, 0x80000, 0LL); if ( v5 ) { v6 = v5; memset(haystack, 0, sizeof(haystack)); for ( i = 0LL; i < 0x1FF; ++i ) { if ( _read_chk(v6, v8, 1LL, 1LL) != 1 ) break; if ( v8[0] == 10 ) break; haystack[i] = v8[0]; } if ( strstr(haystack, byte_4904A) || strstr(haystack, byte_49056) ) exit(0); close(v6); } } } v3 = readdir(v1); } while ( v3 ); } return (DIR *)closedir(v1); } return result; }
result = opendir(byte_49020);这里就是open了/proc/self/task
strcmp(d_name, byte_305E5),即和”/proc/self/fd/%s”比较
这里即openat /proc/self/task/%s/status,”/proc/self/fd/%s”
1 2 _snprintf_chk(s, 512LL, 0LL, 512LL, byte_49030, d_name); v5 = openat(-100, s, 0x80000, 0LL);
就是检测线程名和fd有没有”gum-js-loop”或”gmain”特征字符
1 strstr(haystack, byte_4904A) || strstr(haystack, byte_49056)
sub_1c158 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 DIR *sub_1C158() { DIR *result; // x0 DIR *v1; // x19 struct dirent *v2; // x0 struct dirent *v3; // x22 char v4[16]; // [xsp+8h] [xbp-4C8h] BYREF int v5; // [xsp+18h] [xbp-4B8h] char file[512]; // [xsp+88h] [xbp-448h] BYREF char s[512]; // [xsp+288h] [xbp-248h] BYREF __int64 v8; // [xsp+488h] [xbp-48h] v8 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40); result = opendir(byte_4905C); if ( result ) { v1 = result; v2 = readdir(result); if ( v2 ) { v3 = v2; do { memset(s, 0, sizeof(s)); memset(file, 0, sizeof(file)); _snprintf_chk(file, 512LL, 0LL, 512LL, "/proc/self/fd/%s", v3->d_name); lstat(file, (struct stat *)v4); if ( (v5 & 0xF000) == 40960 ) { readlink(file, s, 0x200u); if ( strstr(s, byte_4906A) ) exit(0); } v3 = readdir(v1); } while ( v3 ); } return (DIR *)closedir(v1); } return result; }
这里就是获取fd,对特征字符”Injector”的判断
sub_1c26c 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 __int64 sub_1C26C() { ... ... v29 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40); v18 = 0LL; v19 = 0LL; v21 = &v18; v22 = 0LL; v20 = &v18; v0 = fopen(byte_49074, "r"); if ( v0 ) { v1 = v0; v27 = 0; v26 = 0LL; v25 = 0; v24 = 0LL; memset(s, 0, sizeof(s)); if ( !feof(v1) ) { v2 = off_47FC8; do { if ( !fgets(v28, 4096, v1) ) break; if ( sscanf(v28, "%lx-%lx %s %lx %s %ld %s", &v16, &v15, &v26, &v13, &v24, &v14, s) == 7 ) { if ( strstr(s, byte_49084) ) { if ( strchr((const char *)&v26, 120) ) { if ( strchr((const char *)&v26, 114) ) { sub_28258((int)&v12, s); std::_Rb_tree<std::string,std::string,std::_Identity<std::string>,std::less<std::string>,std::allocator<std::string>>::_M_insert_unique<std::string>( v17, &v12); v3 = (void *)(v12 - 24); if ( (void *)(v12 - 24) != v2 ) { v4 = (unsigned int *)(v12 - 8); do v5 = __ldaxr(v4); while ( __stlxr(v5 - 1, v4) ); if ( v5 <= 0 ) j_operator delete(v3); } } } } } } while ( !feof(v1) ); } fclose(v1); } v6 = v20; if ( v20 == &v18 ) { LABEL_22: std::_Rb_tree<std::string,std::string,std::_Identity<std::string>,std::less<std::string>,std::allocator<std::string>>::_M_erase( v17, v19); v10 = 0LL; v19 = 0LL; v20 = &v18; v21 = &v18; v22 = 0LL; } else { while ( 1 ) { v7 = operator new(0x158uLL); *(_OWORD *)(v7 + 184) = 0u; *(_OWORD *)(v7 + 168) = 0u; *(_OWORD *)(v7 + 152) = 0u; *(_OWORD *)(v7 + 136) = 0u; *(_OWORD *)(v7 + 120) = 0u; *(_BYTE *)(v7 + 200) = 0; *(_OWORD *)(v7 + 56) = 0u; *(_OWORD *)(v7 + 40) = 0u; *(_OWORD *)(v7 + 24) = 0u; *(_OWORD *)(v7 + 8) = 0u; *(_QWORD *)v7 = 0LL; *(_OWORD *)(v7 + 304) = 0u; *(_OWORD *)(v7 + 320) = 0u; *(_OWORD *)(v7 + 272) = 0u; *(_OWORD *)(v7 + 288) = 0u; *(_OWORD *)(v7 + 240) = 0u; *(_OWORD *)(v7 + 256) = 0u; *(_OWORD *)(v7 + 208) = 0u; *(_OWORD *)(v7 + 224) = 0u; v8 = (char *)v6[4]; v9 = (_QWORD *)v7; *(_QWORD *)(v7 + 336) = 0LL; if ( (sub_18774(v7, v8) & 1) == 0 || (sub_18240(v9 + 3, *v9) & 1) == 0 ) break; if ( (sub_1806C((int)v9 + 24, (int)byte_49094, byte_4909F) & 1) != 0 ) exit(0); sub_18F0C(v9); operator delete(v9); v6 = (__int64 *)sub_27B04(v6); if ( v6 == &v18 ) goto LABEL_22; } sub_18F0C(v9); operator delete(v9); v10 = v19; } return std::_Rb_tree<std::string,std::string,std::_Identity<std::string>,std::less<std::string>,std::allocator<std::string>>::_M_erase( v17, v10); }
sscanf(v28, “%lx-%lx %s %lx %s %ld %s”, &v16, &v15, &v26, &v13, &v24, &v14, s) == 7这里是open了maps文件,
/proc/self/maps 是一个特殊的文件,它包含了当前进程的内存映射信息。当你打开这个文件时,它会显示一个列表,其中包含了进程中每个内存区域的详细信息。这些信息通常包括:
起始地址(Start Address)
结束地址(End Address)
权限(如可读、可写、可执行)
共享/私有标志(Shared or Private)
关联的文件或设备(如果内存区域是文件映射的)
内存区域的偏移量
内存区域的类型(如匿名映射、文件映射、设备映射等) 当注入frida后,在maps文件中就会存在 frida-agent-64.so
、frida-agent-32.so
等文件。
七个字段值依次为:内存区域(start和end)–权限–文件在内存中的偏移量–设备号–文件索引节点–路径
检测了路径是否在/data/local/tmp目录,是否是可读可执行的程序,以及”frida-agent”特征字符
sub_1b8d4 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 void __noreturn sub_1B8D4() { unsigned int v0; // w0 __useconds_t v1; // w19 unsigned int v2; // w0 v0 = sub_CB28(); if ( v0 >= 0x64 ) v1 = v0; else v1 = 2000000; while ( 1 ) { v2 = sub_1AE48(); if ( v2 == -1 || v2 && ((unsigned int)sub_1AB54(v2) & 1) == 0 || (unsigned int)sub_1B730() == 777 ) sub_11FA4(); usleep(v1); } }
sub_1ae48 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 __int64 sub_1AE48() { ... ... v32 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40); memset(s, 0, sizeof(s)); *(_OWORD *)v30 = xmmword_304DF; v0 = _strlen_chk(v30, 0x10u); if ( (int)v0 >= 1 ) { if ( v0 < 2uLL ) { v1 = 0LL; LABEL_7: v7 = v0 - v1; v8 = &v30[v1]; do { v9 = dword_305BC[(unsigned int)v1 % 3]; --v7; LODWORD(v1) = v1 + 1; *v8++ ^= v9; } while ( v7 ); goto LABEL_9; } v1 = v0 - (unsigned __int64)(v0 & 1); v2 = 0; v3 = 1; v4 = &v30[1]; v5 = v1; do { v6 = dword_305BC[v3 % 3]; v5 -= 2LL; v3 += 2; LOBYTE(v6) = *v4 ^ v6; *(v4 - 1) ^= LOBYTE(dword_305BC[v2 % 3]); *v4 = v6; v4 += 2; v2 += 2; } while ( v5 ); if ( (v0 & 1) != 0 ) goto LABEL_7; } LABEL_9: _sprintf_chk(s, 0LL, 1024LL, v30, (unsigned int)dword_49014); v10 = fopen(s, "r"); if ( v10 ) { v11 = v10; memset(haystack, 0, sizeof(haystack)); v28 = 0; v27 = 0xA3CD; v26 = 0xCEC9DBC2FAC8D5CDLL; v12 = _strlen_chk((const char *)&v26, 0xBu); if ( (int)v12 < 1 ) goto LABEL_19; if ( v12 < 2uLL ) { v13 = 0LL; LABEL_17: v20 = v12 - v13; v21 = (char *)&v26 + v13; do { v22 = dword_305BC[(unsigned int)v13 % 3]; --v20; LODWORD(v13) = v13 + 1; *v21++ ^= v22; } while ( v20 ); goto LABEL_19; } v13 = v12 - (unsigned __int64)(v12 & 1); v15 = 0; v16 = 1; v17 = (char *)&v26 + 1; v18 = v13; do { v19 = dword_305BC[v16 % 3]; v18 -= 2LL; v16 += 2; LOBYTE(v19) = *v17 ^ v19; *(v17 - 1) ^= LOBYTE(dword_305BC[v15 % 3]); *v17 = v19; v17 += 2; v15 += 2; } while ( v18 ); if ( (v12 & 1) != 0 ) goto LABEL_17; LABEL_19: while ( fgets(haystack, 1024, v11) ) { v23 = strstr(haystack, (const char *)&v26); if ( v23 ) { v24 = atoi(v23 + 10); if ( v24 ) { v14 = v24; fclose(v11); return v14; } break; } } fclose(v11); return 0; } else { return (unsigned int)-1; } }
这里就是获取进程信息,看TracePid的值(如果TracePid的值为0说明正在被调试)
sub_1ab54 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 FILE *__fastcall sub_1AB54(unsigned int a1) { ... ... v30 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40); memset(s, 0, sizeof(s)); *(_OWORD *)v28 = xmmword_304DF; if ( a1 == -1 ) return 0LL; v2 = _strlen_chk(v28, 0x10u); if ( (int)v2 >= 1 ) { if ( v2 >= 2uLL ) { v3 = v2 - (unsigned __int64)(v2 & 1); v4 = 0; v5 = 1; v6 = &v28[1]; v7 = v3; do { v8 = dword_305BC[v5 % 3]; v7 -= 2LL; v5 += 2; LOBYTE(v8) = *v6 ^ v8; *(v6 - 1) ^= LOBYTE(dword_305BC[v4 % 3]); *v6 = v8; v6 += 2; v4 += 2; } while ( v7 ); if ( (v2 & 1) == 0 ) goto LABEL_10; } else { v3 = 0LL; } v9 = v2 - v3; v10 = &v28[v3]; do { v11 = dword_305BC[(unsigned int)v3 % 3]; --v9; LODWORD(v3) = v3 + 1; *v10++ ^= v11; } while ( v9 ); } LABEL_10: _sprintf_chk(s, 0LL, 1024LL, v28, a1); result = fopen(s, "r"); if ( !result ) return result; v13 = result; memset(haystack, 0, sizeof(haystack)); v26 = 157; *(_DWORD *)needle = 0xFDC0F7C9; v14 = _strlen_chk(needle, 6u); if ( (int)v14 < 1 ) goto LABEL_19; if ( v14 < 2uLL ) { v15 = 0LL; LABEL_17: v21 = v14 - v15; v22 = &needle[v15]; do { v23 = dword_305BC[(unsigned int)v15 % 3]; --v21; LODWORD(v15) = v15 + 1; *v22++ ^= v23; } while ( v21 ); goto LABEL_19; } v15 = v14 - (unsigned __int64)(v14 & 1); v16 = 0; v17 = 1; v18 = &needle[1]; v19 = v15; do { v20 = dword_305BC[v17 % 3]; v19 -= 2LL; v17 += 2; LOBYTE(v20) = *v18 ^ v20; *(v18 - 1) ^= LOBYTE(dword_305BC[v16 % 3]); *v18 = v20; v18 += 2; v16 += 2; } while ( v19 ); if ( (v14 & 1) != 0 ) goto LABEL_17; do { LABEL_19: if ( !fgets(haystack, 1024, v13) ) goto LABEL_22; v24 = strstr(haystack, needle); } while ( !v24 ); if ( atoi(v24 + 5) == dword_49014 ) { LABEL_22: fclose(v13); return (FILE *)(&byte_0 + 1); } fclose(v13); return 0LL; }
这里就是打开了获取status,PPid
sub_1b730 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 __int64 sub_1B730() { ... ... v16 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40); memset(s, 0, sizeof(s)); memset(name, 0, sizeof(name)); memset(v13, 0, sizeof(v13)); v0 = getpid(); _sprintf_chk(name, 0LL, 1024LL, "/proc/%d/task", v0); v1 = opendir(name); if ( !v1 ) return 0xFFFFFFFFLL; v2 = v1; v3 = readdir(v1); if ( v3 ) { while ( 1 ) { d_name = v3->d_name; v4 = v3->d_name[0]; if ( v4 ) { v6 = &v3->d_name[1]; while ( (unsigned int)v4 - 48 > 9 ) { v7 = (unsigned __int8)*v6++; v4 = v7; if ( !v7 ) goto LABEL_14; } v8 = getpid(); _sprintf_chk(s, 0LL, 512LL, "/proc/%d/task/%s/stat", v8, d_name); result = open(s, 0); if ( (_DWORD)result == -1 ) return result; v10 = result; result = _read_chk(result, v13, 1024LL, 1024LL); if ( result == -1 ) return result; v11 = 0LL; do v12 = (unsigned __int8)v13[v11++]; while ( v12 != 0x29 ); close(v10); if ( ((unsigned __int8)v13[(unsigned int)(v11 + 1)] | 0x20) == 't' && v13[(unsigned int)(v11 + 2)] == ' ' ) return 777LL; } LABEL_14: v3 = readdir(v2); if ( !v3 ) goto LABEL_15; } } else { LABEL_15: closedir(v2); return 0LL; } }
就是获取线程信息然后看线程的状态是否为”t”。在 /proc
文件系统中,进程和线程的状态字符通常有以下几种常见的表示:
R
: 运行 (running or runnable)
S
: 睡眠 (interruptible sleep)
D
: 不可中断的睡眠 (uninterruptible sleep)
T
: 停止 (stopped)
Z
: 僵尸 (zombie)
X
: 退出 (dead)
sub_26e5c 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 __int64 sub_26E5C() { unsigned int v0; // w0 int v1; // w8 unsigned int v3; // [xsp+10h] [xbp-70h] bool v4; // [xsp+16h] [xbp-6Ah] bool v5; // [xsp+17h] [xbp-69h] _ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)); v0 = sub_C930(); v1 = -1782206741; v3 = v0; while ( 1 ) { while ( 1 ) { while ( v1 > -1137393265 ) { if ( v1 > -499842569 ) { if ( v1 == -499842568 ) { if ( (sub_1678C() & 1) != 0 ) v1 = -1150116660; else v1 = -1827189700; } else { v5 = v3 != 0; v1 = -1137393264; } } else if ( v1 == -1137393264 ) { if ( v4 && v5 ) v1 = -499842568; else v1 = -1150116660; } else { v1 = -1372371036; } } if ( v1 > -1372371037 ) break; if ( v1 == -1827189700 ) { sub_269AC(0LL); v1 = -1150116660; } else { v1 = -779687515; } } if ( v1 != -1372371036 ) break; v4 = v3 < 0xD; v1 = 629336195; } return 0LL; }
sub_1678c 这函数比较长有一千多行,这里就不放了
看了下有
获取/proc/%d/cmdline,获取maps信息,判断是否加载了libmsaoaidsec.so
对Android SDK版本获取,获取META-INF/CERT.RSA,META-INF/ANDROID.RSA,后面也看到一些和rsa有关的数字,这里可能是在做签名检测之类的?
总结 这样看来似乎就是一些特征字符的检测,那么我们试着用hluda等魔改的frida来hook,发现就不会退出了
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 3049155267@qq.com