Windows进程注入
原理很简单,用Windows API函数CreateRemoteThread
即可。不过进程注入一般分为两种情况,第一种是最常见的情况,为dll注入。就是将dll注入到进程当中实现自己所想要的操作,dll里的功能就是自己编写的代码。
Dll注入
- 先调用
OpenProcess
获取目标进程的句柄 - 再调用
VirtualAllocEx
在目标进程中分配一块内存,用来存储自己的内容,例如dll文件的路径名 - 再调用
WriteProcessMemory
填充分配的内存 - 再调用
CreateRemoteThread
在目标进程中注入线程函数(具体看代码) - 再调用
WaitForSingleObject
等待线程函数执行结束 - 最终结束处理,调用
VirtualFreeEx
和CloseHandle
做资源释放
具体怎么完成的看代码,先看注入代码:
1 |
|
dll怎么写,举个最简单的例子:
1 |
|
卸载dll也同样的原理,注入卸载dll的FreeLibrary
线程即可:
1 | void UnInjectDll(DWORD dwPid, char *szDllName) |
不过上面这种卸载方法也一点小问题,我尝试过之后是不能二次注入的(也有可能是我的问题),也就是卸载是没有办法完全卸载的,从而不能第二次注入进去。
还有一种卸载的方法我没有尝试,也贴一下:
1 | bool UnInjectDll(const TCHAR* ptszDllFile, DWORD dwProcessId) |
可能这种方式比较有效,可以尝试一下。
dll注入一般情况是需要对目标进程做一些代码改动的,注入了dll之后最重要的是需要拿到目标进程中的各个dll的基地址,这样才方便后续做动作。
获取目标进程的所有dll基址
一般流程:
- 拿到TEB结构体地址
- 通过TEB拿到PEB地址
- 通过PEB拿到PEB_LDR_DATA指针(里面存放进程中装载的所有dll信息)
- 通过PEB_LDR_DATA拿到LIST_ENTRY链表头指针(dll信息的链表指针)
- 遍历_LIST_ENTRY,找到DLL基址
看代码:
1 |
|
代码注入
代码注入就是不把dll注入到目标进程中去,而是自己编写所要注入的代码,在代码里面完成自己想要的操作。但是这个其实是有难度的,自己编写的注入进程(A)和被注入目标进程(B)不在同一个进程空间,所以B无法调用A中的函数,也无法访问A中的数据。(这就是为什么大家更乐意用dll注入的方式,因为注入的dll和目标进程属于同一进程空间)
因此,在A中编写注入到B中的代码时,需要注意不论是函数、变量、还是结构体等其他东西,都需要在B中构造好后再让B去执行。
直接看代码,前面的注入流程都一样,区别就在于创建的线程函数ThreadProc
:
1 | //该结构体用于接收API和4个字符串 |
看下来其实可以发现代码注入只适合写小型的注入,一旦涉及到需要执行大量操作,那么要准备的数据和函数就会变得更多了…
参考链接
dll注入:
https://www.cnblogs.com/17bdw/p/6527998.html
https://blog.csdn.net/u012319493/article/details/50456685
https://blog.csdn.net/sky04/article/details/7027225
代码注入:
https://blog.csdn.net/SKI_12/article/details/82947635
获取DLL基址:
https://blog.csdn.net/weixin_43206704/article/details/87903325