1. 引言 2. 使用注册表注入DLL 3. 使用Windows挂钩来注入DLL 4. 使用远程线程来注入DLL 5. 使用木马DLL来注入DLL 6. 把DLL作为调试器来注入 7. 使用createprocess来注入代码 8. api拦截 9. Detours - Inline Hook
1. 引言
应用程序需要跨越进程边界来访问另一个进程的地址空间的情况如下
1. 我们想要从另一个进程创建的窗口派生子类窗口 2. 我们需要一些手段来辅助调试,例如我们需要确定另一个进程正在使用哪些DLL 3. 我们想对另一个进程安装Hook
我们接下来要研究将一个DLL注入到另一个进程的地址空间中,一旦DLL代码进入另一个地址空间,那么我们就可以在那个进程中实现安全防御逻辑。这里需要注意是的,DLL注入是一个一个前提条件,因为Windows的内存管理体系是不允许另一个进程直接修改当前进程的API行为的,而WriteProcessMemory又只能修改小范围的跨进程内存地址,这种情况下,我们要实现运行时中跨进程API Hook(有别于Linux LD_PRELOAD那种需要重新启动进程才能生效的全局Glibc库API劫持思路),就必须进行DLL注入
0x1: Detect and Plug GDI Leaks in Your Code with Two Powerful Tools for Windows XP
Relevant Link:
http://wotseb.bokee.com/6568089.html http://blog.naver.com/hypermin/70011196503
2. 使用注册表注入DLL
windows整个系统的配置都保存在这个注册表中,我们可以通过调整其中的设置来改变系统的行为
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows
1. AppInit_Dlls: 该键的值可能会包含一个DLL的文件名或一组DLL的文件名(通过空格或逗号分隔)(由于空格是用来分隔文件名的,所以我们必须避免在文件名中包含空格)。第一个DLL的文件名可以包含路径,但其他DLL包含的路径则会被忽略,出于这个原因,我们最好是将自己的DLL放到windows的系统目录中,这样就不必指定路径了 2. LoadAppInit_Dlls: 为了能让系统使用AppInit_Dlls这个注册表项,需要创建一个LoadAppInit_Dlls,类型为DWORD的注册表项,并将它的值设置为1
当User32.dll被映射到一个新的进程时,会收到DLL_PROCESS_ATTACH通知,当User32.dll对它进行处理的时候,会取得上述注册表键的值,并调用LoadLibary来载入这个字符串中指定的每个DLL。当系统载入每个DLL的时候,会调用它们的DllMain函数,并将参数fdwReason的值设置为DLL_PROCESS_ATTACH,这样每个DLL都能够对自己进行初始化
0x1: 该方法的风险点
1. 由于被注入的DLL是在进程的生命周期的早期(Loader)被载入的,因此我们在调用函数的时候应该谨慎,调用Kernel32.dll中的函数应该没有问题,但是调用其他DLL中的函数可能会导致失败,甚至可能会导致蓝屏 2. User32.dll不会检查每个DLL的载入或初始化是否成功
0x2: 该方案的缺点
1. 我们的DLL只会被映射到那些使用了User32.dll的进程中,所有基于GUI的应用程序都使用了User32.dll,但大多数基于CUI的应用程序都不会使用它。因此,如果想要将DLL注入到编译器或者链接器或者命令行程序,这种方法就不可行 2. 我们的DLL会被映射到每个基于GUI的应用程序中,但我们可能只想把DLL注入到一个或少数几个应用程序中。我们的DLL被映射到越多的进程中,它导致"容器"进程崩溃的可能性也就越大 3. 我们注入的DLL会在应用程序终止之前,一直存在于进程的地址空间中,最好是只在需要的时候才注入我们的DLL
3. 使用Windows挂钩来注入DLL
我们可以用挂钩(SetWindowsHookEx)来将一个DLL注入到进程的地址空间中。注意,当系统把挂钩过滤函数(hook filter function)所在的DLL注入或映射到地址空间中时,会映射整个DLL,而不仅仅只是挂钩过滤函数,这意味着该DLL内的所有函数存在于被注入的进程中,能够被被注入进程中的任何线程调用
0x1: 该方案的优缺点