改造 Cydia Substrate 框架用于函数内代码的HOOK
2014-12-24 13:36
274 查看
上一次分析了Cydia Substrate so hook 框架的实现,实际使用中,发现这样的框架并不能满足我的一些需求,比如我要知道一个函数内部某处代码的运行时的寄存器值,用原始的框架就无法做到。
想实现的功能是只要指定一个地址,就可以打印该处代码执行时的寄存器环境、HOOK的地址以及线程的TID,同时支持多个地址的添加。
先实现一个通用的消息打印函数
里面具体的参数意义后面再讲。
printAllReg要由一个中转函数来调用,这个函数必须满足如下要求:
1.调用前后不能改变R0-R12,LR寄存器的值
2.调用完打印函数后,跳到old函数
3.把监控地址入栈,这个要求比较关键,不然打印出来不知道是哪处代码在打印,也就没有意义了。
根本满足这三点要求,C语言函数肯定是不行的,只有用arm汇编来实现了
红框里的指令都是我们需要patch的指令
0x1A2B3001为这值占用了四个字节,这个值是要入栈给printAllReg的,我们在这里写入HOOK的地址,就能被printAllReg函数所用了。
再回头来看下printAllReg里int Reg_R12 =*(pSP2+1);这样指令的作用,从中转函数我们知道,调用printAllReg时,堆栈里值是这样排列的LR,HOOK
Addr,R12,R11,R10,R9,R8,R7,R6,R5,R4;Stack_SP2指向的就是HookAddr,向后递推,就可以把R12-R4的地址读出来了,当然也可以改下printAllReg的调用界面,把这些值全放参数里传过来。
第一个红框,patch成跳转指令,0x16e0放把下四个字节内容加载到PC的指令,0x16e4放跳转地址
使用如下函数进行patch
经过这个函数patch后的中转函数,如下图所示
每个hook都会分配一段代码内存用于保存这样的中转函数,以后需要监控一个指定函数时,只需要调用setAddrHook,输入地址就可以了。限于Cydia
Substrate框架的限制,输入的hook地址指向的前面12个字节最好不要被跳转所分割。
也可以按此方法对HOOK函数的过滤函数进行通用化改造,实现输入函数地址即可打印函数调用信息的界面
(创建了一个Android逆向分析群,欢迎有兴趣的同学加入,群号码:376745720)
想实现的功能是只要指定一个地址,就可以打印该处代码执行时的寄存器环境、HOOK的地址以及线程的TID,同时支持多个地址的添加。
先实现一个通用的消息打印函数
void printAllReg(int Reg_R0,int Reg_R1,int Reg_R2,int Reg_R3,int Stack_SP,int Stack_SP2) { int *pSP2 = &Stack_SP2; int Reg_R12 = *(pSP2+1); int Reg_R11 = *(pSP2+2); int Reg_R10 = *(pSP2+3); int Reg_R9 = *(pSP2+4); int Reg_R8 = *(pSP2+5); int Reg_R7 = *(pSP2+13); int Reg_R6 = *(pSP2+12); int Reg_R5 = *(pSP2+11); int Reg_R4 = *(pSP2+10); char *pFormat="Hookaddr:0x%08x tid=%x R0:0x%08x R1:0x%08x R2:0x%08x R3:0x%08x \nR4:0x%08xR5:0x%08x R6:0x%08x R7:0x%08x R8:0x%08x R9:0x%08x R10:0x%08x R11:0x%08xR12:0x%08x "; LOGD(pFormat,(Stack_SP2-1-(int)pSSELibBase),gettid(),Reg_R0,Reg_R1,Reg_R2,Reg_R3,Reg_R4,Reg_R5,Reg_R6,Reg_R7,Reg_R8,Reg_R9,Reg_R10,Reg_R11,Reg_R12); }
里面具体的参数意义后面再讲。
printAllReg要由一个中转函数来调用,这个函数必须满足如下要求:
1.调用前后不能改变R0-R12,LR寄存器的值
2.调用完打印函数后,跳到old函数
3.把监控地址入栈,这个要求比较关键,不然打印出来不知道是哪处代码在打印,也就没有意义了。
根本满足这三点要求,C语言函数肯定是不行的,只有用arm汇编来实现了
void HookAddr() { __asm__( "PUSH {R0-R7} \t\n"//保存可能会改变的寄存器 "mov r4,r8 \t\n" "PUSH {R4} \t\n" "mov r4,r9 \t\n" "PUSH {R4} \t\n" "mov r4,r10 \t\n" "PUSH {R4} \t\n" "mov r4,r11 \t\n" "PUSH {R4} \t\n" "mov r4,r12 \t\n" "PUSH {R4} \t\n"//将r8-r12入栈,直接push {R8}这样的指令是不支持的 "ldr r7,=0x1a2b3001\t\n"//0x1a2b3001是什么意思? "PUSH {R7} \t\n" "PUSH {LR} \t\n"//将返回地址入栈,printAllReg执行完后,lr寄存器会变掉 "ldr r7, =printAllReg \t\n"//将两个地址入栈后,调用打印函数 "BLX r7 \t\n" "POP {R7} \t\n" "mov lr,r7 \t\n"//恢复lr "POP {R7} \t\n" "POP {R4} \t\n" "mov r12,r4 \t\n"//r12经过rlx后,会变掉,这里专门恢复一下 "POP {R0-R3} \t\n" //平衡堆栈 "POP {R0-R7} \t\n" //恢复r0-r7 "MOV R0,R0 \t\n" //让下面的bx pc指令4字节对齐 "BX PC \t\n"//转到arm模式,以进行跳转 "MOV R0,R0 \t\n"//占位 "MOV R0,R0 \t\n"//占位,这里后面会被patch掉 "MOV R0,R0 \t\n"//占位,这里后面会被patch掉 "MOV R0,R0 \t\n"//占位,这里后面会被patch掉 "BX LR \t\n" ); }这段函数经过编译后,用IDA反汇编的结果如下:
红框里的指令都是我们需要patch的指令
0x1A2B3001为这值占用了四个字节,这个值是要入栈给printAllReg的,我们在这里写入HOOK的地址,就能被printAllReg函数所用了。
再回头来看下printAllReg里int Reg_R12 =*(pSP2+1);这样指令的作用,从中转函数我们知道,调用printAllReg时,堆栈里值是这样排列的LR,HOOK
Addr,R12,R11,R10,R9,R8,R7,R6,R5,R4;Stack_SP2指向的就是HookAddr,向后递推,就可以把R12-R4的地址读出来了,当然也可以改下printAllReg的调用界面,把这些值全放参数里传过来。
第一个红框,patch成跳转指令,0x16e0放把下四个字节内容加载到PC的指令,0x16e4放跳转地址
使用如下函数进行patch
void setAddrHook(void* rawFunc) { int memSize = 0x60; char *memBase = mmap(0,memSize,PROT_READ| PROT_WRITE | PROT_EXEC,MAP_ANONYMOUS | MAP_PRIVATE,0,0); if(memBase) { void*pHookFunc; pHookFunc= (char*)HookAddr; if(((int)pHookFunc)%4) { pHookFunc = (char*)HookAddr -1; } memcpy(memBase,pHookFunc,memSize); MSHookFunction(rawFunc, (void*)(memBase+1),(void**)(memBase+0x38)); *(int*)(memBase+0x40)=(int)rawFunc; *(int*)(memBase+0x34)=0xe51ff004; int* pFunc = (int*)((char*)rawFunc -1); } }
经过这个函数patch后的中转函数,如下图所示
每个hook都会分配一段代码内存用于保存这样的中转函数,以后需要监控一个指定函数时,只需要调用setAddrHook,输入地址就可以了。限于Cydia
Substrate框架的限制,输入的hook地址指向的前面12个字节最好不要被跳转所分割。
也可以按此方法对HOOK函数的过滤函数进行通用化改造,实现输入函数地址即可打印函数调用信息的界面
(创建了一个Android逆向分析群,欢迎有兴趣的同学加入,群号码:376745720)
相关文章推荐
- 改造 Cydia Substrate 框架用于函数内代码的HOOK
- NDIS Hook的框架代码
- js调用父框架函数与弹窗调用父页面函数的简单代码
- 操作系统是怎么工作的——函数的堆栈框架/嵌入式代码
- PHP uniqid()函数可用于生成不重复的唯一标识符,该函数基于微秒级当前时间戳。在高并发或者间隔时长极短(如循环代码)的情况下,会出现大量重复数据。即使使用了第二个参数,也会重复,最好的方案是结
- DeepLearningToolbox(1)代码框架分析之关键函数的主要功能
- 用于双目视觉的程序框架,里面是代码和一些说明
- YAHFA--ART环境下的Hook框架(代码详解)
- 网站自动提交至百度站长收录平台函数(适用任何框架代码)
- Lea指令计算地址(用于四则混合运算),附上一个函数调用例子及其反汇编代码,很清楚
- 虚函数Hook代码
- 天书上的练习hook ZwCreateSection函数代码
- linux 函数hook实现数据包过滤基本框架
- 修改函数代码HOOK的封装
- Spring MVC框架下在java代码中访问applicationContext.xml文件中配置的文件(可以用于读取配置文件内容)
- 【转帖】 NDIS Hook的框架代码
- eval函数用于计算代码串,而不引用任何特定
- TGraphicControl(自绘就2步,直接自绘自己,不需要调用VCL框架提供的函数重绘所有子控件,也不需要自己来提供PaintWindow函数让管理框架来调用)与TControl关键属性方法速记(Repaint要求父控件执行详细代码来重绘自己,还是直接要求Invalidate无效后Update刷新父控件,就看透明不透明这个属性,因为计算显示的区域有所不同)
- 用于解答算法题目的Python3代码框架
- C++实现修改函数代码HOOK的封装方法