Python中 a, b = b, a 的具体字节码实现? 以及会出现的问题!

通过字节码混淆来保护Python代码 Python开发者常常面临这样一个难题,即如何保护代码中的技术秘密。笔者尝试过的一些Python代码保护工具要么难以有效实现该目标,要么有效但是有着不可忽视的缺点。本文首先对常见的Python代码保护机制以及几个比较容易获得的Python代码保护工具进行了简单的分析,然后展示了通过字节码混淆来保护Python代码的技术原理。 阅读详情

首先引入问题:

class Solution:
    def findDisappearedNumbers(self, nums):
        rst = list()

        # 循环遍历每一个数组元素
        for i in range(len(nums)):
            # 判断该元素位置上的值,是否需要交换, 注意 循环条件
            while nums[i] != i + 1 and nums[i] != nums[nums[i] - 1]:
                # 需要使用一个变量来代替,不能直接去交换
                a = nums[i] - 1 
                nums[i], nums[a] = nums[a], nums[i]
                
        # 再次遍历数组,找出缺失数字
        for i, num in enumerate(nums):
            if i + 1 != num:
                rst.append(i+1)
        return rst
  • 可以看到代码中交换两个数组中的两个位置的数, 我是用了一个变量来解决。 为什么不能直接写呢? 因为会出错! 具体看下面的引出问题:
  • 原意是想让 a[2] a[3] 元素交换位置,但是缺改变了三个元素,非常奇怪?
    在这里插入图片描述
  • 同样问题展示:并且有相应的解答:
    点击链接查看:问题描述
    在这里插入图片描述

我的想法和推敲(太深奥,可能不太准确)

(ps)字节码这里就不去细说了,非常多东西。推荐:
做出分析解释:
  • 下面正式对上述问题做出解释分析,直接去讲这个问题的推理, 不在记录知识点,因为前面推荐的文章和专栏已经非常精炼,全面了。

  • (1) 首先编译出字节码:

    • 每列代表的含义,第一列代表 源代码行号, 第二个代表偏移地址, 字节码形式,区分每条指令。第三个代表指令名字,第四个代表 操作数,指令所需的参数。 第五个括号则是 取操作数对应的具体内内容。
    >>> def a():
    ...     a = [1, 2, 3, 4, 5, 6, 7, 8]
    ...     a[2], a[a[2]] = a[a[2]], a[2]
    ... 
    >>> import dis
    >>> dis.dis(a)
      2           0 LOAD_CONST               1 (1)
                  2 LOAD_CONST               2 (2)
                  4 LOAD_CONST               3 (3)
                  6 LOAD_CONST               4 (4)
                  8 LOAD_CONST               5 (5)
                 10 LOAD_CONST               6 (6)
                 12 LOAD_CONST               7 (7)
                 14 LOAD_CONST               8 (8)
                 16 BUILD_LIST               8
                 18 STORE_FAST               0 (a)
    
      3          20 LOAD_FAST                0 (a)
                 22 LOAD_FAST                0 (a)
                 24 LOAD_CONST               2 (2)
                 26 BINARY_SUBSCR
                 28 BINARY_SUBSCR
                 30 LOAD_FAST                0 (a)
                 32 LOAD_CONST               2 (2)
                 34 BINARY_SUBSCR
                 36 ROT_TWO
                 38 LOAD_FAST                0 (a)
                 40 LOAD_CONST               2 (2)
                 42 STORE_SUBSCR
                 44 LOAD_FAST                0 (a)
                 46 LOAD_FAST                0 (a)
                 48 LOAD_CONST               2 (2)
                 50 BINARY_SUBSCR
                 52 STORE_SUBSCR
                 54 LOAD_CONST               0 (None)
                 56 RETURN_VALUE
    
    
  • (2) 分析字节码的含义:(第二个文章里有讲解,建议观看原文,我理解的可能不准确)

    • 官方文档的讲解,更是简短,不易理解,这里给出链接
    • LOAD_CONST: 主要要是将常量加载进栈(数据栈)。 根据操作数,在代码对象的co_consts 中根据下表索引进行取值,将常量对象引用压入栈中,实际对象在堆中存储。一条指令将一个对象或一个对象的值压入栈时,就意味着该对象的引用(或指针)入栈。 当一个对象或其值从栈弹出时,同理如此再次弹出引用。 解释器知道如何使用这些引用来检索或存储对象的数据!
    • STORE_NAME: 代码对象所保存的 名字列表co_names(资料中的描述), 根据操作数,对应索引找到 对应变量名字的引用(就是说变量的引用存储在 对应索引位置中)。
      • 将栈中的 常量引用出栈,并保存到对应的 变量所指向的 堆内存的某个位置。
    • LOAD_CONST: 访问 常量元组 co_consts对应索引位置的 常量对象的 引用。将引用压入栈中。
    • LOAD_NAME: 将变量的引用指向的变量值,压入栈中。(详细看文章讲解,对于变量,引用,指针的概念,比较绕)
    • BINARY_SUBTRACT 和 STORE_SUBSCR 可以查看对应的官方文档上面给出来了,并且下面还要去讲这两个,因为不太清楚具体用法概念,不敢分析~ 传播错误知识。
  • (3) 进行我的推理(只供参考):

    • 通过上面的讲解,可以先试着分析简单的 a,b = b, a 理解下。
    >>> def func1():
    ...     a = 1
    ...     b = 2
    ...     a, b = b, a
    ... 
    >>> dis.dis(func1)
      2           0 LOAD_CONST               1 (1)    # 加载常量1对象的引用进栈
                  2 STORE_FAST               0 (a)	  # 出栈1的引用,并存储在堆中,由 a指向
    
      3           4 LOAD_CONST               2 (2)	  # 同理
                  6 STORE_FAST               1 (b)	  # 同理
    
      4           8 LOAD_FAST                1 (b)    # 加载 b指向对象的引用 进栈
                 10 LOAD_FAST                0 (a)	  # 同理
                 12 ROT_TWO							  # 将栈中的,两个元素反转。比如(打个比方)进栈是 a, b ,现在 变为 b, a 。 栈顶由b 变为 a
                 14 STORE_FAST               0 (a)    # 将栈顶元素弹出来,然后a指向栈顶弹出的引用
                 16 STORE_FAST               1 (b)	  # 同理, 这样就实现 a,b 指向的对象交换了
                 18 LOAD_CONST               0 (None)  # 专栏和文章里有解释
                 20 RETURN_VALUE
    
    • 下面分析,上面图片的问题

    • (1)分析第二行代码生成的字节码,主要就是利用 BUILD_LIST,将常量元素引用依次加入到栈中, 然后生成列表,并将 a变量只想到 对应的列表引用。
      在这里插入图片描述

    • (2)分析第三行代码

    • a[2], a[a[2]] = a[a[2]], a[2]

    • 20-28 :主要是实现 = 右边的 a[a[2]]

    			 20 LOAD_FAST                0 (a)    # a 指向的列表 引用进栈
                 22 LOAD_FAST                0 (a)	  # 同上
                 24 LOAD_CONST               2 (2)	  # 常量引用进栈,整体顺序是由外到内的
                 26 BINARY_SUBSCR			# 操作看下图  根据现在站内元素为(模拟) a, a, 2, 将a,2出栈,计算a[2] 引用压入栈中
                 28 BINARY_SUBSCR			# 同上,执行完毕后 得到a[a[2]]的引用,就是 a[3] 对应的引用
    
    • 官方文档中介绍 TOS 是栈顶元素, TOS1是栈顶元素下面一个元素,也就是第二个元素,TOS2依次类推。
      在这里插入图片描述
    • 执行完毕后,此时栈内的元素为 a[3] (此位置索引,对应的对象引用)只有这一个元素。
    • 30-34: 和上面一样的操作,计算 = 右面的 a[2]
     			 30 LOAD_FAST                0 (a)
                 32 LOAD_CONST               2 (2)
                 34 BINARY_SUBSCR
    
    • 此时栈内为 a[3], a[2] (笼统的表示,其实是他们指向对象的引用)
    • 36 : ROT_TWO,交换TOS,TOS1元素。 栈内为 a[2] , a[3]。 a[3] 为栈顶元素。
    • 下面重点来了,导致错误的原因,就是下面的字节码!!! 也是我个人的推敲不一定准确:
    • 38-42: 开始执行 = 左面的,处理a[2]
    			 38 LOAD_FAST                0 (a)   # 这两条加载 a, 2 进栈
                 40 LOAD_CONST               2 (2)
                 42 STORE_SUBSCR
                 # 此时的栈内是 a[2], a[3], a, 2
                 # 执行 42 :  a[2] = a[3], 这句话导致 a[2] 对应指向的对象变为了 a[3] 所指向的 也就是4.
    

    在这里插入图片描述

    • 我理解的是,STORE_SUBSCR 取出三个操作数之后,是不放回去的(理解不太对,光放文档也有提到二元操作,放回)此时栈 只剩下一个 a[2] 了,a[2] 是指向对象的引用,也就是 3的引用。
      44-52:
    			 44 LOAD_FAST                0 (a)
                 46 LOAD_FAST                0 (a)
                 48 LOAD_CONST               2 (2)
                 50 BINARY_SUBSCR
                 52 STORE_SUBSCR
    			# 执行起来就是  a[a[2]] = a[2]
    			# 迷不过来的地方,我理解的是,前面的字节码操作,已经使 a[2]指向的对象变成了 4.
    			# 这里就变成了 a[4] = a[2]  而 = 右面的 a[2] 是栈底的,代表原来 3对象的指向
    			# 这样就使得 a[4] 所对应的指向 变为了 3. 
    			# 这里的 STORE_SUBSCR 和 BINARY_SUBSCR 操作的区别感觉就是。STORE_SUBSCR,类似于STORE_NAME, a[4] 就相当于是一个变量名, 然后进行 STORE_NAME操作。 右面的 a[2] 就是一个具体的 3对象的指针。
    
    • 因为不会画图(不知道怎么表示列表),所以上述的表述 都用的 a[] 来表示,但是意义不同。比较乱,全是我的猜想,不一定很正确。
    • 通过上面的两步,就能解释了, 第一个 STORE_SUBSCR 使 a[2] 变成 4, 第二个 STORE_SUBSCR 使a[4] 变为 3.
因为这些知识点设及的东西很多,比如书python解释性慢在哪里? 什么时候给对象判断类型,分配内存空间,还有栈,堆空间的理解都是不够的,网上资料不多,并且内容错综复杂。经过很多查阅, 算是对 对象管理,字节码执行,字节码对象,栈帧对象有个更深的认识,但是还是很片面,以上所述,仅供参考~ 未来 有新的理解和认识,再来修改。
Python的pyc字节码反编译反汇编相关知识 常用pyc转py的工具 pycdc Decompyle++ Decompyle++旨在将编译后的Python字节码转换回有效的、人类可读的Python源代码。虽然其他项目取得了不同程度的成功,但Decompyle++的独特之处在于,它寻求支持来自任何版本的Python的字节码。 Decompyle++包含一个字节码反汇编器(pycda)和一个反编译器(pycdc)。 该工具需要手动编译,使用kali编译以后的样本:https://pan.baidu.com/s/1tAzVPMzFmhWko915yguO 阅读详情

相关推荐

MTK PE+2.0介绍

  PE+2.0介绍:   1.      PE+2.0的状态机: 2.      升压波形协议及编码规则: PE+2.0软件设计:   在充电器类型为标充且底层电量SOC在1%—95%之间时,开始PE+2.0升压充电器的检测:首先将VBUSreset至5V,之后发送8.5的current pattern再获取此时VBUS电压和8.5V比较,若其与8.5的差值绝对值在0.5之...

raydom07的博客 1万+

Python中的a,b=b,a

在数值交换中,通常会用到a,b=b,a 例题:编写程序,输入三个整数,最小的放在 a 中,最大的放在 c 中,中间的放在 b 中。 a1=int(input()) b1=int(input()) c1=int(input()) if a1>b1: a1,b1=b1,a1 if a1>c1 a1,c1=c1,a1 if b1>c1 b1,c1=c1,b1 print(a1,b1,c1)#从大到小排序 print("最小值"+str(a)) print("最大值"

m0_49317668的博客 5224

前端实现微信扫一扫的思路

本篇文章的关键点就是讲解了我在实现处理多张二维码的场景时的思路,利用canvas遮挡识别过的二维码这个思路是pbk-bin大佬最先想到的,在实现这个需求以后还是很感叹这个思路的巧妙。👏pbk-bin🎁~如果文章对你有帮助,不妨赠人玫瑰,手有余香,预计将会在下篇更新较为完整的微信扫一扫界面和功能。

fang_my的博客 2488

python的a,b = b,a原理

python中提供交换两个值的操作:a,b = b,a 其原理如下: 1、让变量a指向“b值的地址”, 2、再让变量b指向“a值的地址” 用这种形式实现输出斐波拉契数列的方法如下: a,b = 0, 1 while b<100: print (b), a, b = b, a+b 其输出将是:1,1,2,3,5,8,13… 注意在数组下标使用值进行交换时,这会引发一些问题: ...

qq_38673794的博客 4086

Trae+雪球MCP,化身专业的股票分析师(玩转100个MCP系列第二弹)

大家好呀,我是程序员夏叶,深度AI编程使用者,专注于分享AI编程方面的使用技巧、经验以及前沿资讯,有兴趣的可以关注我的公众号,一起学习,共同进步。第二弹,使用Trae+雪球MCP,获取股票实时行情,分析股票走向等,写代码间隙看看股票价格,研究研究行情,哈哈。真的很不错呀,最关键的是,足够隐蔽,同事以为你在写代码,实际你在浏览股票行情,哈哈,感兴趣的可以试一下哦。说实话,沧州明珠这只股我算是砸手里了,不过还好买的不多,哈哈。

cpp加油站的专栏 517

【图像去噪】基于加权核范数最小化算法实现图像去噪附matlab代码

1 简介 WNNM是一种约束矩阵奇异值稀疏性的低秩算法,在NNM理论基础上增加了核范数权重,有效利用了自然图像的先验信息并提高了核范数的灵活性. 2 部分代码 ​clcclear allclose allnSig = 100;O_Img = double(imread('Monarch.png'));​randn('seed', 0);N_Img = O_Img + nSig* randn(size(O_Img)); ..

qq_59747472的博客 3114

Python心法:a,b=b,a原理

交换两个变量的值,Python的这条指令颠覆很多人的三观。这是因为大家的三观是学C语言建立的。 在C语言中,系统会为每个变量分配内存空间。而在python中,Python为每个值分配内存空间。 所以,a,b=b,a 这条指令,先是变量a被赋“b值”的地址,然后变量b被赋“a值”的地址,所以没毛病。 再看一个例子,用Python输出一个Fibonacci数列。 Fibonacci数列是F[n...

猫头军师兵书 1万+

华为ONU远程登录管理配置

华为P602E、EG8040CONU、EG8240H5、W626E等ONU、ONT默认无法配置管理IP,无法远程telnet登录管理。校园网项目中因故障诊断需要远程登录ONU可以通过OLT的远程WEB代理功能链接登录,具体配置如下:

symstandsun的博客 6108

python两个数值互换(浅析a,b=b,a原理)

python交换两个值得方法非常简单,即a,b=b,a,一步操作就交换了两个值,那么这是为什么呢?真相:Python的变量并不直接存储值,而只是引用一个内存地址,交换变量时,只是交换了引用的地址。先看下面这段程序:import disdef func(a,b): a,b=b,a print(a,b)a=10 b=20 func(a,b) dis.dis(func) 一般来说一个P

土豆洋芋山药蛋的博客 7万+

如何使用 Python 爬取 58 同城招聘信息

职位名称:招聘的岗位名称,如“前端开发”、“数据分析师”等。公司名称:招聘公司的名称。薪资待遇:职位的薪资范围,通常以“面议”、“10k-20k”这样的形式表示。工作地点:公司所在的城市及具体地址。公司福利:例如五险一金、带薪年假、绩效奖金等。发布时间:职位信息的发布时间。一个典型的招聘页面 URL 格式通常如下:在这个页面上,职位信息会分页展示,爬虫需要模拟翻页,获取多个页面的招聘信息。

2201_76125261的博客 1291

【GEOS-Chem模拟教程第二期上】生物质燃烧排放 GFED4 数据配置

生物质燃烧排放 GFED4 数据配置

WW、forever的博客 1298

Python交换变量表达式a, b = b, a的理解

Python交换变量表达式a, b = b, a的理解 初学python,接触Pythonic风格的交换变量值a, b = b, a表达式,觉得非常简洁方便,但一直不能理解其中的机理,通过网络查询和学习,理解如下: a, b = b, a 假设:a=1 b=2 等号右边b,a是一个表达式,代表元组(a, b),假设a=1,b=2,则b,a运算结果为(2,1),运算后这个元组的元素的值就固定了,与变量a,b无关了,这时候如果去改变变量a,b的值,元

chichihu的博客 6692

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

python中a* b是什么意思_python的 a,b=b,a+b 和 a=b b=a+b 的区别

区别就是:赋值运算,先计算赋值号(也就是=号左边的,再赋值)1、a, b = b, a+b 这种赋值先计算等值 右边 就是 b=1 a+b=1再赋值给a和b,那么 a=1, b=12、a = b b = a+b此时 b=1, 那么a=1 那么最后 b=2a, b = b, a+b 这个表达式的意思就是说,先计算=号的右边b的值,a+b的值,算好了,然后再分别赋值给a 和b就可以了。扩展资料:Pyt...

weixin_39725844的博客 4412

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

python a b_python的 a,b=b,a+b 和 a=b b=a+b 的区别

展开全部区别就是:赋值32313133353236313431303231363533e78988e69d8331333366303066运算,先计算赋值号(也就是=号左边的,再赋值)1、a, b = b, a+b 这种赋值先计算等值 右边 就是 b=1 a+b=1再赋值给a和b,那么 a=1, b=12、a = bb = a+b此时 b=1, 那么a=1 那么最后 b=2a, b = b, a...

weixin_39805906的博客 349

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

【新手python程序员必须明白的真相】138.新手python程序员必须明白的解包赋值的妙用:a,b=b,a背后的原理

编程就像搭乐高,看似简单的语法背后都藏着精妙的设计。当你再看到时,希望你能会心一笑,想起今天看到的字节码舞蹈和栈操作魔术。记住,每个优雅的代码片段都是程序员智慧的结晶,保持这份好奇,你的代码终将成为他人眼中的魔法。编程路上,你我皆是求道者,但行好事,莫问前程——因为好代码自己会说话。

967

数据结构01-python变量标识的本质 ---(a,b = b, a)实现原理

文章目录问题引出个人理解a, b = b, a的字节码层面的执行 问题引出 我们先来看一下下面这段代码: # python a = 10 b = 20 a,b = b,a 我们发现这是python中特有的语法,在C/C++中尝试运行这段代码的话会直接报错 为了弄清除这个问题,我们看一下下面这个图 个人理解 从图中我们可以看到,和C/C++不同的是,python中一切皆为对象,这里的a保存的是对象 (int 10)的地址,b保存的是对象(int 20)的地址。因此在python中,不需要静态指定数据类型,

qq_22473333的博客 418

python--基础知识点--交换赋值(b, c, a = a, b, c)的底层原理

python交换三个值得方法非常简单,即b, c, a = a, b, c,一步操作就交换了,那么这是为什么呢? 1. 真相 Python的变量并不直接存储值,而只是引用一个内存地址,交换变量时,只是交换了引用的地址。 先看下面这段程序: import dis def test(a, b, c): b, c, a = a, b, c return a, b, c if __name__ == '__main__': a = 1 b = 2 c = 3

Chasing__Dreams的博客 5288

Python 字节码与字节码混淆

Python 字节码与字节码混淆 Python 字节码 虽然 Python 作为解释型语言,但是其也不是直接对源代码进行解释 Python 解释器会将源代码处理成字节码后,借助 Python 解释器运行程序 通过 Python 自带的模块 dis 可以将目标函数转换成字节码 import dis def fun(x, y, z): a = 1 a += 1 print("aaa") fun(1, 2, 3) return dis.dis(fun) 控

Bi0x的博客 1173

python中a += b与a = a + b不等价。

偶然发现的坑,记录一下示例代码初步分析深入分析举一反三 示例代码 def func_a(): a = ['a'] b = a b += ['b'] print(a,b,id(a)==id(b)) def func_b(): a = ['a'] b = a b = b + ['b'] print(a,b,id(a)==id(b)) func_a() #运行结果为['a',...

DDua_CN的博客 765

python的字节码(ByteCode)

本文介绍了python中字节码的实现过程

phoenix_wangxd的博客 3229

CTF逆向-[羊城杯 2020]Bytecode-WP-Python字节码反编译

CTF逆向-[羊城杯 2020]Bytecode-WP-Python字节码反编译 来源:https://buuoj.cn/ 内容:无 附件:https://pan.baidu.com/s/15XJLq9jFV_pOtPMzNXG9XA?pwd=tlwo 提取码:tlwo 答案:GWHT{cfa2b87b3f746a8f0ac5c5963faeff73} 总体思路 反编译汇编成py源码 检查源码逻辑发现是一个约束求解(解方程) 使用z3输入条件得到flag 详细步骤 文件信息,打开发现是Python的

serfend's blog 3297

java字节码与python字节码互转

def pb2jb(byte_arr): """ python字节码转java字节码 :param byte_arr: :return: """ return [int(i) - 256 if int(i) > 127 else int(i) for i in byte_arr] def jb2pb(byte_arr): """ ...

风中的承诺 1889

Python3 字节码混淆

文章目录前言什么是 pyc 文件?pyc 的版本号pyc 的基本格式解题 前言 emmm,关于字节码混淆,最早碰到还是在校赛的时候,当时一脸懵逼,什么情况,怎么 uncompyle6 不能反编译 pyc 了,不过之后也就不了了之了,今天特地写此博文纪念 DASCTF Oct X 吉林工师魔法赛 中的一道 RE 题 —— 魔法叠加,出题人是真的阴间????   什么是 pyc 文件? 简单来说,pyc 文件就是 Python 的字节码文件; 众所周知,Python 是一种全平台的解释性语言,全平台其

sid10t. 3万+

只需一条语句“a,b=b,a”,就能直接交换两个变量

本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,,版权归原作者所有,如有问题请及时联系我们以作处理 作者:Python猫 来源:腾讯云 PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取 python免费学习资料以及群交流解答点击即可加入 从接触 Python 时起,我就觉得 Python 的元组解包(unpacking)挺有意思,非常简洁好用。 最显而易见的例子就是多重赋值,即在一条语句中同时给多个变量赋值: >>> x,...

pythonputao的博客 724
上一篇: 关于linux操作系统中文件描述符以及Python 中open函数的理解
下一篇: Python双链表详细讲解实现:模拟计算机缓存淘汰算法,FIFO,LRU以及LFU!
我是py呀
博客等级 码龄8年 205粉丝 130原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值