几天前,我通过修补单个调用指令编写了一个简单的钩子/绕道。它可以在 Ubuntu 12.xyz(32 位)上运行,现在我更新到 Linux Mint 17.1(32 位)并且出现分段错误。
我有两个项目
- 调用名为 goodGuy 的函数的目标项目
- 由 dlopen() 加载的库项目,它覆盖目标应用程序中调用指令的偏移量
在覆盖调用指令偏移之前,我通过以下方式修改了页面的保护:
mprotect(pageOf(address),pagesize,PROT_WRITE|PROT_EXEC|PROT_READ)
这工作正常(返回 0)。
当我调试我的程序时,它在尝试写入调用地址时崩溃:
memcpy((void*)(address + 1),(void*)&callOffset,4);
看起来我不允许覆盖指令,但为什么呢?
我禁用了 ALSR 并-z execstack -fno-stack-protector
在 g++ 中使用了标志。
你知道如何让我的应用程序写指令吗?
谢谢你,亚历克斯
编辑
对不起各位,代码如下:
目标应用:
#include <dlfcn.h>
#include <stdio.h>
#include <stdio.h>
#include <iostream>
void goodGuy();
//full lib path !
char libPath[] = "INSER_YOUR_PATH_HERE/lib.so";
int main(){
dlopen(libPath,RTLD_NOW);
goodGuy();
return 0;
}
void goodGuy(){
printf("good guy :)\n");
}
和共享库代码:
#include <stdio.h>
#include <cstring>
#include <stdint.h>
#include <sys/mman.h>
#include <unistd.h>
void badGuy();
int pagesize = sysconf(_SC_PAGESIZE);
void *pageOf(void* p){
return (void*)((unsigned int)p & ~(pagesize - 1));
}
extern "C" void __attribute__ ((constructor)) DllLoad(void){
uint32_t addressOfCall = 0x0804862a; //Address where goodGuy is called in target app
uint32_t addressOfNextInstruction = addressOfCall + 5;
uint32_t callOffset = (uint32_t)badGuy - addressOfNextInstruction;
mprotect(pageOf((void*)(addressOfCall + 1)),pagesize, PROT_WRITE|PROT_EXEC|PROT_READ);
memcpy((void*)(addressOfCall + 1),(void*)&callOffset,4);
}
void badGuy(){
printf("bad guy :(\n");
}
要找出addressOfCall,用gdb打开目标应用程序gdb target
并显示主函数,disas main
看看+29
gdb$ disas main
Dump of assembler code for function main()
0x0804860d <+0>: push ebp
0x0804860e <+1>: mov ebp,esp
0x08048610 <+3>: and esp,0xfffffff0
0x08048613 <+6>: sub esp,0x10
0x08048616 <+9>: mov DWORD PTR [esp+0x4],0x2
0x0804861e <+17>: mov DWORD PTR [esp],0x804a060
0x08048625 <+24>: call 0x80484f0 <dlopen@plt>
___________
|0x0804862a| <+29>: call 0x8048636 <goodGuy()>
|__________|
0x0804862f <+34>: mov eax,0x0
0x08048634 <+39>: leave
0x08048635 <+40>: ret