驱动开发:内核LoadLibrary实现DLL注入
远程线程注入是最常用的一种注入技术,在应用层注入是通过CreateRemoteThread
这个函数实现的,该函数通过创建线程并调用 LoadLibrary
动态载入指定的DLL来实现注入,而在内核层同样存在一个类似的内核函数RtlCreateUserThread
,但需要注意的是此函数未被公开,RtlCreateUserThread
其实是对NtCreateThreadEx
的包装,但最终会调用ZwCreateThread
来实现注入,RtlCreateUserThread
是CreateRemoteThread
的底层实现。
内核级别的LoadLibrary实现DLL注入的过程与用户级别的LoadLibrary实现DLL注入的过程类似,只不过是在内核模式下实现。具体而言,实现内核级别的LoadLibrary实现DLL注入。
基于LoadLibrary实现的注入原理具体实现分为如下几步;
- 1.调用
AllocMemory
,在对端应用层开辟空间,函数封装来源于《内核远程堆分配与销毁》
章节; - 2.调用
MDLWriteMemory
,将DLL路径字符串写出到对端内存,函数封装来源于《内核MDL读写进程内存》
章节; - 3.调用
GetUserModuleAddress
,获取到kernel32.dll
模块基址,函数封装来源于《内核远程线程实现DLL注入》
章节; - 4.调用
GetModuleExportAddress
,获取到LoadLibraryW
函数的内存地址,函数封装来源于《内核远程线程实现DLL注入》
章节; - 5.最后调用本章封装函数
MyCreateRemoteThread
,将应用层DLL动态转载到进程内,实现DLL注入;
总结起来就是首先在目标进程申请一块空间,空间里面写入要注入的DLL的路径字符串或者是一段ShellCode,找到该内存中LoadLibrary
的基址并传入到RtlCreateUserThread
中,此时进程自动加载我们指定路径下的DLL文件。
注入依赖于RtlCreateUserThread
这个未到处内核函数,该内核函数中最需要关心的参数是ProcessHandle
用于接收进程句柄,StartAddress
接收一个函数地址,StartParameter
用于对函数传递参数,具体的函数原型如下所示;
typedef DWORD(WINAPI* pRtlCreateUserThread)( |
由于我们加载DLL使用的是LoadLibraryW
函数,此函数在运行时只需要一个参数,我们可以将DLL的路径传递进去,并调用LoadLibraryW
以此来将特定模块拉起,该函数的定义规范如下所示;
HMODULE LoadLibraryW( |
根据上一篇文章中针对注入头文件lyshark.h
的封装,本章将继续使用这个头文件中的函数,首先我们实现这样一个功能,将一段准备好的UCHAR
字符串动态的写出到应用层进程内存,并以宽字节模式写出在对端内存中,这段代码可以写为如下样子;
|
运行如上方所示的代码,将会在目标进程7112
中开辟一段内存空间,并写出C:\hook.dll
字符串,运行效果图如下所示;
此处你可以通过x64dbg
附加到应用层进程内,并观察内存0000000002200000
会看到如下字符串已被写出,双字类型则是每一个字符空一格,效果图如下所示;
继续实现所需要的子功能,实现动态获取Kernel32.dll
模块里面LiadLibraryW
这个导出函数的内存地址,这段代码相信你可以很容易的写出来,根据上节课的知识点我们可以二次封装一个GetProcessAddress
来实现对特定模块基址的获取功能,如下是完整代码案例;
|
编译并运行如上驱动代码,将自动获取PID=5200
进程中Kernel32.dll
模块内的LoadLibraryW
的内存地址,输出效果图如下所示;
实现注入的最后一步就是调用自定义函数MyCreateRemoteThread
该函数实现原理是调用RtlCreateUserThread
开线程执行,这段代码的最终实现如下所示;
|
编译这段驱动程序,并将其放入虚拟机中,在C盘下面放置好一个名为lyshark_hook.dll
文件,运行驱动程序将自动插入DLL到Win32Project
进程内,输出效果图如下所示;
回到应用层进程,则可看到如下图所示的注入成功提示信息;