一、背景
二、dll注入说明
DLL注入技术,一般来讲是向一个正在运行的进程插入/注入代码的过程。我们注入的代码以动态链接(DLL)的形式存在。DLL文件在运行时将按需加载。
三、dll注入能做什么:
1.为目标进程添加新的“实用”功能;
2.需要一些手段来辅助调试被注入dll的进程;
3.为目标进程安装勾子程序(API Hook);
四、dll注入方法:
1.修改注册表来注入dll;
2.使用CreateRemoteThread函数对运行中的进程注入dll;
3.使用SetWindowsHookEx函数对应用程序挂钩(HOOK)迫使程序加载dll;4.替换应用程序一定会使用的dll;
5.把dll作为调试器来注入;
6.用CreateProcess对子进程注入dll
(一)、修改注册表注入dll
如果使用过Windows,那么对注册表应该不会陌生。整个系统的配置都保存在注册表中,我们可以通过修改其中的设置来改变系统的行为。首先打开注册表并定位到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows项,如下图所示,他显示了该注册表项中的条目。
AppInit_Dlls键值位于注册表 HKLM\Microsoft\Windows NT\CurrentVersion\Windows下面,相对于其他的注册表启动项来说,这个键值的特殊之处在于任何使用到User32.dll 的EXE、DLL、OCX等类型的PE文件都会读取这个地方,并且根据约定的规范将这个键值下指向的DLL文件进行加载,加载的方式是调用 LoadLibrary。
由于AppInit_Dlls是一种系统全局性的Hook(system-wide hook),要规避此类的Hook的确很困难,虽然使用驱动程序进行保护能够规避此类问题,但也不是非要使用驱动程序进行处理的。前文说过,只有当使用到User32.DLL这个模块的时候才会触发读取AppInit_Dlls指向的DLL,如果不使用User32.DLL,那么AppInit_Dlls是不会被使用到的。但是要让一个程序不使用User32.DLL会变得非常困难(命令行窗口没有使用User32.DLL),因为任何的窗口、消息都和这个模块有关,为了保证有良好的用户体验,100%的窗口程序都和这个模块有关。从开发角度来说,最好的一种解决办法就是将程序功能逻辑和界面逻辑完全分离,功能逻辑模块负责功能,界面逻辑模块负责界面显示,2者之间采用IPC机制进行交互,功能逻辑模块不依靠User32.DLL,,而且作为独立进程进行处理,这样就可以规避AppInit_Dlls造成的Hook了。
1.如何使用
AppInit_DLLs键的值可以是一个dll的文件名或一组dll的文件名(通过逗号或空格来分隔),由于空格是用来分隔文件名的,因此dll文件名不能含有空格。第一个dll的文件名可以包含路径,但其他的dll包含的路径将被忽略。
2.使用约定
LoadAppInit_DLLs键的值表示AppInit_DLLs键是否有效,为了让AppInit_DLLs键的值有效,需要将LoadAppInit_DLLs的值设置为1。
3.一些缺点
(1)只有调用了User32.dll的进程才会发生这种dll注入。
(2)该方法会使得所有的调用了User32.dll的程序都被注入指定的dll。
(3)这种注入会使得在应用程序的整个生命周期内被注入的dll都不会被卸载。
(二)使用CreateRemoteThread函数对运行中的进程注入dll
dll注入技术要求目标进程中的一个线程调用LoadLibrary函数来载入我们想要注入的dll,由于我们不能轻易的控制别人进程中的线程,因此这种方法要求我们在目标进程中创建一个线程并在线程中执行LoadLibrary函数加载我们要注入的dll。
主要函数
1.创建进程函数
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
);
2.LoadLibrary加载自己的DLL
HMODULE WINAPI LoadLibrary(
_In_ LPCTSTR lpFileName
);
3.VirtualAllocEx开辟加载DLL的内存
LPVOID WINAPI VirtualAllocEx(
_In_ HANDLE hProcess,
_In_opt_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flAllocationType,
_In_ DWORD flProtect
);
4.WriteProcessMemory函数将dll文件路径的数据复制到目标进程中。
BOOL WINAPI WriteProcessMemory(
_In_ HANDLE hProcess,
_In_ LPVOID lpBaseAddress,
_In_ LPCVOID lpBuffer,
_In_ SIZE_T nSize,
_Out_ SIZE_T *lpNumberOfBytesWritten
);
6.梳理下步骤。
(2).用WriteProcessMemory函数把本进程中保存dll路径的内存中的数据拷贝到第(1)步得到的目标进程的内存中。
(4).用CreateRemoteThread函数让目标进程执行LoadLibraryW来加载被注入的dll。函数结束将返回载入dll后的模块句柄。
(5).用VirtualFreeEx释放第(1)步开辟的内存。
在需要卸载dll时我们可以在上述第(5)步的基础上继续执行以下步骤:
(7).用CreateRemoteThread函数让目标进程执行FreeLibrary来卸载被注入的dll。(其参数是第(4)步返回的模块句柄)。
如果不在上述步骤基础上执行操作,卸载dll时你需要这么做:
(1).获得被注入的dll在目标进程的模块句柄。
(2).重复上述步骤的第(6)、(7)两步。
五、操作
1.创建一个弹窗dll
使用g 编译一下生成MessageBox.dll:g –share -o MessageBox.dll MessageBox.cpp
(坑)直接使用编译使用失败
需要使用vs2019–>dll动态链接库编译
编译完成
2.使用vs2019中c 应用控制台项目
编译RemoteInject.cpp生成RemoteInject.exe
编译生成RemoteInject.exe
在这里对上面源码中的部分函数进行简单剖析:
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);
调用OpenProcess() API,通过参数dwPID,来获取dwPID所对应进程的句柄。在得到PROCESS_ALL_ACCESS权限以后,就可以使用获取的句柄(hProcess)来控制对应进程。
pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGA_READWRITE);
为即将写入目标进程的DLL文件的路径(字符串)在目标进程空间中申请内存。
writeProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllName, dwBufSize, NULL);
注入测试
首先找到想要注入进程的PID
使用命令tasklist | findstr “nodepad ”
测试时,注入dll使用绝对路径。
普通用户权限,注入成功。
六、获取文中项目文件
七、参考文章
https://www.cnblogs.com/wf751620780/p/10730013.html
https://juejin.cn/post/7017729981627269128
https://blog.csdn.net/u013565525/article/details/27585387
若有侵权,请联系删除。