远程线程注入引出的问题
一、远程线程注入基本原理
远程线程注入——相信对Windows底层编程和系统安全熟悉的人并不陌生,其主要核心在于一个Windows API函数CreateRemoteThread,通过它可以在另外一个进程中注入一个线程并执行。在提供便利的同时,正是因为如此,使得系统内部出现了安全隐患。常用的注入手段有两种:一种是远程的dll的注入,另一种是远程代码的注入。后者相对起来更加隐蔽,也更难被杀软检测。本文具体实现这两种操作,在介绍相关API使用的同时,也会解决由此引发的一些问题。
顾名思义,远程线程注入就是在非本地进程中创建一个新的线程。相比而言,本地创建线程的方法很简单,系统API函数CreateThread可以在本地创建一个新的线程,其函数声明如下:
HANDLE WINAPI CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
PDWORD lpThreadId
);
这里最关心的两个参数是lpStartAddress和lpParameter,它们分别代表线程函数的入口和参数,其他参数一般设置为0即可。由于参数的类型是LPVOID,因此传入的参数数据需要用户自己定义,而入口函数地址类型必须是LPTHREAD_START_ROUTINE类型。LPTHREAD_START_ROUTINE类型定义为:
typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter);
typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE;
按照上述定义声明的函数都可以作为线程函数的入口,和CreateThread类似,CreateRemoteThread的声明如下: HANDLE WINAPI CreateRemoteThread(
HANDLE hProcess,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);
可见该函数就是比CreateThread多了一个参数用于传递远程进程的打开句柄,而我们知道打开一个进程需要函数OpenProcess,其函数声明为: HANDLE WINAPI OpenProcess(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwProcessId
); 第一个参数表示打开进程所要的访问权限,一般使用PROCESS_ALL_ACCESS来获得所有权限,第二个参数表示进程的继承属性,这里设置为false,最关键的参数是第三个参数——进程的ID。因此在此之前必须获得进程名字和PID的对应关系,TlHelp32.h库内提供的函数CreateToolhelp32Snapshot、Process32First、Process32Next提供了对当前进程的遍历访问,使用这里有段公用代码可以使用:
//获取进程name的ID
DWORD getPid(LPTSTR name)
{
HANDLE hProcSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);//获取进程快照句柄
assert(hProcSnap!=INVALID_HANDLE_VALUE);
PROCESSENTRY32 pe32;
pe32.dwSize=sizeof(PROCESSENTRY32);
BOOL flag=Process32First(hProcSnap,&pe32);//获取列表的第一个进程
while(flag)
{
if(!_tcscmp(pe32.szExeFile,name))
{
CloseHandle(hProcSnap);
return pe32.th32ProcessID;//pid
}
flag=Process32Next(hProcSnap,&pe32);//获取下一个进程
}
CloseHandle(hProcSnap);
return 0;
}
因此,按照以上的方式,使用getpid获取指定名称进程pid,传入OpenProcess打开进程获取进程句柄。但是你会发现这时候进程是无法打开的,或者说进程不能以完全访问的权限打开,因此必须提高本地程序的权限,这是远程注入线程引发的第一个问题,这里也有一段通用代码: //提升进程权限
int EnableDebugPrivilege(const LPTSTR name)
{
HANDLE token;
TOKEN_PRIVILEGES tp;
//打开进程令牌环
if(!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&token))
{
cout |