【Android 逆向】ART 函数抽取加壳 ⑤ ( unistd.h#execve 函数分析 | 使用自定义的 myexecve 函数替换 libc.so#execve 函数 )


两篇博客中 , 简单介绍了 禁用 dex2oat 机制 的原理 , 下面开始 实现 dex2oat 禁用功能 ;


【Android 逆向】ART 函数抽取加壳 ③ ( 禁用 dex2oat 操作 HOOK 点介绍 | 集成 InLineHook ) 博客中 , 介绍了 HOOK 点 , 以及 集成 HOOK C 代码的库 InLineHook ;


【Android 逆向】ART 函数抽取加壳 ④ ( 对 libc.so#execve 函数进行内联 HOOK 操作 ) 博客中 , 对 libc.so#execve 函数 进行了 内联 HOOK 操作 , 可以对该函数进行拦截 ;


本篇博客实现 自定义的 myexecve 函数 替换 libc.so#execve 函数 ;





一、bionic/libc/include/unistd.h#execve 函数分析



libc.so#execve 函数 定义在 Android 源码的 " bionic/libc/include/unistd.h " 头文件中 , 函数原型如下 :

int execv(const char* __path, char* const* __argv);
int execvp(const char* __file, char* const* __argv);
int execvpe(const char* __file, char* const* __argv, char* const* __envp) __INTRODUCED_IN(21);
// ★ 此处为 execve 函数原型
int execve(const char* __file, char* const* __argv, char* const* __envp);

源码地址 : http://androidxref.com/8.0.0_r4/xref/bionic/libc/include/unistd.h


" int execve(const char* __file, char* const* __argv, char* const* __envp); " 函数解析 :

  • const char* __file 参数 : 表示要运行的 二进制程序文件路径 , 这里指的是 Dex 字节码文件路径 , 如果要拦截 指定路径中的字节码文件不进行 OAT 优化 , 可以再此处进行过滤 , 检测到某个文件路径 , 直接返回空不执行任何代码逻辑 ;




二、使用自定义的 myexecve 函数替换 libc.so#execve 函数



在 博客中 , 介绍了调用 " hook\include\inlineHook.h " 中定义的 " registerInlineHook " 函数注册被 Hook 的函数 , 其原型如下 :

enum ele7en_status registerInlineHook(uint32_t target_addr, uint32_t new_addr, uint32_t **proto_addr);

uint32_t target_addr 参数是 execve 函数在 libc.so 的地址 , uint32_t new_addr 参数是自定义替换 execve 函数执行的函数地址 , uint32_t **proto_addr 参数是 execve 原函数的地址 ;


首先 , 定义一个函数指针变量 , 接收

" int execve(const char* __file, char* const* __argv, char* const* __envp); " 函数

的地址 , 之后如果需要真实调用时需要用到 ;

int ( *android_execve )(const char* __file, char* const* __argv, char* const* __envp);

定义指针 , 指向一个函数 , 函数的参数是 const char* __file, char* const* __argv, char* const* __envp , 返回值是 int 类型 ;


该函数指针在进行 " hook\include\inlineHook.h " 中定义的 " registerInlineHook " 函数时 被赋值 ;


复杂函数指针参考博客 【C 语言】指针 与 数组 ( 指针 | 数组 | 指针运算 | 数组访问方式 | 字符串 | 指针数组 | 数组指针 | 多维数组 | 多维指针 | 数组参数 | 函数指针 | 复杂指针解读) 六. 函数指针 3. 解读 复杂的 指针声明 ( 难点 重点 | ①找出中心标识符 ②先右 后左 看 确定类型 提取 ③ 继续分析 左右看 … ) 进行分析 ;


复杂指针阅读技巧 ( 主要是 区分 函数指针 和 数组指针 ) 右左法则 :

  • 1.最里层标示符 : 先找到最里层的圆括号中的标示符;

    数组指针和函数指针的标示符 ( 指针变量名 ) 都在中间的圆括号中, 因此该步骤先找到指针变量名

  • 2.右左看 : 先往右看, 再往左看 ;

  • 3.确定类型 : 遇到 圆括号 “()” 或者 方括号 “[]” 确定部分类型, 调转方向 ; 遇到 * 说明是指针 , 每次确定完一个类型 , 将该类型提取出来 , 分析剩下的 ;

    一种可能性 :
    int (*) [5] , 遇到中括号说明是数组指针类型,
    int(*)(int, int) , 遇到圆括号 说明是函数指针类型 ;

  • 4.重复 2 , 3 步骤 : 一直重复, 直到 指针 阅读结束 ;


然后 , 定义 自定义的 execve 函数 , 用于 替换 Android 自带的 execve 函数 , 主要用于拦截 dex2oat 字节码文件 ,

  • 这里将需要拦截的字节码都放在 dex2oat 目录中 , 检测到 dex2oat 目录 , 就退出 ;
  • 不需要拦截的 , 直接调用原函数执行 ;

源码示例 :

// 用于接收 Android 自带的 execve 函数
int (*android_execve)(const char *__file, char *const *__argv, char *const *__envp);

// 自定义的 execve 函数 , 用于替换 Android 自带的 execve 函数
// 主要用于拦截 dex2oat 字节码文件
int myexecve(const char *__file, char *const *__argv, char *const *__envp) {
    
    
	// 这里将需要拦截的字节码都放在 dex2oat 目录中
    if (strstr(__file, "dex2oat")) {
    
    
        return 0;
    } else {
    
    
    	// 不需要拦截的 , 直接调用原函数执行 
        return android_execve(__file, __argv, __envp);
    }
}

猜你喜欢

转载自blog.csdn.net/han1202012/article/details/127485216