正如标题所说,我正面临着使用包含ASM代码的x64编译器编译Delphi XE2项目的问题。当我尝试编译它时,我收到错误“不支持的语言功能:'ASM'”。
我试图从包含ASM代码的过程中删除delphi代码然后我得到“操作码和操作数的无效组合”。
以下是代码的一部分..
type
TDllLoadInfo = record
Module: pointer;
EntryPoint: pointer;
end;
TGetProcAddrExInfo = record
pExitThread: pointer;
pGetProcAddress: pointer;
pGetModuleHandle: pointer;
lpModuleName: pointer;
lpProcName: pointer;
end;
TInjectLibraryInfo = record
pLoadLibrary: pointer;
lpModuleName: pointer;
pSleep: pointer;
end;
procedure DllEntryPoint(lpParameter: pointer); stdcall;
var
LoadInfo: TDllLoadInfo;
begin
LoadInfo := TDllLoadInfo(lpParameter^);
asm
xor eax, eax
push eax
push DLL_PROCESS_ATTACH
push LoadInfo.Module
call LoadInfo.EntryPoint
end;
end;
procedure GetProcAddrExThread(lpParameter: pointer); stdcall;
var
GetProcAddrExInfo: TGetProcAddrExInfo;
begin
GetProcAddrExInfo := TGetProcAddrExInfo(lpParameter^);
asm
push GetProcAddrExInfo.lpModuleName
call GetProcAddrExInfo.pGetModuleHandle
push GetProcAddrExInfo.lpProcName
push eax
call GetProcAddrExInfo.pGetProcAddress
push eax
call GetProcAddrExInfo.pExitThread
end;
end;
procedure InjectLibraryThread(lpParameter: pointer); stdcall;
var
InjectLibraryInfo: TInjectLibraryInfo;
begin
InjectLibraryInfo := TInjectLibraryInfo(lpParameter^);
asm
push InjectLibraryInfo.lpModuleName
call InjectLibraryInfo.pLoadLibrary
@noret:
mov eax, $FFFFFFFF
push eax
call InjectLibraryInfo.pSleep
jmp @noret
end;
end;
有没有办法编译这个项目而不会出现任何错误或将asm代码转换为delphi / pascal? 谢谢你的时间。顺便说一句,我不知道ASM。
答案 0 :(得分:8)
你不能在64位的非汇编过程中使用内联汇编,仅在32位中。 Embarcadero的文档中明确说明了这一点:
Converting 32-bit Delphi Applications to 64-bit Windows | Inline Assembly code
如果您的应用程序包含内联汇编(ASM)代码,则需要检查ASM代码并进行以下更改:
- 64位应用程序不支持将汇编语句与Pascal代码混合。使用Pascal代码或完全用汇编语言编写的函数替换汇编语句 ...
在您的示例中,没有理由使用内联汇编。您可以(并且应该)使用纯Pascal代码来支持32位和64位:
type
TDllEntryPointFunc = function(hinstDLL: HINSTANCE; fdwReason: DWORD; lpvReserved: Pointer): BOOL; stdcall;
TGetModuleHandleFunc = function(const lpModuleName: PChar): HMODULE; stdcall;
TGetProcAddressFunc = function(hModule: HMODULE; lpProcName: PAnsiChar): Pointer; stdcall;
TExitThreadFunc = procedure(dwExitCode: DWORD); stdcall;
TLoadLibraryFunc = function(const lpFileName: PChar): HMODULE; stdcall;
TSleepFunc = procedure(dwMilliseconds: DWORD); stdcall;
procedure DllEntryPoint(lpParameter: Pointer); stdcall;
var
LoadInfo: TDllLoadInfo;
pEntryPoint: TDllEntryPointFunc;
begin
LoadInfo := TDllLoadInfo(lpParameter^);
@pEntryPoint := LoadInfo.EntryPoint;
pEntryPoint(LoadInfo.Module, DLL_PROCESS_ATTACH, nil);
end;
procedure GetProcAddrExThread(lpParameter: Pointer); stdcall;
var
GetProcAddrExInfo: TGetProcAddrExInfo;
pGetModuleHandle: TGetModuleHandleFunc;
pGetProcAddress: TGetProcAddressFunc;
pExitThread: TExitThreadFunc;
Module: HMODULE;
Proc: Pointer;
begin
GetProcAddrExInfo := TGetProcAddrExInfo(lpParameter^);
@pGetModuleHandle := GetProcAddrExInfo.pGetModuleHandle;
@pGetProcAddress := GetProcAddrExInfo.pGetProcAddress;
@pExitThread := GetProcAddrExInfo.pExitThread;
Module := pGetModuleHandle(PChar(GetProcAddrExInfo.lpModuleName));
Proc := pGetProcAddress(Module, PAnsiChar(GetProcAddrExInfo.lpProcName));
pExitThread(DWORD(Proc));
end;
procedure InjectLibraryThread(lpParameter: Pointer); stdcall;
var
InjectLibraryInfo: TInjectLibraryInfo;
pLoadLibrary: TLoadLibraryFunc;
pSleep: TSleepFunc;
begin
InjectLibraryInfo := TInjectLibraryInfo(lpParameter^);
@pLoadLibrary := InjectLibraryInfo.pLoadLibrary;
@pSleep := InjectLibraryInfo.pSleep;
pLoadLibrary(PChar(InjectLibraryInfo.lpModuleName));
repeat
pSleep(-1);
until False;
end;
答案 1 :(得分:4)
代码无法直接正确移植到x64,因为它会执行64位指针截断 - 详见下文。
The x64 compiler does not support inline assembly:
64位应用程序不支持将汇编语句与Pascal代码混合使用。使用Pascal代码或完全用汇编编写的函数替换汇编语句。
这里使用装配是不必要的。我不确定为什么原作者会选择去解决这个问题。通过转换为Pascal来处理此类移植问题总是最好的,这样编译器就可以完成所有工作。
您可以按以下方式编写代码:
type
TDllLoadInfo = record
Module: HMODULE;
EntryPoint: function(hinstDLL: HMODULE; fdwReason: DWORD;
lpvReserved: Pointer): BOOL; stdcall;
end;
TGetProcAddrExInfo = record
ExitThread: procedure(dwExitCode: DWORD); stdcall;
GetProcAddress: function(hModule: HMODULE;
lpProcName: PAnsiChar): Pointer; stdcall;
GetModuleHandle: function(lpModuleName: PWideChar): HMODULE; stdcall;
lpModuleName: PWideChar;
lpProcName: PAnsiChar;
end;
TInjectLibraryInfo = record
LoadLibrary: function(lpFileName: PWideChar): HMODULE; stdcall;
lpModuleName: PWideChar;
Sleep: procedure(dwMilliseconds: DWORD); stdcall;
end;
procedure DllEntryPoint(lpParameter: pointer); stdcall;
var
LoadInfo: ^TDllLoadInfo absolute lpParameter;
begin
LoadInfo.EntryPoint(LoadInfo.Module, DLL_PROCESS_ATTACH, nil);
end;
procedure GetProcAddrExThread(lpParameter: pointer); stdcall;
var
GetProcAddrExInfo: ^TGetProcAddrExInfo absolute lpParameter;
ModuleHandle: HMODULE;
ProcAddress: Pointer;
begin
ModuleHandle := GetProcAddrExInfo.GetModuleHandle(GetProcAddrExInfo.lpModuleName);
ProcAddress := GetProcAddrExInfo.GetProcAddress(ModuleHandle,
GetProcAddrExInfo.lpProcName);
GetProcAddrExInfo.ExitThread(DWORD(ProcAddress)); // !!!! x64 pointer truncation !!!!
end;
procedure InjectLibraryThread(lpParameter: Pointer); stdcall;
var
InjectLibraryInfo: ^TInjectLibraryInfo absolute lpParameter;
begin
InjectLibraryInfo.LoadLibrary(InjectLibraryInfo.lpModuleName);
while True do // rather pointless to loop ....
InjectLibraryInfo.Sleep(INFINITE);
end;
代码假定您已获得W
后缀Unicode API函数的函数指针。如果没有,请使用PAnsiChar
代替PWideChar
。
然而,在这一点上,我们需要评估并考虑我们刚刚做了什么。我们试图将64位指针推入32位DWORD
线程退出代码。这不一定适合。如果将库加载到4GB以上的地址,那么您将遭受指针截断。
因此,这里的底线是您无法正确将此代码移植到x64。您需要找到此代码的变体,该变体能够从线程返回64位值。但它必须以不同的方式这样做,因为你不能将64位值放入线程返回值。