Android Exception Hook
承接上一篇文章Android Inline Hook,接下来我们看一下android系统中基于异常的hook方式,这种方式与inline hook相比实现较为简单,但执行效率是它的短板。
exception hook的执行流程大致如下:

如图所示,在hook过程中需要多次对hook点指令和hook点的下一条指令进行修改,由此造成在执行效率上的损耗。
首先我们需要将hook点指令替换为一条不合法的异常指令,当程序执行到该位置时进程会接收到信号SIGILL(illegal instruction),然后进入到我们注册的SIgnal Handler中,在信号处理函里我们需要做两件事,一是执行我们的hook逻辑(如修改寄存器的值),二是恢复hook点指令并将hook点指令的下一条指令替换为异常指令,再恢复程序的运行。当程序运行到hook点的下一条指令时会再次触发异常进入信号处理函数,这一次我们需要在信号处理函数中将hook点指令再次替换为异常指令,然后恢复hook点的下一条指令,最后恢复程序运行。
由此可见,我们在信号处理函数中需要对异常的发生位置进行判断,对hook点跟hook点的下一条指令进行区分。当然最重要的是理解Linux系统中的信号机制。
void signal_handler(int signum, siginfo_t *Ssiginfo, void *context)
{
//信号处理函数
ucontext_t *uc = context;
struct sigcontext *sigc = &uc->uc_mcontext;
}
struct sigaction sig;
//initialize the signal set
sigemptyset(&sig.sa_mask);
//make sigaction.sa_sigaction specifies the
//signal-handling function for signum
sig.sa_flags = SA_SIGINFO;
//attach our handler
sig.sa_sigaction = signal_handler;
sigaction(SIGILL, &sig, NULL);
通过sigaction函数对信号进行注册后我们便可以在信号处理函数中对其进行处理。Linux用户手册中对该函数进行了详细的说明,可参阅:Linux Programmer's Manual SIGACTION(2)
在信号处理函数中我们可以通过结构体sigcontext获取异常发生时各个寄存器的信息,其定义如下:
struct sigcontext {
unsigned long trap_no; unsigned long error_code; unsigned long oldmask;
unsigned long arm_r0; unsigned long arm_r1; unsigned long arm_r2;
unsigned long arm_r3; unsigned long arm_r4; unsigned long arm_r5;
unsigned long arm_r6; unsigned long arm_r7; unsigned long arm_r8;
unsigned long arm_r9; unsigned long arm_r10; unsigned long arm_fp;
unsigned long arm_ip; unsigned long arm_sp; unsigned long arm_lr;
unsigned long arm_pc; unsigned long arm_cpsr;unsigned long fault_address;
};
例如我们可以通过pc寄存器的值确定程序执行的位置。
完整程序如下:
#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <ucontext.h>
#include <sys/mman.h> int g_code_type;
long g_code_address;
uint32_t g_code_origin;
uint32_t g_code_next; long get_module_addr(pid_t pid, const char *module_name)
{
FILE *fp;
char file_path[];
char file_line[];
if (pid < ) {
snprintf(file_path, sizeof(file_path), "/proc/self/maps");
} else {
snprintf(file_path, sizeof(file_path), "/proc/%d/maps", pid);
}
fp = fopen(file_path, "r");
if (fp == NULL) {
return -;
}
long addr_start = -, addr_end = ;
while (fgets(file_line, sizeof(file_line), fp)) {
if (strstr(file_line, module_name)) {
if ( == sscanf(file_line, "%8lx-%8lx", &addr_start, &addr_end)) {
break;
}
}
}
fclose(fp);
return addr_start;
} bool change_addr_attr(long address, bool writable) {
//根据内存页大小对齐
long page_size = sysconf(_SC_PAGESIZE);
long page_start = address & (~(page_size - ));
if (writable == true) {
return mprotect((void*)page_start, page_size, PROT_READ | PROT_WRITE | PROT_EXEC) != -;
} else {
return mprotect((void*)page_start, page_size, PROT_READ | PROT_EXEC) != -;
}
} bool write_code(long address, uint32_t data)
{
if (change_addr_attr(address, true) == false) {
return false;
}
if (g_code_type == IS_THUMB) {
*((uint16_t*)address) = (uint16_t)data;
} else {
*((uint32_t*)address) = data;
}
return change_addr_attr(address, false);
} bool write_ill_instruction(long address, uint32_t *save)
{
if (g_code_type == IS_THUMB) {
*save = *((uint16_t*)address);
} else if (g_code_type == IS_ARM) {
*save = *((uint32_t*)address);
}
return write_code(address, 0xFFFFFFFF);
} static void signal_handler(int signum, siginfo_t *Ssiginfo, void *context)
{
ucontext_t *uc = context;
struct sigcontext *sigc = &uc->uc_mcontext; long next_address = g_code_address + (IS_ARM ? : ); if (sigc->arm_pc == g_code_address) {
//恢复hook点指令
write_code(g_code_address, g_code_origin);
//将hook点下一条指令改为异常指令
write_ill_instruction(next_address, &g_code_next);
} else if (sigc->arm_pc == next_address){
//恢复hook点下一条指令
write_code(next_address, g_code_next);
//将hook点指令改为异常指令
write_ill_instruction(g_code_address, &g_code_origin);
} else {
exit(EXIT_FAILURE);
}
} bool hook_exception_make(const char *library, long address, enum code_type type)
{
g_code_type = type; struct sigaction sig;
sigemptyset(&sig.sa_mask);
sig.sa_flags = SA_SIGINFO;
sig.sa_sigaction = signal_handler;
sigaction(SIGILL, &sig, NULL); long target_address = get_module_addr(-, library);
g_code_address = target_address + address;
return write_ill_instruction(g_code_address, &g_code_origin);
}
Android Exception Hook的更多相关文章
- 使用cydia substrate 来进行android native hook
cydia不仅可以hook java代码,同样可以hook native代码,下面举一个例子来进行android native hook 我是在网上找到的supermathhook这个项目,在他基 ...
- android ART hook
0x00 前言 之前一直都是在Dalvik 虚拟机上在折腾,从Android 4.4开始开始引入ART,到5.0已经成为默认选择.而且最近看到阿里开源的 Dexposed 框架,已经提供了对于andr ...
- Android Xpose Hook(一)
实验环境: Droid4x模拟器 (目前Android版本4.2.2) Android Studio 1.下载相关工具 XposedInstaller下载 http://repo.xp ...
- ***CI异常记录到日志:CodeIgniter中设计一个全局exception hook
在CodeIgniter中,当发生异常时,经常要通知系统管理员,因此有必要在全局的高度上 捕捉异常,因此可以写一个hook, 比如在config目录的hook.php中,加入: $hook['pre_ ...
- android inline hook
最近终于沉下心来对着书把hook跟注入方面的代码敲了一遍,打算写几个博客把它们记录下来. 第一次介绍一下我感觉难度最大的inline hook,实现代码参考了腾讯GAD的游戏安全入门. inline ...
- Android Native Hook技术(二)
Hook技术应用 已经介绍了安卓 Native hook 原理,这里介绍 hook 技术的应用,及 Cyida Substrate 框架. 分析某APP,发现其POST请求数据经过加密,我们希望还原其 ...
- Android Native Hook技术(一)
原理分析 ADBI是一个著名的安卓平台hook框架,基于 动态库注入 与 inline hook 技术实现.该框架主要由2个模块构成:1)hijack负责将so注入到目标进程空间,2)libbase是 ...
- android的hook方面知识点
android hook分为另种: native层hook---理解ELF文件 java层---虚拟机特性和Java上的反射的作用 注入代码: 存放在哪? 用mmap函数分配临时内存来完成代码存放,对 ...
- Android Exception 13(Can't create handler inside thread that has not called Looper.prepare())
10-12 17:02:55.500: E/AndroidRuntime(28343): FATAL EXCEPTION: Timer-2 10-12 17:02:55.500: E/AndroidR ...
随机推荐
- 64位CreateProcess逆向:(二)0环下参数的整合即创建进程的整体流程
转载:https://bbs.pediy.com/thread-207683.htm 点击下面进入总目录: 64位Windows创建64位进程逆向分析(总目录) 在上一篇文章中,我们介绍了Create ...
- 屠龙术&平凡的世界
x 听过很多道理,却依然过不好这一生 小时候,总觉得世上肯定存在屠龙术.就像<倚天屠龙记>里面张无忌学的<乾坤大挪移>/<九阳真经>一般, 学会了就可以一人单挑光明 ...
- Js限制Input框只能输入数字
<input type="text" onkeyup="value=value.replace(/[^\d]/g,'')" /> <input ...
- Bootstrap 下拉框点击没反应
应该是第一次点击下拉框没反应,我把HTML复制出来单独运行,都是好的,就是在项目里面无法运行 哪里的js出问题了?找不到原因,控制台里的js也不报错 解决方法: $(function () { $(' ...
- [转] ABP框架Web API跨域问题的解决方案
原文地址:https://www.cnblogs.com/farb/p/ABPWebAPICrossDomain.html 1.在Web Api 项目下安装 Microsoft.AspNet.Web ...
- HDU6608-Fansblog(Miller_Rabbin素数判定,威尔逊定理应用,乘法逆元)
Problem Description Farmer John keeps a website called ‘FansBlog’ .Everyday , there are many people ...
- nginx实现tcp负载均衡
1 安装支持库 yum -y install make zlib zlib-devel gcc-c++ libtool openssl openssl-devel yum install pcre-d ...
- Java基础笔试练习(九)
1.下面所示的java代码,运行时,会产生()类型的异常 ? int Arry_a[] = new int[10]; System.out.println(Arry_a[10]); A.Arithme ...
- c++模板使用及常见问题
一.为什么使用模板?? 使用模板的目的是为了避免重复声明和定义一系列基本功能相同的函数或者类,其区别因传入参数的不同而产生不同类型的数据,其基本工作过程都是一致的! 二.调用模板函数产生不明确问题 ( ...
- 酷!微软发布新终端工具,Win 10 将自带 Linux 内核
原创:技术最前线(id:TopITNews) 北京时间 5 月 7 日,2019 年微软 Build 开发者大会在雷德蒙德召开.今年大会上亮点很多,本文汇总一些和开发者相关的内容. 1. Window ...