对某APP的逆向之旅(3)
来源:互联网 发布:javascript什么意思 编辑:程序博客网 时间:2024/05/20 08:22
书接上回,本次对前面解密后的so进行分析
来到start函数
进入主函数 sub_9960
首先创建本地socket,用于通信,然后while循环中,不断读取java层的消息,执行对应的功能函数。
创建socket的代码如下:
void __fastcall sub_9960(int a1, void **a2){ ...... ...... port = atoi(&s); v6 = vars; socket = sub_A258("127.0.0.1", port); v8 = vars; *(_DWORD *)(v6 + 4) = socket; sub_A064(*(_DWORD *)(v8 + 4) > 0); pid = getppid(); pid2 = pid;
循环处理的功能子函数如下:
void __fastcall sub_9960(int a1, void **a2){ ...... ...... do { v16 = (_BYTE *)*v13; ++v13; v28 = *v16; v17 = (const char **)sub_9F40(); v18 = v17; switch ( v28 ) { case 35: sub_A198(*(_DWORD *)(vars + 4), v29); break; default: break; case 72: v28 = *(_DWORD *)(vars + 4); v24 = hook(vars, v17, v31); sub_A0B8(v28, (int)v24, 72); break; case 73: v28 = *(_DWORD *)(vars + 4); v23 = sub_ABF4(); sub_A0B8(v28, v23, 73); break; case 98: v28 = *(_DWORD *)(vars + 4); v22 = sub_AC84(); sub_A0B8(v28, v22, 98); break; case 99: v28 = *(_DWORD *)(vars + 4); v21 = sub_AAFC(); sub_A0B8(v28, v21, 99); break; case 112: v28 = *(_DWORD *)(vars + 4); v20 = sub_AB34(); sub_A0B8(v28, v20, 112); break; case 113: sub_AA90(vars); return; case 116: sub_B144(v17); break; case 117: v28 = *(_DWORD *)(vars + 4); v19 = sub_9FF0() != 0; sub_A0B8(v28, v19, 117); break; } ++v12; } while ( v12 != v15 ); if ( !v18 ) goto LABEL_3; free(v18); v31 = 0; memset(&buf, 0, 0x200u); socket2 = *(_DWORD *)(vars + 4); if ( socket2 > 0 ) goto LABEL_4; } } else {LABEL_4: if ( recv(socket2, &buf, 0x200u, 0) > 0 ) goto LABEL_5; } sub_AA90(vars);}
函数首先进入的是hook函数,该函数名是我自己修改的。
本次,我们主要分析该so函数的核心,hook的原理及实现。
来到hook函数,如下:
const char *__fastcall hook(int a1, const char **a2, int a3){ int v3; // r4@1 const char *result; // r0@2 int v5; // r0@3 int v6; // r2@3 unsigned int v7; // r3@5 v3 = a1; if ( a3 ) { result = *a2; if ( *a2 ) { v5 = atoi(result); v6 = *(_DWORD *)(v3 + 16); *(_DWORD *)v3 = v5; if ( v5 == v6 ) { result = (const char *)1; } else { result = (const char *)hookmain(v5, (_DWORD *)(v3 + 12), dword_11B08); if ( result ) { result = 0; } else { v7 = *(_DWORD *)(v3 + 12); if ( v7 > 0x8000 && v7 != -1 ) { result = (const char *)1; *(_DWORD *)(v3 + 16) = *(_DWORD *)v3; } } } } } else { result = 0; } return result;}
继续跟进
int __fastcall hook(int a1, _DWORD *a2, int a3){ _DWORD *v3; // r5@1 int v4; // r6@1 int v5; // r7@1 int v6; // r5@2 char *v7; // r3@4 char v9; // [sp+8h] [bp-80h]@1 __mode_t mode; // [sp+18h] [bp-70h]@3 v3 = a2; v4 = a1; v5 = a3; if ( stat(timescale_path[0], (struct stat *)&v9) ) { v6 = -1; } else { *(_DWORD *)_errno() = 0; chmod(timescale_path[0], (mode | 4) & 0xFFFF); if ( v5 ) v7 = "1"; else v7 = "0"; v6 = inject(v4, timescale_path[0], "init", v7, v3); chmod(timescale_path[0], (unsigned __int16)mode); } return v6;}
可以看到,首先会修改文件的权限,然后进行注入。注意里面的函数名都是我分析后,自己修改过的
来到inject函数,代码片段如下:
v21 = src + 15360; v22 = get_remote_addr(v10, linker_path[0], (int)&dlopen); v23 = get_remote_addr(v10, linker_path[0], (int)&dlsym); v24 = get_remote_addr(v10, linker_path[0], (int)&dlclose); dlopen_addr_s = v22; dlsym_addr_s = v23; dlclose_addr_s = v24; strcpy((char *)&unk_110DC, v28); dlopen_param1_s = (char *)&unk_110DC + v21 - (_DWORD)&inject_start_s; strcpy((char *)&unk_111DC, v5); dlsym_param2_s = (char *)&unk_111DC + v21 - (_DWORD)&inject_start_s; saved_hook_addr = 0x4A0 + v21; saved_cpsr_s = v56; unk_112DC = *(_DWORD *)&dest; unk_112E0 = v41; unk_112E4 = v42; unk_112E8 = v43; unk_112EC = v44; unk_112F0 = v45; unk_112F4 = v46; unk_112F8 = v47; unk_112FC = v48; unk_11300 = v49; unk_11304 = v50; unk_11308 = v51; unk_1130C = v52; unk_11310 = v53; unk_11314 = v54; unk_11318 = v55; saved_r0_pc_s = 0x2A0 + v21; v25 = strlen(s); memcpy(&unk_113DC, s, v25 + 1); inject_function_param_s = 0x3A0 + v21; write_remote_memory_main(v10, v21, &inject_start_s, 0x600u); memcpy(&src, &dest, 0x48u); v38 = v21; v39 = v21; v26 = sub_B410(v10, &src); sub_B5EC(v10);
前面为获取dlopen等系统函数的地址,这个没什么可说的,不明白的,建议上网找下hook注入方面的文章看看。
来到修改内存的函数write_remote_memory_main,如下:
signed int __fastcall write_remote_memory_main(int pid, int remote_clock_gettime, void *pMem, unsigned int length){ int remote_clock_gettime1; // r11@1 int pMem1; // r9@1 unsigned int length1; // r4@1 int pid1; // r8@1 unsigned int v9; // r10@3 int v10; // r7@3 int v11; // r4@4 int v12; // r5@4 int v13; // r5@6 int v14; // r3@8 int v15; // [sp+4h] [bp-34h]@3 __int32 dest; // [sp+Ch] [bp-2Ch]@5 remote_clock_gettime1 = remote_clock_gettime; pMem1 = (int)pMem; length1 = length; pid1 = pid; if ( write_remote_memory1(pid, pMem, length, remote_clock_gettime) == -1 )// 第一种写入内存方式失败,则执行第二种写入内存的方式,采用的是ptrace方式写入 { v9 = length1 >> 2; // v9 = 2 v10 = remote_clock_gettime1; v15 = length1 & 3; if ( length1 >> 2 ) { v11 = remote_clock_gettime1; v12 = 0; do { memcpy(&dest, (const void *)(v11 + pMem1 - remote_clock_gettime1), 4u); ++v12; ptrace(PTRACE_POKETEXT, pid1, v11, dest);// int ptrace(int request, int pid, int addr, int data); // PTRACE_POKETEXT, PTRACE_POKEDATA往内存地址中写入一个字节。内存地址由addr给出。 v11 += 4; } while ( v12 != v9 ); v13 = 4 * v12; // hook的前8个字节 v10 = remote_clock_gettime1 + v13; pMem1 += v13; } if ( v15 ) { dest = ptrace(PTRACE_PEEKTEXT, pid1, v10, 0);// 从内存地址中读取一个字节 v14 = 0; do { *((_BYTE *)&dest + v14) = *(_BYTE *)(pMem1 + v14); ++v14; } while ( v14 != v15 ); ptrace(PTRACE_POKETEXT, pid1, v10, dest); } } return 1;}
其中采用了两种方式写入内存,分别为:利用修改/proc/pid/mem实现和利用ptrace实现。
下面看下第一种方式的实现:
ssize_t __fastcall write_remote_memory1(int pid, const void *pMem, size_t length, __off_t remote_clock_gettime){ size_t v4; // r5@1 const void *v5; // r6@1 __off_t v6; // r7@1 int fd; // r0@1 int v8; // r8@1 ssize_t v9; // r5@2 ssize_t result; // r0@4 char s; // [sp+4h] [bp-34h]@1 int v12; // [sp+1Ch] [bp-1Ch]@1 v4 = length; v5 = pMem; v6 = remote_clock_gettime; v12 = _stack_chk_guard; snprintf(&s, 0x18u, "/proc/%u/mem", pid); fd = open(&s, 1); v8 = fd; if ( fd == -1 ) { v9 = -1; } else { lseek(fd, v6, 0); v9 = write(v8, v5, v4); close(v8); } result = v9; if ( v12 != _stack_chk_guard ) _stack_chk_fail(v9); return result;
比较简单,直接修改/proc/pid/mem实现。
第二种方式,是通过inline hook系统函数的前8个字节实现的。
其实,还有第三种方式的,有时间再详细介绍吧
0 0
- 对某APP的逆向之旅(3)
- 对某APP的逆向之旅(1)
- 对某APP的逆向之旅(2)
- 对某游戏发包流程的一次逆向之旅
- 对恶意APP"Roidsec"的逆向分析
- 对一个免费通话恶意APP的逆向分析
- 对恶意APP"淘宝宝贝分享图"的逆向分析
- Android逆向之旅---分析某直播App的协议加密原理以及调用加密方法进行协议参数构造
- Android逆向之旅---某直播APP的协议加密原理分析以及调用加密方法进行协议参数构造
- APP逆向(上)
- APP逆向(中)
- Android逆向之旅---获取加固后应用App的所有方法信息
- 逆向实战之对某航软件URL参数的解密
- 一次函数调用过程对堆栈的逆向分析之旅
- 对深蓝少年之机甲勇士的逆向分析
- 对好搜小说app哈希算法的一次逆向
- 逆向某停车app(原创)
- apktool(android app逆向)
- hadoop实践(二)-hadoop和ssh配置
- 第十六周项目1-(2)-小玩文件
- 企业网站建设的作用与意义
- 预防discuz网站的cc攻击
- C++ 21----- 用cin输入
- 对某APP的逆向之旅(3)
- PRO2-Day3
- 将自定义python模块增加到类库搜索路径下面
- 深入浅出聊Unity3D优化:从Draw Calls到GC
- Androidstudio 设置永久行号
- UIWebView相关API学习
- linux 安装jdk 和 tomcat
- 理解 Objective-C Runtime
- VS中常用的快捷键 提速