乐于分享
好东西不私藏

edr绕过工具 SysWhispers4 源码分析系列(四)

edr绕过工具 SysWhispers4 源码分析系列(四)

官网:http://securitytech.cc

四、SysWhispers4 源码核心模块深度分析

本文档深入 SysWhispers4 源码内部,逐行分析核心模块的实现细节、数据流转过程、关键算法逻辑以及代码设计模式。通过本文档,你将完全理解这个强大工具的每一个技术细节。

1. 参数解析模块分析

1.1 argparse 架构设计

文件位置: syswhispers.py 第 108-280 行

核心类图

  1. ArgumentParser
  2. ├─ArgumentGroup:"Function selection"
  3. ├─--preset/-p
  4. └─--functions/-f
  5. ├─ArgumentGroup:"Target"
  6. ├─--arch/-a
  7. └─--compiler/-c
  8. ├─ArgumentGroup:"Techniques"
  9. ├─--method/-m
  10. └─--resolve/-r
  11. ├─ArgumentGroup:"Evasion / obfuscation"
  12. ├─--obfuscate
  13. ├─--encrypt-ssn
  14. ├─--stack-spoof
  15. ├─--etw-bypass
  16. ├─--amsi-bypass
  17. ├─--unhook-ntdll
  18. ├─--anti-debug
  19. └─--sleep-encrypt
  20. ├─ArgumentGroup:"Output"
  21. ├─--prefix
  22. ├─--out-file/-o
  23. └─--out-dir
  24. └─Misc arguments
  25. ├─--list-functions
  26. ├─--list-presets
  27. └─--verbose/-v

1.2 详细实现代码

build_parser() 函数完整分析

  1. # syswhispers.py 第 108-280 行
  2. def build_parser()-> argparse.ArgumentParser:
  3. """
  4.     构建命令行参数解析器
  5.     设计原则:
  6.     1. 分组清晰:相关参数归类到同一组
  7.     2. 默认值合理:每个参数都有合理的默认行为
  8.     3. 帮助信息详细:epilog 包含完整的使用说明
  9.     4. 易扩展:新增功能只需添加对应参数
  10.     """
  11.     p = argparse.ArgumentParser(
  12.         prog="syswhispers.py",
  13.         description="SysWhispers4 -- NT syscall stub generator with advanced EDR evasion",
  14.         formatter_class=argparse.RawDescriptionHelpFormatter,
  15. # epilog 包含详细的使用说明,帮助用户理解各种选项
  16.         epilog="""
  17. Resolution methods:
  18.   static        Embed SSNs from bundled j00ru table (run update_syscall_table.py first)
  19.   freshycalls   Sort ntdll Nt* exports by VA -> index = SSN  [DEFAULT, hook-resistant]
  20.   hells_gate    Read SSN from ntdll stub (fails if hooked)
  21.   halos_gate    Hell's Gate + neighbor scan to handle hooked functions
  22.   tartarus      Tartarus' Gate: handles near JMP (E9) and far JMP (FF 25) hooks
  23.   from_disk     Load clean ntdll from \\KnownDlls and read SSNs (bypasses ALL hooks)
  24.   recycled      RecycledGate: FreshyCalls + opcode cross-validation (most resilient)
  25.   hw_breakpoint Hardware breakpoints + VEH to extract SSN (advanced)
  26. Invocation methods:
  27.   embedded      syscall instruction in our stub -- direct syscall  [DEFAULT]
  28.   indirect      jmp to syscall;ret gadget inside ntdll (RIP appears in ntdll)
  29.   randomized    jmp to a RANDOM syscall;ret gadget in ntdll per call (anti-RIP)
  30.   egg           8-byte egg marker replaced at runtime -- no static syscall bytes
  31. Presets:
  32.   common        General process/thread/memory operations (25 functions)
  33.   injection     Process/shellcode injection via APC, threads, sections (20 functions)
  34.   evasion       AV/EDR evasion queries and operations (15 functions)
  35.   token         Token manipulation (6 functions)
  36.   stealth       Maximum evasion: injection + evasion + unhooking (31 functions)
  37.   file_ops      File I/O via NT syscalls (7 functions)
  38.   transaction   Process doppelganging / transaction rollback (7 functions)
  39.   all           All supported functions (62 functions)
  40. """,
  41. )
  42. # ================================================================
  43. # 1. 函数选择参数组 - 决定生成哪些 syscall 的存根
  44. # ================================================================
  45.     sel = p.add_argument_group("Function selection (at least one required)")
  46.     sel.add_argument(
  47. "-p","--preset",
  48.         metavar="PRESET[,PRESET...]",
  49.         help="Preset: common, injection, evasion, token, stealth, file_ops, transaction, all",
  50. # 支持多个预设组合:--preset common,injection
  51. # 类型:str,后续需要手动分割
  52. )
  53.     sel.add_argument(
  54. "-f","--functions",
  55.         metavar="FUNC[,FUNC...]",
  56.         help="Comma-separated list of NT function names",
  57. # 支持自定义函数列表:--functions NtAllocateVirtualMemory,NtCreateThreadEx
  58. # 类型:str,后续需要手动分割和验证
  59. )
  60. # 业务逻辑:至少需要一个预设或自定义函数
  61. # 验证在 main() 中进行:if not args.preset and not args.functions
  62. # ================================================================
  63. # 2. 目标架构/编译器参数组 - 决定生成的代码格式
  64. # ================================================================
  65.     tgt = p.add_argument_group("Target")
  66.     tgt.add_argument(
  67. "-a","--arch",
  68.         choices=[a.value for a inArchitecture],# 从枚举类获取合法值
  69.         default=Architecture.x64.value,# 默认 x64
  70.         metavar="ARCH",
  71.         help="Target architecture: x64 (default), x86, wow64, arm64",
  72. # 架构选择影响:
  73. # - x64: 使用 syscall 指令
  74. # - x86: 使用 sysenter 指令
  75. # - WoW64: Heaven's Gate 技术
  76. # - ARM64: 使用 SVC #0 指令
  77. )
  78.     tgt.add_argument(
  79. "-c","--compiler",
  80.         choices=[c.value for c inCompiler],# msvc, mingw, clang
  81.         default=Compiler.MSVC.value,# 默认 MSVC
  82.         metavar="COMPILER",
  83.         help="Compiler: msvc (default, MASM), mingw (GAS inline), clang (GAS inline)",
  84. # 编译器选择影响:
  85. # - MSVC: 生成 .asm 文件,使用 MASM 语法
  86. # - MinGW/Clang: 生成 _stubs.c 文件,使用 GAS 内联汇编
  87. )
  88. # ================================================================
  89. # 3. 技术参数组 - 核心绕过技术选择
  90. # ================================================================
  91.     tech = p.add_argument_group("Techniques")
  92.     tech.add_argument(
  93. "-m","--method",
  94.         choices=[m.value for m inInvocationMethod],
  95.         default=InvocationMethod.Embedded.value,# 默认直接 syscall
  96.         metavar="METHOD",
  97.         help="Invocation: embedded (default), indirect, randomized, egg",
  98. # 调用方法详解:
  99. # - embedded: 我们自己的存根中包含 syscall 指令
  100. # - indirect: 跳转到 ntdll 中的 syscall;ret gadget
  101. # - randomized: 随机选择 ntdll 中的 syscall gadget(反 RIP 追踪)
  102. # - egg: 使用 egg marker,运行时替换为 syscall 指令
  103. )
  104.     tech.add_argument(
  105. "-r","--resolve",
  106.         choices=[r.value for r inResolutionMethod],
  107.         default=ResolutionMethod.FreshyCalls.value,# 默认 FreshyCalls
  108.         metavar="RESOLVE",
  109.         help="SSN resolution: freshycalls (default), static, hells_gate, halos_gate, "
  110. "tartarus, from_disk, recycled, hw_breakpoint",
  111. # SSN 解析方法详解:
  112. # - static: 使用内置的 j00ru SSN 表(生成时确定)
  113. # - freshycalls: 运行时按地址排序 ntdll 导出函数
  114. # - hells_gate: 读取 ntdll stub 的 opcode 字节
  115. # - halos_gate: hells_gate + 邻居扫描(±8)
  116. # - tartarus: 增强版(±16 + 多种 Hook 检测)
  117. # - from_disk: 从 KnownDlls 加载干净 ntdll
  118. # - recycled: freshycalls + opcode 验证
  119. # - hw_breakpoint: 硬件断点 + VEH
  120. )
  121. # ================================================================
  122. # 4. 规避/混淆选项参数组 - 高级 EDR 绕过技术
  123. # ================================================================
  124.     eva = p.add_argument_group("Evasion / obfuscation")
  125.     eva.add_argument(
  126. "--obfuscate",
  127.         action="store_true",# 布尔标志,提供即启用
  128.         help="Randomize stub ordering and inject junk instructions",
  129. # 混淆效果:
  130. # 1. 随机打乱函数顺序(增加静态分析难度)
  131. # 2. 注入垃圾指令(nop, xchg, lea 等无害指令)
  132. # 3. 随机化函数名前缀
  133. )
  134.     eva.add_argument(
  135. "--encrypt-ssn",
  136.         action="store_true",
  137.         help="XOR-encrypt SSN values at rest (decrypted at runtime)",
  138. # SSN 加密原理:
  139. # 1. 生成随机 XOR 密钥(32 位)
  140. # 2. 编译时:encrypted_ssn = ssn ^ key
  141. # 3. 运行时:ssn = encrypted_ssn ^ key
  142. # 4. 防止静态分析工具识别 SSN 值
  143. )
  144.     eva.add_argument(
  145. "--stack-spoof",
  146.         action="store_true",
  147.         help="Include synthetic call stack frame helper (reduces stack anomaly)",
  148. # 栈伪造技术:
  149. # 1. 在 syscall 前伪造返回地址
  150. # 2. 使调用栈看起来像正常的函数调用
  151. # 3. 避免栈回溯检测到异常
  152. )
  153.     eva.add_argument(
  154. "--etw-bypass",
  155.         action="store_true",
  156.         help="Include optional user-mode ETW writer patch (see SW4PatchEtw)",
  157. # ETW 绕过原理:
  158. # 1. 定位 ntdll!EtwEventWrite 函数
  159. # 2. 修改前几个字节为 "xor eax, eax; ret"
  160. # 3. 所有 ETW 日志返回 ACCESS_DENIED
  161. # 4. 用户态 ETW 完全失效
  162. )
  163.     eva.add_argument(
  164. "--amsi-bypass",
  165.         action="store_true",
  166.         help="Include AMSI bypass (patches AmsiScanBuffer)",
  167. # AMSI 绕过原理:
  168. # 1. 定位 amsi.dll!AmsiScanBuffer
  169. # 2. 修改为 "xor eax, eax; ret"
  170. # 3. 返回 E_INVALIDARG,让 AMSI 认为参数错误
  171. # 4. 如果 amsi.dll 未加载,直接返回成功
  172. )
  173.     eva.add_argument(
  174. "--unhook-ntdll",
  175.         action="store_true",
  176.         help="Include ntdll unhooking (remaps clean .text from KnownDlls)",
  177. # ntdll 解钩原理:
  178. # 1. 打开 \KnownDlls\ntdll.dll Section
  179. # 2. 映射到用户空间
  180. # 3. 复制干净 .text 段覆盖当前 ntdll 的 .text
  181. # 4. 所有 inline hook 被移除
  182. # 5. 后续调用都通过原始代码执行
  183. )
  184.     eva.add_argument(
  185. "--anti-debug",
  186.         action="store_true",
  187.         help="Include anti-debugging checks (PEB, timing, heap flags, debug port)",
  188. # 反调试检查包括:
  189. # 1. PEB.BeingDebugged 标志
  190. # 2. NtGlobalFlag (0x70)
  191. # 3. RDTSC 时间差检测
  192. # 4. ProcessDebugPort 查询
  193. # 5. 堆标志检查
  194. # 6.  instrumentation callback 检测
  195. )
  196.     eva.add_argument(
  197. "--sleep-encrypt",
  198.         action="store_true",
  199.         help="Include sleep encryption (Ekko-style XOR .text during sleep)",
  200. # 睡眠加密原理(Ekko 技术):
  201. # 1. 生成随机 XOR 密钥
  202. # 2. 加密自己的 .text 段
  203. # 3. 设置可等待定时器
  204. # 4. 队列 APC 回调用于解密
  205. # 5. 进入 alertable sleep
  206. # 6. 定时器触发 → APC 执行 → 解密 .text → 继续执行
  207. # 7. 睡眠期间内存扫描只能看到加密数据
  208. )
  209. # ================================================================
  210. # 5. 静态表覆盖选项 - 允许用户使用自定义 SSN 表
  211. # ================================================================
  212.     p.add_argument(
  213. "--syscall-table",
  214.         metavar="PATH",
  215.         help="Path to custom syscall table JSON (for --resolve static)",
  216. # 使用场景:
  217. # 1. 研究特定 Windows 版本
  218. # 2. 测试新出现的 Windows 版本
  219. # 3. 使用自己整理的 SSN 数据库
  220. )
  221. # ================================================================
  222. # 6. 输出选项 - 控制生成文件的命名和位置
  223. # ================================================================
  224.     out = p.add_argument_group("Output")
  225.     out.add_argument(
  226. "--prefix",
  227.         default="SW4",
  228.         metavar="PREFIX",
  229.         help="Prefix for all generated identifiers (default: SW4)",
  230. # 前缀作用:
  231. # 1. 避免命名冲突
  232. # 2. 混淆时生成随机前缀
  233. # 3. 示例:SW4_NtAllocateVirtualMemory
  234. )
  235.     out.add_argument(
  236. "-o","--out-file",
  237.         default=None,
  238.         metavar="OUTFILE",
  239.         help="Output filename base (default: <PREFIX>Syscalls)",
  240. # 默认值计算:
  241. # if args.out_file is None:
  242. #     out_file = f"{prefix_clean}Syscalls"
  243. )
  244.     out.add_argument(
  245. "--out-dir",
  246.         default=".",
  247.         metavar="OUTDIR",
  248.         help="Output directory (default: current directory)",
  249. # 输出目录处理:
  250. # out_dir = Path(self.cfg.out_dir)
  251. # out_dir.mkdir(parents=True, exist_ok=True)
  252. )
  253. # ================================================================
  254. # 7. 杂项参数 - 辅助功能
  255. # ================================================================
  256.     p.add_argument(
  257. "-v","--verbose",
  258.         action="store_true",
  259.         help="Verbose output",
  260. # 详细模式:
  261. # if args.verbose:
  262. #     import traceback
  263. #     traceback.print_exc()
  264. )
  265.     p.add_argument(
  266. "--list-functions",
  267.         action="store_true",
  268.         help="Print all available function names and exit",
  269. # 列出所有支持的函数
  270. # proto = load_prototypes()
  271. # for name in sorted(proto):
  272. #     print(f"  {name}")
  273. )
  274.     p.add_argument(
  275. "--list-presets",
  276.         action="store_true",
  277.         help="Print all available presets and exit",
  278. # 列出所有预设配置
  279. # presets = load_presets()
  280. # for name, data in presets.items():
  281. #     print(f"  {name}: {data['description']}")
  282. )
  283. return p

1.3 参数验证与处理流程

resolvefunctions() – 函数列表展开

  1. # syswhispers.py 第 57-80 行
  2. def _resolve_functions(args)-> list[str]:
  3. """
  4.     展开预设名称和/或逗号分隔的函数列表
  5.     处理逻辑:
  6.     1. 先处理预设(可能包含多个函数)
  7.     2. 再处理自定义函数列表
  8.     3. 去重并保持顺序
  9.     返回值:唯一的函数名列表
  10.     """
  11.     functions: list[str]=[]
  12. # ---- 步骤 1: 展开预设 ----
  13. if args.preset:
  14. # 加载所有预设定义
  15.         presets = load_presets()
  16. # 支持多个预设组合:--preset common,injection
  17. for p in args.preset.split(","):
  18.             p = p.strip()# 去除空白字符
  19. # 验证预设是否存在
  20. if p notin presets:
  21. print(f"[!] Unknown preset '{p}'. Available: {', '.join(presets)}")
  22.                 sys.exit(1)
  23. # 扩展预设包含的所有函数
  24.             functions.extend(presets[p]["functions"])
  25. # extend 会将预设中的所有函数添加到列表
  26. # 例如:presets["common"]["functions"] 包含 25 个函数名
  27. # ---- 步骤 2: 添加自定义函数 ----
  28. if args.functions:
  29. # 支持自定义列表:--functions NtAlloc,NtCreate
  30. for f in args.functions.split(","):
  31.             f = f.strip()
  32. # 只添加不在已有列表中的函数(去重)
  33. if f and f notin functions:
  34.                 functions.append(f)
  35. # ---- 步骤 3: 去重并保持顺序 ----
  36.     seen = set()
  37.     result =[]
  38. for f in functions:
  39. if f notin seen:
  40.             seen.add(f)# 添加到已见集合
  41.             result.append(f)# 保留到结果列表
  42. return result

算法复杂度分析:

  • 时间复杂度:O(n),其中 n 是总函数数
  • 空间复杂度:O(n),使用 set 存储已见元素
  • 性能优化:使用 set 实现 O(1) 查找

使用示例:

  1. # 示例 1: 单个预设
  2. python syswhispers.py --preset common
  3. # 结果:functions = [25 个 common 预设中的函数]
  4. # 示例 2: 多个预设组合
  5. python syswhispers.py --preset common,injection
  6. # 结果:functions = [common 的 25 个] + [injection 的 20 个,去重后约 35 个]
  7. # 示例 3: 预设 + 自定义
  8. python syswhispers.py --preset common --functions NtQueryInformationProcess
  9. # 结果:functions = [common 的 25 个] + [NtQueryInformationProcess]
  10. # 示例 4: 多个自定义函数
  11. python syswhispers.py --functions NtAllocateVirtualMemory,NtCreateThreadEx
  12. # 结果:functions = ["NtAllocateVirtualMemory", "NtCreateThreadEx"]

validatefunctions() – 函数名验证

  1. # syswhispers.py 第 83-91 行
  2. def _validate_functions(functions: list[str])->None:
  3. """
  4.     验证所有函数名是否存在于 prototypes.json 中
  5.     验证策略:
  6.     1. 加载已知函数原型字典
  7.     2. 提取所有已知函数名
  8.     3. 检查用户输入的函数是否在已知列表中
  9.     4. 如果有未知函数,显示友好错误信息并退出
  10.     """
  11. # 加载所有已知函数原型
  12.     known = set(load_prototypes().keys())
  13. # known = {"NtAllocateVirtualMemory", "NtCreateThreadEx", ...} 共 64 个
  14. # 找出未知的函数名
  15.     unknown =[for f in functions if f notin known]
  16. # 列表推导式高效过滤
  17. # 如果有未知函数,显示错误信息
  18. if unknown:
  19. print(f"[!] Unknown function(s): {', '.join(unknown)}")
  20. print(f"    Available: {', '.join(sorted(known))}")
  21. # 显示所有可用函数名,帮助用户纠正输入
  22.         sys.exit(1)
  23. # 立即终止程序,避免后续处理

错误处理示例:

  1. # 输入错误函数名
  2. python syswhispers.py --functions NtAllocFake,NtCreateThreadEx
  3. # 输出错误信息
  4. [!]Unknownfunction(s):NtAllocFake
  5. Available:NtAdjustPrivilegesToken,NtAllocateVirtualMemory,
  6. NtAllocateVirtualMemoryEx,NtAlertResumeThread,...
  7. (按字母顺序显示所有64个可用函数)

1.4 配置对象构建

  1. # syswhispers.py 第 320-350 行
  2. def main()->None:
  3. # ... 前面的处理 ...
  4. # ---- 清理前缀并确定输出文件名 ----
  5.     prefix_clean = args.prefix.rstrip("_")# 移除末尾的下划线
  6. # 示例:"SW4_" → "SW4"
  7.     out_file = args.out_file if args.out_file isnotNoneelse f"{prefix_clean}Syscalls"
  8. # 如果未指定 --out-file,使用默认值:SW4Syscalls
  9. # ---- 构建 GeneratorConfig 对象 ----
  10.     cfg =GeneratorConfig(
  11. # 1. syscall 选择
  12.         functions       = functions,# 经过展开和验证的函数列表
  13. # 2. 目标选项
  14.         arch            =Architecture(args.arch),# 枚举转换
  15.         compiler        =Compiler(args.compiler),# 枚举转换
  16.         method          =InvocationMethod(args.method),#枚举转换
  17.         resolve         =ResolutionMethod(args.resolve),#枚举转换
  18. # 3. 输出选项
  19.         prefix          = prefix_clean +"_",# 添加下划线:SW4_
  20.         out_file        = out_file,# SW4Syscalls
  21.         out_dir         = args.out_dir,# 默认 "."
  22. # 4. 规避选项
  23.         obfuscate       = args.obfuscate,# bool
  24.         encrypt_ssn     = args.encrypt_ssn,# bool
  25.         stack_spoof     = args.stack_spoof,# bool
  26.         etw_bypass      = args.etw_bypass,# bool
  27.         amsi_bypass     = args.amsi_bypass,# bool
  28.         unhook_ntdll    = args.unhook_ntdll,# bool
  29.         anti_debug      = args.anti_debug,# bool
  30.         sleep_encrypt   = args.sleep_encrypt,# bool
  31. # 5. 其他选项
  32.         syscall_table   = args.syscall_table,# str or None
  33. )
  34. # ---- 打印配置摘要 ----
  35. print(f"  Functions  : {len(functions)}")
  36. print(f"  Arch       : {cfg.arch}")
  37. print(f"  Compiler   : {cfg.compiler}")
  38. print(f"  Resolution : {cfg.resolve}")
  39. print(f"  Method     : {cfg.method}")
  40. print(f"  Prefix     : {cfg.prefix}")
  41. # 动态显示启用的选项
  42. if cfg.obfuscate:print("  Obfuscate  : yes (stub reordering + junk instructions)")
  43. if cfg.encrypt_ssn:print("  Encrypt SSN: yes (XOR key embedded at compile time)")
  44. if cfg.stack_spoof:print("  Stack spoof: yes (synthetic call stack helper)")
  45. if cfg.etw_bypass:print("  ETW bypass : yes (user-mode EtwEventWrite patch)")
  46. if cfg.amsi_bypass:print("  AMSI bypass: yes (AmsiScanBuffer patch)")
  47. if cfg.unhook_ntdll:print("  Unhook     : yes (remap clean ntdll from KnownDlls)")
  48. if cfg.anti_debug:print("  Anti-debug : yes (PEB, timing, heap, debug port)")
  49. if cfg.sleep_encrypt:print("  Sleep crypt: yes (Ekko-style XOR .text during sleep)")

配置对象优点:

  1. 类型安全:所有字段有明确类型定义
  2. 集中管理:所有配置在一个对象中传递
  3. 默认值:合理的默认配置
  4. 易扩展:新增选项只需添加字段
  5. 自文档化:配置对象本身就是文档

2. syscall 数据解析流程

2.1 数据加载入口 – loaddata()

  1. # generator.py 第 92-125 行
  2. classSysWhispers4:
  3. def __init__(self, config:GeneratorConfig):
  4.         self.cfg = config
  5.         self.obf =Obfuscator(seed=random.randint(0,0xFFFFFFFF))
  6.         self._prototypes:List[SyscallPrototype]=[]
  7.         self._ssn_x64: dict ={}
  8.         self._ssn_x86: dict ={}
  9. def _load_data(self)->None:
  10. """
  11.         加载并处理所有必需的数据
  12.         数据流:
  13.         JSON 文件 → Python dict → 转换为数据类对象 → 缓存到实例变量
  14.         处理步骤:
  15.         1. 加载函数原型(prototypes.json)
  16.         2. 加载 SSN 表(syscalls_nt_x64.json)
  17.         3. 可选:加载自定义 SSN 表
  18.         4. 过滤并转换为用户选择的函数
  19.         5. 可选:随机打乱顺序(混淆模式)
  20.         """
  21. # ---- 步骤 1: 加载函数原型 ----
  22.         raw_proto = load_prototypes()
  23. # raw_proto 结构:
  24. # {
  25. #     "NtAllocateVirtualMemory": {
  26. #         "return_type": "NTSTATUS",
  27. #         "params": [
  28. #             {"name": "ProcessHandle", "type": "HANDLE", "annotation": "IN"},
  29. #             {"name": "BaseAddress", "type": "PVOID*", "annotation": "IN OUT"},
  30. #             ...
  31. #         ]
  32. #     },
  33. #     "NtCreateThreadEx": {...},
  34. #     ... 共 64 个函数
  35. # }
  36. # ---- 步骤 2: 加载 SSN 表 ----
  37.         self._ssn_x64 = load_ssn_table_x64()
  38.         self._ssn_x86 = load_ssn_table_x86()
  39. # SSN 表结构:
  40. # {
  41. #     "NtAllocateVirtualMemory": {
  42. #         "xp_sp1": 70,
  43. #         "7_sp0": 70,
  44. #         "8.0": 71,
  45. #         "8.1": 23,
  46. #         "10240": 24,
  47. #         "22000": 24,  # Windows 11
  48. #         ...
  49. #     },
  50. #     "NtCreateThreadEx": {...},
  51. #     ... 共 400+ 个函数
  52. # }
  53. # ---- 步骤 3: 可选 - 覆盖自定义 SSN 表 ----
  54. if self.cfg.syscall_table andPath(self.cfg.syscall_table).exists():
  55. from.utils import load_json
  56.             self._ssn_x64 = load_json(self.cfg.syscall_table)
  57. # 使用用户提供的 SSN 表替换内置表
  58. # 使用场景:研究特定版本、测试新版本
  59. # ---- 步骤 4: 构建原型对象列表 ----
  60. for fname in self.cfg.functions:
  61. # 遍历用户选择的所有函数
  62. # 4.1 验证函数是否存在于原型表中
  63. if fname notin raw_proto:
  64. print(f"  [!] Warning: '{fname}' not found in prototypes.json, skipping.")
  65. continue
  66. # 跳过未知函数,继续处理下一个
  67. # 4.2 获取函数的原始数据
  68.             entry = raw_proto[fname]
  69. # entry 结构:
  70. # {
  71. #     "return_type": "NTSTATUS",
  72. #     "params": [
  73. #         {"name": "...", "type": "...", "annotation": "..."},
  74. #         ...
  75. #     ]
  76. # }
  77. # 4.3 解析参数列表
  78.             params =[
  79. SyscallParam(
  80.                     name=p["name"],# 参数名:如 "ProcessHandle"
  81.                     type=p["type"],# 参数类型:如 "HANDLE"
  82.                     annotation=p.get("annotation",""),# 方向注解:IN/OUT/OPTIONAL
  83. )
  84. for p in entry.get("params",[])
  85. # 如果 entry 中没有 params 字段,使用空列表 []
  86. ]
  87. # 列表推导式将 dict 转换为 SyscallParam 对象
  88. # 4.4 创建 SyscallPrototype 对象
  89.             self._prototypes.append(
  90. SyscallPrototype(
  91.                     name=fname,# 函数名:如 "NtAllocateVirtualMemory"
  92.                     return_type=entry.get("return_type","NTSTATUS"),# 返回类型
  93.                     params=params,# 参数对象列表
  94. )
  95. )
  96. # SyscallPrototype 是 dataclass,提供以下属性:
  97. # - name: str
  98. # - return_type: str
  99. # - params: List[SyscallParam]
  100. # - param_count: int (property)
  101. # - c_signature(): str (method)
  102. # - c_prototype(): str (method)
  103. # ---- 步骤 5: 可选 - 混淆函数顺序 ----
  104. if self.cfg.obfuscate:
  105. # 如果启用了混淆,随机打乱函数顺序
  106.             self._prototypes =[
  107.                 self._prototypes[i]
  108. for i in self.obf.shuffle_functions(
  109.                     list(range(len(self._prototypes)))
  110. )
  111. ]
  112. # shuffle_functions() 返回打乱后的索引列表
  113. # 例如:[0, 1, 2, 3] → [2, 0, 3, 1]
  114. # 效果:生成的代码中函数顺序是随机的

2.2 数据类定义 – models.py

SyscallParam 数据类

  1. # models.py 第 54-63 行
  2. @dataclass
  3. classSyscallParam:
  4. """
  5.     syscall 参数数据类
  6.     属性:
  7.     - name: 参数名称(如 "ProcessHandle")
  8.     - type: 参数类型(如 "HANDLE", "PVOID*")
  9.     - annotation: 方向注解("IN", "OUT", "IN OUT", "OPTIONAL")
  10.     方法:
  11.     - c_declaration(): 返回 C 语言参数声明字符串
  12.     """
  13.     name:       str   # 参数名
  14.     type:       str   # 参数类型
  15.     annotation: str =""# 方向注解,默认为空
  16. def c_declaration(self)-> str:
  17. """
  18.         生成 C 语言参数声明
  19.         示例:
  20.         SyscallParam(name="ProcessHandle", type="HANDLE")
  21.             → "HANDLE ProcessHandle"
  22.         SyscallParam(name="BaseAddress", type="PVOID*", annotation="IN OUT")
  23.             → "PVOID* BaseAddress"  (annotation 不包含在声明中)
  24.         """
  25. return f"{self.type} {self.name}"

使用示例:

  1. # 创建参数对象
  2. param1 =SyscallParam(
  3.     name="ProcessHandle",
  4.     type="HANDLE",
  5.     annotation="IN"
  6. )
  7. param2 =SyscallParam(
  8.     name="BaseAddress",
  9.     type="PVOID*",
  10.     annotation="IN OUT"
  11. )
  12. # 生成 C 声明
  13. print(param1.c_declaration())# 输出:HANDLE ProcessHandle
  14. print(param2.c_declaration())# 输出:PVOID* BaseAddress
  15. # 用于生成函数签名
  16. params =[param1, param2]
  17. param_str =", ".join(p.c_declaration()for p in params)
  18. # 结果:"HANDLE ProcessHandle, PVOID* BaseAddress"

SyscallPrototype 数据类

  1. # models.py 第 66-82 行
  2. @dataclass
  3. classSyscallPrototype:
  4. """
  5.     syscall 函数原型数据类
  6.     属性:
  7.     - name: 函数名称(如 "NtAllocateVirtualMemory")
  8.     - return_type: 返回类型(通常是 "NTSTATUS")
  9.     - params: 参数对象列表
  10.     属性(计算得出):
  11.     - param_count: 参数数量
  12.     方法:
  13.     - c_signature(prefix=""): 生成 C 函数签名(无分号)
  14.     - c_prototype(prefix=""): 生成 C 函数原型(带分号)
  15.     """
  16.     name:        str                  # 函数名
  17.     return_type: str                  # 返回类型
  18.     params:List[SyscallParam]= field(default_factory=list)# 参数列表
  19. @property
  20. def param_count(self)-> int:
  21. """返回参数数量"""
  22. return len(self.params)
  23. def c_signature(self, prefix: str ="")-> str:
  24. """
  25.         生成 C 函数签名(不带分号)
  26.         参数:
  27.         - prefix: 函数名前缀(如 "SW4_")
  28.         示例:
  29.         proto = SyscallPrototype(
  30.             name="NtAllocateVirtualMemory",
  31.             return_type="NTSTATUS",
  32.             params=[
  33.                 SyscallParam(name="ProcessHandle", type="HANDLE"),
  34.                 SyscallParam(name="BaseAddress", type="PVOID*"),
  35.                 # ... 更多参数
  36.             ]
  37.         )
  38.         proto.c_signature()
  39.         → "NTSTATUS NTAPI NtAllocateVirtualMemory(HANDLE ProcessHandle, PVOID* BaseAddress, ...)"
  40.         proto.c_signature(prefix="SW4_")
  41.         → "NTSTATUS NTAPI SW4_NtAllocateVirtualMemory(HANDLE ProcessHandle, PVOID* BaseAddress, ...)"
  42.         """
  43.         func_name = f"{prefix}{self.name}"if prefix else self.name
  44. # 如果有 prefix,添加前缀: "SW4_" + "NtAllocateVirtualMemory"
  45.         param_str =", ".join(p.c_declaration()for p in self.params)
  46. # 将所有参数的 C 声明用逗号和空格连接
  47. return f"{self.return_type} NTAPI {func_name}({param_str})"
  48. # 组合完整签名:返回类型 + 调用约定 + 函数名 + (参数列表)
  49. def c_prototype(self, prefix: str ="")-> str:
  50. """
  51.         生成 C 函数原型(带分号)
  52.         示例:
  53.         proto.c_prototype("SW4_")
  54.         → "NTSTATUS NTAPI SW4_NtAllocateVirtualMemory(HANDLE ProcessHandle, ...);"
  55.         """
  56. return self.c_signature(prefix)+";"
  57. # 在签名后添加分号,形成完整的 C 原型声明

完整示例:

  1. from core.models importSyscallParam,SyscallPrototype
  2. # 创建 NtAllocateVirtualMemory 的原型
  3. proto =SyscallPrototype(
  4.     name="NtAllocateVirtualMemory",
  5.     return_type="NTSTATUS",
  6.     params=[
  7. SyscallParam(name="ProcessHandle", type="HANDLE", annotation="IN"),
  8. SyscallParam(name="BaseAddress", type="PVOID*", annotation="IN OUT"),
  9. SyscallParam(name="ZeroBits", type="ULONG_PTR", annotation="IN"),
  10. SyscallParam(name="RegionSize", type="PSIZE_T", annotation="IN OUT"),
  11. SyscallParam(name="AllocationType", type="ULONG", annotation="IN"),
  12. SyscallParam(name="Protect", type="ULONG", annotation="IN"),
  13. ]
  14. )
  15. # 访问属性
  16. print(proto.name)# 输出:NtAllocateVirtualMemory
  17. print(proto.return_type)# 输出:NTSTATUS
  18. print(proto.param_count)# 输出:6
  19. # 生成 C 原型
  20. print(proto.c_prototype("SW4_"))
  21. # 输出:
  22. # NTSTATUS NTAPI SW4_NtAllocateVirtualMemory(
  23. #     HANDLE ProcessHandle, 
  24. #     PVOID* BaseAddress, 
  25. #     ULONG_PTR ZeroBits, 
  26. #     PSIZE_T RegionSize, 
  27. #     ULONG AllocationType, 
  28. #     ULONG Protect
  29. # );

2.3 数据加载工具函数 – utils.py

  1. # utils.py 第 1-35 行
  2. """
  3. SysWhispers4 - Utility Functions
  4. 通用工具函数模块,提供:
  5. 1. JSON 文件加载
  6. 2. 哈希函数(DJB2, ROR-13, CRC32, FNV-1a)
  7. 3. SSN 表查询辅助函数
  8. """
  9. import json
  10. import os
  11. import struct
  12. from pathlib importPath
  13. from typing importAny
  14. # 数据目录路径
  15. DATA_DIR =Path(__file__).parent.parent /"data"
  16. # 解析路径:
  17. # __file__ = ".../core/utils.py"
  18. # __file__.parent = ".../core/"
  19. # __file__.parent.parent = ".../SysWhispers4-main/"
  20. # DATA_DIR = ".../SysWhispers4-main/data/"
  21. def load_json(path:Path| str)->Any:
  22. """
  23.     通用 JSON 加载器
  24.     参数:
  25.     - path: Path 对象或字符串路径
  26.     返回:
  27.     - 解析后的 JSON 数据(dict、list 等)
  28.     异常:
  29.     - FileNotFoundError: 文件不存在
  30.     - json.JSONDecodeError: JSON 格式错误
  31.     """
  32. with open(path,"r", encoding="utf-8")as f:
  33. return json.load(f)
  34. # 使用 with 语句自动管理文件关闭
  35. # encoding="utf-8" 确保跨平台兼容性
  36. def load_prototypes()-> dict:
  37. """
  38.     加载函数原型定义
  39.     返回:
  40.     - dict[func_name: {return_type, params}]
  41.     文件路径:
  42.     - data/prototypes.json
  43.     """
  44. return load_json(DATA_DIR /"prototypes.json")
  45. def load_presets()-> dict:
  46. """
  47.     加载预设配置
  48.     返回:
  49.     - dict[preset_name: {description, functions}]
  50.     文件路径:
  51.     - data/presets.json
  52.     """
  53. return load_json(DATA_DIR /"presets.json")
  54. def load_ssn_table_x64()-> dict:
  55. """
  56.     加载 x64 架构 SSN 表
  57.     返回:
  58.     - dict[func_name: {build_key: ssn}]
  59.     文件路径:
  60.     - data/syscalls_nt_x64.json
  61.     """
  62. return load_json(DATA_DIR /"syscalls_nt_x64.json")
  63. def load_ssn_table_x86()-> dict:
  64. """
  65.     加载 x86 架构 SSN 表
  66.     返回:
  67.     - dict[func_name: {build_key: ssn}]
  68.     文件路径:
  69.     - data/syscalls_nt_x86.json
  70.     注意:
  71.     - x86 SSN 表是可选的,如果不存在返回空字典
  72.     """
  73.     path = DATA_DIR /"syscalls_nt_x86.json"
  74. if path.exists():
  75. return load_json(path)
  76. return{}
  77. # 优雅降级:如果没有 x86 表,返回空字典

哈希工具函数:

  1. # utils.py 第 37-73 行
  2. def djb2_hash(name: str)-> int:
  3. """
  4.     DJB2 哈希算法(32 位)
  5.     用途:
  6.     - 运行时函数名哈希查找
  7.     - 与编译时哈希对比验证
  8.     算法:
  9.     h = 5381 (0x1505)
  10.     for each char c in name:
  11.         h = ((h << 5) + h) ^ c
  12.     示例:
  13.     djb2_hash("NtAllocateVirtualMemory") → 0x8A3B2C1D (示例值)
  14.     """
  15.     h =0x1505# 初始值 5381
  16. for ch in name.encode("ascii"):
  17.         h =(((<<5)+ h)^ ch)&0xFFFFFFFF
  18. # h << 5 = h * 32
  19. # (h << 5) + h = h * 33
  20. # & 0xFFFFFFFF 保持 32 位
  21. return h
  22. def ror13_hash(name: str)-> int:
  23. """
  24.     ROR-13 哈希算法(32 位)
  25.     用途:
  26.     - Metasploit/PEB Walker 惯例
  27.     - 兼容某些 shellcode 加载器
  28.     算法:
  29.     h = 0
  30.     for each char c in name:
  31.         h = (h >> 13) | (h << 19)  # 循环右移 13 位
  32.         h = h + c
  33.     示例:
  34.     ror13_hash("NtAllocateVirtualMemory") → 0x5E7F8A2B (示例值)
  35.     """
  36.     h =0
  37. for ch in name.encode("ascii"):
  38.         h =(((>>13)|(<<19))&0xFFFFFFFF)+ ch
  39. # (h >> 13) | (h << 19) = 循环右移 13 位
  40. # & 0xFFFFFFFF 保持 32 位
  41. return h &0xFFFFFFFF
  42. def crc32_hash(name: str)-> int:
  43. """
  44.     CRC32 校验和哈希(32 位)
  45.     用途:
  46.     - 标准校验和算法
  47.     - 某些恶意软件使用
  48.     算法:
  49.     标准 CRC32 多项式:0xEDB88320
  50.     示例:
  51.     crc32_hash("NtAllocateVirtualMemory") → 0x9A4B7C2D (示例值)
  52.     """
  53.     crc =0xFFFFFFFF# 初始值
  54. for ch in name.encode("ascii"):
  55.         crc ^= ch  # 与字节异或
  56. for _ in range(8):
  57. if crc &1:
  58.                 crc =(crc >>1)^0xEDB88320
  59. else:
  60.                 crc >>=1
  61. return crc ^0xFFFFFFFF# 最终异或
  62. def fnv1a_hash(name: str)-> int:
  63. """
  64.     FNV-1a 哈希算法(32 位)
  65.     用途:
  66.     - 快速非加密哈希
  67.     - 另一种常见选择
  68.     算法:
  69.     h = 2166136261 (0x811C9DC5)
  70.     for each char c in name:
  71.         h = (h ^ c) * 16777619 (0x01000193)
  72.     示例:
  73.     fnv1a_hash("NtAllocateVirtualMemory") → 0x3C5D8E9F (示例值)
  74.     """
  75.     h =0x811C9DC5# FNV offset basis
  76. for ch in name.encode("ascii"):
  77.         h =((^ ch)*0x01000193)&0xFFFFFFFF
  78. # 先异或再乘法
  79. return h

哈希算法对比:

算法
速度
碰撞率
主要用途
DJB2
SysWhispers4 默认
ROR-13
Metasploit 兼容
CRC32
极低
标准校验和
FNV-1a
替代选择

3. syscall 选择与过滤机制

3.1 预设系统详解

presets.json 结构分析

  1. {
  2. "common":{
  3. "description":"Common functions for process/thread/memory operations",
  4. "functions":[
  5. "NtAllocateVirtualMemory",
  6. "NtFreeVirtualMemory",
  7. "NtWriteVirtualMemory",
  8. "NtReadVirtualMemory",
  9. "NtProtectVirtualMemory",
  10. "NtQueryVirtualMemory",
  11. "NtCreateThreadEx",
  12. "NtOpenProcess",
  13. "NtOpenThread",
  14. "NtSuspendThread",
  15. "NtResumeThread",
  16. "NtGetContextThread",
  17. "NtSetContextThread",
  18. "NtTerminateProcess",
  19. "NtTerminateThread",
  20. "NtClose",
  21. "NtDuplicateObject",
  22. "NtWaitForSingleObject",
  23. "NtUnmapViewOfSection",
  24. "NtMapViewOfSection",
  25. "NtCreateSection",
  26. "NtQueryInformationProcess",
  27. "NtSetInformationProcess",
  28. "NtQuerySystemInformation",
  29. "NtDelayExecution"
  30. ]
  31. },
  32. "injection":{
  33. "description":"Functions for process/shellcode injection (APC, thread, section)",
  34. "functions":[
  35. "NtAllocateVirtualMemory",
  36. "NtFreeVirtualMemory",
  37. "NtWriteVirtualMemory",
  38. "NtReadVirtualMemory",
  39. "NtProtectVirtualMemory",
  40. "NtCreateThreadEx",
  41. "NtOpenProcess",
  42. "NtOpenThread",
  43. "NtSuspendThread",
  44. "NtResumeThread",
  45. "NtGetContextThread",
  46. "NtSetContextThread",
  47. "NtUnmapViewOfSection",
  48. "NtMapViewOfSection",
  49. "NtCreateSection",
  50. "NtQueueApcThread",
  51. "NtQueueApcThreadEx",
  52. "NtAlertResumeThread",
  53. "NtTestAlert",
  54. "NtClose"
  55. ]
  56. },
  57. //...7个预设
  58. }

预设设计理念:

  1. 场景化:每个预设对应一个具体使用场景
  2. 最小化:只包含必要的函数,减少代码体积
  3. 可组合:多个预设可以组合使用
  4. 可扩展:易于添加新的预设

3.2 函数分类统计

基于 prototypes.json 的完整分析:

  1. # 分析脚本
  2. import json
  3. from collections importCounter
  4. with open('data/prototypes.json')as f:
  5.     prototypes = json.load(f)
  6. # 按参数量分类
  7. param_distribution =Counter()
  8. for func_name, func_data in prototypes.items():
  9.     param_count = len(func_data.get('params',[]))
  10.     param_distribution[param_count]+=1
  11. print("参数分布统计:")
  12. for params, count in sorted(param_distribution.items()):
  13.     percentage =(count / len(prototypes))*100
  14. print(f"  {params:2d} 个参数:{count:2d} 个函数 ({percentage:.1f}%)")
  15. # 按功能分类(手动标注)
  16. functional_categories ={
  17. "内存操作":[
  18. "NtAllocateVirtualMemory",
  19. "NtFreeVirtualMemory",
  20. "NtWriteVirtualMemory",
  21. "NtReadVirtualMemory",
  22. "NtProtectVirtualMemory",
  23. "NtQueryVirtualMemory",
  24. ],
  25. "进程/线程":[
  26. "NtCreateThreadEx",
  27. "NtOpenProcess",
  28. "NtOpenThread",
  29. "NtTerminateProcess",
  30. "NtTerminateThread",
  31. "NtSuspendThread",
  32. "NtResumeThread",
  33. ],
  34. "同步/通信":[
  35. "NtWaitForSingleObject",
  36. "NtDelayExecution",
  37. "NtCreateSection",
  38. "NtMapViewOfSection",
  39. "NtUnmapViewOfSection",
  40. ],
  41. "信息查询":[
  42. "NtQueryInformationProcess",
  43. "NtQuerySystemInformation",
  44. "NtQueryInformationThread",
  45. ],
  46. "句柄操作":[
  47. "NtClose",
  48. "NtDuplicateObject",
  49. ],
  50. //...更多分类
  51. }
  52. print("\n功能分类统计:")
  53. for category, functions in functional_categories.items():
  54. print(f"  {category}: {len(functions)} 个函数")

输出结果:

  1. 参数分布统计:
  2. 2个参数:3个函数(4.7%)
  3. 3个参数:5个函数(7.8%)
  4. 4个参数:12个函数(18.8%)
  5. 5个参数:15个函数(23.4%)
  6. 6个参数:18个函数(28.1%)
  7. 7个参数:7个函数(10.9%)
  8. 8个参数:2个函数(3.1%)
  9. 10个参数:1个函数(1.6%)
  10. 11个参数:1个函数(1.6%)
  11. 功能分类统计:
  12. 内存操作:6个函数
  13. 进程/线程:7个函数
  14. 同步/通信:5个函数
  15. 信息查询:3个函数
  16. 句柄操作:2个函数
  17. ...

3.3 函数过滤逻辑

完整过滤流程图

  1. 用户输入(--preset /--functions)
  2. _resolve_functions()
  3. ├─展开预设
  4. └─ presets.json 加载
  5. └─ common 25个函数
  6. └─ injection 20个函数
  7. ├─添加自定义函数
  8. └─解析逗号分隔列表
  9. └─去重并保持顺序
  10. └─使用set跟踪已见元素
  11. _validate_functions()
  12. ├─加载 prototypes.json
  13. ├─检查每个函数是否存在
  14. └─错误时显示可用函数列表
  15. GeneratorConfig.functions
  16. _load_data()
  17. ├─遍历 functions 列表
  18. ├─ raw_proto 获取原型数据
  19. ├─创建SyscallPrototype对象
  20. └─添加到self._prototypes
  21. 可选混淆
  22. └─ shuffle_functions()打乱顺序

实际案例分析

案例 1:纯预设模式

  1. python syswhispers.py --preset common

处理过程:

  1. # 1. 加载 presets.json
  2. presets ={
  3. "common":{
  4. "description":"...",
  5. "functions":["NtAllocateVirtualMemory",...]# 25 个
  6. },
  7. //...
  8. }
  9. # 2. 展开预设
  10. args.preset ="common"
  11. functions =[]
  12. for p in["common"]:# split(",")
  13.     functions.extend(presets["common"]["functions"])
  14. # functions = [25 个函数名]
  15. # 3. 去重(这里没有重复)
  16. seen = set()
  17. result =[]
  18. for f in functions:
  19. if f notin seen:
  20.         seen.add(f)
  21.         result.append(f)
  22. # result = [25 个唯一函数]
  23. # 4. 验证
  24. _validate_functions(result)
  25. # 检查所有 25 个函数都在 prototypes.json 中
  26. # ✓ 全部通过
  27. # 5. 构建原型对象
  28. for fname in result:
  29.     entry = raw_proto[fname]
  30.     params =[SyscallParam(...)for p in entry['params']]
  31.     proto =SyscallPrototype(name=fname, return_type="...", params=params)
  32.     self._prototypes.append(proto)
  33. # 最终:self._prototypes 包含 25 个 SyscallPrototype 对象

案例 2:预设组合模式

  1. python syswhispers.py --preset common,injection

处理过程:

  1. # 1. 展开多个预设
  2. args.preset ="common,injection"
  3. functions =[]
  4. for p in["common","injection"]:
  5.     functions.extend(presets[p]["functions"])
  6. # functions 现在包含:
  7. # - common 的 25 个函数
  8. # - injection 的 20 个函数
  9. # 总计 45 个,但有重复
  10. # 2. 去重
  11. seen = set()
  12. result =[]
  13. for f in functions:
  14. if f notin seen:
  15.         seen.add(f)
  16.         result.append(f)
  17. # 假设 common 和 injection 有 10 个公共函数
  18. # result = 25 + (20 - 10) = 35 个唯一函数
  19. # 3. 验证和构建原型对象
  20. # ... 同上 ...

案例 3:混合模式

  1. python syswhispers.py --preset common --functions NtQueryInformationThread

处理过程:

  1. # 1. 展开预设
  2. functions =[]
  3. functions.extend(presets["common"]["functions"])# 25 个
  4. # 2. 添加自定义函数
  5. args.functions ="NtQueryInformationThread"
  6. for f in["NtQueryInformationThread"]:
  7. if f and f notin functions:
  8.         functions.append(f)
  9. # functions = [25 个 common 函数] + ["NtQueryInformationThread"]
  10. # 总计 26 个函数
  11. # 3. 去重、验证、构建
  12. # ... 同上 ...

4. 模板渲染生成逻辑

4.1 代码生成器架构

  1. # generator.py 核心结构
  2. classSysWhispers4:
  3. """
  4.     主代码生成引擎
  5.     设计模式:
  6.     1. 模板方法模式:定义生成流程,子类重写具体步骤
  7.     2. 策略模式:不同的解析方法/调用方法作为策略
  8.     3. 构建者模式:逐步构建复杂的输出文件
  9.     """
  10. def __init__(self, config:GeneratorConfig):
  11.         self.cfg = config                    # 生成配置
  12.         self.obf =Obfuscator(seed=...)# 混淆器
  13.         self._prototypes:List[...]=[]# 函数原型列表
  14.         self._ssn_x64: dict ={}# x64 SSN 缓存
  15.         self._ssn_x86: dict ={}# x86 SSN 缓存
  16. def generate(self)->Dict[str, str]:
  17. """
  18.         生成所有输出文件
  19.         返回:
  20.         {
  21.             "SW4Syscalls_Types.h": "<内容>",
  22.             "SW4Syscalls.h": "<内容>",
  23.             "SW4Syscalls.c": "<内容>",
  24.             "SW4Syscalls.asm": "<内容>"
  25.         }
  26.         """
  27.         self._load_data()# 加载数据
  28.         cfg = self.cfg
  29.         outputs:Dict[str, str]={}
  30. # 1. 生成类型头文件
  31.         types_fname = f"{cfg.out_file}_Types.h"
  32.         outputs[types_fname]= self._gen_types_header()
  33. # 2. 生成声明头文件
  34.         hdr_fname = f"{cfg.out_file}.h"
  35.         outputs[hdr_fname]= self._gen_syscalls_header(types_fname)
  36. # 3. 生成 C 源文件
  37.         c_fname = f"{cfg.out_file}.c"
  38.         outputs[c_fname]= self._gen_syscalls_c(hdr_fname)
  39. # 4. 生成汇编存根
  40. if cfg.compiler ==Compiler.MSVC:
  41.             asm_fname = f"{cfg.out_file}.asm"
  42.             outputs[asm_fname]= self._gen_asm_msvc()
  43. else:
  44.             asm_fname = f"{cfg.out_file}_stubs.c"
  45.             outputs[asm_fname]= self._gen_asm_gas_inline()
  46. return outputs
  47. def write_outputs(self, outputs:Dict[str, str])->None:
  48. """写入所有生成的文件到磁盘"""
  49.         out_dir =Path(self.cfg.out_dir)
  50.         out_dir.mkdir(parents=True, exist_ok=True)
  51. for fname, content in outputs.items():
  52.             fpath = out_dir / fname
  53.             fpath.write_text(content, encoding="utf-8")
  54. print(f"  [+] Generated {fpath}")

4.2 类型头文件生成

  1. # generator.py 第 199-300 行
  2. def _gen_types_header(self)-> str:
  3. """
  4.     生成 SW4Syscalls_Types.h
  5.     内容包括:
  6.     1. 保护宏(#pragma once)
  7.     2. 必需的系统头文件
  8.     3. NT 宏定义
  9.     4. 信息类枚举
  10.     5. 结构体定义
  11.     6. 内部使用的辅助类型
  12.     """
  13.     p = self.cfg.prefix  # 如 "SW4_"
  14.     guard = f"{p}SYSCALLS_TYPES_H"# 如 "SW4_SYSCALLS_TYPES_H"
  15. return f"""\
  16. /*
  17.  * {self.cfg.out_file}_Types.h -- generated by SysWhispers4
  18.  * DO NOT EDIT -- regenerate with syswhispers.py
  19.  *
  20.  * Resolution : {self.cfg.resolve}
  21.  * Method     : {self.cfg.method}
  22.  * Arch       : {self.cfg.arch}
  23.  * Compiler   : {self.cfg.compiler}
  24.  */
  25. #pragma once
  26. #ifndef {guard}
  27. #define {guard}
  28. #include <windows.h>
  29. #include <winternl.h>
  30. /* =========================================================================
  31.  *  NT 宏定义(如果未定义)
  32.  * ========================================================================= */
  33. #ifndef NT_SUCCESS
  34. # define NT_SUCCESS(Status)  (((NTSTATUS)(Status)) >= 0)
  35. #endif
  36. #ifndef STATUS_SUCCESS
  37. # define STATUS_SUCCESS      ((NTSTATUS)0x00000000L)
  38. #endif
  39. #ifndef STATUS_ACCESS_DENIED
  40. # define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L)
  41. #endif
  42. #ifndef STATUS_INFO_LENGTH_MISMATCH
  43. # define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
  44. #endif
  45. /* =========================================================================
  46.  *  信息类枚举(PROCESSINFOCLASS, THREADINFOCLASS, etc.)
  47.  * ========================================================================= */
  48. #ifndef _PROCESSINFOCLASS
  49. typedef enum _PROCESSINFOCLASS {{
  50.     ProcessBasicInformation           = 0,
  51.     ProcessDebugPort                  = 7,
  52.     ProcessWow64Information           = 26,
  53.     ProcessImageFileName              = 27,
  54.     ProcessBreakOnTermination         = 29,
  55.     ProcessSubsystemInformation       = 75,
  56.     ProcessInstrumentationCallback    = 40,
  57. }} PROCESSINFOCLASS;
  58. #endif
  59. #ifndef _THREADINFOCLASS
  60. typedef enum _THREADINFOCLASS {{
  61.     ThreadBasicInformation            = 0,
  62.     ThreadTimes                       = 1,
  63.     ThreadPriority                    = 2,
  64.     ThreadBasePriority                = 3,
  65.     ThreadAffinityMask                = 4,
  66.     ThreadImpersonationToken          = 5,
  67.     ThreadDescriptorTableEntry        = 6,
  68.     ThreadEnableAlignmentFaultFixup   = 7,
  69.     ThreadEventPair                   = 8,
  70.     ThreadQuerySetWin32StartAddress   = 9,
  71.     ThreadZeroTlsCell                 = 10,
  72.     ThreadPerformanceCount            = 11,
  73.     ThreadAmILastThread               = 12,
  74.     ThreadIdealProcessor              = 13,
  75.     ThreadPriorityBoost               = 14,
  76.     ThreadSetTlsArrayAddress          = 15,
  77.     ThreadIsIoPending                 = 16,
  78.     ThreadHideFromDebugger            = 17,
  79. }} THREADINFOCLASS;
  80. #endif
  81. /* =========================================================================
  82.  *  结构体定义(PS_ATTRIBUTE_LIST, CLIENT_ID, etc.)
  83.  * ========================================================================= */
  84. #ifndef _PS_ATTRIBUTE_LIST
  85. typedef struct _PS_ATTRIBUTE {{
  86.     ULONG_PTR Attribute;
  87.     SIZE_T    Size;
  88.     union {{
  89.         ULONG_PTR Value;
  90.         PVOID     ValuePtr;
  91.     }};
  92.     PSIZE_T   ReturnLength;
  93. }} PS_ATTRIBUTE, *PPS_ATTRIBUTE;
  94. typedef struct _PS_ATTRIBUTE_LIST {{
  95.     SIZE_T       TotalLength;
  96.     PS_ATTRIBUTE Attributes[1];
  97. }} PS_ATTRIBUTE_LIST, *PPS_ATTRIBUTE_LIST;
  98. #endif
  99. #ifndef _CLIENT_ID
  100. typedef struct _CLIENT_ID {{
  101.     PVOID UniqueProcess;
  102.     PVOID UniqueThread;
  103. }} CLIENT_ID, *PCLIENT_ID;
  104. #endif
  105. #ifndef _IO_STATUS_BLOCK
  106. typedef struct _IO_STATUS_BLOCK {{
  107.     union {{
  108.         NTSTATUS Status;
  109.         PVOID    Pointer;
  110.     }};
  111.     ULONG_PTR Information;
  112. }} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
  113. #endif
  114. /* =========================================================================
  115.  *  内部使用的辅助类型
  116.  * ========================================================================= */
  117. /* SSN 表项(用于静态解析) */
  118. typedef struct _{p}SSN_ENTRY {{
  119.     DWORD  Count;
  120.     struct {{
  121.         DWORD Build;
  122.         DWORD Ssn;
  123.     }} Entries[64];
  124. }} {p}SSN_ENTRY;
  125. /* 导出表项(用于 FreshyCalls/Hell's Gate 扫描) */
  126. typedef struct _{p}EXPORT {{
  127.     PVOID Address;
  128.     DWORD Hash;
  129.     DWORD Ordinal;
  130. }} {p}EXPORT, *P{p}EXPORT;
  131. #endif /* {guard} */
  132. """

生成的头文件示例:

  1. /*
  2.  * SW4Syscalls_Types.h -- generated by SysWhispers4
  3.  * DO NOT EDIT
  4.  */
  5. #pragma once
  6. #ifndef SW4_SYSCALLS_TYPES_H
  7. #define SW4_SYSCALLS_TYPES_H
  8. #include<windows.h>
  9. #include<winternl.h>
  10. // NT 宏定义
  11. #ifndef NT_SUCCESS
  12. # define NT_SUCCESS(Status)  (((NTSTATUS)(Status)) >= 0)
  13. #endif
  14. // 信息类枚举
  15. typedefenum _PROCESSINFOCLASS {
  16. ProcessBasicInformation=0,
  17. ProcessDebugPort=7,
  18. // ...
  19. } PROCESSINFOCLASS;
  20. // 结构体定义
  21. typedefstruct _CLIENT_ID {
  22.     PVOID UniqueProcess;
  23.     PVOID UniqueThread;
  24. } CLIENT_ID,*PCLIENT_ID;
  25. // 辅助类型
  26. typedefstruct _SW4_SSN_ENTRY {
  27.     DWORD  Count;
  28. struct{
  29.         DWORD Build;
  30.         DWORD Ssn;
  31. }Entries[64];
  32. } SW4_SSN_ENTRY;
  33. #endif/* SW4_SYSCALLS_TYPES_H */

4.3 声明头文件生成

  1. # generator.py 第 302-400 行
  2. def _gen_syscalls_header(self, types_header: str)-> str:
  3. """
  4.     生成 SW4Syscalls.h
  5.     内容包括:
  6.     1. 包含类型头文件
  7.     2. 初始化函数声明
  8.     3. 可选功能函数声明(ETW/AMSI/Unhook 等)
  9.     4. 所有 syscall 函数原型
  10.     """
  11.     p = self.cfg.prefix
  12.     guard = f"{p}SYSCALLS_H"
  13. # 生成所有函数的原型声明
  14.     protos ="\n".join(
  15.         f"EXTERN_C {proto.c_prototype(prefix=p)}"
  16. for proto in self._prototypes
  17. )
  18. # EXTERN_C 确保 C++ 兼容
  19. # proto.c_prototype("SW4_") → "NTSTATUS NTAPI SW4_NtAllocateVirtualMemory(...);"
  20. # 根据启用的功能添加初始化函数声明
  21.     init_comment ={
  22. ResolutionMethod.Static:"static table -- no init required",
  23. ResolutionMethod.FreshyCalls:"FreshyCalls -- sorts ntdll Nt* exports by VA",
  24. ResolutionMethod.HellsGate:"Hell's Gate  -- reads SSN from ntdll stub",
  25. ResolutionMethod.HalosGate:"Halo's Gate  -- Hell's Gate + neighbor scan",
  26. ResolutionMethod.TartarusGate:"Tartarus' Gate -- handles near/far JMP hooks",
  27. ResolutionMethod.SyscallsFromDisk:"SyscallsFromDisk -- loads clean ntdll",
  28. ResolutionMethod.RecycledGate:"RecycledGate -- FreshyCalls + opcode validation",
  29. ResolutionMethod.HWBreakpoint:"HW Breakpoint -- DR registers + VEH",
  30. }[self.cfg.resolve]
  31. # 可选功能声明
  32.     egg_init =""
  33. if self.cfg.method ==InvocationMethod.Egg:
  34.         egg_init = f"\nEXTERN_C BOOL {p}HatchEggs(VOID);  /* Patch egg markers */"
  35.     etw_init =""
  36. if self.cfg.etw_bypass:
  37.         etw_init = f"\nEXTERN_C BOOL {p}PatchEtw(VOID);   /* Patch ETW writer */"
  38.     amsi_init =""
  39. if self.cfg.amsi_bypass:
  40.         amsi_init = f"\nEXTERN_C BOOL {p}PatchAmsi(VOID);  /* Patch AMSI */"
  41.     unhook_init =""
  42. if self.cfg.unhook_ntdll:
  43.         unhook_init = f"\nEXTERN_C BOOL {p}UnhookNtdll(VOID); /* Remap ntdll */"
  44.     antidebug_init =""
  45. if self.cfg.anti_debug:
  46.         antidebug_init = f"\nEXTERN_C BOOL {p}AntiDebugCheck(VOID); /* Check debugger */"
  47.     sleep_init =""
  48. if self.cfg.sleep_encrypt:
  49.         sleep_init = f"\nEXTERN_C VOID {p}SleepEncrypt(DWORD ms); /* Encrypted sleep */"
  50. return f"""\
  51. /*
  52.  * {self.cfg.out_file}.h -- generated by SysWhispers4
  53.  * DO NOT EDIT
  54.  */
  55. #pragma once
  56. #ifndef {guard}
  57. #define {guard}
  58. #include "{types_header}"
  59. #ifdef __cplusplus
  60. extern "C" {{
  61. #endif
  62. /* =========================================================================
  63.  *  运行时初始化
  64.  *  {init_comment}
  65.  * ========================================================================= */
  66. EXTERN_C BOOL {p}Initialize(VOID);
  67. {egg_init}{etw_init}{amsi_init}{unhook_init}{antidebug_init}{sleep_init}
  68. /* =========================================================================
  69.  *  syscall 函数原型
  70.  * ========================================================================= */
  71. {protos}
  72. #ifdef __cplusplus
  73. }}
  74. #endif
  75. #endif /* {guard} */
  76. """

生成的头文件示例:

  1. /*
  2.  * SW4Syscalls.h -- generated by SysWhispers4
  3.  */
  4. #pragma once
  5. #ifndef SW4_SYSCALLS_H
  6. #define SW4_SYSCALLS_H
  7. #include"SW4Syscalls_Types.h"
  8. #ifdef __cplusplus
  9. extern"C"{
  10. #endif
  11. /* 运行时初始化 */
  12. EXTERN_C BOOL SW4_Initialize(VOID);
  13. /* 可选功能 */
  14. EXTERN_C BOOL SW4_PatchEtw(VOID);
  15. EXTERN_C BOOL SW4_UnhookNtdll(VOID);
  16. /* syscall 函数原型 */
  17. EXTERN_C NTSTATUS NTAPI SW4_NtAllocateVirtualMemory(
  18.     HANDLE ProcessHandle,
  19.     PVOID*BaseAddress,
  20.     ULONG_PTR ZeroBits,
  21.     PSIZE_T RegionSize,
  22.     ULONG AllocationType,
  23.     ULONG Protect
  24. );
  25. EXTERN_C NTSTATUS NTAPI SW4_NtCreateThreadEx(
  26.     PHANDLE ThreadHandle,
  27.     ACCESS_MASK DesiredAccess,
  28.     POBJECT_ATTRIBUTES ObjectAttributes,
  29.     HANDLE ProcessHandle,
  30.     PVOID StartRoutine,
  31.     PVOID Argument,
  32.     ULONG CreateFlags,
  33.     SIZE_T ZeroBits,
  34.     SIZE_T StackSize,
  35.     SIZE_T MaximumStackSize,
  36.     PPS_ATTRIBUTE_LIST AttributeList
  37. );
  38. // ... 更多函数
  39. #ifdef __cplusplus
  40. }
  41. #endif
  42. #endif/* SW4_SYSCALLS_H */

总结

通过对 SysWhispers4 核心模块的深度源码分析,我们理解了:

参数解析模块

  • argparse 的分组设计哲学
  • 函数列表展开和验证算法
  • 配置对象的构建流程

数据解析流程

  • JSON 数据的加载和转换
  • 数据类的设计和使用
  • 哈希函数的选择和实现

syscall 选择机制

  • 预设系统的设计理念
  • 函数过滤和去重算法
  • 原型对象的构建过程

模板生成逻辑

  • 代码生成器的架构设计
  • 各类文件的生成策略
  • 条件编译和可选功能

这些知识不仅帮助我们理解 SysWhispers4 的工作原理,也为开发类似工具提供了宝贵的参考。

  • 公众号:安全狗的自我修养

  • vx:2207344074

  • http://gitee.com/haidragon

  • http://github.com/haidragon

  • bilibili:haidragonx

本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » edr绕过工具 SysWhispers4 源码分析系列(四)

猜你喜欢

  • 暂无文章