【问题标题】:Writing self modifying code in C on windows, Unable to write patch在 Windows 上用 C 语言编写自修改代码,无法编写补丁
【发布时间】:2019-09-28 21:42:57
【问题描述】:

我正在尝试编写一些自修改代码,但是一旦我找到了要在内存中写入补丁的位置,我实际上无法将补丁写入内存。

我尝试使用不同的方法来确保我尝试修补的内存区域的权限对于我想要做的事情是正确的 (PAGE_EXECUTE_READWRITE)。我认为问题在于我如何称呼WriteProcessMemory,尽管我不确定这是为什么。

#include <windows.h>
#include <psapi.h>
#include <stdio.h>

#define PATTERN "\x55\x48\x89\xe5\x48\x83\xec\x20\x48\x8d\x0d\x91\x2a\x00\x00\xe8\x3c\x16\x00\x00\x90\x48\x83\xc4\x20\x5d\xc3"
#define REPLACE "\x55\x48\x89\xe5\x90\x5d\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90x\90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xc3"
#define LEN 27

DWORD SearchPattern(unsigned char* mem, unsigned char* signature, DWORD signatureLen) 
{
    ULONG offset = 0;

    for (int i = 0; i < 0x200000; i++) {
        if (*(unsigned char*)(mem + i) == signature[0] && *(unsigned char*)(mem + i + 1) == signature[1]) {
            if (memcmp(mem + i, signature, signatureLen) == 0) {
                // Found the signature
                offset = i;
                break;
            }
        }
    }

    return offset;
}

void patch_mem()
{
    DWORD oldProtect, oldOldProtect;

    unsigned char *exe = (unsigned char *)GetModuleHandle("patching_tests.exe");
    DWORD patternOffset = SearchPattern(exe, PATTERN, LEN);
    if (patternOffset == 0)
    {
        printf("Error finding offset, returning\n");
        return;
    }

    printf("offset: %#010x\n", (exe + patternOffset));

    VirtualProtect((exe + patternOffset), LEN, PAGE_EXECUTE_READWRITE, &oldProtect);
    CopyMemory((exe + patternOffset), REPLACE, LEN);
    VirtualProtect((exe + patternOffset), LEN, oldProtect, &oldOldProtect);

    HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
    if (!FlushInstructionCache(handle, (LPCVOID)(exe + patternOffset), LEN))
    {
        printf("FlushInstructionCache, %d\n", GetLastError());
    }

    return;
}

int say_hi()
{
    printf("hi!\n");
}

int main()
{
    printf("calling say_hi...\n");
    say_hi();

    printf("patching memory...\n");
    patch_mem();

    printf("calling say_hi again...\n");
    say_hi();

    return 0;
}

目的是修改 say_hi 函数中的程序集,使其只返回而不是打印 hi!

我是否还可以指出,我想在不使用指向 say_hi 函数的指针的情况下执行此操作,而是在内存中搜索它。这是因为我将在一个无法访问指向函数的直接指针的项目中实现此技术。

更新: 我已经删除了对WriteProcessMemory 的调用,并将其替换为CopyMemory。我现在还使用GetModuleHandle 来获取模块的基地址。现在它将自行编译...尽管它似乎仍然没有覆盖say_hi 函数中的代码。

【问题讨论】:

  • 代码失败的原因是什么?
  • 在自己的进程中读/写内存时不需要使用(Read|Write)ProcessMemory()。您可以直接读/写内存,例如使用memcpy()CopyMemory()。仅当在其他进程中读取/写入内存时才使用(Read|Write)ProcessMemory()
  • 代码失败,因为它没有写入该位置,say_hi 函数仍在执行,而不仅仅是返回。
  • 嗯,我尝试过使用CopyMemory()memcpy(),但我仍然无法使用这些方法使其工作。例如CopyMemory((LPVOID)(base_address + patternOffset), REPLACE, LEN)
  • @Dylanhalls 好吧,对于初学者来说,您的代码甚至不应该如图所示编译,因为patch_mem() 甚至在声明之前尝试使用base_address。所以这不可能是你真正的代码。

标签: c windows winapi self-modifying


【解决方案1】:

首先,在宏REPLACE中,有一个错误"\x90x\90",不知道是不是你发帖的时候写错了。

那么,int say_hi() 一定有返回值,比如

int say_hi()
{
    printf("hi!\n");
    return 0;
}

或者只使用void返回类型。

您尝试修改的函数内存可能不正确,或者它们可能被跳过。请注意,您正在搜索的模式将在不同的内存中具有相同的数据(因为您的程序中定义了#define PATTERN 常量),因此您修改的很可能是PATTERN

您可以通过memcmp(PATTERN, REPLACE, LEN);查看:

DWORD SearchPattern(unsigned char* mem, unsigned char* signature, DWORD signatureLen)
{
    ULONG offset = 0;

    for (int i = 0; i < 0x20000; i++) {
        if (*(unsigned char*)(mem + i) == signature[0] && *(unsigned char*)(mem + i + 1) == signature[1]) {
            if (memcmp(mem + i, signature, signatureLen) == 0) {

                if (mem + i == signature)
                    continue;  //Found the memory of the PATTERN
                // Found the signature
                offset = i;
                break;
            }
        }
    }

    return offset;
}

我可以通过正确的PATTERN找到say_hi的执行指令并修改。

【讨论】:

    猜你喜欢
    • 2011-05-17
    • 2020-04-10
    • 1970-01-01
    • 2011-03-04
    • 2011-06-16
    • 1970-01-01
    • 1970-01-01
    • 2021-09-12
    • 1970-01-01
    相关资源
    最近更新 更多