DLL远线程注入
远程线程创建和内存自由分配
远线程注入技术:
强制创建一个目标进程的线程:将我们的外挂木马DLL加载进去
加载
LoadLibrary api函数来处理
强制创建一个目标进程的线程
CreateRemoteThread
HANDLE CreateRemoteThread( HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId );
作用:
创建在另一个进程的虚拟空间中运行的线程
参数
HANDLE hProcess
要在进程中创建线程的进程句柄
采用OpenProcess函数来获取进程句柄打开现有的本地进程对象
HANDLE OpenProcess( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId );
获取句柄函数参数:
第一个dwDesiredAccess表示进程的访问权限,一般采用第一个宏PROCESS_ALL_ACCESS表示获得所有的访问权限
第二个 BOOL binheritHandle
如果该值为TRUE,则此进程创建的进程将继承该句柄。否则,进程将不会继承此句柄。
这里我们只是采用注入所以不用继承
第三个 dwProcessId
要打开的本地进程的标识符。也就是进程ID
LPSECURITY_ATTRIBUTES lpThreadAttributes
lpThreadAttributes
指向
这里我们不用深究,通常直接采用NULL就好
SIZE_T dwStackSize
堆栈的初始大小,如果参数为0就使用默认值,我们直接采用默认值好了
LPTHREAD_START_ROUTINE lpStartAddress,
指向由线程执行的,类型为LPTHREAD_START_ROUTINE的应用程序定义的函数的指针,该指针表示远程进程中线程的起始地址。
也就是说该变量必须为LPTHREAD_START_ROUTINE类型的回调函数,表示远程进程中线程的起始位置,所以这里需要赋值为远程进程的地址。
其实就是需要调用的函数的函数指针,只是类型必须用指定的LPTHREAD_START_ROUTINE类型来处理也就是你要插入线程的函数的进程函数名。
这个参数的名称就相当于是一个回调函数的名字,
LPVOID lpParameter,
指向要传递给线程函数的变量(可以理解为参数)的指针。
也就是线程要执行的函数的参数的变量
这里需要用到VirtualAllocEx()函数
VirtualAllocEx():在指定进程的虚拟地址空间内保留,提交或更改内存区域的状态。该函数将其分配的内存初始化为零。因为CreateRemoteThread是创建一个在另一个进程的虚拟地址空间中运行的线程
LPVOID VirtualAllocEx( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect );
分配虚拟内存函数
参数
第一个hProcess表示进程的句柄
lpAddress表示需要分配的页面起始地址,一般直接采用NULL用默认值就好。
dwSize:分配内存区域的大小分配给要执行的函数的变量,也就是函数参数dll所在路径的位置。也就是传的一个文件路径的大小
flAllocationType:也就是内存的类型,一般情况下采用第一个宏定义就好了MEM_COMMIT
flProtect:需要指定一个内存保护常量来处理, PAGE_READWRITE这个宏表示即可以读也可以写
返回值:
如果申请成功会返回一个虚拟内存的基质
申请完一个虚拟内存后还要写入
相当于申明一个变量后给变量赋值
使用WriteProcessMemory函数来处理
BOOL WriteProcessMemory( HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten );
hProcess表示进程句柄
lpBaseAddress表示基质的位置也就是用VirtualAllocEX申请的虚拟内存地址的基质
lpBuffer表示指向缓冲区的指针,也就是需要写入的字符串的指针
nSize:表示写入的字节数
lpNumberOfBytesWritten:
指向变量的指针,该变量接收传输到指定进程中的字节数。此参数是可选的。如果lpNumberOfBytesWritten为NULL,则忽略该参数。一般填NULL,这个没啥用
DWORD dwCreationFlags,
控制线程创建的标志。
值 | 含义 |
---|---|
0 | 线程在创建后立即运行。 |
CREATE_SUSPENDED0x00000004 | 该线程以挂起状态创建,并且直到 |
STACK_SIZE_PARAM_IS_A_RESERVATION0x00010000 | 所述dwStackSize参数指定堆栈的初始保留大小。如果未指定此标志,则dwStackSize指定提交大小。 |
LPDWORD lpThreadId
指向接收线程标识符的变量的指针。
如果此参数为NULL,则不返回线程标识符。
代码实现:
DLL注入优化
在多线程的情况下:希望等待某一线程完成后再继续做其他事情。
可以使用Windows API :WaitForSingleObject或者 WaitForMultipleObject来等待线程
防止线程阻塞
WaitForSingleObject:
DWORD WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds );
第一个参数是对象 的句柄,第二个参数是超时间隔(毫秒为单位)如果指定了非零值,则函数将等待,直到发出信号通知对象或间隔过去为止。如果dwMilliseconds为零,则如果未用信号通知对象,则函数不会进入等待状态;否则,函数将进入等待状态。它总是立即返回。如果dwMilliseconds为INFINITE,则该函数仅在信号通知对象时返回。
在创建进程和线程等句柄后应该关闭