【问题标题】:AT&T to inline asm in Visual Studio 2017AT&T 在 Visual Studio 2017 中内联 asm
【发布时间】:2019-01-26 17:37:28
【问题描述】:

我正在尝试将用 AT&T 语法编写的程序集从 DevC++ 项目转换为 Visual Studio 中的内联程序集。

这是我要转换的 AT&T:

void Painter::drawRectangle(int surface, int x, int y, int width, int height, int red, int green, int blue) {
    asm("mov %0, %%eax":: "r" (0x004EAA90));
    asm("call *%eax");
    asm("mov %eax, %ecx");
    asm("mov (%ecx), %eax");
    asm("push %0":: "m" (blue));
    asm("push %0":: "m" (green));
    asm("push %0":: "m" (red));
    asm("push %0":: "m" (height));
    asm("push %0":: "m" (width));
    asm("push %0":: "m" (y));
    asm("push %0":: "m" (x));
    asm("push %0":: "m" (surface));
    asm("call *0x14(%eax)");
}

到目前为止我做了什么:

void _drawrectangle(int surface, int x, int y, int width, int height, int red, int green, int blue)
{    
    __asm
    {
        mov eax, 0x004eaa90
        call dword ptr [eax]
        mov ecx, eax
        mov eax, [ecx]
        push blue
        push green
        push red
        push height
        push width
        push y
        push x
        push surface
        call dword ptr [eax + 0x14]
    }
}

我在我的 DLL 中编写这个,我已经将它注入到游戏中。游戏一打开就崩溃。而且我已经在 C++ 中使用了另一个绘图函数,它起作用了。

希望你能帮助我/引导我朝着正确的方向前进。谢谢。

【问题讨论】:

  • mov eax, ecx 应该是mov eax, [ecx]。为什么要颠倒参数推送的顺序?
  • 在任何情况下看起来只是两个函数调用,为什么你需要汇编呢?
  • 你也不应该使用内联汇编。只需使用普通汇编,那么您不必担心第一个示例中的代码会因为您使用的内联汇编代码是错误的而损坏。或者就像 Jester 所说的,普通的 C++ 也可以。
  • @500-InternalServerError Ops,测试后忘记切换命令。
  • 原始代码已经损坏,除非你很幸运并使用-fno-omit-frame-pointer 进行编译,因为你在不告诉编译器的情况下操纵了堆栈指针。

标签: visual-studio assembly inline-assembly att dll-injection


【解决方案1】:

以下是在不使用内联汇编的情况下用 C++ 编写函数的方法:

#ifndef _MSC_VER
/* For GCC and clang */
#undef __thiscall
#define __thiscall __attribute__((thiscall))
#endif

struct some_interface {
    virtual void _unknown_0() = 0;
    virtual void _unknown_4() = 0;
    virtual void _unknown_8() = 0;
    virtual void _unknown_C() = 0;
    virtual void _unknown_10() = 0;
    virtual void __thiscall drawRectangle(int surface, int x, int y,
                          int width, int height,
                          int red, int green, int blue) = 0;
};

const auto get_interface = (some_interface *(*)()) 0x4EAA90;

void 
drawRectangle(int surface, int x, int y, int width, int height,
          int red, int green, int blue) {
    get_interface()->drawRectangle(surface, x, y, width, height,
                       red, green, blue);
}

您尝试翻译的代码首先调用一个函数,该函数返回一个指向某个类对象的指针,该类对象至少定义了 6 个虚拟方法。然后它调用该对象的第 6 个虚拟方法。 some_interface 结构最低限度地重新创建了该类,因此可以调用第 6 个虚拟方法。 get_interface 常量是一个函数指针,指向位于 0x4EAA90 的函数,在 C++ 中,函数指针可以像函数一样使用。

以上代码generates the following assembly in GCC 8.2:

drawRectangle(int, int, int, int, int, int, int, int):
        subl    $12, %esp
        movl    $5155472, %eax
        call    *%eax
        movl    (%eax), %edx
        movl    %eax, %ecx
        pushl   44(%esp)
        pushl   44(%esp)
        pushl   44(%esp)
        pushl   44(%esp)
        pushl   44(%esp)
        pushl   44(%esp)
        pushl   44(%esp)
        pushl   44(%esp)
        call    *20(%edx)
        addl    $12, %esp
        ret

还有following assembly with Visual C++ 2017:

void drawRectangle(int,int,int,int,int,int,int,int) PROC                  ; drawRectangle, COMDAT
        mov     eax, 5155472                          ; 004eaa90H
        call    eax
        push    DWORD PTR _blue$[esp-4]
        mov     ecx, eax
        push    DWORD PTR _green$[esp]
        mov     edx, DWORD PTR [eax]
        push    DWORD PTR _red$[esp+4]
        push    DWORD PTR _height$[esp+8]
        push    DWORD PTR _width$[esp+12]
        push    DWORD PTR _y$[esp+16]
        push    DWORD PTR _x$[esp+20]
        push    DWORD PTR _surface$[esp+24]
        call    DWORD PTR [edx+20]
        ret     0
void drawRectangle(int,int,int,int,int,int,int,int) ENDP                  ; drawRectangle

【讨论】:

  • 完美。谢谢
  • 您能否详细说明一下您是如何看到界面中至少有6个虚拟功能的?在 0-4-8-C 计数到 10 之后,我也不明白它是如何发生的
  • @SornNaserZupanicMaksumic 十六进制 C + 4 = 10。
  • 你怎么知道它是对象中的函数而不是变量?
  • 另外,如果你有时间,即使不推荐:你将如何在内联汇编中编写它?包括保存和加载寄存器。我玩过从 Godbolt 生成的 VS 2017 代码,但没有运气。只是好奇。
猜你喜欢
  • 2013-10-25
  • 2010-12-28
  • 1970-01-01
  • 1970-01-01
  • 2019-10-26
  • 2012-01-12
  • 2018-04-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多