去年校赛的题目
- 当时没做出来….后来也没做出来,今天平台更新,抱着试试看的心理答了这道题
- 难度还可以接受,因为是在实现一个很正常的汇编,所以可以看懂
逻辑分析
- 主函数逻辑很简单,输入flag后验证长度是否能被3整除,随后传入函数中,进行加密的操作,然后一个逐字符比较
1 | int __cdecl main() |
加密函数1
- 进入第一个函数,按照顺序翻译,我们发现,函数前后有两个函数,大概如下
- 变量我都是重命名过的,实际上可以看出来这个函数的作用就是在实现push和pop,对应的我们可以将里面用到的全局变量改下名字.
1 | int __cdecl sub_8048567(int a1) |
- 然后我们其实可以看出来,这个加密函数的头部就是在做push ebp \ mov ebp,esp的操作
- 随后esp-=48,开了48字节的空间,然后将字符串mov到虚拟栈内,注意小端序,字符串是”feeddeadbeefcafe”
- 随后就是愉快的循环加密了,ebp-12位置就是循环的下标i,循环次数为字符串的长度
- 其他的运算就可以直接翻译了,还要注意的是一个函数
1 | unsigned int __cdecl sub_80485AB(unsigned int a1) |
- 传入的变量a1是刚才栈内的key的长度,reg_i可以从循环内看出其实是循环的下标,然后配合上(ebp - 29),其实就是在取key[i%len]
- 下面是整理过的运算
1 | int __cdecl sub_8048633(int input, unsigned int len) |
- 可以分析得程序在进行flag[i]^key[i%len(key)]的操作
加密函数2
- 除去此函数的头尾部分的push/pop操作,直接分析关键函数体
- 两个for循环,第一层循环是3轮,第二层循环次数不能直接看出来
- 但是我们可以发现,循环内部在ida一贯反编译for循环的形式上,比较range的if-break结构的前面居然还有一些东西
- 分析这段代码后我们得知,这个值其实是一个定值orz,这是在实现一个(0x55555556*i)>>32等价于i/3的一个操作
- flag长度为54,从check循环可以看出来.
- 现在得知内层循环一共是18次,(ebp-4)是i,(ebp-8)是j,随后继续分析函数
1 | void __cdecl sub_80488C7(int input, int out, int len) |
- 原来这是一个打乱flag的操作
- 那么整理好加密顺序,首先异或加密,然后打乱flag,直接对应恢复就好了
放上脚本
1 | flagenc1 = [0, 3, 9, 58, 5, 14, 2, 22, 15, 31, |