总体难度不是很大,第三道题我赛后搞了六七个小时才做出,不是因为难,只是因为我对c语言的指针很不熟悉,影响了对验证逻辑的理解。
RE1 签到
v6[i-112]
即v5[i]
1 | s = list('akhb~chdaZrdaZudqduvdZvvv|') |
encrypt3
首先输入一个即将输入字符串的长度n
然后输入字符串,记为input
然后程序使用enc_flag(网上查了查,意思是encrypt flag)对input加密(说解密也行叭~)
将结果输出,记为output.
分析关键代码:
v10=input[0] ^ input[1] ^ input[2] ^ ... ^ input[n-1]
output[i] = v10 ^ enc_flag[i]
enc_flag[i]
已知。
可以看出,v10与input有关,但不管input的内容是什么,v10只是个char。所以可以爆破出所有的output。
程序中没有提示flag是input还是output,但是我们求出output后就已经发现了flag了。
我觉得input没法求,毕竟只需要逐位异或满足v10是某一特定值(爆破求出是64)即可,input的可能的字符串取值空间极大。
1 | enc_flag = [38,44,33,39,59,35,34,115,117,114,113,33,36,117,118,119,35,120,38,114,117,113,38,34,113,114,117,114,36,112,115,118,121,112,35,37,121,61] |
RE3 (忘了本题名称了)
输入四个int,经过sub_401863()进行变换,得到4个int,并和v9~v12比较数值,相等则输入的4个int的十六进制形式就是flag.
sub_401863() 函数:
第一部分:求出dword_408A40[]
虽然参数里有input,但是函数内部没用到input。用到了main中的v15~v18.
值是固定的,所以动态调试拿到,一共32个int.
之后进入一个32次的循环,循环内部有第2,3,4,5部分。
第二部分:求出v12
函数内部是一个4次循环,每次循环得到一个byte,合起来即一个INT。
对于每个byte:
v12[j] = input[i+2][j]^input[i+1][j]^input[i+3][j]^dword_408A40[i][j]
,
所以v12在形式上为:v12[0]v12[1]v12[2]v12[3]
按字节异或和按int异或其实是等同的,所以简化为:
v12 = input[i+2]^input[i+1]^input[i+3]^dword_408A40[i]
第三部分:求出v11
得到v11,4个_BYTE,即INT
v11[j] = byte_404100[16*(__int8(v12[j]>>4)) + (v12[j]&0xF)]
可以归纳为v11[j] = byte_404100[v12[j]]
byte_404100为已知的长度为0xff的数组,可以使用idc脚本导出二进制流文件。
导出后(记文件名称为dump),可以使用下面的代码提取成数组:
1 | import binascii |
代码没优化,其实不需要这么多行,先这样放在这里吧。
第四部分:求出v10
__ROL4__
是uint32循环左移,__ROL2__
是uint16循环左移,__ROL1__
是uint8循环左移
__ROR4__
是uint32循环右移,__ROR2__
是uint16循环右移,__ROR1__
是uint8循环右移
这些名称都是ida的定义,可以在ida根目录\plugins\defs.h
中详细查看:
(我tm一开始没注意v10的计算同时包含左移和右移,我眼瞎,以为都是__ROL4__
)
第五部分:求a[i+4]
a[i+4][j] = a[i][j] ^ v10[j]
求四个byte,合起来一个int.
按字节异或和按int异或其实是等同的,所以简化为:
a[i+4] = a[i] ^ v10
归纳
程序输入4个int,然后通过32次循环,每次循环求出一个input[i+4]
这里的input不完全代表输入,input[0]到input[3]是输入,但是此后的input[4]到input[35]都是求出来的。
验证input[32],input[33],input[34],input[35]是否和main中的v9~v12相等。
为了不影响理解,我把input[]这个数组起个别名:数组a[]
我们把代数式整合一下:
1 | v12 = a[i+1] ^ a[i+2] ^ a[i+3] ^ dword_408A40[i] |
对于上面的算式,我们已知的有dword_408A40[]
,byte_404100[]
,a[32]~a[35]
我们需要求出的是a[0]~a[3]
所以先求v12,再求v11,再求v10,最后求a[i],直到倒着求出a[0]~a[3]
脚本
脚本没整理,有些臃肿,大家将就看吧。
1 | ''' |
结果有两组,分别是int和uint(内存中存储的十六进制是相同的)