本文内容仅供网络安全学习与防御研究,严禁用于非法用途,作者不承担任何法律责任
一.什么是shellcode
作者自己认为shellcode 就是一段纯二进制的机器码,它能让计算机直接执行一些你想要的结果,不需要编译器、不需要运行环境,丢进内存触发就能跑。那么问题来了如何把他丢进内存触发呢?
二.shellcode的运行一般流程
一般是把shellcode与一些其他功能部分的代码做成.exe文件(也就是所谓的shellcode加载器)执行,大概流程为——做好的.exe双击 → 系统创建进程 → 加载器代码运行 → 申请可执行内存 → 写入shellcode到内存 → 告诉CPU去执行这段内存 → CPU开始跑shellcode→ 达到你要的效果
三.shellcode加载器的编写
按照第二步所说我们主要要完成三个步骤
1.申请可执行内存
2.写入shellcode到内存
3.执行内存中的代码
我们这里主讲Windows了,那下面就看看如何做到这三步了
第一步:申请可执行内存
Windows系统自带了可供我们使用的api函数,这里要用到第一个api函数——VirtualAlloc 函数 (memoryapi.h)
这里给予微软官方的解释

语法使用框架如下:
LPVOID VirtualAlloc(
[in, optional] LPVOID lpAddress,
[in] SIZE_T dwSize,
[in] DWORD flAllocationType,
[in] DWORD flProtect
);
我给大家总结一下参数意思(官方给的解释太多了,真晕,我会用{}里的内容补充说明,想看原版的去微软官网看吧):
lpAddress:目标内存起始地址{
为NULL:系统自动选择合适的地址
为非 NULL:手动指定地址。
无效指定地址会返回 ERROR_INVALID_ADDRESS 错误
}
dwSize: 分配内存大小(字节){
lpAddress=NULL:大小自动向上取整到下一页边界
lpAddress≠NULL:分配所有包含指定地址范围的内存页(跨页会占用两个页)
最终分配大小一定是内存页大小的整数倍(系统最小分配单位)
}
flAllocationType:内存分配类型{
类型有
MEM_COMMIT (0x1000):为已保留内存分配实际存储,首次访问清零且物理页延迟分配;可搭配MEM_RESERVE一步分配;单独使用且无保留地址会报错;重复提交无异常;enclave地址必须使用。
MEM_RESERVE (0x2000):保留进程的虚拟地址空间范围,而无需在内存或磁盘上的分页文件中分配任何实际物理存储。
可以在对 VirtualAlloc 函数的后续调用中提交保留页。 若要在一个步骤中保留和提交页面,请使用 MEM_COMMIT | MEM_RESERVE调用 VirtualAlloc。其他内存分配函数(如 malloc 和 LocalAlloc)在释放之前无法使用保留的内存范围。
MEM_RESET (0x80000):标记指定内存区域数据无需保留,暂停分页文件读写且不取消提交。此标志不可与其他值混用,不保证内存清零,忽略 flProtect 但需设有效值,仅支持分页文件共享视图。
MEM_RESET_UNDO (0x1000000):撤销MEM_RESET,恢复内存数据
flProtect:内存保护属性
定义分配后内存的访问权限,提交内存时必选:{
常用取值
PAGE_READWRITE 可读可写(最常用
PAGE_EXECUTE_READWRITE 可读可写可执行
PAGE_READONLY 只读
PAGE_EXECUTE 仅可执行
PAGE_NOACCESS 禁止任何访问
特殊:使用MEM_RESET时,此参数无效,但仍需填合法值(如PAGE_NOACCESS)
}
2.写入shellcode到内存
我们到了第二步就要认识一个Windows api函数—— RtlCopyMemory(其实有很多很多相似功能的API来写入这里就挑选一种)

语法如下:
void RtlCopyMemory(
void* Destination,
const void* Source,
size_t Length
);
参数解释如下:
[out] Destination
指向要将字节复制到的目标内存块的指针。
[in] Source
指向要从中复制字节的源内存块的指针。
[in] Length
要从源复制到目标的字节数。
3.执行内存中的代码
方法有很多种,咱们假设定已经用 VirtualAlloc 分配好内存、拷贝好 Shellcode,变量统一用:LPVOID pAlloc;
我们大概列出几种如:
1.直接调用:
((void(*)())pAlloc)();
2.CreateThread 创建子线程执行
HANDLE hThread = CreateThread(
NULL, 0,
(LPTHREAD_START_ROUTINE)pAlloc,
NULL, 0, NULL
);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
等等很多方法这里就不细说了,网上都有模板方法任你挑选
565

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



