【问题标题】:How to inline assembly in C++?如何在 C++ 中内联汇编?
【发布时间】:2019-03-14 20:10:06
【问题描述】:

我正在尝试将一些程序集注入到应用程序中,但在这一行出现错误: 这是完整的代码

#define _TOJUMP 0xCDFA43 

BYTE bak_InitDamageBuff[6];

void unHook(BYTE* from, BYTE* backup, size_t size) {
    DWORD protect;
    VirtualProtect(from, size, PAGE_EXECUTE_READWRITE, &protect);
    memcpy(from, backup, size);
    VirtualProtect(from, size, protect, &protect);
}

void Hook(BYTE* from, void* to, BYTE* backup, size_t size) {
    DWORD protect;
    VirtualProtect(from, size, PAGE_EXECUTE_READWRITE, &protect);
    memcpy(backup, from, size);
    DWORD diff = ((DWORD)to - (DWORD)from) - size;
    memset(from, 0x90, size);
    *(BYTE*)from = 0xE9;
    *(DWORD*)((DWORD)from + 1) = diff;
    VirtualProtect(from, size, protect, &protect);
}

DWORD return_address = _TOJUMP + 0x6;
static __declspec(naked) void NewInitDamageBuff() {
    _asm {
        mov [edx + 0x29D0], 0x‭0F4240‬;    <-------------
        jmp return_address;
    }
}

void Main_thread() {
    while (1) {
        Hook((PBYTE)_TOJUMP, &NewInitDamageBuff, bak_InitDamageBuff, 6);
    }
}

这有什么问题?

编译器是Visual Studio

我在葡萄牙语中使用它,但我尝试翻译错误

-数字的后缀不正确

-整数 litarals 必须至少有一个数字

  • 一些不好的令牌

【问题讨论】:

  • 不明确的操作数大小,你需要告诉编译器你想要dword ptrword ptr,还是什么。这可能是错误消息告诉您的内容,但您忽略了它,所以这不是minimal reproducible example
  • 对于初学者来说,每个call 都应该遇到ret,并且不知道这个函数是否是这种情况(如果你甚至可以称它为函数),不清楚你是什么正在做,这是勾搭的尝试吗?你甚至知道edxcall 生成时的状态吗?您似乎很确定这是一个有效的内存地址,但您是如何得出这个结论的?
  • 我遇到错误 那为什么它们没有包含在您的帖子中?我们无法从我们所在的位置看到您的屏幕,但您可以。您没有理由不在帖子中包含这些错误。请edit 这样做。当你使用它时,你也可以为你正在使用的编译器添加一个标签。
  • @Havenard:函数可以以jmp 尾调用而不是ret 结束。这是完全正常的。但是,是的,它不应该被称为return_address
  • @MichaelPetch:嘿,有趣的是,我们在编辑几个小时后同时回到这个问题,使其成为非最小的主要 CVE。根据我的复制/粘贴 hexdump,x 是一个普通的 ASCII x,但后面跟着一些时髦的东西。我没有在 unicode 表中查找它。

标签: c++ visual-studio assembly inline-assembly


【解决方案1】:

0x‭0F4240‬ 中有一些非 ASCII 字符;这就是 MSVC 令人窒息的地方。


MSVC 内联 asm 确实接受 0xDEADBEEF C 样式十六进制格式的数字文字(与 MASM 不同),因此您的 asm 看起来应该编译/汇编。 (好不好用是另外一回事。)

错误信息是:

<source>(9): error C2059: syntax error: 'bad suffix on number'
<source>(9): error C2153: integer literals must have at least one digit
<source>(9): error C3872: '0xac': this character is not allowed in an identifier
<source>(9): error C2400: inline assembler syntax error in 'second operand'; found 'bad token'

我将您的函数放在the Godbolt compiler explorer 上以获取实际的错误消息,并使用DWORD 的typedef,因为Godbolt 没有Windows.h 来定义它。

typedef unsigned long DWORD;
#define _TOJUMP 0xCDFA43

DWORD return_address = _TOJUMP + 0x6;
static __declspec(naked) void NewInitDamageBuff() {
    _asm {
        mov [edx + 0x29D0], 0x‭0F4240‬;   // original
        mov [edx + 0x29D0], 0x0F4240;   // retyped compiles fine if you comment out the original
        jmp return_address;
    }
}

这些错误消息让我觉得里面有一个非 ASCII 字符正在阻塞,然后在我的 Linux 桌面上复制/粘贴到 hexdump -C 即可确认:

00000000  6d 6f 76 20 5b 65 64 78  20 2b 20 30 78 32 39 44  |mov [edx + 0x29D|
00000010  30 5d 2c 20 30 78 e2 80  ad 30 46 34 32 34 30 e2  |0], 0x...0F4240.|
00000020  80 ac 3b 0a                                       |..;.|

(输出的 ASCII 端的. 表示不可打印的字节)。

所以在 mov 的源操作数中的 0x 之后,有一个 80 ad 30 3 字节 UTF-8 序列,显然不会打印任何东西。

【讨论】:

  • 几分钟前在 cmets 中得出了这个结论。我不知道他们是如何到达那里的。; 之前还有另一个这样的角色@
猜你喜欢
  • 2013-07-23
  • 2013-11-26
  • 1970-01-01
  • 2017-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多