本教程详细介绍了DLL注入的概念、原理及其在Windows操作系统中的应用,并提供了实用的编程示例和技巧。适合对逆向工程及软件开发感兴趣的读者学习。
远程注入DLL的方法有很多种,并且是许多木马病毒隐藏进程的方式之一。通过程序加载的DLL在任务管理器里不会显示出来。这里介绍一种使用CreateRemoteThread函数创建远程线程的方式来实现DLL注入。
首先,我们需要提升自身的权限,因为进行远程注入时不可避免地要访问目标进程的内存空间;如果没有足够的系统权限,则无法执行任何操作。接下来是用于提升所需权限的函数:
```pascal
function EnableDebugPriv: Boolean;
var hToken: THandle; tp: TTokenPrivileges; rl: Cardinal;
begin
Result := false; // 打开进程令牌环
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken);
if LookupPrivilegeValue(nil, SeDebugPrivilege, tp.Privileges[0].Luid) then begin
tp.PrivilegeCount := 1;
tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED; // 调整权限
Result := AdjustTokenPrivileges(hToken, false, tp, SizeOf(tp), nil, rl);
end;
end;
```
关于OpenProcessToken()和AdjustTokenPrivileges()这两个API的简单介绍:
- OpenProcessToken(): 获取进程访问令牌句柄。
- AdjustTokenPrivileges(): 调整进程权限。
远程注入DLL实际上是通过CreateRemoteThread函数创建一个远程线程来调用LoadLibrary函数加载指定的DLL。然而,如何让这个远程线程知道要加载哪个DLL呢?要知道,在Windows系统中,每个进程都有独立的4GB虚拟地址空间。因此,我们需要在目标进程中分配内存并写入欲注入的DLL路径。
实现这一功能需要以下API:
- OpenProcess(): 打开目标进程以获取操作权限。
- VirtualAllocEx(): 在远程进程内存中申请一块用于存放DLL文件名的空间。
- WriteProcessMemory(): 将DLL路径写入到上述空间内。
然后,我们就可以调用CreateRemoteThread来创建一个远程线程,该线程会调用LoadLibrary函数加载指定的DLL。
以下是具体的实现代码:
```pascal
function InjectDll(const DllFullPath: string; const dwRemoteProcessId: Cardinal): Boolean;
var hRemoteProcess, hRemoteThread: THandle; pszLibFileRemote: Pointer;
pszLibAFilename: PwideChar; pfnStartAddr: TFNThreadStartRoutine;
memSize, WriteSize, lpThreadId :Cardinal;
begin
Result := false;
if EnableDebugPriv then begin // 调整权限,使程序可以访问其他进程的内存空间
hRemoteProcess := OpenProcess(PROCESS_ALL_ACCESS, false, dwRemoteProcessId);
try
GetMem(pszLibAFilename, Length(DllFullPath) * 2 + 1);
StringToWideChar(DllFullPath, pszLibAFilename, Length(DllFullPath) * 2 + 1);
memSize := (1 + lstrlenW(pszLibAFilename)) * SizeOf(WCHAR);
pszLibFileRemote := VirtualAllocEx(hRemoteProcess, nil, memSize, MEM_COMMIT, PAGE_READWRITE);
if Assigned(pszLibFileRemote) then begin
WriteProcessMemory(hRemoteProcess, pszLibFileRemote, pszLibAFilename, memSize, WriteSize);
lpThreadId := 0;
pfnStartAddr := GetProcAddress(LoadLibrary(Kernel32.dll), LoadLibraryW);
hRemoteThread := CreateRemoteThread(hRemoteProcess, nil, 0, pfnStartAddr, pszLibFileRemote, 0, lpThreadId);
if (hRemoteThread <> 0) then Result := true;
end;
finally
CloseHandle(hRemoteProcess);
end;
end;
end;
```
接下来是卸载目标进程中注入的DLL的过程,其原理与注入过程相似,唯一的区别在于远程调用的是FreeLibrary函数。代码如下:
```pascal
function UnInjectDll(const DllFullPath: string; const dwRemoteProcessId: Cardinal): Boolean;
var hRemoteProcess, hRemoteThread : THandle; pszLibFileRemote : PChar;
pszLibAFilename :PwideChar ; pfnStartAddr : TFNThreadStartRoutine ;
memSize , WriteSize , lpThreadId ,dwHandle :Cardinal;
begin
Result := false;
if EnableDebugPriv then begin // 调整权限,使程序可以访问其他进程的内存空间
hRemoteProcess := OpenProcess(PROCESS_ALL_ACCESS, false, dwRemoteProcessId);
try
GetMem(pszLibAFilename, Length(DllFullPath) * 2 + 1);
StringToWideChar(DllFullPath, pszLibAFilename