这是非常有趣的话题。
试想,让另一个程序执行你的代码,以达到一些非常的目的,这时需要注入dll。
一.注入dll
1.通过注册表项 HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs 来指定你的dll的路径,那么当一个GUI程序启动时就要加载User32.dll,而User32.dll将会检查这个值,如果有的话就LoadLibrary该Dll。这个方法不好,因为大多数情况我们只需要针对性的注入,并且没办法注入到不使用User32.dll的进程中;
2.用SetWindowsHookEx函数,并传递目标线程ID、需要挂载的Dll在本进程中的映射地址(hInstance)、替换函数在本进程中的地址。这样,当被挂载进程的这个线程要执行相应的操作时(GETMESSAGE、键盘消息之类的),就会发现已经安装了WH_XX,The system checks to see whether the DLL containing the GetMsgProc function is mapped into Process B's address space,如果还未映射该Dll,则强制LoadLibrary。然后系统调用hThisInstance + (GetMsgProc - hInstance),从而实现了事件的通知。这种方法的好处是可以针对某个进程安装Hook,缺点是容易被目标进程发现、同样只适用于GUI进程。如果不再想使用挂钩了,那么需要调用UnhookWindowsHookEx,卸载Hook。
3.使用远程线程注入Dll(Injecting a DLL Using Remote Threads)
这个方法比较好。流程是这样的:
•调用VirtualAllocEx,在目标进程保留一块内存,并提交,其长度是你要注入Dll的全路径长度nLen + 1,返回地址pv;
•调用WriteProcessMemory,在目标进程的pv处写入Dll的全路径,注意要添加\0结束符;
•获取本进程的LoadLibrary函数的地址,方法是调用pfn = GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryA")——之所以获取本进程的地址,是因为kernel32.dll在每个进程的映射地址都相同,倘若不同,那么此方法则无效;
•调用HANDLE hThread = CreateRemoteThread(hProcessRemote, NULL, 0, pfn, pv, 0, NULL)来创建远程线程,其实这个线程函数就是LoadLibrary函数,因此将执行映射Dll到目标进程的操作;
•调用VirtuallFreeEx(hProcessRemote, pv)释放提交的内存;
这便完成了dll注入。
缺点是不能用在windows98上。但是对于xp都要被微软抛弃的年代,windows98地影响不大了。
4.披着羊皮的狼:使用特洛伊Dll来注入Dll(Injecting a DLL with a Trojan DLL)
其实就是替换某个目标进程要加载的a.dll,并把a.dll的所有引出函数用函数转发器在自己的dll引出。
5.用调试函数插入Dll
ReadProcessMemory和WriteProcessMemory是windows提供的调试函数。如果在方法3中调用WriteProcessMemory写入的不是字串而是精心编排好的机器指令,并且写在目标进程特定的地址空间,那么这段机器指令就有机会执行——而这段机器指令恰好完成了LoadLibrary功能;
6.其他方法(略)
二.挂接API(API Hooking)
其实,这是许多注入的Dll都愿意做的事情。
所谓挂接API就是在目标进程调用windows API之前,先执行我们的仿API函数,从而控制系统API的行为,达到特殊的目的。
我们的仿造函数必须与要替换的系统API有相同的型参表以及相同的返回值类型.
1.改写系统API代码的前几个字节,通过写入jmp指令来跳转到我们的函数。在我们的函数里执行操作,可以直接返回一个值,也可以将系统API的前几个字节复原,调用系统API,并返回系统API的值——随便你想怎么做。
此方法的缺点是对于抢占式多线程的系统不太管用。
2.通过改写目标进程IAT中要调用的函数地址来达到目的。具体操作见书中示例。
试想,让另一个程序执行你的代码,以达到一些非常的目的,这时需要注入dll。
一.注入dll
1.通过注册表项 HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs 来指定你的dll的路径,那么当一个GUI程序启动时就要加载User32.dll,而User32.dll将会检查这个值,如果有的话就LoadLibrary该Dll。这个方法不好,因为大多数情况我们只需要针对性的注入,并且没办法注入到不使用User32.dll的进程中;
2.用SetWindowsHookEx函数,并传递目标线程ID、需要挂载的Dll在本进程中的映射地址(hInstance)、替换函数在本进程中的地址。这样,当被挂载进程的这个线程要执行相应的操作时(GETMESSAGE、键盘消息之类的),就会发现已经安装了WH_XX,The system checks to see whether the DLL containing the GetMsgProc function is mapped into Process B's address space,如果还未映射该Dll,则强制LoadLibrary。然后系统调用hThisInstance + (GetMsgProc - hInstance),从而实现了事件的通知。这种方法的好处是可以针对某个进程安装Hook,缺点是容易被目标进程发现、同样只适用于GUI进程。如果不再想使用挂钩了,那么需要调用UnhookWindowsHookEx,卸载Hook。
3.使用远程线程注入Dll(Injecting a DLL Using Remote Threads)
这个方法比较好。流程是这样的:
•调用VirtualAllocEx,在目标进程保留一块内存,并提交,其长度是你要注入Dll的全路径长度nLen + 1,返回地址pv;
•调用WriteProcessMemory,在目标进程的pv处写入Dll的全路径,注意要添加\0结束符;
•获取本进程的LoadLibrary函数的地址,方法是调用pfn = GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryA")——之所以获取本进程的地址,是因为kernel32.dll在每个进程的映射地址都相同,倘若不同,那么此方法则无效;
•调用HANDLE hThread = CreateRemoteThread(hProcessRemote, NULL, 0, pfn, pv, 0, NULL)来创建远程线程,其实这个线程函数就是LoadLibrary函数,因此将执行映射Dll到目标进程的操作;
•调用VirtuallFreeEx(hProcessRemote, pv)释放提交的内存;
这便完成了dll注入。
缺点是不能用在windows98上。但是对于xp都要被微软抛弃的年代,windows98地影响不大了。
4.披着羊皮的狼:使用特洛伊Dll来注入Dll(Injecting a DLL with a Trojan DLL)
其实就是替换某个目标进程要加载的a.dll,并把a.dll的所有引出函数用函数转发器在自己的dll引出。
5.用调试函数插入Dll
ReadProcessMemory和WriteProcessMemory是windows提供的调试函数。如果在方法3中调用WriteProcessMemory写入的不是字串而是精心编排好的机器指令,并且写在目标进程特定的地址空间,那么这段机器指令就有机会执行——而这段机器指令恰好完成了LoadLibrary功能;
6.其他方法(略)
二.挂接API(API Hooking)
其实,这是许多注入的Dll都愿意做的事情。
所谓挂接API就是在目标进程调用windows API之前,先执行我们的仿API函数,从而控制系统API的行为,达到特殊的目的。
我们的仿造函数必须与要替换的系统API有相同的型参表以及相同的返回值类型.
1.改写系统API代码的前几个字节,通过写入jmp指令来跳转到我们的函数。在我们的函数里执行操作,可以直接返回一个值,也可以将系统API的前几个字节复原,调用系统API,并返回系统API的值——随便你想怎么做。
此方法的缺点是对于抢占式多线程的系统不太管用。
2.通过改写目标进程IAT中要调用的函数地址来达到目的。具体操作见书中示例。