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的分享 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 解决方案
以下是针对问题的逐步排查和修复建议:
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 的输出,我可以进一步帮你分析。
你直接远线程调用GetProcAddress就行了,或者你读目标进程peb拿到模块列表也可以,不过需要注意32位和64位的兼容性 lies2014 发表于 2025-3-29 08:57
GetProcAddress 只能获取本进程模块的函数地址,pInstallHook := GetProcAddress(hDll, PAnsiChar(AnsiStri ...
大佬,请问一下什么情况下不同进程加载的系统模块地址会不同呢?我之前看一本书上没有讲到不同的特殊情况
页:
[1]