在运行时修改函数(拉出局部变量)

2023-11-30

想象一下这个简单的函数创建变量的修改值default, modified:

default = 0
def modify():
    modified = default + 1
    print(modified)  # replace with OS call, I can't see the output

modify()  # 1
default  # 0

拆解:

import dis
dis.dis(modify)
2           0 LOAD_GLOBAL              0 (default)
            3 LOAD_CONST               1 (1)
            6 BINARY_ADD
            7 STORE_FAST               0 (modified)
3          10 LOAD_GLOBAL              1 (print)
           13 LOAD_FAST                0 (modified)
           16 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
           19 POP_TOP
           20 LOAD_CONST               0 (None)
           23 RETURN_VALUE

我无法更改功能modify(),但我直接(我可以看到代码)或间接(反汇编)知道其中的内容。我需要的是获得一个值modified变量,所以我想也许有一种方法可以删除特定的部分(print(modified)) 的函数通过dis模块,但我没有找到任何东西。

有什么办法可以删除除了return_value after 16 CALL_FUNCTION并将其替换为例如return modified?或者是否有其他方法可以在不实际执行最后一行的情况下提取局部变量?

作为一种可能的解决方案,我认为有 3 种方法:

  • 拉出反汇编的代码并根据它们创建我自己的函数(或就地),并删除我不想要的代码(之后的所有内容)16 ...)
  • 修改函数的return值,以便它返回modified(不幸的是调用了操作系统函数)
  • 根据源代码手动重新创建函数

我想避免第二种方式,这可能比第一种方式更容易,但我必须避免第三种方式,所以......有什么方法可以解决我的问题吗?


还有第四种选择:更换print() global:

printed = []
print = lambda *args: printed.extend(args)
modify()
del print
modified = printed[0]

否则可能会生成修改后的字节码,但这很容易导致导致解释器崩溃的错误(对无效字节码的保护为零),因此请注意。

您可以使用具有更新的字节码的新代码对象来创建新的函数对象;根据您显示的 dis 中的偏移量,我手动创建了新的字节码,该字节码将返回索引 0 处的局部变量:

>>> altered_bytecode = modify.__code__.co_code[:8] + bytes(
...     [dis.opmap['LOAD_FAST'], 0,   # load local variable 0 onto the stack
...      dis.opmap['RETURN_VALUE']])) # and return it.
>>> dis.dis(altered_bytecode)
          0 LOAD_GLOBAL              0 (0)
          2 LOAD_CONST               1 (1)
          4 BINARY_ADD
          6 STORE_FAST               0 (0)
          8 LOAD_FAST                0 (0)
         10 RETURN_VALUE

RETURN_VALUE返回栈顶的对象;我所做的就是注入一个LOAD_FAST加载什么的操作码modified引用到堆栈上。

你必须创建一个新的code对象,然后是一个新的function对象包装代码对象,使其可调用:

>>> code = type(modify.__code__)
>>> function = type(modify)
>>> ocode = modify.__code__
>>> new_modify = function(
...     code(ocode.co_argcount, ocode.co_kwonlyargcount, ocode.co_nlocals, ocode.co_stacksize,
...          ocode.co_flags, altered_bytecode,
...          ocode.co_consts, ocode.co_names, ocode.co_varnames, ocode.co_filename,
...          'new_modify', ocode.co_firstlineno, ocode.co_lnotab, ocode.co_freevars,
...          ocode.co_cellvars),
...     modify.__globals__, 'new_modify', modify.__defaults__, modify.__closure__)
>>> new_modify()
1

显然,这首先需要对 Python 字节码的工作原理有一定的了解;这dis模块确实包含各种代码的描述,并且dis.opmap字典让您映射回字节值。

有一些模块试图使这变得更容易;看一眼byteplay, the bytecode的模块pwnypack project或其他几个,如果您想进一步探索这一点。

我也衷心推荐您观看玩转 Python 字节码推介会由 Scott Sanderson、Joe Jevnik 在 PyCon 2016 上提供,并使用他们的codetransformer module。非常有趣且信息丰富。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在运行时修改函数(拉出局部变量) 的相关文章

随机推荐

  • 如何在 map() 中使用异步代码(Flutter、Firestore)

    我正在使用 Flutter 和 Firestore 插件开发一个群聊应用程序 从数据库获取数据并将快照转换为消息列表完全可以正常工作 但现在我想将数据库中的 uid 转换为用户名 uid 及其用户名保存在数据库中 这是我的代码 final
  • 使用 XSLT 2.0 的两阶段转换

    我正在尝试将 CSV 文件作为输入并将其转换为 XML 我是 XSLT 新手 我找到了一种将 CSV 转换为 XML 的方法 使用来自安德鲁韦尔奇 像这样 输入 CSV 文件 car manufacturer model color pri
  • yaml 中的“>-”和“|-”有什么区别?

    我想确切地知道 gt 和 之间的区别 特别是在 kubernetes yaml 清单中 折叠块标量中的换行符 gt 受到行折叠 文字块标量中的换行符 不是 行折叠将非空行之间的单个换行符替换为空格 并且在空行的情况下 将周围非空行之间的换行
  • ASP.NET Core执行Linux shell命令

    有没有办法从 ASP NET Core 应用程序中执行 Linux shell 命令并将值返回到变量中 目前最好的可能性似乎是使用预发布版SSH Net Core https www nuget org packages SSH Net C
  • 使用 PHP 脚本进行 ERR_CONNECTION_RESET

    我有一个 PHP 脚本 可以下载和处理一些文件 有时文件数量非常大 因此需要一些时间 但是 当有大量文件需要处理时 连接会中断并出现 ERR CONNECTION RESET 错误 Chrome 这是我的配置 upload max file
  • 从网站上的按钮下载文件的 Python 脚本

    我想通过单击以下网址中的 导出到 Excel 按钮来下载 xls 文件 https apps tampagov net CallsForService Webapp Default aspx type TPD 更具体地说 按钮 name c
  • offsetTop 与 jQuery.offset().top

    我读过offsetLeft and offsetTop不能在所有浏览器中正常工作 jQuery offset 应该为此提供一个抽象 以提供正确的值 xbrowser 我想要做的是获取元素被单击的位置相对于元素左上角的坐标 问题是jQuery
  • 在 iOS 上读取 sms.db 和 call_history.db 文件?

    我正在为越狱的 iPhone 5s iOS 7 1 1 开发一个应用程序 以获取存储在相应 db 文件中的通话日志和消息 我有一些疑问 我有一个有效的证书 配置文件 并且我的应用程序是使用此配置文件签名的 因此是否有必要删除此配置文件并使用
  • 错误:控制到达非 void 函数的末尾

    我在学习C 我从教科书上复制了这段代码 在编译代码时 最后出现错误 错误说 控制到达非 void 函数的末尾 它位于代码的末尾 include ComplexNumber hpp include
  • 限制线程数和 Java 并发

    我找不到使用最新 JAVA 并发例程的具体案例的示例 我打算使用threads处理可能包含 0 到数千个请求的开放队列中的项目 我想限制在任何给定时间都有不少于 0 且不超过 10 个线程处理队列项目 是否有针对这种特定类型案例的 Java
  • 如何使用 JqGrid 更改 select2 下拉列表的选定值?

    我用的是奥列格的选择2演示 但我想知道是否可以更改下拉菜单中当前选择的值 例如 如果加载的四个值是 Any Fruit Vegetable Meat 下拉列表默认为 Any 我怎样才能将其更改为 Fruit 在 JqGrid 事件中load
  • Android Studio 空白活动

    我使用的是 Android Studio 2 1 没有 空白活动 选项 我见过有人问过这个问题 一般的建议是 自己做一个 问题是我对 Android 开发一无所知 所以我正在学习这个教程http developer android com
  • jQuery onclick 删除表格行

    如何点击删除表格行 这里有一个jsfiddle 我只想删除 del 链接嵌套的行 而不是脚本现在执行的最后一行 单击呼叫delTableRow 函数并且需要更改该函数以删除嵌套的 del 链接行
  • jqGrid 多选上的 PrettyCheckable

    我有一个jqGrid带有我用 CSS 自定义的多选复选框的表格和漂亮可检查 要自定义我设置的表格的所有复选框 prettyCheckable 如下 jQuery document ready function input type chec
  • sqoop 与 mysql 的导入问题

    我有一个基于 cdh5 的 hadoop ha 设置 我尝试使用 sqoop 从 mysql 导入表失败 并出现以下错误 15 03 20 12 47 53 ERROR manager SqlManager Error reading fr
  • 空格上仅支持 JavaScript 的自动换行功能?

    我发现的大多数自动换行功能都绑定到 css 和 或浏览器 dom 我正在 javascript 环境 rhino 中工作 需要找到或设计一个更好的自动换行 该换行可以在给定行长度值之前的空白处中断 我当前的解决方案只是搜索给定字符之前的最后
  • C++ 中如何进行柯里化?

    什么是柯里化 C 中如何进行柯里化 请解释一下STL容器中的活页夹 1 什么是柯里化 柯里化只是意味着将多个参数的函数转换为单个参数的函数 使用一个例子可以很容易地说明这一点 取一个函数f它接受三个参数 int f int a std st
  • 解决 pex 内部类

    当被测试的类是内部类时 有什么方法可以让 pex 工作吗 密封课程怎么样 我的意思是 毕竟这种类型的工具非常适合 API 测试 有时您可能希望至少将内容保留在内部 Thanks 通过以下方式为测试组件提供内部可见性InternalsVisi
  • 有没有办法模糊匹配或提供分数作为行值应与哪个 ID 或组关联的假设?

    我有一个看起来像这样的数据集 structure list ID c 1 2 3 4 5 6 7 8 9 10 Date c 2020 01 n04 2020 04 03 2020 12 10 2020 09 12 2020 11 19 2
  • 在运行时修改函数(拉出局部变量)

    想象一下这个简单的函数创建变量的修改值default modified default 0 def modify modified default 1 print modified replace with OS call I can t