【问题标题】:How does one pass on parameters in assembly?如何在汇编中传递参数?
【发布时间】:2014-11-05 01:01:47
【问题描述】:

我正在研究 C++ 和 ASM 中的钩子,目前我刚刚制作了一个简单的内联钩子,它在目标函数的第一条指令中放置一个跳转,在这种情况下是 OutputDebugString,仅用于测试目的。

问题是我的钩子在经过大约 3 天的研究并弄清楚了事情是如何工作的细节和平静之后终于工作了,但是有一个问题我不知道如何更改进入我的“假人”的参数" 函数,然后跳到原始函数的其余部分。

正如你在我的代码中看到的那样,我试图在 C++ 中简单地更改参数,但当然这不起作用,因为我之后会弹出所有寄存器:/

无论如何这里是我的虚拟函数,它是挂钩函数跳转到的:

static void __declspec(naked) MyDebugString(LPCTSTR lpOutputString) {
     __asm {
         PUSHAD
     }

     //Where i suppose i could run my code, but not be able to interfere with parameters :/
     lpOutputString = L"new message!";

     __asm {
         POPAD
         MOV EDI, EDI
         PUSH EBP
         MOV EBP, ESP
         JMP Addr
     }

     original_DebugString(lpOutputString);
}

我明白为什么代码不能像我说的那样工作,我只是看不到适当的解决方案,非常感谢任何帮助。

【问题讨论】:

  • 你需要将你的参数移动到工作寄存器,做一个 ADD 来做必要的改变,然后再次移动到你将用于函数参数的位置。
  • 在纯汇编语言中,您通常在寄存器中传递参数。当将汇编与 C(或其他)混合时,您处理传递的参数,因为该语言认为适合传递它们。在这种情况下,它可能在堆栈上(就在返回地址下方)。也就是说,您的代码似乎没有任何实际意义。
  • 我建议你只用一些参数和局部变量创建一个 c/c++ 函数,例如__stdcall 约定,并在反汇编器中查看编译器生成的 asm 代码如何与参数和局部堆栈变量交互并从中学习。它使用了一个简单的技巧,不必总是计算有多少 push*/pop*s。
  • 另外,如果你真的不想处理每个初学者在被编译器帮助你的所有漂亮的 c/c++ 魔法宠坏后所经历的 asm 地狱:如果你挂钩一个函数,并且您知道该函数的确切原型(包括调用约定),您可以给您的钩子函数提供完全相同的原型并在函数体中编写 100% c/c++(因此,摆脱__declspec(naked)

标签: c++ assembly hook


【解决方案1】:

每个编译器都有一个使用汇编语言调用函数的协议。该协议可能会在他们的手册中详细说明。

查找函数协议的更快方法是让编译器为您的函数生成汇编语言列表。

编写内联汇编的最佳方法是:

  1. 先用C++源码写函数
  2. 接下来打印出函数的汇编列表。
  3. 查看并了解编译器生成的程序集的工作原理。
  4. 最后,修改内部组件以满足您的需求。

我的偏好是尽可能高效地编写 C++ 代码(或帮助编译器使用最佳汇编语言)。然后我查看程序集清单。我只更改内联程序集以调用处理器特殊功能(例如块移动指令)。

【讨论】:

    猜你喜欢
    • 2016-10-24
    • 2016-10-01
    • 2014-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-08
    • 1970-01-01
    相关资源
    最近更新 更多