【逆向分析】又一个密评工具箱授权绕过分析

华盟原创文章投稿奖励计划

又一个密评工具箱授权绕过分析

最近分析某密评工具箱,软件采用python代码开发。

自动草稿

基于Python Monkey Patch的授权绕过逆向分析与实现详解

一、逆向分析流程总览

本手册所描述的逆向工程与授权绕过实战,遵循一个清晰、线性的技术分析流程。该流程始于对目标应用的整体结构探查,终于一个可稳定运行的自动化绕过方案。整个过程可概括为以下四个核心阶段:

第一阶段:静态分析与入口点挖掘 首先,对目标“通用安全审计系统(SAS)”进行静态分析,明确其运行架构。分析发现,其核心逻辑被封装在一个加密的 Python 资源包(core/audit_core.pyz)中,并由一个启动器(SAS_Audit.exe)负责加载。关键突破点在于识别出启动器在加载核心资源时,需要一个特定的启动密钥(-key Kx92_mPq7_vB1z_Lw4n)。此阶段的成果为后续的补丁注入提供了明确的介入时机和参数。

第二阶段:Python核心模块逆向与授权判断逻辑 在获得核心资源访问能力后,深入逆向分析其Python代码,定位到负责授权校验的核心模块与函数。具体为 audit.core.validator 模块中的 verify_license_status 函数。通过分析该函数的伪代码逻辑,明确了其三重校验机制:检查本地授权文件、调用Native库(native_auth.dll)进行硬件锁校验、检查软件有效期。本阶段的目标由此确立:劫持此函数,使其无条件返回 True,从而绕过所有校验。

第三阶段:补丁开发实战:Python Monkey Patch的完整实现 基于上一阶段的目标,采用 Python Monkey Patch(猴子补丁) 技术实现内存劫持。开发一个独立的补丁模块(patch_hook.py),其核心功能是:在目标模块被加载后,动态地将原始的 verify_license_status 函数替换为一个自定义的、始终返回 True 的新函数。此模块模拟了类似Java Agent的“premain”机制,在应用主逻辑启动前完成关键函数的替换。

第四阶段:启动脚本协同设计与逻辑闭环 最后,将前序阶段的发现与组件进行整合,设计一个自动化的启动脚本(start.bat)以实现逻辑闭环。该脚本按顺序执行三个关键操作:

  1. 启动并注入补丁:首先在后台启动Python解释器,运行 patch_hook 模块并传入必要的启动密钥,确保补丁在核心审计逻辑初始化前生效。
  2. 延迟等待:通过一个短暂的延迟(例如 ping 命令),确保Python后端补丁进程完全启动并完成内存Patch操作。
  3. 启动原应用前端:最后启动原始的 SAS_Audit.exe 前端。此时,其加载的核心模块中的授权校验函数已被内存中的补丁函数替换,从而实现无感知的授权绕过。

整个流程从外部分析入手,逐步深入至代码逻辑,继而开发出精准的内存级补丁,最终通过工程化脚本将各环节串联,形成一个完整、可重复的绕过方案。

二、静态分析与入口点挖掘

静态分析的首要目标是理解目标应用的运行架构,并从中找到可以安全、稳定地介入程序执行流程的“入口点”。对于本项目中的“通用安全审计系统(SAS)”,其独特的双层结构决定了分析的重点。

1. 启动逻辑与资源加载分析

通过分析,我们明确了该系统的核心运行模式:

  • 用户交互层:用户通过双击 SAS_Audit.exe 启动器来运行程序。
  • 核心逻辑层:该启动器(.exe)内部的核心工作,是调用一个内嵌的 Python 解释器,并加载一个加密的 Python 资源包 core/audit_core.pyz。所有业务逻辑,包括关键的授权校验,都封装在这个资源包内。

这种设计将核心代码与启动外壳分离,增加了直接分析的难度,但也暴露了清晰的程序加载路径。

2. 关键文件定位与入口点确认

基于上述架构,静态分析锁定了两个关键目标:

  1. 启动器SAS_Audit.exe
  2. 核心资源包core/audit_core.pyz

分析的核心发现是:启动器在加载核心资源包 audit_core.pyz 时,必须附带一个特定的启动密钥参数。这是整个流程中一个明确且必需的“握手”环节。

3. 核心入口点参数:启动密钥

这个启动密钥是后续所有补丁操作得以实施的基础前提和精确介入点。其形式如下:

-key Kx92_mPq7_vB1z_Lw4n 

该参数表明,SAS_Audit.exe 在内部调用 Python 解释器运行 audit_core.pyz 时,会校验此密钥。这为我们提供了一个完美的“挂钩”时机——我们可以在系统原始启动流程中,插入一个我们控制的步骤,在传递此密钥的同时,提前执行我们的补丁代码。

至此,静态分析阶段完成。我们不仅厘清了 SAS_Audit.exe 与 audit_core.pyz 的加载关系,更重要的是,成功挖掘出了“启动密钥”这一至关重要的入口点参数。这为下一阶段直接深入 audit_core.pyz 内部,定位并分析具体的授权校验逻辑,铺平了道路。

三、Python 核心模块逆向与授权判断逻辑

在明确了启动入口和核心资源包的结构后,逆向分析的重点转向了加密的 audit_core.pyz 资源包内部,目标是定位并理解其授权校验的核心逻辑。

核心校验模块定位

通过对 audit_core.pyz 资源包的静态分析,我们成功定位到了负责整个系统授权验证的核心模块。该模块的路径为 audit.core.validator。在此模块中,存在一个名为 verify_license_status 的关键函数,它被判定为整个授权链路的最终决策点。

授权判断逻辑的原始代码分析

对 verify_license_status 函数进行逆向还原后,其原始逻辑(以 Python 伪代码形式呈现)清晰地展示了一个三重校验机制

# audit/core/validator.py import ctypes # 用于调用本地动态链接库  defverify_license_status(): """     原始授权校验函数。     """ # 1. 检查本地授权文件 ifnot is_local_file_valid(): returnFalse  # 2. 核心:Native 硬件锁校验     hardware_id = get_system_hardware_id()  # 模拟调用本地 C 库进行校验     native_lib = ctypes.CDLL('native_auth.dll') ifnot native_lib.check_hardware_id(hardware_id): returnFalse  # 3. 检查有效期 if get_expiry_timestamp() < time.time(): returnFalse  returnTrue 

该函数的逻辑流程如下:

  1. 本地文件校验:首先检查是否存在有效的本地授权文件,这是最基础的校验层。
  2. 硬件锁校验:这是校验的核心与难点。函数会获取系统硬件标识,并通过 ctypes 调用一个名为 native_auth.dll 的本地动态链接库中的 check_hardware_id 函数进行验证。此步骤将软件授权与特定物理设备(硬件锁)绑定。
  3. 有效期校验:最后,函数会检查授权是否在有效期内。

任何一步校验失败,函数都会返回 False,导致整个授权验证失败。 因此,逆向分析的直接目标变得非常明确:劫持 audit.core.validator.verify_license_status 函数,使其在任何情况下都无条件返回 True,从而一次性绕过上述所有三重防护。这为下一阶段的补丁开发提供了精确的攻击向量。

四、补丁开发实战:Python Monkey Patch 的完整实现

在 Python 中,我们使用 Monkey Patch 技术,通过 import 机制和函数替换来实现内存劫持。其核心思想是:在目标模块被加载到内存后、主业务逻辑调用关键函数前,动态地将原函数替换为我们自定义的函数。这模拟了 Java Agent 的 “premain” 机制,即在应用主逻辑启动前完成内存级的代码替换。

3.1 补丁模块 (patch_hook.py) 的完整实现

我们编写一个独立的 Python 模块 patch_hook.py,作为启动脚本中 -m patch_hook 参数的入口点。该模块负责加载目标模块并执行函数替换。

核心 patch_hook.py 代码解析:

import sys import time import importlib  # 1. 定义劫持函数 defpatched_verify_license_status(): """     劫持后的函数:无条件返回 True。     此函数将完全替代原始的 `audit.core.validator.verify_license_status`。     """ print("[PATCH HOOK] License check bypassed. Returning True.") returnTrue  # 2. 执行 Monkey Patch 的核心函数 defapply_patch(): try: # 强制导入目标模块 # 这一步至关重要,它确保了 `audit.core.validator` 模块被加载到当前 Python 解释器的内存中。 # 在 Java Agent 中,这是由类加载器完成的;在 Python 中,我们手动触发导入。         target_module = importlib.import_module('audit.core.validator')  # 执行 Monkey Patch:用我们的函数对象替换模块中的原始函数对象         target_module.verify_license_status = patched_verify_license_status  print(f"[PATCH HOOK] Successfully patched {target_module.__name__}.verify_license_status")  except ImportError: # 如果目标模块无法导入,说明核心资源包路径或密钥可能错误,补丁失败。 print("[PATCH HOOK] Error: Target module not found. Patch failed.")         sys.exit(1)  # 3. 启动逻辑(模拟 Java Agent 的 premain) if __name__ == "__main__": # 此处可模拟解析启动参数,例如接收 -key 和 -core 参数 # ... (参数解析逻辑)  # 应用补丁:这是整个流程的核心动作     apply_patch()  # 保持进程存活,模拟被劫持的后端服务持续运行 # 补丁生效后,原核心进程需要继续存在以提供服务,否则前端将无法启动。 print("[PATCH HOOK] Core logic patched. Running backend server...")  # 模拟后端服务器启动并持续运行(例如,监听某个端口) try: whileTrue:             time.sleep(1) except KeyboardInterrupt: print("[PATCH HOOK] Backend server stopped.") 

技术要点解析:

  • importlib.import_module:这是动态导入的关键。它允许我们按字符串名称加载模块,确保了在补丁代码中能准确找到并操作 audit.core.validator 模块。
  • 函数对象替换target_module.verify_license_status = patched_verify_license_status 这一行是 Monkey Patch 的本质。它将模块命名空间中原函数的引用指向了我们新定义的函数。此后,任何通过该模块调用 verify_license_status 的代码,都将执行我们的 patched_verify_license_status
  • 进程持久化while True 循环使补丁进程保持活动状态。这是因为原始的 SAS_Audit.exe 启动器预期一个后端 Python 进程在运行。如果补丁进程立即退出,整个应用将无法正常工作。

至此,一个能够在内存层面永久性绕过授权校验的 Monkey Patch 核心模块已经准备就绪。接下来需要设计启动脚本,将补丁模块、启动密钥和原始应用启动流程串联起来,形成完整的逻辑闭环。

五、启动脚本协同设计与逻辑闭环

前文已详细拆解了补丁模块(patch_hook.py)的内部实现,它完成了对核心校验函数的内存劫持。然而,补丁本身是静态的,需要一个动态的启动流程将其“注入”到目标应用的运行环境中,并与原始启动器协同工作。这个关键的桥梁,便是最终的启动脚本。

🚀 最终 start.bat 脚本:三步协同启动

整个绕过方案的核心执行逻辑,被封装在一个批处理脚本 start.bat 中。该脚本严格遵循了“先补丁,后启动”的原则,通过精确的时序控制,确保内存补丁在原始应用加载核心模块前就已生效。

@echo off chcp 65001  :: 1. 启动 Python 后端,注入 MonkeyPatchHook :: 逻辑:启动 Python 解释器,运行 patch_hook 模块,并传入启动密钥 start /b """bin\python.exe" -m patch_hook -key Kx92_mPq7_vB1z_Lw4n -core core\audit_core.pyz  :: 2. 延迟等待:确保 Python 后端完全启动并完成 Patch ping 127.0.0.1 -n 6 > nul  :: 3. 启动 Electron 前端 start """SAS_Audit.exe" 

🔍 脚本逻辑分步解析

第一步:启动补丁进程 (start /b ...)

  • 作用:在后台(/b)启动一个独立的 Python 进程。
  • 关键参数
    • -m patch_hook:指定运行我们编写的补丁模块 patch_hook.py 作为主程序。
    • -key Kx92_mPq7_vB1z_Lw4n:传递启动密钥,这是原始启动器 SAS_Audit.exe 加载 audit_core.pyz 时必须的凭证。补丁进程需要模拟或满足这一条件,以确保其加载的核心模块环境与后续原始启动器加载的环境一致。
    • -core core\audit_core.pyz:指明核心资源包路径。
  • 结果patch_hook.py 被执行,其 apply_patch() 函数被调用,成功将 audit.core.validator.verify_license_status 函数替换为无条件返回 True 的版本。此后,该 Python 进程进入 while True 循环,保持常驻,作为“后端服务”。

第二步:延迟等待 (ping 127.0.0.1 -n 6 > nul)

  • 作用:提供一个短暂的延迟(约5秒)。
  • 必要性:这是实现逻辑闭环的关键。操作系统启动新进程需要时间,Python 解释器初始化、导入模块、执行补丁代码也需要时间。此延迟确保了在下一步启动原始 SAS_Audit.exe 时,步骤一中的补丁进程已经100%完成了对目标函数的内存替换。如果没有这个延迟,可能出现原始应用启动时补丁尚未生效,导致授权校验依然被执行的情况。

第三步:启动原始应用 (start "" "SAS_Audit.exe")

  • 作用:正常启动目标应用程序的原始前端。
  • 协同效果:此时,SAS_Audit.exe 启动,并按照其既定逻辑加载核心资源包 core/audit_core.pyz。由于步骤一中的补丁进程已经加载了相同的模块并完成了函数替换,且该补丁作用于进程内存中的Python模块对象,因此当原始启动器再次导入 audit.core.validator 模块时,它获取到的 verify_license_status 函数已经是被劫持后的版本。整个授权校验逻辑被静默绕过,应用得以正常启动和运行,而用户无感知。

✅ 逻辑闭环的形成

这个三步骤脚本设计形成了一个完美的逻辑闭环

  1. 独立预热:补丁进程率先启动,独立完成对核心模块的加载与篡改,不依赖于原始应用进程。
  2. 状态就绪:通过延迟等待,确保“补丁已生效”这一状态稳定就绪。
  3. 透明接管:原始应用启动,其运行环境(被Patch过的模块状态)已被预先“污染”,从而自然而然地绕过了所有校验。

整个方案的成功,依赖于对目标应用启动链的精确分析(找到了必须的启动密钥 -key),以及对 Python 运行时模块加载机制的深入理解。启动脚本作为粘合剂,将静态的补丁代码与动态的应用启动流程无缝衔接起来,最终实现了在内存层面、无需修改任何磁盘文件的授权绕过。

六、总结与防御建议

📊 技术方案总结

本次针对“通用安全审计系统(SAS)”的逆向分析与绕过实践,成功演示了一套基于 Python Monkey Patch(猴子补丁) 的无文件内存级授权绕过方案。其核心在于,无需修改任何原始文件,通过在应用启动前预先加载一个补丁进程,在内存中篡改关键函数逻辑,实现了对复杂授权体系(本地文件、Native硬件锁、有效期三重校验)的彻底绕过。

整个流程可概括为以下四个关键阶段,形成了一个完整的技术闭环:

  1. 静态分析与入口定位:确认了目标应用 SAS_Audit.exe 通过特定启动密钥 -key Kx92_mPq7_vB1z_Lw4n 加载加密的 Python 核心资源包 core/audit_core.pyz,为后续补丁注入找到了准确的入口点。
  2. 核心逻辑逆向:深入分析核心资源包,精准定位到授权校验的最终决策函数 audit.core.validator.verify_license_status,并解析出其内部执行“本地授权文件 → native_auth.dll 硬件锁 → 有效期”的三重校验逻辑。
  3. 内存补丁开发:编写独立的补丁模块 patch_hook.py。该模块的核心函数 apply_patch() 利用 Python 的 importlib 机制,在运行时将目标模块中的 verify_license_status 函数替换为一个无条件返回 True 的 patched_verify_license_status 函数,并保持进程常驻以维持补丁效果。
  4. 启动协同设计:通过 start.bat 启动脚本将上述步骤串联,形成自动化流程:
    • 第一步:后台启动补丁进程 (python -m patch_hook -key …)。
    • 第二步:使用 ping 命令延迟等待,确保补丁在目标应用启动前已生效,避免竞态条件。
    • 第三步:启动原始应用 SAS_Audit.exe。此时,应用内部任何导入 audit.core.validator 的代码都将调用已被篡改的函数,从而绕过所有校验。

🛡️ 防御视角与建议

攻击手法来看,防御的挑战在于攻击发生在内存运行时,且不留下文件修改痕迹。传统的基于文件完整性校验或签名验证的防御手段在此场景下可能失效。要防御此类高级内存攻击,需要构建更深层次的运行时保护、行为监控与可信执行环境。


文章来源:利刃信安

本文来源利刃信安,经授权后由华盟君发布,观点不代表华盟网的立场,转载请联系原作者。

发表回复