[强网拟态 2022] Reverse赛题复现
急死了,赛中unlambda分析的差不多了结果写化简写炸了,windows_call隐约感觉到和aes有关但是最后跑去刚unlambda了,最后没进决赛
要是我能AK Re的话就没这么多逼问题了,急死了急死了
comeongo
纯纯的动调题,check1里面的encoding发现offset是base58的表,并且是name+passwd的1-8位转成的base58。check2里面发现9-12位是base64,并且有+-12的偏移或者没有偏移,输出一下当明文misc做;动调到byte_compare,可以发现passwd的13-14位是vG,前面有个地方有个rax,和13-16位有关系,密文是unk数组,然后runtime_other里面发现最后两位差为63和31,由于是明文flag,可以直接当misc题做做。过了校验md5一下就行。
上午还想着抢二血呢,结果一路做到下午4点半,笑了
unlambda
赛中摸了一大半,思路基本是对的,结果后面替换的时候用的栈没用正则导致寄了。
首先阅读一些blog
https://zhuanlan.zhihu.com/p/30510749
https://zhuanlan.zhihu.com/p/57972301
那么大概可以搞懂这个题了。
l = lambda _ : (_ (lambda _ : lambda __: lambda ___ : (_ (___)) (__ (___))))(lambda _ : lambda __: _)
代表着iota组合子,l(l)
是I,l(l(l(l)))
是K,l(l(l(l(l))))
是S。
I = lambda _ : arr[_(lambda _ : _ + 1)(0)]
在取出相应位的flag
那么现在我们使用正则先进行第一次替换
l = lambda _: (_(lambda _: lambda __: lambda ___: (_(___))(__(___))))(lambda _: lambda __: _)
id = lambda _: _(lambda _: _ + 1)(0)
stack = []
cnt = 0
flag = False
find_id = []
for i in range(len(checker)):
if checker[i] == 'I':
flag = True
elif flag:
if checker[i] == '(':
stack.append(i)
cnt += 1
elif checker[i] == ')':
st = stack.pop()
cnt -= 1
if cnt == 0:
flag = False
find_id.append(checker[st + 1: i])
for i in find_id:
checker = checker.replace('I(' + i + ')', 'arr[' + str(id(eval(i))) + ']')
checker = checker.replace('l(l(l(l(l))))', 'S')
checker = checker.replace('l(l(l(l)))', 'K')
checker = checker.replace('l(l)', 'I')
print(checker)
这里以checker_0为例,可以发现,替换后会变成
S(S(K(S(K(S))(K)))(S))(K(K))(arr[4])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[0])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[42])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[28])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[20])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[39])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[56])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[30])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[27])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[2])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[52])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[62])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[48])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[58])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[60])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[6])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[23])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[19])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[12])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[43])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[57])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[44])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[53])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[55])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[51])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[25])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[26])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[29])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[17])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[38])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[40])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[32])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[37])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[18])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[11])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[3])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[50])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[21])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[8])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[33])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[16])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[47])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[22])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[9])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[59])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[41])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[5])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[34])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[10])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[61])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[45])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[15])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[1])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[7])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[35])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[54])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[24])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[46])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[36])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[14])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[31])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[13])(K(I))(S(S(K(S(K(S))(K)))(S))(K(K))(arr[49])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[63])(K)(K(I)))(K(I))))(K(I)))))))))(K(I))))(K(I)))(K(I)))))(K(I))))))(K(I))))(K(I)))))(K(I)))))(K(I))))(K(I)))))(K(I))))(K(I))))))(K(I)))(K(I))))(K(I)))(K(I))))(K(I)))(K(I)))(K(I))))(K(I))))))(K(I))))(K(I))))(K(I)))(K(I)))(K(I)))(K(I)))(K(I)))(K(I)))(K(I))
这样会发现有大量的重复成分,在wiki上查一下可以发现K(I)=False
,那么再化简一步可以发现
S(S(K(S(K(S))(K)))(S))(K(K))(arr[4])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[0])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[42])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[28])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[20])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[39])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[56])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[30])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[27])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[2])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[52])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[62])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[48])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[58])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[60])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[6])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[23])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[19])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[12])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[43])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[57])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[44])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[53])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[55])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[51])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[25])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[26])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[29])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[17])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[38])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[40])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[32])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[37])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[18])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[11])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[3])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[50])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[21])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[8])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[33])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[16])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[47])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[22])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[9])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[59])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[41])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[5])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[34])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[10])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[61])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[45])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[15])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[1])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[7])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[35])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[54])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[24])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[46])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[36])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[14])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[31])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[13])(False)(S(S(K(S(K(S))(K)))(S))(K(K))(arr[49])(S(S(K(S(K(S))(K)))(S))(K(K))(arr[63])(K)(False))(False)))(False))))))))(False)))(False))(False))))(False)))))(False)))(False))))(False))))(False)))(False))))(False)))(False)))))(False))(False)))(False))(False)))(False))(False))(False)))(False)))))(False)))(False)))(False))(False))(False))(False))(False))(False))(False)
仍然有大量的S(S(K(S(K(S))(K)))(S))(K(K))
,用大眼瞪后发现,arr[63]后有一个(K),剩下都是(False),在wiki上查一下会发现K=True
,翻着wiki的布尔表达式对上式进行递归化简可以发现其等价于一个if-then-else结构。那么我们将其替换为if
if(arr[4])(if(arr[0])(if(arr[42])(if(arr[28])(if(arr[20])(if(arr[39])(if(arr[56])(if(arr[30])(False)(if(arr[27])(if(arr[2])(False)(if(arr[52])(if(arr[62])(False)(if(arr[48])(False)(if(arr[58])(False)(if(arr[60])(if(arr[6])(False)(if(arr[23])(if(arr[19])(if(arr[12])(if(arr[43])(False)(if(arr[57])(if(arr[44])(if(arr[53])(False)(if(arr[55])(if(arr[51])(if(arr[25])(False)(if(arr[26])(False)(if(arr[29])(False)(if(arr[17])(if(arr[38])(False)(if(arr[40])(if(arr[32])(False)(if(arr[37])(False)(if(arr[18])(if(arr[11])(False)(if(arr[3])(if(arr[50])(False)(if(arr[21])(False)(if(arr[8])(if(arr[33])(False)(if(arr[16])(False)(if(arr[47])(if(arr[22])(False)(if(arr[9])(if(arr[59])(False)(if(arr[41])(False)(if(arr[5])(False)(if(arr[34])(if(arr[10])(False)(if(arr[61])(False)(if(arr[45])(if(arr[15])(if(arr[1])(False)(if(arr[7])(if(arr[35])(False)(if(arr[54])(False)(if(arr[24])(False)(if(arr[46])(False)(if(arr[36])(False)(if(arr[14])(False)(if(arr[31])(if(arr[13])(False)(if(arr[49])(if(arr[63])(True)(False))(False)))(False))))))))(False)))(False))(False))))(False)))))(False)))(False))))(False))))(False)))(False))))(False)))(False)))))(False))(False)))(False))(False)))(False))(False))(False)))(False)))))(False)))(False)))(False))(False))(False))(False))(False))(False))(False)
现在逻辑就更加明显了。这样会一层一层的判断arr[i]是T还是F,最终会约束checker[i] = 1,也就是说我们需要让其全部为真。if代表的if-then-else结构中,其后面跟的如果是(False)则自身为真,否则为假(可以理解为: if(a)(b)(c) := if a then c else b
。
搞定6个checker后,可以得到flag为:
flag{JelL0_wy_De@r_l@mBdA_ExprESzl0n_wITh_iOt@!}
要是赛中不全部用栈模拟,加点正则替换,可能就做出来了😭
windows_call
赛中给我橄榄的动调题,赛后刚了一天
这里显然在限制flag格式,可以看出是46位flag,格式为flag{0-9a-zA-Z}
这里是做了两次MD5,到现在也没能理解到底是在干什么。。。
可以参考这篇blog里的源码:https://www.cnblogs.com/huojuncheng/p/3415832.html
有没有可能根本没用呢,毕竟我今年新生赛也出了个md5基本没啥用的题😩
后面我们能发现这里调用了一步VirtualAlloc系统函数,然后发现了flag的前8位和iv和key的生成有关,
下面这里先做了AES,然后有一堆限制条件来限制flag的前8位
整理一下,考虑用z3把1-8位flag梭出来,然后去解一下CBC模式的AES,密文就是v42那4个
from z3 import *
from Crypto.Cipher import AES
iv = [0 for i in range(16)]
key = [0 for i in range(16)]
# a = BitVec('a', 32)
# b = BitVec('b', 32)
a = 51688
b = 52384
temp = a ^ b
for i in range(16):
iv[i] = ((temp >> 8) + i) ^ ((temp & 0xFF) +i)
v28 = 0
for i in range(16):
v29 = (iv[i] ^ (i - 64)) & 0xFF
key[i] = v29
v28 += v29
# solver = Solver()
# solver.add((a + 0x3800) & 0xFFFF <= 0x800)
# solver.add((b + 0x3500) & 0xFFFF <= 0x500)
# solver.add((b - a) & 0xFFFF == 0x2B8)
# solver.add(v28 == 0x8A8)
# solver.add(b & 0xFF == 0xA0)
# solver.add(a & 0xFF00 < 0xCA00)
# if solver.check() == sat:
# m = solver.model() # [b = 52384, a = 51688]
# print(m)
# else:
# print("OOps!")
enc = [0x84, 0x37, 0xA0, 0xF3, 0xEC, 0x36, 0x34, 0xFC, 0x94, 0xA2, 0x38, 0x6F, 0x3F, 0x34, 0x7E, 0x7C]
aes = AES.new(key=bytes(key), iv=bytes(iv),mode=AES.MODE_CBC)
dec = aes.decrypt(bytes(enc))
print(dec) # b'\x8b\x98T\xcd\xd0\xac2\x1by\x0f\xc7N\xfaR\x0f\xbc'
# E8C9A0CC8B9854CDD0AC321B790FC74EFA520FBC
Indir
虚拟机题,继续练练手吧