当前位置: 首页 > article >正文

Nuitka 已不再安全? Nuitka/Cython 打包应用逆向工具 -- pymodhook

pymodhook是一个记录任意对Python模块的调用的库,用于Python逆向分析。
pymodhook库类似于Android的xposed框架,但不仅能记录函数的调用参数和返回值,还能记录模块的类的任意方法调用,以及任意派生对象的访问,基于pyobject.objproxy库实现。
备注:请勿用本工具注入未授权的商业软件!

GitHub: qfcy/PyModuleHook

目录

    • DLL注入工具
        • 1.复制模块文件
        • 2.修改 `__hook__.py`
        • 3.注入DLL
        • 4.获取注入结果
    • 附:pymodhook库的用法
        • 示例
        • 详细用法
        • 工作原理

DLL注入工具

由于只依赖于加载的python3x.dll,工具支持记录Nuitka/Cython打包的应用的模块调用,而不仅仅是PyInstaller。

1.复制模块文件

首先用pip install pymodhook安装pymodhook及其依赖的pyobject包,
再打开<Python安装目录>/Lib/site-packages文件夹(Python安装目录视环境而异),将pyobject包,pymodhook.pypymodhook-patches目录,和__hook__.py复制到目录下:

另外如果是Python 3.8或以下的版本,还需要复制astor模块。

2.修改 __hook__.py

__hook__.py是注入的DLL执行的第一段Python代码,默认的__hook__.py是:

# 放入打包程序目录的__hook__.py的模板
import atexit, pprint, tracebackCODE_FILE = "hook_output.py"
OPTIMIZED_CODE_FILE = "optimized_hook_output.py"
VAR_DUMP_FILE = "var_dump.txt"
ERR_FILE = "hooktool_err.log"def export_code():try:with open(CODE_FILE, "w", encoding="utf-8") as f:f.write(get_code())with open(VAR_DUMP_FILE, "w", encoding="utf-8") as f:dump_scope(file=f)with open(OPTIMIZED_CODE_FILE, "w", encoding="utf-8") as f:f.write(get_optimized_code())except Exception:with open(ERR_FILE, "w", encoding="utf-8") as f:traceback.print_exc(file=f)try:from pymodhook import *from pyobject.objproxy import ReprFormatProxyinit_hook()hook_modules("wx","matplotlib.pyplot","requests",deep_hook=True) # 本行可修改atexit.register(export_code)
except Exception:with open(ERR_FILE, "w", encoding="utf-8") as f:traceback.print_exc(file=f)

一般只需要将调用hook_modules()的这行,修改成自定义的其他模块即可。deep_hook=True选项一般用于Cython/Nuitka打包的应用,对于普通应用deep_hook是可选的。
另外对于特定库,可能还需要自行修改pymodhook-patches目录。

3.注入DLL

在项目的Release页面下载DLLInject_win_amd64.zip。
下载后解压并运行hook_win32.exe,搜索目标进程并选中,再点击"Inject DLL"按钮:

如果注入成功,会看到这个提示:

4.获取注入结果

注入成功后如果程序退出(非强制终止进程),模块hook的结果hook_output.py, optimized_hook_output.pyvar_dump.txt会在被注入进程的工作目录生成。
hook_output.py是原始的详细调用记录,optimized_hook_output.py是简化后的模块调用代码,var_dump.txt为所有变量的转储。
如果结果生成失败,还会额外生成一个文件hooktool_err.log,记录错误消息。

optimized_hook_output.py的示例:

import tkinter as tk
Canvas = tk.Canvas
import matplotlib.pyplot as plt
import requests
var0 = tk.Tk()
ex_var1 = int(tk.wantobjects)
var15 = var0.tk
var0.title('Tk')
var0.withdraw()
var0.iconbitmap('paint.ico')
var0.geometry('400x300')
var0.overrideredirect(ex_var1)
var43 = Frame(var0, bg='gray92')
var43._last_child_ids = {}
var28 = Canvas(var43, bg='#d0d0d0', fg='#000000')
var28.pack(expand=ex_var1, fill='x')
var28._last_child_ids = {}
# external var53: <function object at 0x000001F3F0A27180>
var0.bind('<Button-1>', var53)
var0.mainloop()
...

var_dump.txt的示例:

{...,'ex_var855': True,'ex_var860': True,'ex_var875': True,...'var123': <function BaseWidget.__init__ at 0x04616B28>,'var124': <tkinter.ttk.Button object .!frame.!button3>,'var125': {'command': <bound method Painter.save of <painter.Painter object at 0x047298F0>>,'text': '保存','width': 4},'var126': None,'var127': <function BaseWidget._setup at 0x04616AE0>,'var128': {'command': <bound method Painter.save of <painter.Painter object at 0x047298F0>>,'text': '保存','width': 4},...'var146': '.!frame.!button3','var147': <built-in method call of _tkinter.tkapp object at 0x048C3890>,'var148': '','var152': <function BaseWidget.__init__ at 0x04616B28>,'var153': <tkinter.ttk.Button object .!frame.!button4>,'var154': {'command': <bound method Painter.clear of <painter.Painter object at 0x047298F0>>,'text': '清除','width': 4},...
}

附:pymodhook库的用法

运行命令pip install pymodhook,即可安装pymodhook库。

示例

hook了numpymatplotlib库的示例:

from pymodhook import *
init_hook()
hook_modules("numpy", "matplotlib.pyplot", for_=["__main__"]) # 记录numpy和matplotlib的调用
enable_hook()
import numpy as np
import matplotlib.pyplot as plt
arr = np.array(range(1,11))
arr_squared = arr ** 2
mean = np.mean(arr)
std_dev = np.std(arr)
print(mean, std_dev)plt.plot(arr, arr_squared)
plt.show()# 显示记录的代码
print(f"原始调用记录:\n{get_code()}\n")
print(f"优化后的代码:\n{get_optimized_code()}")

运行后会出现类似IDA等工具生成的代码:

原始调用记录:
import numpy as np
matplotlib = __import__('matplotlib.pyplot')
var0 = matplotlib.pyplot
var1 = np.array
var2 = var1(range(1, 11))
var3 = var2 ** 2
var4 = np.mean
var5 = var4(var2)
var6 = var2.mean
var7 = var6(axis=None, dtype=None, out=None)
var8 = np.std
var9 = var8(var2)
var10 = var2.std
var11 = var10(axis=None, dtype=None, out=None, ddof=0)
ex_var12 = str(var5)
ex_var13 = str(var9)
var14 = var0.plot
var15 = var14(var2, var3)
var16 = var2.shape
var17 = var2.shape
var18 = var2[(slice(None, None, None), None)]
var19 = var18.ndim
var20 = var3.shape
var21 = var3.shape
var22 = var3[(slice(None, None, None), None)]
var23 = var22.ndim
var24 = var2.values
var25 = var2._data
var26 = var2.__array_struct__
var27 = var3.values
...
var51 = var41.__array_struct__
var52 = var0.show
var53 = var52()优化后的代码:
import numpy as np
import matplotlib.pyplot as plt
var2 = np.array(range(1, 11))
plt.plot(var2, var2 ** 2)
plt.show()
详细用法
  • init_hook(export_trivial_obj=True, hook_method_call=False, **kw)
    初始化模块hook,需要在调用hook_module()hook_modules()之前调用。

    • export_trivial_obj:是否不继续hook模块函数返回的基本类型(如整数、列表、字典等)。
    • hook_method_call:是否hook模块类实例的方法内部调用(即方法的self传入的是ProxiedObj而不是原先的对象)
    • 其它参数通过**kw传递给ObjChain
  • hook_module(module_name, for_=None, hook_once=False, deep_hook=False, deep_hook_internal=False, hook_reload=True)
    钩住(hook)一个模块,后续导入这个模块时会返回hook后的模块。

    • module_name:要hook的模块名(如"numpy")。
    • for_:只有从特定模块(如["__main__"])导入时才应用hook,能避免底层模块之间相互依赖导致的报错。如果不提供,默认对所有模块全局应用hook。
    • hook_once:只在首次导入时返回hook后的库,后续直接返回原模块。
    • deep_hook:是否hook模块中的每个函数和类,而不是模块本身。deep_hookTrue时模块始终被hook,for_hook_onceenable_hook不起作用。
    • deep_hook_internaldeep_hookTrue时,是否hook以下划线开头的对象(双下划线对象如__loader__除外)。
    • hook_reload:是否继续hook通过importlib.reload()返回的同一新模块。
  • hook_modules(*modules, **kw)
    一次hook多个模块,如hook_modules("numpy","matplotlib"),关键字参数的其他用法同hook_module函数。

  • unhook_module(module_name)
    取消对指定模块的hook,包括deep_hook后的模块。

    • module_name:要撤销hook的模块名。
  • enable_hook()
    启用模块hook的全局开关(默认关闭)。启用后,导入被hook的模块时才会返回hook对象。deep_hookTrue时不需要手动调用enable_hook

  • disable_hook()
    禁用模块hook的全局开关。禁用时不会导入hook后的模块,除非使用了deep_hook=True

  • import_module(module_name)
    导入并返回子模块对象,而不是根模块。

    • module_name:如"matplotlib.pyplot",会返回pyplot子模块对象。
  • get_code(*args, **kw)
    生成模块原始调用记录的Python代码,可用于重现当前对象依赖关系,以及库调用历史。

  • get_optimized_code(*args, **kw)
    生成优化后的代码,同get_code用法。(代码优化在内部使用了有向无环图(DAG),详细优化原理见pyobject库)

  • get_scope_dump()
    返回当前hook链的变量命名空间(作用域)字典的浅拷贝,用于调试和分析。

  • dump_scope(file=None)
    将整个变量命名空间字典用pprint输出到流file,某个对象的__repr__()方法出错时输出不会中断。file默认为sys.stdout

  • getchain()
    返回用于hook模块的全局pyobject.ObjChain实例,用于手动操作ObjChain。如果尚未调用init_hook(),返回None

pymodhook-patches目录

pymodhook-patches目录内部包含了多个以模块名命名的json文件,包含不能hook的自定义的属性和函数名,用于兼容特定的Python库。
matplotlib.pyplot.json的格式如下:

{// 每个键是可选的"export_attrs":["attr"], // 要导出的属性名(即plt.attr返回原始对象,而不是pyobject.ProxiedObj)"export_funcs":["plot","show"], // 要导出的函数名(即函数的调用返回值是原始对象,而不是pyobject.ProxiedObj)"alias_name":"plt" // 模块的常用别名,用于控制代码生成格式(如import matplotlib.pyplot as plt)
}
工作原理

库在底层使用了pyobject.objproxy库中的ObjChain,用于动态代码生成,而本pymodhook库是pyobject.objproxy的高层封装。详细原理参见pyobject.objproxy的文档。

相关文章:

Nuitka 已不再安全? Nuitka/Cython 打包应用逆向工具 -- pymodhook

pymodhook是一个记录任意对Python模块的调用的库&#xff0c;用于Python逆向分析。 pymodhook库类似于Android的xposed框架&#xff0c;但不仅能记录函数的调用参数和返回值&#xff0c;还能记录模块的类的任意方法调用&#xff0c;以及任意派生对象的访问&#xff0c;基于pyob…...

【C】初阶数据结构14 -- 归并排序

本篇文章主要是讲解经典的排序算法 -- 归并排序 目录 1 递归版本的归并排序 1&#xff09; 算法思想 2&#xff09; 代码 3&#xff09; 时间复杂度与空间复杂度分析 &#xff08;1&#xff09; 时间复杂度 &#xff08;2&#xff09; 空间复杂度 2 迭代版本的归并…...

华为网路设备学习-21 IGP路由专题-路由过滤(filter-policy)

一、路由过滤&#xff08;filter-policy&#xff09; 1、用于控制路由更新、接收的一个工具 2、只能过滤路由信息&#xff0c;无法过滤LSA 二、路由过滤&#xff08;filter-policy&#xff09;与动态路由协议 1、距离矢量路由协议 RIP动态路由协议 交换的是路由表&#xff0…...

NestJS 框架深度解析

框架功能分析 NestJS 是一个基于 Node.js 的渐进式框架&#xff0c;专为构建高效、可扩展的服务器端应用程序而设计。其核心理念结合了 面向对象编程&#xff08;OOP&#xff09;、函数式编程&#xff08;FP&#xff09; 和 函数式响应式编程&#xff08;FRP&#xff09;&…...

人脸识别门禁系统技术文档

人脸识别门禁系统技术文档 序言 本文档详细描述了人脸识别门禁系统的技术实现原理与方法。该系统旨在提供高安全性的门禁管理解决方案&#xff0c;通过先进的人脸识别技术&#xff0c;实现无接触式身份验证&#xff0c;提高安全管理效率。 系统整合了人工智能与计算机视觉技…...

SAP 交货单行项目含税金额计算报cx_sy_zerodivide处理

业务背景&#xff1a;SAP交货单只有数量&#xff0c;没有金额&#xff0c;所以开发报表从订单的价格按数量计算交货单的金额。 用户反馈近期报表出现异常&#xff1a; ****2012/12/12 清风雅雨 规格变更 Chg 修改开始 ** 修改原因:由于余数为0时&#xff0c;可能会报错溢出。…...

【Qt】之音视频编程1:QtAV的背景和安装篇

QtAV 背景与核心概念 1. 什么是 QtAV&#xff1f; QtAV 是一个基于 Qt 框架 和 FFmpeg 的多媒体播放库&#xff0c;旨在为 Qt 应用程序提供高性能、跨平台的音视频播放、处理及渲染功能。它封装了 FFmpeg 的底层编解码能力&#xff0c;并通过 Qt 的图形系统&#xff08;如 QM…...

算法与数据结构 - 二叉树结构入门

目录 1. 普通二叉树结构 1.1. 常见术语 1.2. 完全二叉树 (Complete Binary Tree) 1.3. 满二叉树 (Full Binary Tree) 2. 特殊二叉树结构 2.1. 二叉搜索树 (BST) 2.1.1. BST 基本操作 - 查找 2.1.2. BST 基本操作 - 插入 2.1.3. BST 基本操作 - 删除 2.2. 平衡二叉树…...

如何使用远程桌面控制电脑

目的&#xff1a; 通过路由器使用pc控制台式机&#xff0c;实现了有线/无线pc与台式机的双向远程桌面控制 最核心就两条&#xff1a;get ip地址与被控制机器的账户与密码。 现象挺神奇&#xff1a;被控制电脑的电脑桌面处于休眠模式&#xff0c;此时强行唤醒被控电脑会导致中断…...

SpringMVC-执行流程

目录 前言 一、SpringMVC执行流程 SpringMVC 主要组件 SpringMVC 的执行流程 简要分析执行流程 总结 前言 理解SpringMVC的执行流程是学习SpringMVC工作原理的重要一步。 项目内容参考&#xff1a;SpringMVC-简介及入门-CSDN博客 一、SpringMVC执行流程 SpringMVC 主要组…...

计算机网络网络层(下)

一、互联的路由选择协议&#xff08;网络层控制层面内容&#xff09; &#xff08;一&#xff09;有关路由选择协议的几个概念 1.理想的路由算法 &#xff08;1&#xff09;理想路由算法应具备的特点&#xff1a;算法必须正确和完整的&#xff0c;算法在计算上应简单&#x…...

深入学习Zookeeper的知识体系

目录 1、介绍 1.1、CAP 理论 1.2、BASE 理论 1.3、一致性协议ZAB 1、介绍 2、角色 3、ZXID和myid 4、 历史队列 5、协议模式 6、崩溃恢复模式 7、脑裂问题 2、zookeeper 2.1、开源项目 2.2、功能 2.3、选举机制 3、数据模型 3.1、介绍 3.2、znode分类 4、监听…...

主从架构:技术原理与实现

一.简单介绍分布式锁的复习 今天在一个分布式锁的视频讲解中&#xff0c;提到了主从架构&#xff0c;所以有了这篇文章。 当然我们可以先说说分布式锁&#xff0c;可以使用redis的setnxlua脚本实现&#xff0c;或者也可以用redission实现&#xff0c;或者看门狗机制。 由看门…...

大模型核心运行机制

大模型核心运行机制目录 一、核心架构&#xff1a;Transformer的演进与改进1.1 核心组件包括&#xff1a;1.1.1 自注意力机制&#xff08;Self-Attention&#xff09;1.1.2 多头注意力&#xff08;Multi-Head Attention&#xff09;1.1.3 位置编码&#xff08;Positional Encod…...

uniapp跨平台开发HarmonyOS NEXT应用初体验

之前写过使用uniapp开发鸿蒙应用的教程&#xff0c;简单介绍了如何配置开发环境和运行项目。那时候的HbuilderX还是4.22版本&#xff0c;小一年过去了HbuilderX的正式版本已经来到4.64&#xff0c;历经了多个版本的更新后&#xff0c;跨平台开发鸿蒙应用的体验大幅提升。今天再…...

2025软考【系统架构设计师】:两周极限冲刺攻略(附知识点解析+答题技巧)

距离2025上半年“系统架构设计师”考试已经只剩最后两周了&#xff0c;还没有准备好的小伙伴赶紧行动起来。为了帮助大家更好的冲刺学习&#xff0c;特此提供一份考前冲刺攻略。本指南包括考情分析、答题技巧、注意事项三个部分&#xff0c;可以参考此指南进行最后的复习要领&a…...

C语言主要标准版本的演进与核心区别的对比分析

以下是C语言主要标准版本的演进与核心区别的对比分析 K&R C&#xff08;1978年&#xff09; 定位‌&#xff1a;非标准化的原始版本&#xff0c;由Brian Kernighan和Dennis Ritchie定义 特性‌&#xff1a; 基础语法&#xff1a;函数声明无参数列表&#xff08;如int func…...

使用 goaccess 分析 nginx 访问日志

介绍 goaccess 是一个在本地解析日志的工具, 可以直接在命令行终端环境中使用 TUI 界面查看分析结果, 也可以导出为更加丰富的 HTML 页面. 官网: https://goaccess.io/ 下载安装 常见的 Linux 包管理器中都包含了 goaccess, 直接安装就行. 以 Ubuntu 为例: sudo apt instal…...

vue3与springboot交互-前后分离【完成登陆验证及页面跳转】

vue3实现与springboot交互【完成登陆及页面跳转】 提示&#xff1a;帮帮志会陆续更新非常多的IT技术知识&#xff0c;希望分享的内容对您有用。本章分享的是node.js和vue的使用。前后每一小节的内容是存在的有&#xff1a;学习and理解的关联性。【帮帮志系列文章】&#xff1a…...

【Hot 100】208. 实现 Trie (前缀树)

目录 引言实现 Trie (前缀树)我的解题代码解析代码思路分析优化建议1. 内存泄漏问题2. 使用智能指针优化内存管理3. 输入合法性校验&#xff08;可选&#xff09;4. 其他优化 总结 &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&#xff1a;算法专栏&#x1…...

【2025最新】Vm虚拟机中直接使用Ubuntu 免安装过程直接使用教程与下载

Ubuntu 是一个基于 Debian 的自由开源 Linux 操作系统&#xff0c;面向桌面、服务器和云计算平台广泛应用。 由英国公司 Canonical Ltd. 维护和发布&#xff0c;Ubuntu 强调易用性、安全性和稳定性&#xff0c;适合个人用户、开发者以及企业部署使用。 Ubuntu 默认使用 GNOME …...

思路解析:第一性原理解 SQL

目录 题目描述 &#x1f3af; 应用第一性原理来思考这个 SQL 题目 ✅ 第一步&#xff1a;还原每个事件的本质单位 ✅ 第二步&#xff1a;如果一个表只有事件&#xff0c;如何构造事件对&#xff1f; ✅ 第三步&#xff1a;加过滤条件&#xff0c;只保留“同一机器、同一进…...

相机Camera日志分析之八:高通Camx HAL架构opencamera三级日志详解及关键字

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:相机Camera日志分析之七:高通Camx HAL架构opencamera二级日志详解及关键字 这一篇我们开始讲: 相机Camera日志分析之八:高通Camx HAL架构opencamera三级日志详解及关键字 目录 【关注我,后续持续…...

Vue2 elementUI 二次封装命令式表单弹框组件

需求&#xff1a;封装一个表单弹框组件&#xff0c;弹框和表单是两个组件&#xff0c;表单组件以插槽的形式动态传入弹框组件中。 外部组件使用的方式如下&#xff1a; 直接上代码&#xff1a; MyDialog.vue 弹框组件 <template><el-dialog:titletitle:visible.syn…...

Docker入门教程:常用命令与基础概念

目录 简介常用命令Docker 常用命令汇总docker run 命令格式与参数解析 简介 Docker 是一个客户端-服务器&#xff08;client-server&#xff09;架构的应用程序&#xff0c;其中包含两个主要组件&#xff1a;Docker 客户端和 Docker 守护进程&#xff08;也称为 Docker Daemon…...

Antd中Form详解:

1.获取Form表单值的方式: ① 使用Form.useForm()钩子&#xff08;推荐方式&#xff09; const [form] Form.useForm();const getFormValues () > {const values form.getFieldsValue();};<Form form{form}>...<Form.Item label{null}><Button onClick{ge…...

探索C语言中的二叉树:原理、实现与应用

一、引言 二叉树作为一种重要的数据结构&#xff0c;在计算机科学领域有着广泛的应用&#xff0c;无论是在操作系统的文件系统管理&#xff0c;还是在数据库的索引构建中&#xff0c;都能看到它的身影。在C语言中&#xff0c;我们可以利用指针灵活地构建和操作二叉树。接下来&…...

docker系列-DockerDesktop报错信息(Windows Hypervisor is not present)

Docker Desktop 报错信息 Docker Desktop - Windows Hypervisor is not present Docker Desktop is unable to detect a Hypervisor. Hardware assisted virtualization and data execution protection must be enabled in the BIOS.这是因为 Docker Desktop 需要启用 虚拟化技…...

03.Python 字符串中的空白字符处理

Python 字符串中的空白字符处理 什么是空白字符&#xff1f; 在处理字符串时&#xff0c;常常需要去除多余的空白字符。空白字符包括&#xff1a; 空格&#xff08; &#xff09;制表符&#xff08;\t&#xff09;换行符&#xff08;\n&#xff09;回车符&#xff08;\r&#x…...

《基于 Kubernetes 的 WordPress 高可用部署实践:从 MariaDB 到 Nginx 反向代理》

手把手教你用 Kubernetes 部署高可用 WordPress 博客 本实验通过 Kubernetes 容器编排平台&#xff0c;完整部署了一个高可用的 WordPress 网站架构&#xff0c;包含 MariaDB 数据库、WordPress 应用和 Nginx 反向代理三大核心组件。实验涵盖了从基础环境准备到最终服务暴露的…...