1 使用注册表来注入DLL
在注册表路径HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersioin\Windows\下,AppInit_Dlls键的值可能会包含一个DLL的文件名活一组DLL的文件名(通过空格或逗号分隔)。将自己写的DLL文件的路径值写入AppInit_Dlls中,再创建一个名为LoadAppInit_Dlls,类型为DWORD的注册表项,并将其值设为1.当User32.dll被映射到一个新的进程时,会受到DLL_PROCESS_ATTACH通知。当User32.dll对它进行处理的时候,会获取上述注册表键的值,并调用LoadLibrary来载入这个字符串中指定的每个DLL。
2 使用Widows挂钩来注入DLL
调用函数SetWindowsHookEx来安装钩子,此函数的声明如下:
HHOOK WINAPI SetWindowsHookEx(
In int idHook,
In HOOKPROC lpfn,
In HINSTANCE hMod,
In DWORD dwThreadId
);
idHook表示要安装的挂钩的类型,lpfn是一个函数的地址,在窗口即将处理一条消息的时候,系统应该调用这个函数,hMod标识一个DLL,这个DLL包含了lpfn函数,dwThreadId表示要给哪个线程安装挂钩。如果这个参数传0,表示要给系统中所有GUI线程安装挂钩。
例如进程A使用SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,hInstDll,0)函数安装挂钩后:
- 进程B中的一个线程准备向一个窗口派送一条消息
- 系统检查该线程是否安装了WH_GETMESSAGE挂钩
- 系统检查GetMsgProc所在的DLL是否已经被映射到进程B的地址空间中,如果DLL尚未被映射,那么系统会强制将该DLL映射到进程B的地址空间中,并将进程B中该DLL的锁计数器递增
- 由于DLL的hInstDll是在进程B中映射的,因此系统会对他进行检查,看他在进程A中的位置是否相同,如果相同,那么在两个进程空间中,GetMsgProc函数位于相同的位置,系统就可以直接在进程A的地址空间中调用GetMsgProc。如果不相同,那么系统必须确定GetMsgProc函数在进程B的地址空间中的虚拟内存地址。使用公式GetMsgProc B=hInstDll B+(GetMsgProc A-hInstDll A)获得
- 系统在进程B中递增该DLL的锁计数器
- 系统在进程B的地址空间中调用GetMsgProc函数
- 当GetMsgProc返回的时候,系统递减该DLL在进程B中的锁计数器
3 使用远程线程来注入DLL
- 使用函数VirtualAllocEx在远程进程的地址空间中分配一块内存
- 使用函数WriteProcessMemory函数把DLL的路径名复制到第一步分配的内存中
- 使用函数GetProcAddress得到LoadLibrary函数的实际地址
- 使用函数CreateRemoteThread函数在远程进程中创建一个线程,让新线程调用正确的LoadLibrary函数并在参数中传入第一步分配的内存地址。现在远程进程中有一块内存,它是在第一步分配的,DLL也还在远程进程的地址空间中。为了对它进行清理,需要在远程线程退出之后执行后续步骤
- 使用函数VirtualFreeEx释放第一步分配的内存
- 使用函数GetProcAddress来得到FreeLibrary函数的实际地址
- 使用函数CreateRemoteThread在远程进程中创建一个线程,让该线程调用FreeLibrary函数并在参数中传入远程DLL的
4 动态库劫持
简单来说就是DLL文件替换。通俗说法如下:
A.exe想要调用B.dll,并且使用里面的FunC函数,这样的话我们把B.Dll改名BB.Dll(有的不用,直接根据路径劫持),然后我们自己写一个B.Dll(假的)里面有一个FunC这个函数,然后我们在这个函数里加载BB.Dll(原B.Dll),并且调用里面的FunC函数,之后我们在干一些自己的事,对于A.exe来说通常没什么异常感觉,这样我们的目的就达到了,记住此时的你,也就是B.dll(假的)的权限和内存归属都是A的,也即是你和A是一家的了,类似于代码注入之后直接修改内存一样。
WIndows上的Dll加载有一个默认的规则,就是先在主程序目录下查找B.dll,如果没有就在系统路径下找,如果还没有,就去环境变量路径里找,就因为这个我们可以轻松的在相应的位置给做劫持,然后问题就是如果实现劫持,就要知道B.Dll里面的所有函数名字以及函数参数,这个地方比较不好搞,此地不考虑。
5 APC注入
APC注入的原理是利用当线程被唤醒时APC中的注册函数会被执行的机制,并以此去执行我们的DLL加载代码,进而完成DLL注入的目的,其具体流程如下:
1)当EXE里某个线程执行到SleepEx()或者WaitForSingleObjectEx()时,系统就会产生一个软中断。
2)当线程再次被唤醒时,此线程会首先执行APC队列中的被注册的函数。
3)利用QueueUserAPC()这个API可以在软中断时向线程的APC队列插入一个函数指针,如果我们插入的是Loadlibrary()执行函数的话,就能达到注入DLL的目的。
6 使用CreateProcess注入代码
- 用CreateProcess以CREATE_SUSPENDED的方式启动目标进程
- 找到目标进程的入口
- 将目标进程入口的代码保存起来
- 在目标进程的入口写LoadLibrary(MyDll)实现Dll注入
- 用ResumeThread运行目标进程
- 目标进程就运行了LoadLibrary(MyDll),实现DLL的注入
- 目标进程运行完LoadLibrary(MyDll)后,将原来的代码写回目标进程的入口
- 目标进程jmp到原来的入口,继续运行程序