C++ 内存修补的常量结构声明

C++ 内存修补的常量结构声明,c++,c,hook,code-injection,C++,C,Hook,Code Injection,我正在做反向工程的东西,并通过DLL修补游戏的内存。通常,我坚持使用相同的老方法,在单个或多个函数中修补所有内容。但是,使用一个结构数组来定义需要进行的内存写入并一次遍历它们,感觉可以更好地完成这项任务。更容易管理,国际海事组织 不过我想让它保持不变。因此,数据一次就全部存在(in.rdata),而不必为每个补丁动态分配内存,这是一项简单的任务,包含“bytesize”数据,例如: struct struc_patch { BYTE val[8]; // max size of e

我正在做反向工程的东西,并通过DLL修补游戏的内存。通常,我坚持使用相同的老方法,在单个或多个函数中修补所有内容。但是,使用一个结构数组来定义需要进行的内存写入并一次遍历它们,感觉可以更好地完成这项任务。更容易管理,国际海事组织

不过我想让它保持不变。因此,数据一次就全部存在(in.rdata),而不必为每个补丁动态分配内存,这是一项简单的任务,包含“bytesize”数据,例如:

struct struc_patch
{
    BYTE val[8];    // max size of each patch (usually I only use 5 bytes anyway for call and jmp writes)
                    // I can of course increase this if really needed
    void *dest;
    char size;
} patches[] =
{
    // simply write "01 02 03 04" to 0x400000
    {{0x1, 0x2, 0x3, 0x4}, (void*)0x400000, 4},
};
//[...]
for each(struc_patch p in patches)
{
    memcpy(p.dest, p.val, p.size);
}
但是,当我想更喜欢这些类型时,我发现没有办法将“0x9090”这样的整数指定为字节数组“90”。所以这是行不通的:

struct struc_patch
{
    BYTE val[8];    // max size of each patch (usually I only use 5 bytes anyway for call and jmp writes)
                    // I can of course increase this if really needed
    void *dest;
    char size;
} patches[] =
{
    // how to write "jmp MyHook"? Here, the jmp offset will be truncated instead of overlapping in the array. Annoying.
    {{0xE9, (DWORD)&MyHook - 0x400005}, (void*)0x400000, 5},
};
当然,主要的问题是&MyHook必须由编译器来解决。有没有其他方法可以得到想要的结果并保持不变


老实说,我对STL没有什么经验。因此,如果有一个解决方案使用它,我可能需要详细解释它,以便正确理解代码。我是一个C/C++/WinAPI迷,哈哈,但它是为一个类似性质的游戏编写的,所以它很适合。

更好的处理方法是动态计算地址差。例如():


dwAddr是放入call指令的地址,dwFunc是要调用的函数,dwLen是要替换的指令的长度(基本上用于计算要放入的NOP数)。

我认为STL中的任何内容都不会对您有所帮助,而不是在编译时。 可能有一种奇特的方式来处理模板,就像处理宏一样。(以逗号分隔字节)

但我建议做一些简单的事情,比如:

struct jump_insn
{
    unsigned char opcode;
    unsigned long addr;
} jump_insns[] = {
    {0xe9, (unsigned long)&MyHook - 0x400005}
};

struct mem
{
   unsigned char val[8];
} mems[] = {
    {1,2,3,4}
};

struct struc_patch
{
    unsigned char *val;    // max size of each patch (usually I only use 5 bytes anyway for call and jmp writes)
                    // I can of course increase this if really needed
    void *dest;
    char size;
} patches[] =
{
    // simply write "01 02 03 04" to 0x400000
    {(unsigned char*)(&mems[0]), (void*)0x400000, 4},

    // how to write "jmp MyHook"? Here, the jmp offset will be truncated instead of overlapping in the array. Annoying.
    {(unsigned char*)(&jump_insns[0]), (void*)0x400000, 5},
};
您不能以内联方式完成所有操作,您需要为不同类型的修补程序提供新类型,但它们可以任意长(而不仅仅是8字节),并且所有内容都将以.rodata格式完成。

总之,我的解决方案(感谢Nicolas的建议):

在使用中:

// Patches
jump_insn JMP_HOOK_LoadButtonTextures = {POFF(&HOOK_LoadButtonTextures, 0x400000)};

struc_patch patches[] =
{
    {&JMP_HOOK_LoadButtonTextures, IntToPtr(0x400000)},
};
使用类成员const,我可以更容易、更清晰地定义所有内容,并且可以简单地将所有内容都定义为memcpy。当然,需要使用pack pragma来确保memcpy不会复制字节操作码和DWORD值之间的3个align字节


谢谢大家,帮助我使我的修补方法更加健壮。

我发现了一个使用macroes的肮脏解决方案,我认为它应该可以正常工作,但我还是更喜欢一种更自然的方法。虽然它是由编译器解决的,但它的工作方式正是我想要的:
#定义SPLITDW(v)(BYTE)(v),(BYTE)(v>>8),(BYTE)(v>>16),(BYTE)(v>>24)
{code>{0xE9,SPLITDW((DWORD)和HOOK_-0x400005)},(void*)0x400000,5},
任何其他(和更好的)建议仍然很感谢,但这正是我想做的事情,因为这需要分配数据以动态写入,并为每个补丁做大量的幕后工作,我真诚地认为,最好将所有数据预先确定并作为常量数据,而不是动态地进行。在我当前的代码中,唯一要做的就是复制编译后的数据(以及任何需要的保护——尽管我更喜欢一次性取消对整个EXE的保护并保持这种方式)。如果您想避免动态内存方面的问题,那么您所要做的就是将BYTE*bCode更改为BYTE bCode[8]。我认为您会发现,在“幕后”动态生成内容会减少麻烦(例如,在您的示例中,如果需要将0x400005更改为其他内容,则必须更改两次)。我不知道你为什么偏袒使用const进行修补(你仍然可以在一个结构中使用const数据,并在const结构上重复调用PatchCall)。我只是认为不在编译时完成所有工作是对编译器能力的一点浪费。当然,我必须更改2个地址,但我现在有了
{PATCH_JMP_DATA(0x400000,&HOOK_MyFunc),Ptr32ToPtr(0x400000),5},
,所以这几乎不麻烦。还允许我有更多的控制,如果我想写一个不相关的指针,等等。所有这些都是在编译时完成的,这就避免了编译代码中的大量混乱。我也从来没有看到过将其余的写函数禁用的意义。如果你的钩子能直接通过坏代码,那就是浪费时间。啊,是的,这很好,而且是一种看似“标准”的方式。比我的要好得多,因为数组中没有因声明为最大可能大小而浪费的字节,而且我可以轻松设置操作码写入。谢谢
#pragma pack(push)
#pragma pack(1)
#define POFF(d,a) (DWORD)d-(a+5)
struct jump_insn
{
    const BYTE opcode = 0xE9;
    DWORD offset;
};

struct jump_short_insn
{
    const BYTE opcode = 0xEB;
    BYTE offset;
};

struct struc_patch
{
    void *data;
    void *dest;
    char size;
};
#pragma pack(pop)
// Patches
jump_insn JMP_HOOK_LoadButtonTextures = {POFF(&HOOK_LoadButtonTextures, 0x400000)};

struc_patch patches[] =
{
    {&JMP_HOOK_LoadButtonTextures, IntToPtr(0x400000)},
};