INC操作码编译到错误的地址

时间:2019-07-18 08:59:12

标签: c++ pointers x86 inline-assembly cheat-engine

我正在编译以下代码,但未按预期工作。

有人可以解释为什么以下代码不起作用以及如何更正它吗?

DWORD data_location = 0x0100579C;
DWORD ret = 0x1002FFA;

void __declspec(naked) inc()
{
    // The following is what I'm trying to accomplish which works
    *(DWORD*)data_location = *(DWORD*)data_location + 1;

    __asm
    {   
        inc [data_location] //Should compile as FF 05 9C570001, instead compiles to the address containing the pointer to data_location
        // inc data_location also compiles to the same thing above

        jmp [ret]
    }
}

2 个答案:

答案 0 :(得分:2)

如果我对您的理解正确,那么您希望获得类似的东西

DWORD data_location = 0x0100579C;
DWORD ret = 0x1002FFA;

void __declspec(naked) inc()
{
    __asm
    {   
        mov eax, [data_location]
        inc dword ptr [eax]

        jmp [ret]
    }
}

答案 1 :(得分:2)

[data_location]与MASM语法中的data_location相同。方括号是可选的,而不是您需要从静态存储中取消引用指针的额外级别的间接操作。

请记住,在C中,data_location为您提供了来自内存的值,然后您的C取消引用了那个。但是内联asm使用asm语法。


如果您希望它与硬编码到指令中的地址组合在一起,您需要将地址设置为预处理器常量,而不仅仅是静态存储中的DWORD变量。< / p>

#define data_location  0x0100579C
#define ret_addr  0x1002FFA

void __declspec(naked) inc()
{
    //++*(DWORD*)data_location;
    //((void (*)(void))ret)();

    __asm
    {   
        add  dword ptr ds:[data_location], 1
         // add dword ptr ds:[0x0100579C], 1   // after C preprocessor

        mov  eax, ret_addr
        jmp  eax
    }
}

显然,使MASM / MSVC将ds:视为内存操作数而不是立即数,[0x12345]是必需的。但是它也有一个缺点,就是实际上会在机器代码中发出一个冗余的ds前缀字节。

很显然,您可以通过实际使用来提高效率
++*(DWORD*)data_location;,然后让编译器内联addinc指令。强制调用者实际调用此存根函数只会降低您的速度。

add [mem], immediate仅2块,而Intel CPU上的内存目标inc仅3片。它仅花费1个额外的代码大小字节。

jmp [ret]一起使用的

DWORD ret = ...;可以使用,但这是一个不幸的选择。您实际上并不需要从静态存储中加载目标地址。理想情况下,您会jmp 0x1002FFA并让汇编器计算相对于该绝对目标的相对偏移。但是不幸的是,MASM语法和/或Windows .obj文件不支持。

如果可以使用tmp寄存器,则将地址mov立即放入寄存器中可以避免需要任何静态数据,从而可能使前端更快地整理出错误的分支。不过,它仍然是一个间接分支。


此外,如果您实际上使用过call这个函数,请记住,调用方将推送您留在堆栈中的返回地址,所以这就像一个尾调用。

实际上,如果您只是在jmp函数末尾简单地进行了不带参数的普通函数调用,则可以使编译器为您发出void