推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
penguinWWY
V2EX  ›  Python

发一个看起来没啥用的字节码编辑库

  •  
  •   penguinWWY · Aug 1, 2022 · 2618 views
    This topic created in 1406 days ago, the information mentioned may be changed or developed.

    先贴一下 README


    Pyasmer 是一个 Python 字节码编辑库。它可以用来修改现有的二进制代码(例如, func.code)。

    Pyasmer 可以帮助开发者在 python 代码中执行一些动态地在已有代码中插桩、代理、指令生成,

    使用它需要你具备一定的 Python 字节码和 CPython 虚拟机执行机制,你可以从官方文档获取这些知识: https://docs.python.org/3/library/dis.html。Pyasmer 也会提供一些易于使用的接口,降低使用难度。

    举个例子:

    import sys
    
    from pyasmer.asm_instruction import asm_global_var, asm_fast_var
    from pyasmer.code_writer import CodeWriter
    
    if __name__ == '__main__':
        _frozen_importlib = sys.modules['_frozen_importlib']
        # _find_and_load_unlocked 函数会在 import 模块的时候被调用
        _find_and_load_unlocked = getattr(_frozen_importlib, '_find_and_load_unlocked')
        cw = CodeWriter(_find_and_load_unlocked.__code__)()
        # 在_find_and_load_unlocked 函数开头添加一个 print ,将要被 import 的模块名称打印出来
        #
        # 更新插入位置到函数开头(第 0 条指令)
        cw.update_position(offset=0)
        # None: 忽略返回值
        # asm_global_var('print'): 调用的函数为 print
        # asm_fast_var('name'): 将局部变量`name`传给 print
        cw.call_function(None, asm_global_var('print'), asm_fast_var('name'))
        cw.gen_code()
        # 执行 import 命令
        import ast
    

    输出显示有两个模块在 import 命令过程中被引用。

    output:
        ast
        _ast
    

    目前功能还比较简单,支持插入函数调用、获取属性等功能。

    此外支持通过表达式匹配定位要修改的位置,比如:

    @asm_viewer
    def binary_ops(a, b):
        return [a + b, a - b, a * b, a / b, a + b]
    
    
    def test_match_binary_op():
        cv: CodeViewer = binary_ops.viewer
        # 匹配到两处 a + b 的位置
        binary_add = [x for x in cv.find_snippet_by_expression("a + b", local_vars=["a", "b"])]
        assert len(binary_add) == 2
        # 第 0-2 条指令和第 12-14 条指令
        # LOAD_FAST a
        # LOAD_FAST b
        # BINARY_ADD
        assert binary_add == [(0, 2), (12, 14)]
    

    总之,想要更多的功能欢迎来手搓,使用场景请各自脑补,over~~~

    4 replies    2022-08-01 17:53:04 +08:00
    penguinWWY
        1
    penguinWWY  
    OP
       Aug 1, 2022
    penguinWWY
        2
    penguinWWY  
    OP
       Aug 1, 2022
    yyzq007
        3
    yyzq007  
       Aug 1, 2022
    支持支持
    joApioVVx4M4X6Rf
        4
    joApioVVx4M4X6Rf  
       Aug 1, 2022
    大佬!
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   1148 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 17:35 · PVG 01:35 · LAX 10:35 · JFK 13:35
    ♥ Do have faith in what you're doing.