入口
v4=dword_4020
dword_4020 = [
26, 26, 200, 22, 198, 20, 58, 61, 197, 19, 194, 64, 189, 186, 188,
116, 187, 118, 191, 75, 75, 75, 123, 180, 77, 98, 97, 173, 96, 86, 99,
175, 120, 84, 86, 116
]
先校验input的s长度是否为36
再对字符串s每一位过加密函数sub_11c9
(需要注意这里返回值是无符号的int8)
在里面对当前s[i]+75然后和 无符号int的(i-75)进行 异或
最后返回对比v4
需要注意这里 方法返回值是无符号uint8转换后的 和v4对比
因为里面i-75得出来的是个负数 无符号转换之后得到的是个很长的整数
和前面异或之后长度足以被截断
====================
=(2023/8/29更新另一个解法,感谢h**er师傅提供的脚本和思路)
可以看到下面师傅的脚本中除了异或后转正码之外,并没有额外增加字符转换的部分
key = [26, 26, 200, 22, 198, 20, 58, 61, 197, 19, 194, 64, 189, 186, 188, 116, 187, 118, 191, 75, 75, 75, 123, 180, 77, 98, 97, 173, 96, 86, 99, 175, 120, 84, 86, 116]
flag = ""
for s in range(len(key)):
flag += chr((key[s] ^ (s - 75) & 0xFF) - 75)
print(flag)
其根本原因为:因ascii中flag中可能会出现的有效字符的值+75无论如何都不会超过255:如下例100为ascii的’d’的值
以至于在二进制中数位是无论如何都不会操作到8位之后的9位,下例为100+75的175二进制,可见其为8位
我们先正着走一遍 ,这里我们直接可以拿未经uint处理的-75进行异或 (-75所对应的二进制为-0b1001011)
得到-230也就是-0b11100110 ,依照题意我们将其转化为无符号的数值,我这里先不用uint8截取8位,用unit直接获取全部的值
得到
其二进制为0b11111111111111111111111100011010
我们截取最后8位00011010
转换为10进制即为26
对应着cipherlist的第一位
当然这是在已知答案的情况下进行正向运算。
接下来我们反过来从逆向的角度利用一下这个条件
list第一位是26
依照我们直接将他与第一轮询的(i-75)也就是(0-75)= -75进行异或还原
(26 ^ -75)
得到-81对应的二进制-0b1010001
而后我们将其转换为无符号得到4294967215
其所对应二进制为0b11111111111111111111111110101111
我们取他的8位10101111
即为175 ,然后175-75=100就是最初的’d’
为什么我们可以这样肆无忌惮的直接用不过任何处理cipher与轮询值做异或呢
说白了就还是因为他ascii可还原的值不会超过255,整个过程我们只需要关注到无符号步骤需要转换一次,取一下8位即可,也就是即便int8截取了8位之后也影响不到数据的完整性,255也就代表了8位全1,我们折腾一顿自始至终也是在8位内,丝毫不需要考虑到会被截取导致无法还原明文值,当然这一切都是建立在flag字符目标的值+75没有超过255的情况下。假如他符号给的值超过了255话,那就只能用下面的方式进行爆破了。
====================
他做了uint8截断之后会丢失原来的位数 比赛时候没想出什么好的办法还原。
于是打算撞出来,但是卡住了
这是我的脚本
#正数与负数的异或是统一为正数后进行异或然后再转负数
import ctypes
import string
dword_4020 = [
26, 26, 200, 22, 198, 20, 58, 61, 197, 19, 194, 64, 189, 186, 188,
116, 187, 118, 191, 75, 75, 75, 123, 180, 77, 98, 97, 173, 96, 86, 99,
175, 120, 84, 86, 116
]
s=string.printable
flag = ""
for i in range(len(dword_4020)):
for j in s:
x = ctypes.c_int8((ord(j) + 75) ^ ctypes.c_uint32(i - 75).value).value
if x == dword_4020[i]:
flag+=j
print(flag)
但是挺怪的输出的是 dacc66b5ee876e5acf9eb76a
赛后用c重新写了一遍 才发现我掉了个u…这里输出的结果被认定为有符号8位截断了…
举个例子
啧
最后脚本为
import ctypes
import string
s=string.printable
dword_4020 = [
26, 26, 200, 22, 198, 20, 58, 61, 197, 19, 194, 64, 189, 186, 188,
116, 187, 118, 191, 75, 75, 75, 123, 180, 77, 98, 97, 173, 96, 86, 99,
175, 120, 84, 86, 116
]
for i in range(len(dword_4020)):
for j in s:
x=ctypes.c_uint8((ord(j)+75) ^ ctypes.c_uint32(i-75).value).value
if x == dword_4020[i]:
print(j,end="")
很简单的re题,可惜了