Windows
远程线程注入
信号
信号量为n,最多就只有n个线程执行 其他线程等待
1 2
| CreateSemaphore; ReleaseSemaphore;
|
创建信号:
参数2: 开始放出的信号个数
参数3: 最大的信号个数
释放信号:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #include <iostream> #include<Windows.h> using namespace std;
HANDLE g_hSem = NULL;
DWORD WINAPI WorkThreadProc( LPVOID ipThreadParameter ) { while (true) { WaitForSingleObject(g_hSem, INFINITE); printf("%d\t:洗剪吹...\r\n", GetCurrentThreadId()); Sleep(2000); ReleaseSemaphore(g_hSem, 1, NULL); } }
int main() { g_hSem = CreateSemaphore(NULL, 2, 4, NULL);
const int nThreadCnt = 5; HANDLE aryhThreads[4] = {}; for (int i = 0; i < nThreadCnt; ++i) { aryhThreads[i] = CreateThread(NULL, 0, WorkThreadProc,NULL,0,NULL); } system("pause"); ReleaseSemaphore(g_hSem, 1, NULL); WaitForMultipleObjects(nThreadCnt, aryhThreads, TRUE, INFINITE); CloseHandle(g_hSem); std::cout << "Hello World!\n"; }
|
运行结果:
空的那一行 代表有线程退出
远程线程注入
目标进程中任意一个函数只要是一个参数一个返回值都可以作为线程回调函数
LoadLibrary
即是上述的情况
CreateRemoteThread
传入LoadLibrary
的地址 目标进程就会把LoadLibrary
当线程回调启动
获取目标进程中LoadLibrary
的地址:
所有进程中kernel32.dll
和ntdll.dll
的地址是一样的
参数2:为要分配的页面区域指定所需起始地址的指针 若为NULL 则由系统自己分配
参数3:分配的大小 按页分配
MEM_COMMIT
表示将分配的内存标记为可用,并分配物理内存
MEM_RESERVE
保留进程的虚拟地址空间范围,而无需在内存或磁盘上的分页文件中分配任何实际物理存储。通过使用 MEM_COMMIT
再次调用 VirtualAllocEx
来提交保留页
添加一个dll
CreateRemoteThread:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| #include <iostream> #include<Windows.h> using namespace std;
int main() { HWND hWndCff = FindWindow(NULL, "CFF Explorer VII"); if (hWndCff == NULL) { return 0; } DWORD dwProcId; GetWindowThreadProcessId(hWndCff, &dwProcId);
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcId); if (hProc == NULL) { return 0; }
LPVOID pDllPath = VirtualAllocEx(hProc, NULL, MAX_PATH, MEM_COMMIT, PAGE_READWRITE); if (pDllPath == NULL) { return 0; } char szDllPath[] = { "C:\\vs\\Windows11\\RemoteInject\\x64\\Debug\\Dll1.dll" }; BOOL bRet = WriteProcessMemory(hProc, pDllPath, szDllPath, sizeof(szDllPath), NULL); if (!bRet) { return 0; } HMODULE hKernel32 = GetModuleHandle("kernel32"); if (hKernel32 == NULL) { return 0; } auto pfnLoadLibrary = GetProcAddress(hKernel32, "LoadLibraryA"); if (pfnLoadLibrary == NULL) { return 0; } HANDLE hMod = CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)pfnLoadLibrary, pDllPath, 0, NULL); if (hMod == NULL) { cout << "注入失败" << endl; return 0; } std::cout << "注入成功\n"; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include "pch.h"
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: OutputDebugString("DLL_PROCESS_ATTACH: 你被注入了"); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: OutputDebugString("DLL_PROCESS_ATTACH: 我走了"); break; } return TRUE; }
|
先打开CFF Explorer VII
然后再运行即可显示注入成功
添加一个dialog
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| #include "pch.h" #include<Windows.h> #include<conio.h> #include "resource.h" INT_PTR CALLBACK InjectDlgProc(HWND hDlg, UINT nMsg, WPARAM wParam, LPARAM lParam) { switch (nMsg) { case WM_COMMAND: { switch (LOWORD(wParam)) { case BTN_TEST: MessageBox(hDlg, "测试", NULL, MB_OK); break; default: break; } break; } case WM_CLOSE: EndDialog(hDlg, 0); return TRUE; default: break; } return FALSE; }
DWORD WINAPI ThreadFunc(LPVOID lpParam) {
return DialogBox(GetModuleHandle("Dll1"), MAKEINTRESOURCE(DLG_INJECT), NULL, InjectDlgProc ); }
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { HANDLE hThread; char szMsg[80]; hThread = CreateThread( NULL, 0, ThreadFunc, NULL, 0, NULL); } OutputDebugString("DLL_PROCESS_ATTACH: 你被注入了"); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: OutputDebugString("DLL_PROCESS_ATTACH: 我走了"); break; } return TRUE; }
|
注入成功后便会有一个弹窗
自卸载
卸载Dll
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| #include "pch.h" #include <Windows.h> #include <conio.h> #include "resource.h" INT_PTR CALLBACK InjectDlgProc(HWND hDlg, UINT nMsg, WPARAM wParam, LPARAM lParam) { switch (nMsg) { case WM_COMMAND: { switch (LOWORD(wParam)) { case BTN_TEST: MessageBox(hDlg, "测试", NULL, MB_OK); break; case BTN_FREELIB: FreeLibrary(GetModuleHandle("Dll1")); break; default: break; } break; } case WM_CLOSE: EndDialog(hDlg, 0); return TRUE; default: break; } return FALSE; } DWORD WINAPI ThreadFunc(LPVOID lpParam) { return DialogBox( GetModuleHandle("Dll1"), MAKEINTRESOURCE(DLG_INJECT), NULL, InjectDlgProc); }
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { HANDLE hThread; char szMsg[80]; hThread = CreateThread( NULL, 0, ThreadFunc, NULL, 0, NULL); } OutputDebugString("DLL_PROCESS_ATTACH:你被注入了!!!"); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: OutputDebugString("DLL_PROCESS_DETACH:我走了!!!"); break; } return TRUE; }
|
运行成功后 点击Button2可以卸载Dll 使弹窗消失
返回值会作为线程退出码
正常情况下你调用FreeLibrary
来释放当前执行的代码所在的DLL会导致FreeLibrary
返回以后无法继续执行之后的代码(DLL已经释放了) 于是转而使用FreeLibraryAndExitThread
这个函数会在FreeLibrary
之后结束当前线程,这个操作的代码在kernel32.dll
中,所以不存在上述问题
将加载的动态链接库 (DLL) 的引用计数递减 1,然后调用 ExitThread
以终止调用线程。 函数不返回。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| #include "pch.h" #include <Windows.h> #include <conio.h> #include "resource.h" DWORD WINAPI FreeThreadFunc(LPVOID lpParam) { Sleep(1000); FreeLibraryAndExitThread(GetModuleHandle("Dll1"), 0); return 0; }
INT_PTR CALLBACK InjectDlgProc(HWND hDlg, UINT nMsg, WPARAM wParam, LPARAM lParam) { switch (nMsg) { case WM_COMMAND: { switch (LOWORD(wParam)) { case BTN_TEST: MessageBox(hDlg, "测试", NULL, MB_OK); break; case BTN_FREELIB: CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)FreeLibrary, 0, 0, NULL); EndDialog(hDlg, 0); return FALSE; default: break; } break; } case WM_CLOSE: EndDialog(hDlg, 0); return TRUE; default: break; } return FALSE; }
DWORD WINAPI ThreadFunc(LPVOID lpParam) { DialogBox( GetModuleHandle("Dll1"), MAKEINTRESOURCE(DLG_INJECT), NULL, InjectDlgProc); return 0; }
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { HANDLE hThread; char szMsg[80]; hThread = CreateThread( NULL, 0, ThreadFunc, NULL, 0, NULL); } OutputDebugString("DLL_PROCESS_ATTACH:你被注入了!!!"); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: OutputDebugString("DLL_PROCESS_DETACH:我走了!!!"); break; } return TRUE; }
|
注入后:
卸载后:
1 2 3 4
| WaitForSingleObject(hRemote, INFINITE); HANDLE hRemoteDll = NULL; GetExitCodeThread(hRemote,(LPDWORD) & hRemoteDll);
|
获取线程退出码的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include <windows.h> #include <conio.h> DWORD WINAPI ThreadFunc(LPVOID lpParam) { ExitThread(0x12345678); return 0; }
int main(VOID) { DWORD dwThreadId, dwThrdParam = 1; HANDLE hThread; char szMsg[80]; hThread = CreateThread( NULL, 0, ThreadFunc, &dwThrdParam, 0, &dwThreadId ); WaitForSingleObject(hThread, INFINITE); DWORD dwExitCode = 0; GetExitCodeThread(hThread, (LPDWORD)&dwExitCode); return 0; }
|
1 2 3 4 5
| DWORD WINAPI ThreadFunc(LPVOID lpParam) { return 0x98765432; }
|