c++ - 我的蹦床弹不起来(绕行,C++,GCC)

标签 c++ linux memory gcc detours

感觉我所有的问题都在滥用 Stackoverflow,但它毕竟是一个问答论坛 :) 无论如何,我已经使用了一段时间的弯路,但我还没有实现我自己的一个(我'我们之前使用过包装器)。因为我想完全控制我的代码(谁不想呢?)我决定自己实现一个功能齐全的绕行器,这样我就可以理解代码的每个字节。

代码(下方)尽可能简单,但问题并非如此。我已经成功实现了绕行(即 Hook 到我自己的函数),但我无法实现 trampoline

每当我调用 trampoline 时,根据我使用的偏移量,我会收到“段错误”或“非法指令”。两种情况都以相同的方式结束; '核心倾销'。我认为这是因为我混淆了“相对地址”(注意:我是 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;
}

如果感兴趣,这是正常运行期间的输出(使用上面的确切代码):

This is testing
This is **
Illegal instruction (core dumped)
这是我在第 66 行使用 +/- sizeof(jmpOp) 的结果:

This is testing
This is ******
Segmentation fault (core dumped)

注意:我正在运行 Ubuntu 32 位并使用 g++ global.cpp main.cpp -o main -Iinclude 编译

最佳答案

你不能不分青红皂白地将 Test() 的前 5 个字节复制到你的蹦床中,然后跳转到 Test() 的第 6 个指令字节,因为你不知道前 5 个字节是否字节包含整数个 x86 可变长度指令。为此,您将不得不至少对 Test() 函数进行最少量的自动反汇编,以便找到超过函数开头 5 个或更多字节的指令边界,然后复制适当的数字字节到你的蹦床,然后附加你的跳跃(它不会在你的蹦床上固定偏移)。请注意,在典型的 RISC 处理器(如 PPC)上,您不会遇到此问题,因为所有指令的宽度都相同。

关于c++ - 我的蹦床弹不起来(绕行,C++,GCC),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10458048/

相关文章:

Python:在主内存不足时引发异常

c++ - 模板类中的模板方法特化

c++ - AttachConsole错误5 : Access is denied

c - 如何在C中创建文件夹(需要在Linux和Windows上运行)

c++ - Windows 可执行文件的映射文件是否可写?

Haskell/GHC 内存使用

c++ - WinDBG 适用于从 Visual Studio 2015 保存的转储,但不适用于任务管理器。显示异常代码 "not found"

c++ - 仅允许某些派生类访问基类的成员函数

linux - 找出一个进程在 linux 中使用了多少额外的物理内存

c++ - AOSP : arm-linux-androideabi-gcc: command not found even though it is present in prebuilts folder