远程线程注入(二)线程注入
文章本来是想转这位大大的:http://blog.csdn.net/gaoxin1076/article/details/8117151
谁知道他的代码在我的Codeblocks上根本不能运行,改了好多处还是无解- -
于是乎我参考了别人的代码做了一些修改,能够在Codeblocks上编译,能够注入一些非系统进程,例如QQ- -,但是像explorer.exe、services.exe之类的系统进程
在启动远程线程时会失败,暂时还不知道为何。。
先奉上代码:
//远程线程注入 #include <windows.h> #include <tlhelp32.h> #include <cstdio> typedef struct _RemotePara { char dwMessageBox[12]; DWORD pMessageBox; }RemotePara; //传入到远程线程中的参数 DWORD _stdcall ThreadProc(RemotePara *lpPara) //远程线程函数 { typedef int (_stdcall *MMessageBoxA)(HWND, LPCTSTR, LPCTSTR, DWORD); MMessageBoxA myMessageBox; myMessageBox = (MMessageBoxA)lpPara->pMessageBox; myMessageBox(NULL, lpPara->dwMessageBox, lpPara->dwMessageBox, MB_OK); return 0; } void EnableDebugPriv(void) //提权操作 { HANDLE hToken; LUID sedebugnameValue; TOKEN_PRIVILEGES tkp; if (!OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) return; if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue)) { CloseHandle(hToken); return; } tkp.PrivilegeCount = 1; tkp.Privileges[0].Luid = sedebugnameValue; tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if ( !AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof tkp, NULL, NULL) ) { CloseHandle(hToken); } } //根据进程名,获得进程ID DWORD GetProcessID(char *FileName) { HANDLE hProcess; PROCESSENTRY32 pe; BOOL bRet; //进行进程快照 hProcess = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); pe.dwSize = sizeof(PROCESSENTRY32); //开始进程查找 bRet = Process32First(hProcess, &pe); //循环比较,得出ProcessID while(bRet) { if(strcmp(FileName, pe.szExeFile) == 0) { return pe.th32ProcessID; } else { bRet = Process32Next(hProcess,&pe); } } //返回得到的ProcessID return NULL; } int main(void) { const DWORD THREADSIZE = 1024 * 4; DWORD byte_write; EnableDebugPriv(); //提权 //打开被注入进程 HANDLE hWnd = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetProcessID("QQ.exe")); if (!hWnd) { return 1; } //在被注入进程中申请内存空间 void *pRemoteThread = VirtualAllocEx(hWnd, 0, THREADSIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (!pRemoteThread) { return 2; } //将远程线程函数写入被注入进程 if ( !WriteProcessMemory(hWnd, pRemoteThread, (LPCVOID)&ThreadProc, THREADSIZE, 0) ) { return 3; } //为将要传入线程的参数赋值 RemotePara myRemotePara; ZeroMemory(&myRemotePara, sizeof(myRemotePara)); HINSTANCE hker = LoadLibrary("user32.dll"); //获得MessageBox的函数地址 myRemotePara.pMessageBox = (DWORD)GetProcAddress(hker, "MessageBoxA"); strcat(myRemotePara.dwMessageBox, "hello\0"); FreeLibrary(hker); //在被注入进程中申请传入参数的空间 RemotePara *pRemotePara = (RemotePara *)VirtualAllocEx(hWnd, 0, sizeof(RemotePara), MEM_COMMIT, PAGE_READWRITE); if (!pRemotePara) { return 4; } //将参数写入被注入进程 if ( !WriteProcessMemory(hWnd, pRemotePara, &myRemotePara, sizeof(RemotePara), 0) ) { return 5; } //启动远程线程 HANDLE hTread = CreateRemoteThread(hWnd, 0, 0, (DWORD(_stdcall *)(void *))pRemoteThread, pRemotePara, 0, &byte_write); if (!hTread) { return 6; } return 0; }
创建远程线程有以下几个步骤:
1.获得想要注入代码的进程的句柄,PROCESS_ALL_ACCESS表示获得所有权限
HANDLE hWnd = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetProcessID("QQ.exe"));
2.在远程线程中为传送过去的函数申请内存
void *pRemoteThread = VirtualAllocEx(hWnd, 0, THREADSIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
3.将远程线程函数写入被注入进程
WriteProcessMemory(hWnd, pRemoteThread, (LPCVOID)&ThreadProc, THREADSIZE, 0);
4.获得MessageBoxA在user32.dll中的真正地址
myRemotePara.pMessageBox = (DWORD)GetProcAddress(hker, "MessageBoxA");
5.在远程进程中为传送过去的参数申请内存
RemotePara *pRemotePara = (RemotePara *)VirtualAllocEx(hWnd, 0, sizeof(RemotePara), MEM_COMMIT, PAGE_READWRITE);
6.将参数写入注入进程
WriteProcessMemory(hWnd, pRemotePara, &myRemotePara, sizeof(RemotePara), 0);
7.最后启动远程线程
HANDLE hTread = CreateRemoteThread(hWnd, 0, 0, (DWORD(_stdcall *)(void *))pRemoteThread, pRemotePara, 0, &byte_write);
第一次远程注入可以成功,第二次就不行了,就不能弹出对话框了,貌似进程打开之后马上就关闭了。个人以为原因可能处在dll的fdwReason。有时间尝试着调试一下。
自己改了一下,应该是这样的。上面的代码里面没有FreeLibrary,那么dll还是在远程地址空间里面。第二次想要注入的时候是不会发送DLL_PROCESS_ATTACH 消息的。
DLL_PROCESS_ATTACH消息的发送是这样的:
线程调用LoadLibrary --> Dll是否已经被映射到了进程的地址空间中 (如果是) --> 递增DLL的使用计数 --> 使用计数器是否等于1 (如果是) --> 调用DLL的DllMain并且传入DLL_PROCESS_ATTACH
所以说,在Dll已经被映射到了进程地址空间之后,只不过DLL的使用计数增加了,如果是2,那么很明显就不会调用DLL的DllMain并且传入DLL_PROCESS_ATTACH
但是如果我把dll改一下,把弹框代码写在DLL_THREAD_ATTACH里面,那么每次创建线程的时候就都会收到DLL_THREAD_ATTACH消息了。
脑子里面还是很乱- -
暂时先就这样吧。。