assembly 如何在Microsoft Visual Studio C/C++编译器中关闭与位置无关的代码编译?

q9rjltbz  于 2022-11-13  发布在  C/C++
关注(0)|答案(1)|浏览(225)

我想知道是否有可能关闭这个位置无关的代码,将汇编指令call从类似于

call [rip+0x1234] // this address is relative to the current code position

变成了

call qword ptr[0x12345678] // this address is absolute and doesn't crash the program

原因是我通过从WinAPI调用CreateRemoteThread创建了一个远程线程,我希望能够通过输入普通代码来调用其他WinAPI函数,但是现在PIC打开了,每次我调用远程线程中的任何函数时,我都会遇到访问冲突,进程崩溃。另外值得一提的是,我知道每个进程都有不同的导入函数地址,但我只调用kernel32.dll中的函数,据我所知,kernel32.dll在每个进程中都加载到相同的绝对地址,所以这不是问题。
是否有一些宏或编译器选项?我也想改变这种行为,只编译一个文件,而不是所有的解决方案。
当然,我的CPU架构是amd64,但我认为这无关紧要。
提前感谢!

1bqhqjot

1bqhqjot1#

如果我没理解错的话,这至少在三个层面上是错误的。
1.不保证新的主机进程会导入您调用的API。如果您调用CryptAcquireContext,链接器将确保在构建的PE中添加advapi32.dllCryptAcquireContext的条目,这是源二进制文件。目标可能一开始就没有这样的导入。

  1. call QWORD PTR [target]仍然使用MASM语法中的32位RIP相对位移,用于符号名称而不是文字数字。我不认为你可以强迫cl(尝试使用链接选项/LARGEADDRESSAWARE:no,但它是一个链接选项,而不是编译器选项)。但即使您这样做了,这也适用于 * 您的 * PE,您的PE需要加载到2GiB以下(对于带符号的32位绝对[disp32]),而几乎可以肯定目标PE不会加载。
    gcc -fno-pie -mcmodel=large将对所有内容使用具有64位绝对地址(mov reg, imm64/call reg)的间接调用,并不假设调用目标在+-2GiB内,但MSVC可能没有这样的选项。
    1.绝对地址需要重定位。您可以强制cl/link发出一个不可移动的PE,从而避免重定位的需要,但是,同样,这是针对 * 您的 * PE,而不是目标PE。
    简而言之,您的汇编代码和二进制可执行文件被绑定在一起,以创建一个进程,在该进程中,您的代码将按预期工作。
    如果迁移到另一个进程,则必须弥补差异,这与编写普通代码(包括访问全局数据)不同。
    如果你已经在写一个DLL,最简单的方法就是用SetWindowsHookEx把新创建的远程线程与你的DLL中的一个函数挂钩。Windows会自动把你的整个DLL注入到目标进程中。使用任何你知道至少会被调用一次的挂钩(这很容易,因为你控制着远程线程的代码)。
    否则,您可以在DLL中移动注入的代码,并注入一个填充程序/加载程序,从磁盘/内存中加载所述DLL。

相关问题