windows内的各个进程有各自的地址空间。它们相互独立互不干扰保证了系统的安全性。但是windows也为调试器或是其他工具设计了一些函数,这些函数可以让一个进程对另一个进程进行操作。虽然他们是为调试器设计的,但是任何应用程序都可以调用它们 。接下来我们来谈谈使用远程线程来注入DLL。
从根本上说,DLL注入就是将某一DLL注入到某一进程的地址空间。该进程中的一个线程调用LoadLibrary来载入想要注入的DLL。由于我们不能直接控制其他进程内的线程,因此我们必须在其他进程内创建一个我们自己的线程。我们可以对新创建的线程加以控制,让他调用LoadLibrary来载入DLL。windows提供了一个函数,可以让我们在其他进程内创建一个线程:
在其他进程内创建的线程被称为:远程线程,该进程被称为远程进程。
HANDLE WINAPI CreateRemoteThread(
__in HANDLE hProcess,
__in LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in SIZE_T dwStackSize,
__in LPTHREAD_START_ROUTINE lpStartAddress,
__in LPVOID lpParameter,
__in DWORD dwCreationFlags,
__out LPDWORD lpThreadId
);
很容易吧。该函数除了第一个参数hProcess,标识要创建的线程所属的进程外,其他参数与CreateThread的参数完全相同。
参数lpstartAddress是线程函数的地址。由于是在远程进程创建的,所以该函数一定必须在远程进程的地址空间内。
现在知道了如何在另一个进程创建一个线程,那么我们如何让该线程载入我们的DLL呢?
先别急着让线程调用LoadLibrary载入DLL,现在要考虑的是如何让线程运行起来,即为线程选择线程函数。因为线程是在其他进程内运行的,所以该线程函数必须符合以下条件:
1:该函数符合线程函数的原型,
2:存在于远程线程地址空间内。
仔细分析下,远程线程的任务只有一个。就是调用LoadLibray加载DLL。
既然如此可不可以让LoadLibrary直接作为线程函数呢?
先看第一个条件:函数签名是否相同。你还别说,除了参数类型有点不一样外,其他一摸一样的。由于参数类型可以通过强转实现,所以第一个条件是满足的。
再看第二个条件:该函数是否在远程进程地址空间内。用屁股想一下我们都知道肯定在。另外他们都有相同的函数调用约定,也就是说他们的参数传递是从右到左压栈的,有子程序平衡堆栈。OK,太棒了。使用LoadLibrary作为线程函数真的是太方便了 。
难道是微软故意为我们这样设计的?无从知晓。但在这里要谢谢发现这一技巧的牛人。
查看MSDN可以发现LoadLibrary并不是一个API,它其实是一个宏。
在WinBase.h可以发现这样一句话:
#ifdef UNICODE
#define LoadLibrary LoadLibraryW
#else
#define LoadLibrary LoadLibraryA
#endif
明白了吗?实际上有两个Load*函数,他们的唯一区别就是参数类型不同。如果DLL文件名是以ANSI形式保存的,我们就必须调用LoadLibraryA,如果是UNICODE形式保存的我们就必须调用LoadLibraryW。
接下来我们要做的事情就简单了,只需要调用CreateThread函数,传给标识线程函数的参数LoadLibraryA或是LoadLibraryW。然后将我们要远程进程加载的DLL的路径名的地址作为参数传给它。哈哈,很兴奋吧!一切都是那么的顺!
不要高兴的太早。你就没发现哪有不对的地方吗?传给线程函数的参数是DLL路径名的地址。但是该地址是在我们进城内的。如果远程进程引用此地址的数据,很可能会导致访问违规,远程进程被终止。怎么样很严重吧。但这也给我们一个破坏其他进程的思路。哈哈。自己发挥吧!
为了解决这个问题,我们应该将该字符串放到远程地址的地址空间去。有没有相应的函数呢?当然有!
首先应该在远程进程的地址空间分配一块儿内存。如何做呢!或许你很熟悉VirtualAlloc,但是他没有这个功能。他兄弟VirtualAllocEx可以解决这个问题。看原型:
LPVOID WINAPI VirtualAllocEx(
__in HANDLE hProcess,
__in_opt LPVOID lpAddress,
__in SIZE_T dwSize,
__in DWORD flAllocationType,
__in DWORD flProtect
);
hProcess应该知道是干嘛的吧。他就是标识你要想在那个进程的地址空间申请内存的进程句柄。其他参数跟VirtualAlloc完全相同。此处不再介绍。
当然知道如何申请还有知道如何释放!看他搭档:VirtualFreeEx
BOOL WINAPI VirtualFreeEx(
__in HANDLE hProcess,
__in LPVOID lpAddress,
__in SIZE_T dwSize,
__in DWORD dwFreeType
);
与VirtualFree的区别这只是多一个进程句柄。
现在申请空间的任务完成了,要怎么样将本进程的数据复制到另外一个进程呢?可以使用ReadProcessMemory和WriteProcessMemory
BOOL WINAPI ReadProcessMemory(
__in HANDLE hProcess,
__in LPCVOID lpBaseAddress,
__out LPVOID lpBuffer,
__in SIZE_T nSize,
__out SIZE_T *lpNumberOfBytesRead
);
BOOL WINAPI WriteProcessMemory(
__in HANDLE hProcess,
__in LPVOID lpBaseAddress,
__in LPCVOID lpBuffer,