1 . havetea
IDA:
左边是主函数里可以找到的,可以发现首先让输入key,且为16个长度,并且把输入的key分成两段进行了两次加密;在加密函数crypto里,是一个简单TEA运算,只不过IDA抽风把 +=delta 翻译成了 -=补码;crypto又把输入的数据截成两段进行运算,使用的key可以在程序里找到;之后用加密数据进行比较;
知晓key和加密后的数据使用对应解密方式解密:
1 | for(i=0;i<32;i++) |
解密后得到输入为:please_drink_tea
之后又让输入32长度的内容进行加密,并且用之前输入的16长度作为第二次加密cry的密钥;可以看出这次32长度的内容被分成了4段进行cry加密,而cry其实是和第一次的crypto差不多的TEA运算;加密完之后进行数据比较;
对应解密方式:
1 | for(i=0;i<32;i++) |
解密后得到:flag{c616454f52a6334273b5f455a10ef818}
2.maze
IDA:
通过字符串搜索,找到主要函数,可以看到通过输入的v2来与v3进行 domaze 函数运算;右图为 domaze 函数,可以看出这是个三线迷宫,迷宫整体由v3控制,输入的v2代表玩家移动方向;
通过调试可知,这是个指针制作的迷宫,前24位每8位代表一个方向,第25位开始往后是控制数;比如地址0x112E86A 为1,对应0x112E860处的方向的控制数,当这个控制数为 1 的时候,根据 domaze 函数的计算规则可知,会触发 sub_4C6470 结束函数;而最后一个 0 是代表是否走过这个路口,走过之后会变成 1;
之后通过这个规则去逆推回去:(这些是地址低三位)
正着写回去便是:rrrrtltltlllltlltrtrrr;
md5之后得到:flag{988b0f23719099efcbd66586a168bab9}
3.rota
IDA:
最上面图展示了最终的比较数据;中间左边的图则是一开始的base64编码,下面的图展示了base64的变种码表;中间右边的图展示了最后是生成了一个BOX,用BOX与base64编码后的内容进行加密;
中间有BOX的生成内容,但是无关紧要,因为生成的数据和输入的内容无关,所以是固定的,BOX也就是固定的;
所以只需要破解这个加密就能够得出最终结果;
以上为crypt函数的内容;
调试加分析加软磨硬泡得出爆破代码的核心内容:
1 | for v10 in range(66): |
然后和原代码一样,该循环几次循环几次,该有几个有几个;
得出base64编码后的内容为:cAJ7BzX+6zHrHwnTc/i7Bz6f6t6EBQDvc/xfHt9d6S9XX
再base64解码一遍:
得到:flag{8cdd01062b7e90dd372c3ea9977be53e}
4.gocode
IDA:
gocode提示了这是go语言写的,所以搜索函数main_main找到主函数,通过右上角的图可知输入总长度为37,且是由 PCL{} 括起来的;
看到while(1)和switch 再根据题目名称,可知道这是个类似VM的东西,而根据docode变量可知第一站经过的便是右下角图中的函数,作用是把flag括起来的32个长度内容两两拼接成十六进制数,一共变成16个;
然后便是对不同指令码对应操作进行翻译:
逻辑就是每次经过AA开始判断,如果错误就退出程序,直到走完全部的code码就算成功;
把翻译的写成代码然后用z3来解:(重要代码)
1 | s = Solver() |
解出数字后换成十六进制再拼写在一起便得到:PCL{bdcc4f46d73ec09ee628633d2f227b47}
5.analgo
IDA:
第一眼看去会和上道题很像,也是类似虚拟机的构造,v23是指令,main_anal函数是虚拟机函数,下面的十六进制数是比较数据,判断输入的长度是42;
但是由于这个VM反编译出很多控制数不好分析各个指令码在做什么,同时发现输入是包含flag{}的,且每输入一个,比较结果也对应的变换一个,称之为一一对应;(蓝线是对应关系)
可以看到随着 flag{ 的输入,每输入一个,RCX 和 RDX 就相同一个字节;
那么可以使用之前hgame中 hardasm 题目的解法,将加密后的RCX值输出,与比较数据判断从而爆破;
先把判断搞掉,全nop,直接进入输出 wrong(SecondBC) 的地方;之后修改原程序比较的地方,改为将加密数据放到 SecondBC 这个地方:
但因为 SecondBC 是 rdata段的,拥有只读权限,所以要修改权限:
搜索 .rdata,将 40 00 00 40 改为 40 00 00 C0;
之后写代码爆破:(使用subprocess模组)
1 | import subprocess |
由于这个程序是 8字节 8字节来比较的,所以手动多调几次,传入之前先 add rsi 8 获取之后的加密数据;
然后每轮都改下cur_index += 8;
然后得到:flag{568a3cdd-77e1-4c42-9fee-127e27a5744e}
6.puzzle
一开始发现是个加壳程序,跑一遍发现和UPX加壳很像,一开始是循环解码,然后进入原入口;用PE也显示其为UPX加壳,但是提示不能用指令脱壳;
使用十六进制查看器发现原UPX标记处被改为了vmp,将其改回并用指令对其脱壳;
之后进去过后看IDA:
在scanf之后的是一段循环,通过调试可以知道,这里允许通过 0 ~ 9 字符,并且一共输入56个,否则失败;
这段循环将输入的56个数字放到一些地址里,而地址原来就有些数据;填完之后一共是 9*9 = 81个数据;
然后来到判断 judge 函数,这里它将这81个内容作为参数传入;
经过调试呢,可以发现,输入的内容中,有些是不能重复的,而且不能有 0 ;这可以让想起数独游戏;
把里面给的数据拿出来做成 9 * 9 的数独表,然后进行求解:
解出输入的56个内容为:76135283549798674164925733849217386455934161872359295314
输入源程序之后,便得到: flag{23c3cb3aedbbfdd009d1bf52e530676a}