创建最奇怪的混淆程序,打印字符串“Hello world!”。我决定写一篇解释它到底是如何工作的。所以,这是 Python 2.7 中的条目:
(lambda _, __, ___, ____, _____, ______, _______, ________: getattr( __import__(True.__class__.__name__[_] + [].__class__.__name__[__]), ().__class__.__eq__.__class__.__name__[:__] + ().__iter__().__class__.__name__[_____:________] )( _, (lambda _, __, ___: _(_, __, ___))( lambda _, __, ___: chr(___ % __) + _(_, __, ___ // __) if ___ else (lambda: _).func_code.co_lnotab, _ <p>不允许使用字符串文字,但我为了好玩设置了一些其他限制:它必须是单个表达式(因此没有打印语句),具有最少的内置用法,并且没有整数文字。<br> 开始使用</p> <p>由于我们无法使用打印,我们可以写入 stdout 文件对象:<br> </p> <pre class="brush:php;toolbar:false">import sys sys.stdout.write("Hello world!\n")
但是让我们使用较低级别的东西:os.write()。我们需要 stdout 的文件描述符,它是 1(可以使用 print sys.stdout.fileno() 检查)。
import os os.write(1, "Hello world!\n")
我们想要一个表达式,所以我们将使用 import():
__import__("os").write(1, "Hello world!\n")
我们还希望能够混淆 write(),因此我们将引入 getattr():
getattr(__import__("os"), "write")(1, "Hello world!\n")
这是起点。从现在开始,一切都将混淆三个字符串和整数。
将字符串串在一起
“os”和“write”相当简单,因此我们将通过连接各个内置类的部分名称来创建它们。有很多不同的方法可以做到这一点,但我选择了以下方法:
"o" from the second letter of bool: True.__class__.__name__[1] "s" from the third letter of list: [].__class__.__name__[2] "wr" from the first two letters of wrapper_descriptor, an implementation detail in CPython found as the type of some builtin classes’ methods (more on that here): ().__class__.__eq__.__class__.__name__[:2] "ite" from the sixth through eighth letters of tupleiterator, the type of object returned by calling iter() on a tuple: ().__iter__().__class__.__name__[5:8]
我们开始取得一些进展!
getattr( __import__(True.__class__.__name__[1] + [].__class__.__name__[2]), ().__class__.__eq__.__class__.__name__[:2] + ().__iter__().__class__.__name__[5:8] )(1, "Hello world!\n")
“Hello world!n”更复杂。我们将把它编码为一个大整数,它由每个字符的 ASCII 代码乘以 256 的字符在字符串中的索引次方组成。换句话说,以下总和:
Σn=0L−1cn(256n)
哪里L
是字符串的长度,cn 是 n
个字符。要创建号码:
>>> codes = [ord(c) for c in "Hello world!\n"] >>> num = sum(codes[i] * 256 ** i for i in xrange(len(codes))) >>> print num 802616035175250124568770929992
现在我们需要代码将此数字转换回字符串。我们使用一个简单的递归算法:
>>> def convert(num): ... if num: ... return chr(num % 256) + convert(num // 256) ... else: ... return "" ... >>> convert(802616035175250124568770929992) 'Hello world!\n'
用 lambda 重写一行:
convert = lambda num: chr(num % 256) + convert(num // 256) if num else ""
现在我们使用匿名递归将其转换为单个表达式。这需要一个组合器。从这个开始:
>>> comb = lambda f, n: f(f, n) >>> convert = lambda f, n: chr(n % 256) + f(f, n // 256) if n else "" >>> comb(convert, 802616035175250124568770929992) 'Hello world!\n'
现在我们只需将这两个定义代入表达式中,我们就得到了我们的函数:
>>> (lambda f, n: f(f, n))( ... lambda f, n: chr(n % 256) + f(f, n // 256) if n else "", ... 802616035175250124568770929992) 'Hello world!\n'
现在我们可以将其粘贴到之前的代码中,一路替换一些变量名称 (f → , n → _):
getattr( __import__(True.__class__.__name__[1] + [].__class__.__name__[2]), ().__class__.__eq__.__class__.__name__[:2] + ().__iter__().__class__.__name__[5:8] )( 1, (lambda _, __: _(_, __))( lambda _, __: chr(__ % 256) + _(_, __ // 256) if __ else "", 802616035175250124568770929992 ) )
函数内部
我们在转换函数的主体中留下了一个“”(记住:没有字符串文字!),以及我们必须以某种方式隐藏的大量数字。让我们从空字符串开始。我们可以通过检查某个随机函数的内部结构来即时制作一个:
(lambda _, __, ___, ____, _____, ______, _______, ________: getattr( __import__(True.__class__.__name__[_] + [].__class__.__name__[__]), ().__class__.__eq__.__class__.__name__[:__] + ().__iter__().__class__.__name__[_____:________] )( _, (lambda _, __, ___: _(_, __, ___))( lambda _, __, ___: chr(___ % __) + _(_, __, ___ // __) if ___ else (lambda: _).func_code.co_lnotab, _ <p>我们在这里真正要做的是查看函数中包含的代码对象的行号表。由于它是匿名的,因此没有行号,因此字符串为空。将 0 替换为 _ 以使其更加混乱(这并不重要,因为该函数没有被调用),然后将其插入。我们还将把 256 重构为一个参数,该参数传递给我们混淆的 Convert()连同号码。这需要向组合器添加一个参数:<br> </p> <pre class="brush:php;toolbar:false">import sys sys.stdout.write("Hello world!\n")
绕道
让我们暂时解决一个不同的问题。我们想要一种方法来混淆代码中的数字,但是每次使用它们时重新创建它们会很麻烦(而且不是特别有趣)。如果我们可以实现 range(1, 9) == [1, 2, 3, 4, 5, 6, 7, 8],那么我们可以将当前的工作包装在一个函数中,该函数接受包含以下数字的变量1 到 8,并用这些变量替换正文中出现的整数文字:
import os os.write(1, "Hello world!\n")
即使我们还需要形成 256 和 802616035175250124568770929992,它们也可以通过对这八个“基本”数字进行算术运算来创建。 1-8 的选择是任意的,但似乎是一个很好的中间立场。
我们可以通过函数的代码对象获取函数接受的参数数量:
__import__("os").write(1, "Hello world!\n")
构建参数计数在 1 到 8 之间的函数元组:
getattr(__import__("os"), "write")(1, "Hello world!\n")
使用递归算法,我们可以将其转换为 range(1, 9) 的输出:
"o" from the second letter of bool: True.__class__.__name__[1] "s" from the third letter of list: [].__class__.__name__[2] "wr" from the first two letters of wrapper_descriptor, an implementation detail in CPython found as the type of some builtin classes’ methods (more on that here): ().__class__.__eq__.__class__.__name__[:2] "ite" from the sixth through eighth letters of tupleiterator, the type of object returned by calling iter() on a tuple: ().__iter__().__class__.__name__[5:8]
和之前一样,我们将其转换为 lambda 形式:
getattr( __import__(True.__class__.__name__[1] + [].__class__.__name__[2]), ().__class__.__eq__.__class__.__name__[:2] + ().__iter__().__class__.__name__[5:8] )(1, "Hello world!\n")
然后,进入匿名递归形式:
>>> codes = [ord(c) for c in "Hello world!\n"] >>> num = sum(codes[i] * 256 ** i for i in xrange(len(codes))) >>> print num 802616035175250124568770929992
为了好玩,我们将 argcount 操作分解为一个附加函数参数,并混淆一些变量名称:
>>> def convert(num): ... if num: ... return chr(num % 256) + convert(num // 256) ... else: ... return "" ... >>> convert(802616035175250124568770929992) 'Hello world!\n'
现在有一个新问题:我们仍然需要一种隐藏 0 和 1 的方法。我们可以通过检查任意函数中局部变量的数量来获得这些:
convert = lambda num: chr(num % 256) + convert(num // 256) if num else ""
尽管函数体看起来相同,但第一个函数中的 _ 不是参数,也不是在函数中定义的,因此 Python 将其解释为全局变量:
>>> comb = lambda f, n: f(f, n) >>> convert = lambda f, n: chr(n % 256) + f(f, n // 256) if n else "" >>> comb(convert, 802616035175250124568770929992) 'Hello world!\n'
无论 _ 是否实际在全局范围内定义,都会发生这种情况。
将其付诸实践:
>>> (lambda f, n: f(f, n))( ... lambda f, n: chr(n % 256) + f(f, n // 256) if n else "", ... 802616035175250124568770929992) 'Hello world!\n'
现在我们可以替换 funcs 的值,然后使用 * 将结果整数列表作为八个单独的变量传递,我们得到:
getattr( __import__(True.__class__.__name__[1] + [].__class__.__name__[2]), ().__class__.__eq__.__class__.__name__[:2] + ().__iter__().__class__.__name__[5:8] )( 1, (lambda _, __: _(_, __))( lambda _, __: chr(__ % 256) + _(_, __ // 256) if __ else "", 802616035175250124568770929992 ) )
移位
快到了!我们将用 、_、、_ 等替换 n{1..8} 变量,因为它会与中使用的变量产生混淆我们的内在功能。这不会造成实际问题,因为范围规则意味着将使用正确的规则。这也是我们将 256 重构为 _ 指代 1 而不是我们混淆的 Convert() 函数的原因之一。有点长了,就只贴前半部分了:
(lambda _, __, ___, ____, _____, ______, _______, ________: getattr( __import__(True.__class__.__name__[_] + [].__class__.__name__[__]), ().__class__.__eq__.__class__.__name__[:__] + ().__iter__().__class__.__name__[_____:________] )( _, (lambda _, __, ___: _(_, __, ___))( lambda _, __, ___: chr(___ % __) + _(_, __, ___ // __) if ___ else (lambda: _).func_code.co_lnotab, _ <p>只剩下两件事了。我们从简单的开始:256. 256=28</p> <p>,所以我们可以将其重写为 1 </p><p>我们将对 802616035175250124568770929992 使用相同的想法。一个简单的分而治之算法可以将其分解为数字之和,这些数字本身就是移位在一起的数字之和,依此类推。例如,如果我们有 112,我们可以将其分解为 96 16,然后是 (3 >),这两者都是涉及其他 I/O 方式的转移注意力的内容。</p> <p>数字可以用多种方式分解;没有一种方法是正确的(毕竟,我们可以将其分解为 (1 </p> <pre class="brush:php;toolbar:false">import sys sys.stdout.write("Hello world!\n")
这里的基本思想是,我们测试一定范围内的数字的各种组合,直到得出两个数字,基数和移位,使得基数
range() 的参数 span 表示搜索空间的宽度。这不能太大,否则我们最终将得到 num 作为我们的基数和 0 作为我们的移位(因为 diff 为零),并且由于基数不能表示为单个变量,所以它会重复,无限递归。如果它太小,我们最终会得到类似于上面提到的 (1 span=⌈log1.5|num|⌉ ⌊24−深度⌋
将伪代码翻译成 Python 并进行一些调整(支持深度参数,以及一些涉及负数的警告),我们得到:
(lambda _, __, ___, ____, _____, ______, _______, ________: getattr( __import__(True.__class__.__name__[_] + [].__class__.__name__[__]), ().__class__.__eq__.__class__.__name__[:__] + ().__iter__().__class__.__name__[_____:________] )( _, (lambda _, __, ___: _(_, __, ___))( lambda _, __, ___: chr(___ % __) + _(_, __, ___ // __) if ___ else (lambda: _).func_code.co_lnotab, _ <p>现在,当我们调用convert(802616035175250124568770929992)时,我们得到了一个很好的分解:<br> </p> <pre class="brush:php;toolbar:false">import sys sys.stdout.write("Hello world!\n")
将其作为 802616035175250124568770929992 的替代品,并将所有部件放在一起:
import os os.write(1, "Hello world!\n")
这就是你的。
附录:Python 3 支持
自从写这篇文章以来,有几个人询问了 Python 3 支持的问题。我当时没有想到这一点,但随着 Python 3 不断获得关注(感谢您!),这篇文章显然早就该更新了。
幸运的是,Python 3(截至撰写本文时为 3.6)不需要我们进行太多更改:
__import__("os").write(1, "Hello world!\n")
这是完整的 Python 3 版本:
getattr(__import__("os"), "write")(1, "Hello world!\n")
感谢您的阅读!我仍然对这篇文章的受欢迎程度感到惊讶。
以上是混淆'世界你好!” Python 上的混淆的详细内容。更多信息请关注PHP中文网其他相关文章!

Python列表切片的基本语法是list[start:stop:step]。1.start是包含的第一个元素索引,2.stop是排除的第一个元素索引,3.step决定元素之间的步长。切片不仅用于提取数据,还可以修改和反转列表。

ListSoutPerformarRaysin:1)DynamicsizicsizingandFrequentInsertions/删除,2)储存的二聚体和3)MemoryFeliceFiceForceforseforsparsedata,butmayhaveslightperformancecostsinclentoperations。

toConvertapythonarraytoalist,usEthelist()constructororageneratorexpression.1)intimpthearraymoduleandcreateanArray.2)USELIST(ARR)或[XFORXINARR] to ConconverTittoalist,请考虑performorefformanceandmemoryfformanceandmemoryfformienceforlargedAtasetset。

choosearraysoverlistsinpythonforbetterperformanceandmemoryfliceSpecificScenarios.1)largenumericaldatasets:arraysreducememoryusage.2)绩效 - 临界杂货:arraysoffersoffersOffersOffersOffersPoostSfoostSforsssfortasssfortaskslikeappensearch orearch.3)testessenforcety:arraysenforce:arraysenforc

在Python中,可以使用for循环、enumerate和列表推导式遍历列表;在Java中,可以使用传统for循环和增强for循环遍历数组。1.Python列表遍历方法包括:for循环、enumerate和列表推导式。2.Java数组遍历方法包括:传统for循环和增强for循环。

本文讨论了Python版本3.10中介绍的新“匹配”语句,该语句与其他语言相同。它增强了代码的可读性,并为传统的if-elif-el提供了性能优势

Python中的功能注释将元数据添加到函数中,以进行类型检查,文档和IDE支持。它们增强了代码的可读性,维护,并且在API开发,数据科学和图书馆创建中至关重要。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

WebStorm Mac版
好用的JavaScript开发工具

Dreamweaver Mac版
视觉化网页开发工具

ZendStudio 13.5.1 Mac
功能强大的PHP集成开发环境

PhpStorm Mac 版本
最新(2018.2.1 )专业的PHP集成开发工具

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能