问题描述
感觉像我滥用Stackoverflow与我的所有问题,但它是一个Q& A论坛毕竟:)无论如何,我一直使用detours一段时间,但我还没有实现我自己的我之前使用过包装器)。因为我想完全控制我的代码(谁不?)我决定实现一个完全功能的detour'er我自己,所以我可以理解我的代码的每一个字节。
代码(下面)尽可能简单,但问题是,不是。我已经成功地实现了绕行(即钩子到我自己的功能),但我没有能够实现蹦床。
我称之为蹦床,取决于我使用的偏移量,我得到一个分段故障或非法指令。两种情况都结束了; 'core dumped'。我认为这是因为我混淆了相对地址(注意:我是Linux的新手,所以我远没有掌握GDB)。
在代码中,根据 sizeof(jmpOp)
(在第66行)我得到一个非法指令或分段错误。对不起,如果是显而易见的,我太累了...
//头文件
#include< stdio.h>
#include< sys / mman.h>
#include< unistd.h>
#includeglobal.h//包含字节,ulong,ushort等的类型定义...
#include< cstring>
bool ProtectMemory(void * addr,int flags)
{
//保持页大小值的常量
const size_t pageSize = sysconf(_SC_PAGE_SIZE);
//计算相对页偏移
size_t temp =(size_t)addr;
temp - = temp%pageSize;
//更新地址
addr =(void *)temp;
//更新内存区域保护
return!mprotect(addr,pageSize,flags);
}
const byte jmpOp [] = {0xE9,0x00,0x00,0x00,0x00};
int Test(void)
{
printf(This is testing\ n);
return 5;
}
int MyTest(void)
{
printf(This is ****** \\\
);
return 9;
}
typedef int(* TestType)(void);
int main(int argc,char * argv [])
{
//获取地址
byte * test =(byte *)&
byte * myTest =(byte *)& MyTest;
//调用原始
Test();
//为'test'函数更新内存访问
ProtectMemory((void *)test,PROT_EXEC | PROT_WRITE | PROT_READ);
//为trampoline分配内存
byte * trampoline = new byte [sizeof(jmpOp)* 2];
//复制操作
memcpy(trampoline,test,sizeof(jmpOp));
memcpy(test,jmpOp,sizeof(jmpOp));
//设置trampoline
trampoline + = sizeof(jmpOp);
* trampoline = 0xE9;
//我认为这个地址不正确,我该怎么计算呢?使用当前
//状态(注释'sizeof(jmpOp)'),编译器会提示非法指令。
//如果我取消注释,并使用+或 - ,会出现分段错误...
*(uint *)(trampoline + 1)=((uint)test - (uint)蹦床)/ * + sizeof(jmpOp)* /;
trampoline - = sizeof(jmpOp);
//使蹦床可执行(和读/写)
ProtectMemory((void *)trampoline,PROT_EXEC | PROT_WRITE | PROT_READ);
//设置detour
*(uint *)(test + 1)=((uint)myTest - (uint)test) - sizeof(jmpOp);
//调用'detoured'func
Test();
//调用trampoline(崩溃)
((TestType)trampoline)();
return 0;
}
在感兴趣的情况下,这是正常运行期间的输出确切的代码如下):
这是测试
这是 **
非法指令b 这是如果我在第66行使用+/- sizeof(jmpOp)的结果:这是测试
这是******
分段故障(内核转储)
注意:我运行的是Ubuntu 32位并用
g ++ global.cpp main.cpp -o main -Iinclude
解决方案你不能将Test()的前5个字节不加区别地复制到你的蹦床中,然后跳转到Test()的第6个指令字节,因为你不知道第一个5字节包括整数个x86可变长度指令。为了做到这一点,你必须至少做一个最小量的自动反汇编Test()函数,以找到一个指令边界超过函数的开头5个或更多的字节,然后复制一个适当的数字的字节到你的蹦床,然后附加你的跳跃(这将不是在你的蹦床固定偏移)。注意,在典型的RISC处理器(如PPC)上,你不会有这个问题,因为所有的指令宽度相同。
It feels like I'm abusing Stackoverflow with all my questions, but it's a Q&A forum after all :) Anyhow, I have been using detours for a while now, but I have yet to implement one of my own (I've used wrappers earlier). Since I want to have complete control over my code (who doesn't?) I have decided to implement a fully functional detour'er on my own, so I can understand every single byte of my code.
The code (below) is as simple as possible, the problem though, is not. I have successfully implemented the detour (i.e a hook to my own function) but I haven't been able to implement the trampoline.
Whenever I call the trampoline, depending on the offset I use, I get either a "segmentation fault" or an "illegal instruction". Both cases ends the same though; 'core dumped'. I think it is because I've mixed up the 'relative address' (note: I'm pretty new to Linux so I have far from mastered GDB).
As commented in the code, depending on
sizeof(jmpOp)
(at line 66) I either get an illegal instruction or a segmentation fault. I'm sorry if it's something obvious, I'm staying up way too late...// Header files #include <stdio.h> #include <sys/mman.h> #include <unistd.h> #include "global.h" // Contains typedefines for byte, ulong, ushort etc... #include <cstring> bool ProtectMemory(void * addr, int flags) { // Constant holding the page size value const size_t pageSize = sysconf(_SC_PAGE_SIZE); // Calculate relative page offset size_t temp = (size_t) addr; temp -= temp % pageSize; // Update address addr = (void*) temp; // Update memory area protection return !mprotect(addr, pageSize, flags); } const byte jmpOp[] = { 0xE9, 0x00, 0x00, 0x00, 0x00 }; int Test(void) { printf("This is testing\n"); return 5; } int MyTest(void) { printf("This is ******\n"); return 9; } typedef int (*TestType)(void); int main(int argc, char * argv[]) { // Fetch addresses byte * test = (byte*) &Test; byte * myTest = (byte*) &MyTest; // Call original Test(); // Update memory access for 'test' function ProtectMemory((void*) test, PROT_EXEC | PROT_WRITE | PROT_READ); // Allocate memory for the trampoline byte * trampoline = new byte[sizeof(jmpOp) * 2]; // Do copy operations memcpy(trampoline, test, sizeof(jmpOp)); memcpy(test, jmpOp, sizeof(jmpOp)); // Setup trampoline trampoline += sizeof(jmpOp); *trampoline = 0xE9; // I think this address is incorrect, how should I calculate it? With the current // status (commented 'sizeof(jmpOp)') the compiler complains about "Illegal Instruction". // If I uncomment it, and use either + or -, a segmentation fault will occur... *(uint*)(trampoline + 1) = ((uint) test - (uint) trampoline)/* + sizeof(jmpOp)*/; trampoline -= sizeof(jmpOp); // Make the trampoline executable (and read/write) ProtectMemory((void*) trampoline, PROT_EXEC | PROT_WRITE | PROT_READ); // Setup detour *(uint*)(test + 1) = ((uint) myTest - (uint) test) - sizeof(jmpOp); // Call 'detoured' func Test(); // Call trampoline (crashes) ((TestType) trampoline)(); return 0; }
In case of interest, this is the output during a normal run (with the exact code above):
This is testing This is ** Illegal instruction (core dumped)And this is the result if I use +/- sizeof(jmpOp) at line 66:
This is testing This is ****** Segmentation fault (core dumped)NOTE: I'm running Ubuntu 32 bit and compile with
g++ global.cpp main.cpp -o main -Iinclude
解决方案You're not going to be able to indiscriminately copy the first 5 bytes of Test() into your trampoline, followed by a jump to the 6th instruction byte of Test(), because you don't know if the first 5 bytes comprise an integral number of x86 variable-length instructions. To do this, you're going to have to do at least a minimal amount of automated disassembling of the Test() function in order to find an instruction boundary that's 5 or more bytes past the beginning of the function, then copy an appropriate number of bytes to your trampoline, and THEN append your jump (which won't be at a fixed offset within your trampoline). Note that on a typical RISC processor (like PPC), you wouldn't have this problem, as all instructions are the same width.
这篇关于我的蹦床不会弹跳(迂回,C + +,GCC)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!