Delphi XE3中64位DLL注入到64位进程无法工作

3

我正在使用这段代码将我的64位dll注入到Windows 7 64位的64位进程中,CreateRemoteThread返回200但仍然没有注入dll,我已经测试过我的dll并且它可以正常工作,Process Explorer显示我的代码无法工作。这段代码可能存在什么问题?我正在使用Delphi XE3,并且已经在64位目标平台上编译了代码。

function InjectDLL(dwPID: DWORD; DLLPath: pwidechar): integer;
var
dwThreadID: Cardinal;
hProc, hThread, hKernel: NativeUInt;
BytesWritten: NativeUInt;
pRemoteBuffer, pLoadLibrary: Pointer;
begin
try
hProc := OpenProcess(PROCESS_ALL_ACCESS, False, dwPID);
if hProc = 0 then
begin
  Result := 0;
  Exit;
end;
pRemoteBuffer := VirtualAllocEx(hProc, nil, Length(DLLPath) + 1, MEM_COMMIT,
  PAGE_READWRITE);
if pRemoteBuffer = nil then
begin
  Result := 0;
  Exit;
end;
if WriteProcessMemory(hProc, Pointer(pRemoteBuffer), lpvoid(DLLPath),
  Length(DLLPath) + 1, BytesWritten) = False then
begin
  Result := 0;
  Exit;
end;
hKernel := GetModuleHandle(pwidechar('kernel32.dll'));
pLoadLibrary := (GetProcAddress(hKernel, pansichar('LoadLibraryA')));
hThread := CreateRemoteThread(hProc, Pointer(nil), 0, Pointer(pLoadLibrary),
  Pointer(pRemoteBuffer), 0, dwThreadID);

WaitForSingleObject(hThread, INFINITE);
VirtualFreeEx(hProc, Pointer(pRemoteBuffer), Length(DLLPath) + 1,
  MEM_RELEASE);
CloseHandle(hThread);
CloseHandle(hProc);
// ShowMessage(IntToStr(hThread)+' '+ inttostr(dwThreadID));
Result := 1;
except
on d: exception do
begin
end;
end;
end;

@hvd,我在这里看不到任何可能引发异常的代码。这只是一堆不会引发异常的WinAPI调用。 - David Heffernan
@DavidHeffernan 你确定吗?如果出现“EAccessViolation”异常,我也不会感到惊讶。 - user743382
@hvd,你认为这里哪个API调用导致了AV异常? - David Heffernan
@DavidHeffernan 我期望 pLoadLibrary 被设置为 nil,这样 CreateRemoteThread 就会得到一个不应该得到的 nil 参数。但是仔细想想,这只有在另一个进程中引发异常时才可能(如果它引发异常)导致异常,因此不会被此代码中的 except 处理程序所覆盖。(尽管忽略任何异常仍然是错误的。) - user743382
@hvd 嗯,我同意最后的观点。我的代码完全剥离了异常处理程序。 - David Heffernan
"CreateRemoteThread返回200但是..." > "请注意,即使lpStartAddress指向数据、代码或不可访问的地址,CreateRemoteThread也可能成功。" - Sertac Akyuz
1个回答

4
你正在调用 LoadLibraryA,但传递的是UTF-16编码的数据。要么切换到 LoadLibraryW,要么将模块名称转换为ANSI编码。
我建议使用前者。除了切换到 LoadLibraryW,你还需要复制整个缓冲区。将两个实例中的 Length(DLLPath) + 1 替换为 SizeOf(Char)*(Length(DLLPath) + 1) 即可实现。
一些注释:
  • 使用 PROCESS_ALL_ACCESS 过度了。你只需要 PROCESS_CREATE_THREAD or PROCESS_QUERY_INFORMATION or PROCESS_VM_OPERATION or PROCESS_VM_WRITE or PROCESS_VM_READ
  • GetProcAddress(hKernel, pansichar('LoadLibraryA')) 中的 PAnsiChar 转换似乎不对。因为 'LoadLibraryA' 是UTF-16编码的。直接使用 GetProcAddress(hKernel, 'LoadLibraryA') 或者如果你选择这条路就使用 'LoadLibraryW'
  • 使用 NativeUInt 来处理句柄是错误的。这并不重要,但你应该使用 THandle
  • 使用 MEM_RELEASE 时,必须将大小参数设为 0
将所有内容结合起来,代码应该是这样的:
function InjectDLL(dwPID: DWORD; DLLPath: PWideChar): integer;
var
  dwThreadID: Cardinal;
  hProc, hThread, hKernel: THandle;
  BytesToWrite, BytesWritten: SIZE_T;
  pRemoteBuffer, pLoadLibrary: Pointer;
begin
  hProc := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_QUERY_INFORMATION or PROCESS_VM_OPERATION or PROCESS_VM_WRITE or PROCESS_VM_READ, False, dwPID);
  if hProc = 0 then
    exit(0);
  try
    BytesToWrite := SizeOf(WideChar)*(Length(DLLPath) + 1);
    pRemoteBuffer := VirtualAllocEx(hProc, nil, BytesToWrite, MEM_COMMIT, PAGE_READWRITE);
    if pRemoteBuffer = nil then
      exit(0);
    try
      if not WriteProcessMemory(hProc, pRemoteBuffer, DLLPath, BytesToWrite, BytesWritten) then
        exit(0);
      hKernel := GetModuleHandle('kernel32.dll');
      pLoadLibrary := GetProcAddress(hKernel, 'LoadLibraryW');
      hThread := CreateRemoteThread(hProc, nil, 0, pLoadLibrary, pRemoteBuffer, 0, dwThreadID);
      try
        WaitForSingleObject(hThread, INFINITE);
      finally
        CloseHandle(hThread);
      end;
    finally
      VirtualFreeEx(hProc, pRemoteBuffer, 0, MEM_RELEASE);
    end;
  finally
    CloseHandle(hProc);
  end;
  exit(1);
end;

个人建议传入一个 string 而不是 PWideChar,但也许你有其他的动机。


你好,Dll注入在MAC OS上能行吗?(因为XE3是为跨平台应用程序构建的,并提供良好的操作系统API抽象层) - Marwen Trabelsi
1
@smarty 嗯,这是完全不同的平台。我认为你需要为 Mac 定制一种解决方案。 - David Heffernan
@DavidHeffernan:谢谢,我也是这么想的...但当他们说“本地多平台部署”时,我认为这对好奇的开发人员来说是一个大谎言,实际上他们必须明确什么是“本地多平台”的重新定义... - Marwen Trabelsi
@smarty注入是特定于平台的。没有人会期望跨平台库以某种方式封装注入。 - David Heffernan
@DavidHeffernan,在DLL注入中,“LoadLibraryW”最初是在“injector.exe”上执行还是已经直接在“target.exe”上执行?因为如果已经直接在“target.exe”上执行,那么就可以通过API Hooking技术从“target.exe”截取此API。我对这个说法正确吗? - user6365505
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接