题目清单
- QCTF asong
- 网鼎杯 blend
- hackergame2018 confused flxg
QCTF asong
这道题目逻辑理清楚之后其实很简单,所有的算法都是可逆的。比较坑的两点是sub_400D33函数很关键,但是IDA对它的反汇编一言难尽,要去看汇编;另外sub_400DB4函数其实是对数组的循环移位,一开始看真的没发现,后来看了官方writeup才反应过来,当然也有的大佬的writeup是爆破的,很强。逆向果然是一个考验耐心的工作。
分析sub_400DB4函数
对out中的数据做最后一步处理的关键代码
一开始没发现,后来看了别人的writeup发现,是一个数组向左循环移动三位的功能的代码,于是写出解密函 数如下:
1 |
|
得到结果如下
1 | 0x3d,0x85,0x3c,0x68,0x3c,0x3e,0xf5,0x43,0xa5,0x3d,0xa5,0x33,0x27,0x3e,0x76,0xf5,0x3c,0xf5,0x85,0x76,0xf5,0x68,0x13,0xf5,0x26,0x26,0xa5,0x85,0x3d,0xf5,0x7,0xa9,0x76,0x1d,0x3c,0x2d,0xf,0x68 |
分析sub_400D33函数
再往前是sub_400D33函数对输出字符串的处理,F5之后是如下代码,
上述反编译代码存在一些问题,直接看汇编发现是如下一段置换代码,肯定是可逆的。
1 | sub_400D33(unsigned char* a){ |
动态调试得到其加密置换的顺序如下
1 | 0->0x16->0x14->0x13->0xe->0x11->0x4->0x1e->0x1d->0x1c->0x1b->0x24->0x22->0x21->0x20->0x1f->0x25->0x23->0x1a->0x19->0x5->0x18->0xf->0x17->0x10->0xd->0xc->0x8->0x15->0xb->0xa->0x12->0x3->0x2->0x6->0x9->0x7->0x1->0 |
编写解密置换代码如下
1 |
|
结果如下
1 | 0x85,0x43,0x68,0x85,0xf5,0x26,0x3c,0x3d,0x27,0xf5,0x33,0x68,0x3e,0x3c,0x76,0x26,0xf5,0x76,0xa5,0xf5,0x13,0xa5,0x85,0xf5,0x3e,0xa5,0x2d,0x3d,0xf5,0x7,0x3c,0x76,0x1d,0x3c,0xf,0x68,0x85,0xa9 |
分析sub_400E54函数
再往前看对输出字符串的处理,为如下函数中的for循环部分
a1为输入字符串,我们进入sub_400936函数发现,是一段switch语句,如下
1 | int __fastcall sub_400936(char a1) |
这里写逆算法太麻烦,直接把这个函数复制下来,爆破。调试过程中发现每位符合条件的ascii码不确定,更具语义划定爆破范围。爆破代码如下:
1 |
|
结果如下:
1 | THAT_GIRL_SAYING_NO_FOT_YOUR_VINDICATE |
得到flag
最终flag有两个,如下
1 | QCTF{THAT_GIRL_SAYING_NO_FOT_YOUR_VINDICATE} |
网鼎杯 blend
这道题目主要是学习一下SSE指令集和用qemu模拟运行MBR并用gdb动态调试。
- 静态分析
把文件拖到IDA中,用16位汇编分析,发现其大概逻辑是先判断输入是否是flag开头,然后剩下的部分进行如下判断
但是”cmp edi, [edx+7DA8h]”这个语句中,被比较数无法确定,所以需要开动态调试确定
- 动态调试
用qemu模拟程序运行并用gdb attach进程进行调试,模拟程序运行的代码如下,-s使得这个程序可以attach
1 | qemu-system-i386 -s -drive format=raw,file=./main.bin |
然后打开gdb并执行以下命令
1 | (gdb) set architecture i8086 |
然后就可以开始下断点调试,由于MBR代码是从0x7c00处开始的,注意下断点的时候要把ida中显示的offset与起始位置相加。
1 | (gdb) b *0x7cB2 |
最后就可以根据这些数据编写爆破代码,这里借用z3求解器
1 | from z3 import * |
得到falg如下
1 | flag{mbr_is_funny__eh} |
hackergame2018 confused flxg
打开ida时添加参数-dCULTURE=al,就可以看到中文字符串如下
通过交叉引用定位到关键函数sub_14000498F如下
1 | void __usercall sub_14000498F(__int64 a1@<rbp>) |
在阅读上述代码的时候要注意将a1 + 36这个整体看作一个变量。于是编写解密函数
1 |
|
运行得到结果如下
1 | Zmx4Z3tDb25ncmF0dWxhdGlvbnNfVV9GaU5kX3RoZV90clVlX2ZsWGd9 |
是一个base64编码的字符串,解密得到flag
flxg{Congratulations_U_FiNd_the_trUe_flXg}
也可以写python脚本如下
1 | import base64 |
同样可以得到flag
flxg{Congratulations_U_FiNd_the_trUe_flXg}