RCTF2018 babyre WriteUp
题目给了一个压缩包,里面有两个文件
out文件
这种题型应该就是得到算法后枚举,与正确输出的out作比较
那么首先拿IDA看一下吧
IDA分析
先搜索一下字符串吧
可以看到这些有用的提示,使用交叉引用到汇编指令
用图形化看一下(最后一张有一点歪了,请原谅)
main函数 0x08048B49
比较长,挑重点
返回输出流程 0x804882B
注意到那个红色的报错了吗,是的,我们现在无法F5
显示sp分析失败
经过搜索学习,明白了这种问题一般都是堆栈不平衡导致的,因此我们需要手动调整栈指针
首先 菜单栏OPtions->General
打上勾
然后回到汇编窗口,找到loc_80848CBB
观察发现,lea和retn处的栈指针都是00,导致问题的出现,因此我们应该运用堆栈平衡原理,将其平衡
具体来说,想要修改一个位置的指针,需要将鼠标指向这个指针的上一个指针,然后 Alt+K
将里面的0x9C修改为0x0,确认
现在堆栈平衡,就可以F5了
当然了,还可以选择GDB动态调试,在出错这里下断点,然后步入看汇编,但因为对汇编看的还不是很熟悉,GDB也不常接触,于是只能F5了(流下没技术的泪水)
算法分析
F5看一下
主函数判断输入格式,v4处可以看到,是将其八位即四字节一组(int大小为2字节,8/2=4)进行分组
然后sub_804882B内是回显
sub_8048A41和sub_8048980不太清楚是干嘛的,应该是初始化和转换之类的
算法位于sub_80488E0内
先记住sub_80488E0(&v6, 0xA72BE4C1, 0x1D082C23, seed, v4, v3);,后面有用
内部
看到一个30次的循环,嵌套sub_804868B
进去看看
现在整个算法的全貌就展示在了我们面前
逐位循环0x20F次换算成四字节一组也就是0x20F/4=0x7F
于是我们只需要从0x20到0x7F进行枚举,按照相应算法对out进行比较即可,注意80488E0一开始传入的两个字符串需要互换然后合并
解题脚本如下
#include <stdio.h> #include <string.h> #include <stdint.h> uint32_t foo(uint32_t a1, uint64_t a2) // sub_804868B { int j; uint64_t v5; uint32_t in; in = a1; for (j = 0; j <= 527; ++j) { v5 = a2 >> (j & 0x1F); if (j & 0x20) v5 = v5 >> 32; //高低位转换 in = (in >> 1) ^ ((v5 ^ in ^ (in >> 16) ^ (0x5C743A2E >> (((in >> 1) & 1) + 2 * (2 * (((in >> 20) & 1) + 2* (2 * (in >> 31) + ((in >> 26) & 1))) + ((in >> 9) & 1))))) << 31); } return in; }
int main() { uint32_t data[30] = // out { 0xB80C91FE,0x70573EFE, 0xBEED92AE,0x7F7A8193, 0x7390C17B,0x90347C6C, 0xAA7A15DF,0xAA7A15DF, 0x526BA076,0x153F1A32, 0x545C15AD,0x7D8AA463, 0x526BA076,0xFBCB7AA0, 0x7D8AA463,0x9C513266, 0x526BA076,0x6D7DF3E1, 0xAA7A15DF,0x9C513266, 0x1EDC3864,0x9323BC07, 0x7D8AA463,0xFBCB7AA0, 0x153F1A32,0x526BA076, 0xF5650025,0xAA7A15DF, 0x1EDC3864,0xB13AD888 }; int i; uint32_t j; for (i = 0; i < 30; i++) for (j = 0x20; j < 0x7F; j++) //0x20F/4=0x7F if (foo(j, 0x1D082C23A72BE4C1) == data[i]) //互换,合并 printf("%c", j); printf("\n"); return 0; }
|
Flag
解出: RCTF{Kee1o9_1s_a1ready_so1ved}