作者:黎伟鑫
一、 前言:
远程线程技术指的是通过在其他进程中创建新线程的方法进入该进程的内存地址空间,从而获得对该进程的控制权的方法。
在进程中可以通过CreateThread函数创建线程,被创建的新线程与主线程共享地址空间以及其他的资源。同样,通过CreateRemoteThread函数可以在其他进程内创建新线程,新创建的的远程线程可以共享远程进程的地址空间。
所以通过在远程进程中创建新的方法,就可以进入到远程进程的内存地址空间,也就拥有了和那个远程进程相当的权限,可以在远程进程中执行代码,从而达到远程进程控制、进程隐藏的目的。
二 、基本原理:
2.1. A P I 函数
其中VirtualAllocEx和CreateRemoteThread两个API函数只能NT内核下用。实现的基本过程如下:
(1)通过OpenProcess函数打开进程PID为ProcessID的远程进程:
hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, ProcessId);
(2)通过VirtualAllocEx函数在刚打开的进程中申请IMageSize个字节的内存:
InjectPoint = (LPBYTE)VirtualAllocEx(hProcess, 0, ImageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE) ;
(3)通过WriteProcessMemory函数将NewModule开始的IMageSize个字节的代码写入已经申请的内存中:
WriteProcessMemory(hProcess, InjectPoint, NewModule, ImageSize, NULL) ;
(4)通过CreateRemoteThread函数启动刚写入的代码:
CreateRemoteThread(hProcess, NULL, 0, RemoteEntryPoint, Param, 0, NULL);
2.2. 重定位和函数导入的问题
在远程进程执行的代码中最重要的是要解决代码的重定位和API函数导入的问题,对于参考文献1的方法是通过在远程进程中执行LoadLibrary函数将DLL文件载入,所以系统会自动完成代码的重定位和API函数导入工作:而参考文献2中提到的方法是通过汇编语言进行编程来解决,相对来讲会使编程难度增大,但隐藏性是最好的。在这里,探讨一种新的方法既能使用高级语言进行编程又有完美的隐藏效果的方法。
首先要解决的是重定位问题,这就要用到pE文件中的重定位表,利用重定位表将即将写入远程进程的代码按照在远程进程申请到的内存地址通过RelocCode函数进行重定位,然后将重定位好的代码写入远程进程的内存空间。这些写入的代码必然要用到API函数,所以在远程线程代码调用第一个API之前,要替系统来完成装入API函数对应的DLL文件,ing填好相关API函数入口地址的工作,这就要用到PE文件的输入表提供的信息,输入表记录了一个win32程序需要加载的所有DLL文件名及从中引入的API函数名,这就可以用LoadLIbrary函数注入需要用的DLL文件,在通过GETProcAddress函数获得相应的API函数地址,这里是通过LoadAPI函数来完成这些工作。下面程序中的LoadAPI函数作为远程线程的入口,其用到的API函数LoadLibrary和 GETProcAddress的入口地址有时如何确定的呢?事实上几乎所有的Windows进程都会装入“kernel32.dll”,而这两个函数就定位于“kernel32.dll”中,而且所有装入“kernel32.dll”的进程都会把它装入到同一个虚拟内存地址,即在本地进程中使用到“kernel32.dll”中的API函数和远程进程中对应的API函数地址是一样的,所以在远程进程代码中可以想本地进程一样调用LoadLibrary加载DLL文件,然后用GETProcAddress获得输入函数的入口地址并写入响应的数据结构中,完成API函数的导入。
三、编程实现:
//为了简化代码,下面程序中去掉了对出错处理的代码,实际应用中应该考虑程序运行时可能的出错:
#include “stdafx.h”
static PIMAGE_NT_HEADERS nt_header;
#define IMAGESIZE (nt_header->OptionalHeader.SizeOfImage)
#define EXPORT_TABEL (nt_header->OptionalHeader.DataDirectory[0].VirtualAddress)
#define RELOC_TABEL (nt_header->OptionalHeader.DataDirectory[5].VirtualAddress)
static void RelocCode (PBYTE Image, LPBYTE InjectBase) // 完成代码的重定位
{
DWORD Rva = 0, RvaCount = 0, RelocOffset=0;
WORD *Offset = NULL;
LPBYTE RelocTable = Image + RELOC_TABEL; //重定位表位置
PIMAGE_BASE_RELOCATION basereloc= (PIMAGE_BASE_RELOCATION) RelocTable;
RelocOffset= (DWORD)InjectBase – nt_header ->OptionalHeader.ImageBase; //重定位表偏移
while(basereloc ->VirtualAddress != NULL)// 遍历重定位表,修正需要重定位的代码
{
Offset = (WORD*)(RelocTable + sizeof(IMAGE_BASE_RELOCATION));
RvaCount = (basereloc ->SizeOfBlock – sizeof(IMAGE_BASE_RELOCATION)) / 2;
for(DWORD i=0; ihttp://www.vckbase.com/document/viewdoc/?id=1970 >> 本文固定链接: http://www.vcgood.com/archives/3563