Windows

远程线程注入

信号

信号量为n,最多就只有n个线程执行 其他线程等待

1
2
CreateSemaphore;
ReleaseSemaphore;

创建信号:

img

参数2: 开始放出的信号个数

参数3: 最大的信号个数

释放信号:

img

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";
}


运行结果:

img

空的那一行 代表有线程退出

远程线程注入

img

img

目标进程中任意一个函数只要是一个参数一个返回值都可以作为线程回调函数

LoadLibrary 即是上述的情况

img

CreateRemoteThread 传入LoadLibrary 的地址 目标进程就会把LoadLibrary 当线程回调启动

获取目标进程中LoadLibrary的地址

所有进程中kernel32.dllntdll.dll的地址是一样的

img

img

img

参数2:为要分配的页面区域指定所需起始地址的指针 若为NULL 则由系统自己分配

参数3:分配的大小 按页分配

img

MEM_COMMIT表示将分配的内存标记为可用,并分配物理内存

MEM_RESERVE保留进程的虚拟地址空间范围,而无需在内存或磁盘上的分页文件中分配任何实际物理存储。通过使用 MEM_COMMIT 再次调用 VirtualAllocEx 来提交保留页

添加一个dll

img

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" };//创建的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
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#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然后再运行即可显示注入成功

img

添加一个dialog

image-20240713170650388

image-20240713170757630

image-20240713172846495

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
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#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;
}


注入成功后便会有一个弹窗

img

自卸载

卸载Dll

image-20240713180703774

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
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#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 使弹窗消失

img

返回值会作为线程退出码

正常情况下你调用FreeLibrary来释放当前执行的代码所在的DLL会导致FreeLibrary返回以后无法继续执行之后的代码(DLL已经释放了) 于是转而使用FreeLibraryAndExitThread这个函数会在FreeLibrary之后结束当前线程,这个操作的代码在kernel32.dll中,所以不存在上述问题

img

将加载的动态链接库 (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
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include <Windows.h>
#include <conio.h>
#include "resource.h"
DWORD WINAPI FreeThreadFunc(LPVOID lpParam)//修改
{
Sleep(1000);
FreeLibraryAndExitThread(GetModuleHandle("Dll1"), 0);//卸载指定dll并退出当前线程
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;
}

注入后:

img

卸载后:

image-20240717153506497

1
2
3
4
WaitForSingleObject(hRemote, INFINITE);
HANDLE hRemoteDll = NULL;//dll1句柄
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;
}

image-20240713192040530

1
2
3
4
5
DWORD WINAPI ThreadFunc(LPVOID lpParam)
{
//ExitThread(0x12345678);//将该函数去掉 退出码由返回值决定
return 0x98765432;
}