千影 发表于 2025-3-28 08:41

delphi 远程注入 GetProcAddress 一直获取不到

以下下为 dll,已经用 exe 注入到第三方进程,第三方进程也是我自己做的,上边就是一个按钮输出memo1.lines.add(datetimetostr(now));
;library TimeHookDLL;

uses
Windows, SysUtils, DDetours,inifiles;

type
TGetLocalTime = procedure(var lpSystemTime: TSystemTime); stdcall;

var
TrampolineGetLocalTime: TGetLocalTime = nil;
procedure WriteLog(const Msg: string);
var
LogFile: TextFile;
begin
AssignFile(LogFile, 'D:\1.txt');
try
    if FileExists('D:\1.txt') then
      Append(LogFile)
    else
      Rewrite(LogFile);
    Writeln(LogFile, FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', Now) + ' - ' + Msg);
    CloseFile(LogFile);
except
    // 忽略文件写入错误
end;
end;

function readiniint(path1111,lei1,xiang1:string):Integer ;
var
inifile:TIniFile;
begin

inifile:=nil;
            try
            begin
            inifile:=Tinifile.Create(path1111);
            result:=inifile.ReadInteger(lei1,xiang1,0);
            End;
            except
            Result:=0;
            end;
               inifile.Free;

end;

procedure HookedGetLocalTime(var lpSystemTime: TSystemTime); stdcall;


begin
WriteLog('DLL: HookedGetLocalTime被调用');

if Assigned(TrampolineGetLocalTime) then
    TrampolineGetLocalTime(lpSystemTime);



if readiniint('d:\date.ini','config','change' )=1 then
begin
lpSystemTime.wYear:=readiniint('d:\date.ini','config','Year' );
lpSystemTime.wMonth:=readiniint('d:\date.ini','config','Month' );
lpSystemTime.wDay:=readiniint('d:\date.ini','config','Day' );
lpSystemTime.wHour:=readiniint('d:\date.ini','config','Hour' );
lpSystemTime.wMinute:=readiniint('d:\date.ini','config','Minute' );
lpSystemTime.wSecond:=readiniint('d:\date.ini','config','Second' );


end;
// 修改时间
// lpSystemTime.wYear := 2023;
// lpSystemTime.wMonth := 1;
// lpSystemTime.wDay := 1;

   // Result := TrampolineGetLocalTime(lpSystemTime);



WriteLog(PChar('DLL: 修改后的时间: ' +
    IntToStr(lpSystemTime.wYear) + '/' +
    IntToStr(lpSystemTime.wMonth) + '/' +
    IntToStr(lpSystemTime.wDay)));
end;




procedure Runtest; stdcall;
begin
WriteLog('DLL: runtest');

end;

procedure InstallHook; stdcall;
begin
WriteLog('DLL: 正在安装Hook');
try
    @TrampolineGetLocalTime := InterceptCreate(kernel32, 'GetLocalTime', @HookedGetLocalTime);
    if Assigned(TrampolineGetLocalTime) then
      WriteLog('DLL: Hook安装成功,原始函数地址: ' + IntToHex(NativeInt(@TrampolineGetLocalTime), 8))
    else
      WriteLog('DLL: Hook安装失败 - InterceptCreate返回nil');
except
    on E: Exception do
      WriteLog('DLL: Hook安装异常: ' + E.Message);
end;
end;

procedure RemoveHook; stdcall;
begin
WriteLog('DLL: 正在移除Hook');
if Assigned(TrampolineGetLocalTime) then
begin
    InterceptRemove(@TrampolineGetLocalTime);
    TrampolineGetLocalTime := nil;
    WriteLog('DLL: Hook已移除');
end;
end;


// DLL 入口(初始化)
procedure DLLMain(Reason: DWORD);
begin
case Reason of
    DLL_PROCESS_ATTACH:
   begin

      WriteLog('DLL 已开始运行: ' + IntToStr(GetCurrentProcessId));end;
    DLL_PROCESS_DETACH:
   begin
         WriteLog('DLL 已卸载');   end;
end;
end;

exports
InstallHook name 'InstallHook',
RemoveHook name 'RemoveHook',
Runtest   name 'Runtest';
begin
WriteLog('DLL已加载,正在自动安装Hook');
DLLProc := @DLLMain;
DLLMain(DLL_PROCESS_ATTACH);
InstallHook;
end.
exe中的注入 代码 function InjectDll(pid: Cardinal; Dll: string): Cardinal;
var
hProc: Cardinal;
wDllPath: PwideChar;
pRemote: Pointer;
cbSize: Cardinal;
TempVar: Cardinal;
BytesWritten: SIZE_T; // 改为 SIZE_T 类型
begin
Result := 0;
if pid = 0 then
    Exit;
EnabledDebugPrivilege(true);
cbSize := Length(Dll) * 2 + 21;
GetMem(wDllPath, cbSize);
StringToWideChar(Dll, wDllPath, cbSize);
hProc := OpenProcess(PROCESS_ALL_ACCESS, False, pid);
try
    pRemote := VirtualAllocEx(hProc, nil, cbSize, MEM_COMMIT, PAGE_READWRITE);

    // WriteProcessMemory(hProcess, pDLLPath, PChar(DLLPath), Length(DLLPath) + 1, BytesWritten)
    if WriteProcessMemory(hProc, pRemote, wDllPath, cbSize, BytesWritten) then
    begin
      TempVar := 0;
      Result := CreateRemoteThread(hProc, nil, 0,
      GetProcAddress(GetModuleHandle('Kernel32'), 'LoadLibraryW'), pRemote, 0,
      PDWORD(nil)^);
    end;
finally
    CloseHandle(hProc);
    FreeMem(wDllPath);
end;
end;   


exe里一直已经注入成功,现在想运行里边的函数
procedure runProcess(ProcessID: DWORD; const DllPath: string; hanshu: string);
var
hProcess, hThread: THandle;
pRemoteMemory: Pointer;
ThreadId: DWORD;
BytesWritten: SIZE_T;
LoadLibAddr: Pointer;
dwExitCode: DWORD;
hDll: HMODULE;
pInstallHook: Pointer; // 改为 Pointer 类型
DllName: string;
begin
// 添加调试输出
WriteLog('准备注入DLL到进程: ' + inttostr(ProcessID));
WriteLog('DLL路径: ' + DllPath);

// 获取目标进程句柄
hProcess := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_QUERY_INFORMATION or
    PROCESS_VM_OPERATION or PROCESS_VM_WRITE or PROCESS_VM_READ, False,
    ProcessID);
if hProcess = 0 then
begin
    WriteLog('打开进程失败,错误代码: ' + inttostr(GetLastError));
    RaiseLastOSError;
end;

try
    // 在目标进程中分配内存
    pRemoteMemory := VirtualAllocEx(hProcess, nil, Length(DllPath) + 1,
      MEM_COMMIT or MEM_RESERVE, PAGE_READWRITE);
    if pRemoteMemory = nil then
    begin
      WriteLog('分配远程内存失败');
      RaiseLastOSError;
    end;

    try
      // 写入DLL路径到目标进程
      if not WriteProcessMemory(hProcess, pRemoteMemory, PChar(DllPath),
      Length(DllPath) + 1, BytesWritten) then
      begin
      WriteLog('写入远程内存失败');
      RaiseLastOSError;
      end;

      // 获取 LoadLibraryA 地址
      LoadLibAddr := GetProcAddress(GetModuleHandle('kernel32.dll'),
      'LoadLibraryA');
      if LoadLibAddr = nil then
      begin
      WriteLog('获取LoadLibraryA地址失败');
      RaiseLastOSError;
      end;

      // 创建远程线程调用 LoadLibraryA
      hThread := CreateRemoteThread(hProcess, nil, 0, LoadLibAddr,
      pRemoteMemory, 0, ThreadId);
      if hThread = 0 then
      begin
      WriteLog('创建远程线程失败');
      RaiseLastOSError;
      end;

      try
      // 等待线程结束
      WaitForSingleObject(hThread, INFINITE);

      // 获取线程退出代码
      GetExitCodeThread(hThread, dwExitCode);
      WriteLog('远程线程退出代码: ' + IntToHex(dwExitCode, 8));

      // 获取DLL模块句柄
      DllName := ExtractFileName(DllPath);
      hDll := GetRemoteModuleHandle(hProcess, DllName);
      if hDll <> 0 then
      begin
          WriteLog('DLL已加载,模块句柄: ' + IntToHex(hDll, 8));

          // 获取 Runtest 函数地址
         pInstallHook := GetProcAddress(hDll, PAnsiChar(AnsiString(hanshu)));
      //pInstallHook := GetProcAddress(hDll, PwideChar( String(hanshu)));
          if Assigned(pInstallHook) then
          begin
            WriteLog('找到 ' + hanshu + ' 函数,准备调用');
            hThread := CreateRemoteThread(hProcess, nil, 0, pInstallHook, nil,
            0, ThreadId);

            if hThread <> 0 then
            begin
            WaitForSingleObject(hThread, INFINITE);
            WriteLog(hanshu + ' 调用完成');
            CloseHandle(hThread);
            end
            else
            WriteLog('创建远程线程调用 ' + hanshu + ' 失败,错误代码: ' +
                inttostr(GetLastError));
          end
          else
            WriteLog('无法获取 ' + hanshu + ' 函数地址,错误代码: ' +
            inttostr(GetLastError));
      end
      else
          WriteLog('DLL未正确加载到目标进程');
      finally
      CloseHandle(hThread);
      end;
    finally
      VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE);
    end;
finally
    CloseHandle(hProcess);
end;
WriteLog('DLL注入完成');
end;

运行到 pInstallHook := GetProcAddress(hDll, PAnsiChar(AnsiString(hanshu)));一直找不到函数 。。    使用的DELPHI10。。。用DEEPSEEK 看来看去越整越错 。 请高手来看看哪里错了。
全部代码 已上传度盘
通过网盘分享的文件:HOOK系统时间3_xe10_0006.rar
链接: https://pan.baidu.com/s/1e8Bp6HYmPfDxEJ3TjI7YDQ?pwd=52pj 提取码: 52pj
--来自百度网盘超级会员v8的分享

lies2014 发表于 2025-3-29 08:57

GetProcAddress 只能获取本进程模块的函数地址,pInstallHook := GetProcAddress(hDll, PAnsiChar(AnsiString(hanshu))) 中的 hDll 是其他进程的,当然得不到结果
想取其他进程的函数,你需要远程执行 GetProcAddress,再通过进程间通信机制拿到返回结果
上面的 GetProcAddress(GetModuleHandle('Kernel32'), 'LoadLibraryW') 之所以成功,是因为本进程也有 Kernel32.Dll,实际你取到的是本进程的 LoadLibraryW 地址
只是因为系统模块的地址在不同的进程中通常(不是绝对)是固定的,所以远程执行才可能会成功,实际上这样实现是不严谨的
如何获取远端模块函数地址,这贴有一个 GetRemoteProcAddress 实现方案,你可以参考一下:
https://www.52pojie.cn/thread-1935674-1-1.html

m_h 发表于 2025-6-14 13:07

解决方案
以下是针对问题的逐步排查和修复建议:

1. 确认导出的函数名称
Delphi 在导出函数时可能会添加修饰(如 _FunctionName@N),你需要检查 DLL 实际导出的函数名称。可以使用以下工具或方法:

使用 Dependency Walker 或 dumpbin:
使用 dumpbin /exports TimeHookDLL.dll 查看导出的函数名称。
或者使用 Dependency Walker 打开 DLL,查看 Runtest、InstallHook 等函数的实际导出名称。
如果导出的名称是 _Runtest@0 或类似形式,你需要在 GetProcAddress 中使用这个修饰后的名称。
在 Delphi 中明确导出名称: 修改 DLL 的 exports 部分,确保函数名称不被修饰。例如:
exports
InstallHook name 'InstallHook',
RemoveHook name 'RemoveHook',
Runtest name 'Runtest';
确保 name 后面的字符串与你在 GetProcAddress 中使用的字符串完全一致。
2. 修改 GetProcAddress 的调用
你的代码中使用了 PAnsiChar(AnsiString(hanshu)),这在 Unicode 环境中可能导致问题。建议尝试以下修改:
使用宽字符版本:
pInstallHook := GetProcAddress(hDll, PWideChar(hanshu));
或者确保 hanshu 是 ANSI 字符串,并且与 DLL 导出的名称完全匹配:
pInstallHook := GetProcAddress(hDll, PAnsiChar(hanshu));
如果导出的函数名称有修饰(例如 _Runtest@0),需要显式指定修饰名称:
pInstallHook := GetProcAddress(hDll, '_Runtest@0');
3. 确保 GetRemoteModuleHandle 正确实现
GetRemoteModuleHandle 是一个自定义函数,用于获取目标进程中加载的 DLL 模块句柄。如果这个函数实现有问题,可能导致 hDll 为 0 或无效。以下是一个典型的 GetRemoteModuleHandle 实现,供参考:
function GetRemoteModuleHandle(hProcess: THandle; const ModuleName: string): HMODULE;
var
hSnapshot: THandle;
me32: TModuleEntry32;
begin
Result := 0;
hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE or TH32CS_SNAPMODULE32, GetProcessId(hProcess));
if hSnapshot = INVALID_HANDLE_VALUE then
    Exit;

try
    me32.dwSize := SizeOf(TModuleEntry32);
    if Module32First(hSnapshot, me32) then
    begin
      repeat
      if SameText(me32.szModule, ModuleName) then
      begin
          Result := HMODULE(me32.modBaseAddr);
          Break;
      end;
      until not Module32Next(hSnapshot, me32);
    end;
finally
    CloseHandle(hSnapshot);
end;
end;
在调用 GetRemoteModuleHandle 时,确保 ModuleName 是 DLL 文件名(例如 TimeHookDLL.dll),并且大小写匹配。

4. 使用 LoadLibraryW 替代 LoadLibraryA
你的 runProcess 函数使用了 LoadLibraryA,但在 Unicode 环境中(如 Delphi 10),建议使用 LoadLibraryW:

LoadLibAddr := GetProcAddress(GetModuleHandle('kernel32.dll'), 'LoadLibraryW');
if LoadLibAddr = nil then
begin
WriteLog('获取LoadLibraryW地址失败');
RaiseLastOSError;
end;
同时,修改 DLL 路径的写入为宽字符:

pRemoteMemory := VirtualAllocEx(hProcess, nil, (Length(DllPath) + 1) * SizeOf(WideChar), MEM_COMMIT or MEM_RESERVE, PAGE_READWRITE);
if not WriteProcessMemory(hProcess, pRemoteMemory, PWideChar(DllPath), (Length(DllPath) + 1) * SizeOf(WideChar), BytesWritten) then
begin
WriteLog('写入远程内存失败');
RaiseLastOSError;
end;
5. 确保 DLL 和目标进程的位数匹配
确认目标进程和 DLL 的位数(32 位或 64 位)是否一致。如果目标进程是 32 位,DLL 也必须是 32 位编译的。
在 Delphi 中,检查项目设置,确保 DLL 和注入程序的位数与目标进程匹配。
6. 添加调试日志
为了进一步定位问题,建议在 runProcess 中添加更多日志,记录 hDll 和 pInstallHook,例如:
hDll := GetRemoteModuleHandle(hProcess, DllName);
if hDll <> 0 then
begin
WriteLog('DLL已加载,模块句柄: ' + IntToHex(hDll, 8));
pInstallHook := GetProcAddress(hDll, PAnsiChar(hanshu)); // 或 PWideChar(hanshu)
if Assigned(pInstallHook) then
    WriteLog(hanshu + ' 函数地址: ' + IntToHex(NativeInt(pInstallHook), 8))
else
    WriteLog('无法获取 ' + hanshu + ' 函数地址,错误代码: ' + IntToStr(GetLastError));
end
else
WriteLog('DLL未正确加载到目标进程,错误代码: ' + IntToStr(GetLastError));
7. 检查目标进程的上下文
确保目标进程的 PID 有效,并且 DLL 已正确加载。
使用 Process Explorer 或类似的工具,检查目标进程是否加载了 TimeHookDLL.dll。
8. 验证 DLL 的初始化
你的 DLL 在加载时会自动调用 InstallHook(通过 DLLMain)。确保 InstallHook 没有抛出异常,可能导致 DLL 初始化失败。可以在 DLLMain 中添加更多日志:
procedure DLLMain(Reason: DWORD);
begin
case Reason of
    DLL_PROCESS_ATTACH:
    begin
      WriteLog('DLL 已开始运行: ' + IntToStr(GetCurrentProcessId));
      try
      InstallHook;
      except
      on E: Exception do
          WriteLog('DLL 初始化失败: ' + E.Message);
      end;
    end;
    DLL_PROCESS_DETACH:
    begin
      WriteLog('DLL 已卸载');
      RemoveHook;
    end;
end;
end;
修改后的 runProcess 函数
以下是修改后的 runProcess 函数,综合了上述建议:
procedure runProcess(ProcessID: DWORD; const DllPath: string; hanshu: string);
var
hProcess, hThread: THandle;
pRemoteMemory: Pointer;
ThreadId: DWORD;
BytesWritten: SIZE_T;
LoadLibAddr: Pointer;
dwExitCode: DWORD;
hDll: HMODULE;
pInstallHook: Pointer;
DllName: string;
begin
WriteLog('准备注入DLL到进程: ' + IntToStr(ProcessID));
WriteLog('DLL路径: ' + DllPath);

hProcess := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_QUERY_INFORMATION or
    PROCESS_VM_OPERATION or PROCESS_VM_WRITE or PROCESS_VM_READ, False, ProcessID);
if hProcess = 0 then
begin
    WriteLog('打开进程失败,错误代码: ' + IntToStr(GetLastError));
    RaiseLastOSError;
end;

try
    pRemoteMemory := VirtualAllocEx(hProcess, nil, (Length(DllPath) + 1) * SizeOf(WideChar),
      MEM_COMMIT or MEM_RESERVE, PAGE_READWRITE);
    if pRemoteMemory = nil then
    begin
      WriteLog('分配远程内存失败,错误代码: ' + IntToStr(GetLastError));
      RaiseLastOSError;
    end;

    try
      if not WriteProcessMemory(hProcess, pRemoteMemory, PWideChar(DllPath),
      (Length(DllPath) + 1) * SizeOf(WideChar), BytesWritten) then
      begin
      WriteLog('写入远程内存失败,错误代码: ' + IntToStr(GetLastError));
      RaiseLastOSError;
      end;

      LoadLibAddr := GetProcAddress(GetModuleHandle('kernel32.dll'), 'LoadLibraryW');
      if LoadLibAddr = nil then
      begin
      WriteLog('获取LoadLibraryW地址失败,错误代码: ' + IntToStr(GetLastError));
      RaiseLastOSError;
      end;

      hThread := CreateRemoteThread(hProcess, nil, 0, LoadLibAddr,
      pRemoteMemory, 0, ThreadId);
      if hThread = 0 then
      begin
      WriteLog('创建远程线程失败,错误代码: ' + IntToStr(GetLastError));
      RaiseLastOSError;
      end;

      try
      WaitForSingleObject(hThread, INFINITE);
      GetExitCodeThread(hThread, dwExitCode);
      WriteLog('远程线程退出代码: ' + IntToHex(dwExitCode, 8));

      DllName := ExtractFileName(DllPath);
      hDll := GetRemoteModuleHandle(hProcess, DllName);
      if hDll <> 0 then
      begin
          WriteLog('DLL已加载,模块句柄: ' + IntToHex(hDll, 8));
          pInstallHook := GetProcAddress(hDll, PAnsiChar(hanshu)); // 或使用 PWideChar(hanshu)
          if Assigned(pInstallHook) then
          begin
            WriteLog(hanshu + ' 函数地址: ' + IntToHex(NativeInt(pInstallHook), 8));
            hThread := CreateRemoteThread(hProcess, nil, 0, pInstallHook, nil, 0, ThreadId);
            if hThread <> 0 then
            begin
            WaitForSingleObject(hThread, INFINITE);
            WriteLog(hanshu + ' 调用完成');
            CloseHandle(hThread);
            end
            else
            WriteLog('创建远程线程调用 ' + hanshu + ' 失败,错误代码: ' + IntToStr(GetLastError));
          end
          else
            WriteLog('无法获取 ' + hanshu + ' 函数地址,错误代码: ' + IntToStr(GetLastError));
      end
      else
          WriteLog('DLL未正确加载到目标进程,错误代码: ' + IntToStr(GetLastError));
      finally
      CloseHandle(hThread);
      end;
    finally
      VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE);
    end;
finally
    CloseHandle(hProcess);
end;
WriteLog('DLL注入完成');
end;
调试步骤
检查日志文件:
查看 D:\1.txt 中的日志,确认 DLL 是否正确加载(是否有 DLL 已开始运行 和 DLL: Hook安装成功 的日志)。
检查 runProcess 的日志,确认 hDll 和 pInstallHook 的值。
验证导出的函数名称:
使用 dumpbin /exports TimeHookDLL.dll 或 Dependency Walker 检查导出的函数名称是否为 Runtest、InstallHook 等。
测试简单的函数调用:
先调用 Runtest 函数(它只写日志),确认是否能成功调用。如果 Runtest 无法调用,说明问题出在导出名称或模块句柄。
确认位数匹配:
确保目标进程、注入程序和 DLL 都是 32 位或 64 位。
总结
最可能的问题是导出的函数名称被修饰(例如 _Runtest@0),或者 GetRemoteModuleHandle 返回了错误的模块句柄。建议:

使用 dumpbin 或 Dependency Walker 检查导出的函数名称。
修改 GetProcAddress 使用正确的函数名称(可能需要修饰名称)。
使用 LoadLibraryW 和宽字符路径。
确保 GetRemoteModuleHandle 正确实现并返回有效的模块句柄。
添加详细日志以定位问题。
如果问题仍未解决,请提供 D:\1.txt 的日志内容,以及 dumpbin /exports TimeHookDLL.dll 的输出,我可以进一步帮你分析。







你好,再见 发表于 2025-6-15 11:54

你直接远线程调用GetProcAddress就行了,或者你读目标进程peb拿到模块列表也可以,不过需要注意32位和64位的兼容性

你好,再见 发表于 2025-6-15 11:56

lies2014 发表于 2025-3-29 08:57
GetProcAddress 只能获取本进程模块的函数地址,pInstallHook := GetProcAddress(hDll, PAnsiChar(AnsiStri ...

大佬,请问一下什么情况下不同进程加载的系统模块地址会不同呢?我之前看一本书上没有讲到不同的特殊情况
页: [1]
查看完整版本: delphi 远程注入 GetProcAddress 一直获取不到