'9?':?!;1-$:'@'+o'3'*'='%$30.
具有讽刺意味的是,这不仅大大降低了范围限制,而且还便于携带并且可以与在线解释器一起使用。
分析
让我们从目标字符串开始:
yh[cPWNkz^EKLBiQMuSvI`n\Yw|JVXDUbZmfoRC_xrq{TlpHjGt]OadFAsgeyh[
> <>使用'
或"
以字符串模式将字符压入堆栈,但是要打印63个字符,并且只能使用64个字节,因此必须使用大写字母(对于标准环回技巧,> <>中的无效指令)可以直接打印不可能。因此,我们必须对代码点做一些事情。
转换为代码点可以得到(我在这里使用Python):
>>> L = [ord(c) for c in "yh[cPWNkz^EKLBiQMuSvI`n\Yw|JVXDUbZmfoRC_xrq{TlpHjGt]OadFAsgeyh["]
>>> L
[121, 104, 91, 99, 80, 87, 78, 107, 122, 94, 69, 75, 76, 66, 105, 81, 77, 117, 83, 118, 73, 96, 110, 92, 89, 119, 124, 74, 86, 88, 68, 85, 98, 90, 109, 102, 111, 82, 67, 95, 120, 114, 113, 123, 84, 108, 112, 72, 106, 71, 116, 93, 79, 97, 100, 70, 65, 115, 103, 101, 121, 104, 91]
请注意,后三个数字与前三个相同。这暗示可能正在进行模循环。
让我们看一下我们有多少个不同的元素:
>>> len(set(L))
60
中有63个元素L
,其中前三个与后三个一致。这意味着,除了此碰撞之外,所有其他元素都是唯一的。现在,这暗示着要取幂以质数为模。确实,60 + 1 = 61
是素数,这是一个好兆头。
让我们尝试找到最小的元素
>>> min(L)
65
并使用它按比例缩小所有元素,使min元素为1:
>>> M = [x-64 for x in L]
>>> M
[57, 40, 27, 35, 16, 23, 14, 43, 58, 30, 5, 11, 12, 2, 41, 17, 13, 53, 19, 54, 9, 32, 46, 28, 25, 55, 60, 10, 22, 24, 4, 21, 34, 26, 45, 38, 47, 18, 3, 31, 56, 50, 49, 59, 20, 44, 48, 8, 42, 7, 52, 29, 15, 33, 36, 6, 1, 51, 39, 37, 57, 40, 27]
注意after元素1
是怎样的51
。如果发生某种幂/乘法运算,那么对于我们的乘法器来说是一个不错的猜测。
让我们试一下:
>>> (57*51)%61
40
>>> (40*51)%61
27
>>> all((x*51)%61 == y for x,y in zip(M, M[1:]))
True
答对了!我们现在可以回溯,给出以下代码:
x = 57
for _ in range(63):
print(chr(x + 64), end="")
x = (x*51)%61
然后将其翻译为> <>