远程线程注入技术是进程间通信的一种方式,被计算机病毒木马等广泛使用。计算机病毒通过把自身代码注入一个远程进程的地址空间从而达到伪装自己的目的。一些游戏辅助工具通过远程线程注入技术对游戏进程进行辅助操作。如果你对Windows系统编程有所了解的话,就很容易理解远程线程注入的实现机理。
Windows是一种多任务的操作系统,一方面是指它支持多进程,每个进程有独立的地址空间,另一方面则在于Windows的多线程支持。尽管多线程常常带来很多问题,并且在UN*X世界从来没有成为主流,但是在并发计算越来越流行的时代,多线程还是比较有前景的。在Windows系统中,应用程序通过调用 CreateThread 就可以创建一个线程,这个线程和主线程同属一个进程,共享着进程的所有资源,但是具有自己的堆栈和局部存储,可以平等的获得CPU时间,和主线程同时运行着。
远程线程注入技术是通过调用 CreateRemoteThread 函数在别的进程中创建一个线程,因此这个线程可以称为远程线程,而被注入的远程进程又称为宿主进程。远程线程就像是宿主进程自己调用 CreateThread 创建的线程一样,能够访问宿主进程的所有资源。计算机病毒通过向宿主进程注入一个线程,就可以以宿主进程的身份访问计算机系统,达到控制计算机的目的。
远程线程注入大致包括以下步骤:
1 打开远程进程,你需要用OpenProcess打开远程进程,获得进程句柄,这是Windows编程的典型风格。
2 分配代码空间,使用VirtualAllocEx函数在远程进程的堆空间中分配一块区域用于存放寄生线程的代码。
3 写入线程代码,使用WriteProcessMemory函数把寄生线程的代码写入刚才在宿主进程中分配的代码空间。
4 分配数据空间,在远程进程的堆空间中分配一块区域用于存放寄生线程的数据资源。
5 写入线程参数,把寄生线程的启动参数及其他数据资源写入刚才分配的数据空间。
6 创建远程线程,使用CreateRemoteThread创建远程线程,可以获得此线程的ID和句柄。
7 释放无用资源,关闭过时的进程句柄和线程句柄。
如果在尝试用OpenProcess打开宿主进程遇到一个“拒绝访问”的错误,这时应设法提升本进程的访问权限(首先你必须是Administrator用户才可以)。有三个相关的API可用,包括OpenProcessToken,LookupPrivilegevalue和AdjustTokenPrivileges,这方面资料网上很多,届时百度一下即可。
这是我的一个游戏辅助工具中用到的线程注入工具代码,可以作为远程线程注入的模板:
Windows是一种多任务的操作系统,一方面是指它支持多进程,每个进程有独立的地址空间,另一方面则在于Windows的多线程支持。尽管多线程常常带来很多问题,并且在UN*X世界从来没有成为主流,但是在并发计算越来越流行的时代,多线程还是比较有前景的。在Windows系统中,应用程序通过调用 CreateThread 就可以创建一个线程,这个线程和主线程同属一个进程,共享着进程的所有资源,但是具有自己的堆栈和局部存储,可以平等的获得CPU时间,和主线程同时运行着。
远程线程注入技术是通过调用 CreateRemoteThread 函数在别的进程中创建一个线程,因此这个线程可以称为远程线程,而被注入的远程进程又称为宿主进程。远程线程就像是宿主进程自己调用 CreateThread 创建的线程一样,能够访问宿主进程的所有资源。计算机病毒通过向宿主进程注入一个线程,就可以以宿主进程的身份访问计算机系统,达到控制计算机的目的。
远程线程注入大致包括以下步骤:
1 打开远程进程,你需要用OpenProcess打开远程进程,获得进程句柄,这是Windows编程的典型风格。
2 分配代码空间,使用VirtualAllocEx函数在远程进程的堆空间中分配一块区域用于存放寄生线程的代码。
3 写入线程代码,使用WriteProcessMemory函数把寄生线程的代码写入刚才在宿主进程中分配的代码空间。
4 分配数据空间,在远程进程的堆空间中分配一块区域用于存放寄生线程的数据资源。
5 写入线程参数,把寄生线程的启动参数及其他数据资源写入刚才分配的数据空间。
6 创建远程线程,使用CreateRemoteThread创建远程线程,可以获得此线程的ID和句柄。
7 释放无用资源,关闭过时的进程句柄和线程句柄。
如果在尝试用OpenProcess打开宿主进程遇到一个“拒绝访问”的错误,这时应设法提升本进程的访问权限(首先你必须是Administrator用户才可以)。有三个相关的API可用,包括OpenProcessToken,LookupPrivilegevalue和AdjustTokenPrivileges,这方面资料网上很多,届时百度一下即可。
这是我的一个游戏辅助工具中用到的线程注入工具代码,可以作为远程线程注入的模板:
// 龙第九子 2007/12/12
void RemoteCall(HANDLE hProcess, DWORD FuncEntry, DWORD ParamEntry, DWORD ParamSize)
{
// This function inject a procedure's image codes and rawdata into the specified remote process.
// NOTE: All addersses prefixed by "rmt" belongs to the remote process and cannot be directly accessed.
const DWORD CodeSize = 2048; // Maximum image size of the very procedure
DWORD rmtFuncAddr; // Function address of the very procedure
rmtFuncAddr = (DWORD)VirtualAllocEx(hProcess, 0, CodeSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if(!rmtFuncAddr)
{
cerr<<"Failed to allocate memory space for thread codes."<<endl;
exit(1);
}
DWORD BytesCnt;
BOOL RetCode;
RetCode = WriteProcessMemory(hProcess, (void*)rmtFuncAddr, (const void*)FuncEntry, CodeSize, &BytesCnt);
if(!RetCode || BytesCnt != CodeSize)
{
cerr<<"Failed to write thread codes into remote process."<<endl;
exit(1);
}
bool NoParams; // if there is no parameters for the thread
if(ParamEntry == NULL || ParamSize == 0)
NoParams = true;
else
NoParams = false;
DWORD rmtParamAddr; // parameters' address of the thread
if(!NoParams)
{
rmtParamAddr = (DWORD)VirtualAllocEx(hProcess, 0, ParamSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if(!rmtParamAddr)
{
cerr<<"Failed to allocate memory space for thread data."<<endl;
exit(1);
}
// write data into the remote process
RetCode = WriteProcessMemory(hProcess, (void*)rmtParamAddr, (const void*)ParamEntry, ParamSize, &BytesCnt);
if(!RetCode || BytesCnt != ParamSize)
{
cerr<<"Failed to write data into the remote process."<<endl;
exit(1);
}
}
else
rmtParamAddr = NULL;
// create remote thread
HANDLE hRomoteThread;
DWORD RomoteThreadID;
hRomoteThread = CreateRemoteThread(hProcess, NULL, 0, (unsigned long (__stdcall *)(void *))rmtFuncAddr, (void*)rmtParamAddr, 0, &RomoteThreadID);
if(!hRomoteThread)
{
cerr<<"Failed to create remote thread."<<endl;
exit(1);
}
// wait
WaitForSingleObject(hRomoteThread, INFINITE);
// free resources associated with the remote process.
VirtualFreeEx(hProcess, (void*)rmtFuncAddr, 0, MEM_RELEASE);
if(!NoParams)
VirtualFreeEx(hProcess, (void*)rmtParamAddr, 0, MEM_RELEASE);
CloseHandle(hRomoteThread);
//CloseHandle(hProcess);
}
void RemoteCall(HANDLE hProcess, DWORD FuncEntry, DWORD ParamEntry, DWORD ParamSize)
{
// This function inject a procedure's image codes and rawdata into the specified remote process.
// NOTE: All addersses prefixed by "rmt" belongs to the remote process and cannot be directly accessed.
const DWORD CodeSize = 2048; // Maximum image size of the very procedure
DWORD rmtFuncAddr; // Function address of the very procedure
rmtFuncAddr = (DWORD)VirtualAllocEx(hProcess, 0, CodeSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if(!rmtFuncAddr)
{
cerr<<"Failed to allocate memory space for thread codes."<<endl;
exit(1);
}
DWORD BytesCnt;
BOOL RetCode;
RetCode = WriteProcessMemory(hProcess, (void*)rmtFuncAddr, (const void*)FuncEntry, CodeSize, &BytesCnt);
if(!RetCode || BytesCnt != CodeSize)
{
cerr<<"Failed to write thread codes into remote process."<<endl;
exit(1);
}
bool NoParams; // if there is no parameters for the thread
if(ParamEntry == NULL || ParamSize == 0)
NoParams = true;
else
NoParams = false;
DWORD rmtParamAddr; // parameters' address of the thread
if(!NoParams)
{
rmtParamAddr = (DWORD)VirtualAllocEx(hProcess, 0, ParamSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if(!rmtParamAddr)
{
cerr<<"Failed to allocate memory space for thread data."<<endl;
exit(1);
}
// write data into the remote process
RetCode = WriteProcessMemory(hProcess, (void*)rmtParamAddr, (const void*)ParamEntry, ParamSize, &BytesCnt);
if(!RetCode || BytesCnt != ParamSize)
{
cerr<<"Failed to write data into the remote process."<<endl;
exit(1);
}
}
else
rmtParamAddr = NULL;
// create remote thread
HANDLE hRomoteThread;
DWORD RomoteThreadID;
hRomoteThread = CreateRemoteThread(hProcess, NULL, 0, (unsigned long (__stdcall *)(void *))rmtFuncAddr, (void*)rmtParamAddr, 0, &RomoteThreadID);
if(!hRomoteThread)
{
cerr<<"Failed to create remote thread."<<endl;
exit(1);
}
// wait
WaitForSingleObject(hRomoteThread, INFINITE);
// free resources associated with the remote process.
VirtualFreeEx(hProcess, (void*)rmtFuncAddr, 0, MEM_RELEASE);
if(!NoParams)
VirtualFreeEx(hProcess, (void*)rmtParamAddr, 0, MEM_RELEASE);
CloseHandle(hRomoteThread);
//CloseHandle(hProcess);
}