感觉我在用所有问题都在滥用Stackoverflow,但毕竟这是一个问答论坛:)无论如何,我已经使用绕行了一段时间了,但是我还没有实现自己的一个(我使用过包装器)之前)。由于我想完全控制自己的代码(不是),因此我决定自己实现一个功能齐全的绕行器,这样我就可以理解代码的每个字节。
代码(下面)尽可能简单,但问题并非如此。我已经成功实现了绕行操作(即连接到我自己的功能),但无法实现蹦床。
每当我打电话给蹦床时,根据我使用的偏移量,都会得到“分段错误”或“非法指令”。两种情况都相同。 “核心已弃权”。我认为这是因为我混淆了“相对地址”(注意:我对Linux很陌生,所以我对GDB的掌握还很远)。
如代码中所述,根据sizeof(jmpOp)
(在第66行),我得到了非法指令或分段错误。如果这很明显,我很抱歉,我熬夜了……
// 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;
}
如果有兴趣,这是正常运行期间的输出(使用上面的确切代码):
这是测试
这是 **
非法指令(核心已转储)
如果在第66行使用+/- sizeof(jmpOp),则这是结果:
这是测试
这是 ******
分段故障(核心已转储)
注意:我正在运行32位Ubuntu,并使用
g++ global.cpp main.cpp -o main -Iinclude
进行编译 最佳答案
您将无法随意将Test()的前5个字节复制到蹦床中,然后跳转到Test()的第6个指令字节,因为您不知道前5个字节是否包含一个x86可变长度指令的整数。为此,您将必须至少对Test()函数进行最少的自动反汇编,以查找距离函数开头至少5个字节或更多字节的指令边界,然后复制一个适当的数字字节到蹦床,然后附加您的跳转(跳床内的偏移量不会固定)。请注意,在典型的RISC处理器(如PPC)上,您不会遇到此问题,因为所有指令的宽度相同。