BUU reverse xxor

 

下载下来的是个elf文件,因为懒得上Linux,直接往IDA里扔,

切到字符串的那个窗口,发现Congratulation!,应该是程序成功执行的表示,

 

 双击,按‘x’,回车跟入

 

 找到主函数:

 1 __int64 __fastcall main(__int64 a1, char **a2, char **a3)
 2 {
 3   signed int i; // [rsp+8h] [rbp-68h]
 4   signed int j; // [rsp+Ch] [rbp-64h]
 5   __int64 v6; // [rsp+10h] [rbp-60h]
 6   __int64 v7; // [rsp+18h] [rbp-58h]
 7   __int64 v8; // [rsp+20h] [rbp-50h]
 8   __int64 v9; // [rsp+28h] [rbp-48h]
 9   __int64 v10; // [rsp+30h] [rbp-40h]
10   __int64 v11; // [rsp+40h] [rbp-30h]
11   __int64 v12; // [rsp+48h] [rbp-28h]
12   __int64 v13; // [rsp+50h] [rbp-20h]
13   __int64 v14; // [rsp+58h] [rbp-18h]
14   __int64 v15; // [rsp+60h] [rbp-10h]
15   unsigned __int64 v16; // [rsp+68h] [rbp-8h]
16 
17   v16 = __readfsqword(0x28u);
18   puts("Let us play a game?");
19   puts("you have six chances to input");
20   puts("Come on!");
21   v6 = 0LL;
22   v7 = 0LL;
23   v8 = 0LL;
24   v9 = 0LL;
25   v10 = 0LL;
26   for ( i = 0; i <= 5; ++i ) //以&v6为首地址,获取并写入6个32位的WORD型数据
27   {
28     printf("%s", "input: ", (unsigned int)i);
29     __isoc99_scanf("%d", (char *)&v6 + 4 * i);
30   }
31   v11 = 0LL;
32   v12 = 0LL;
33   v13 = 0LL;
34   v14 = 0LL;
35   v15 = 0LL;
36   for ( j = 0; j <= 4; j += 2 ) //以&v11为首地址,将之前获取的数据经sub_400686处理之后写入
37   {
38     dword_601078 = *((_DWORD *)&v6 + j);  //每次取相邻的两个
39     dword_60107C = *((_DWORD *)&v6 + j + 1);
40     sub_400686((unsigned int *)&dword_601078, &unk_601060); //将其中更地位的数据的地址传入
41     *((_DWORD *)&v11 + j) = dword_601078; //将处理之后的值写回原地址
42     *((_DWORD *)&v11 + j + 1) = dword_60107C;
43   }
44   if ( (unsigned int)sub_400770(&v11) != 1 )  //检查函数,判断你的输入是否正确
45   {
46     puts("NO NO NO~ ");
47     exit(0);
48   }
49   puts("Congratulation!\n");
50   puts("You seccess half\n");
51   puts("Do not forget to change input to hex and combine~\n");
52   puts("ByeBye");
53   return 0LL;
54 }

函数很简单,执行的流程也可以说是一目了然。

我们先看sub_4006770:

 

总共6个值,已经给出来了3个,剩下三个组了一个很友善的三元一次方程组,贼良心。

 

 结果已经有了,下面就是根据sub_400686逆推正确的输入:

 

 这个算法有点把子意思,反正我是看的去有些晕。但这不重要,也不需要去做什么深入分析,强行逆转就好。

加法变减法,代码的执行顺序完全倒转,至于异或了的再来一次

核心部分也就是那个for循环处理之后也就是这样:

1 v5 = 0x458BCD42*64;
2   for ( i = 0; i <= 63; ++i )
3   {
4      v4 -= (v3 + v5 + 20) ^ ((v3 << 6) + a2[2]) ^ ((v3 >> 9) + a2[3]) ^ 0x10;
5 
6     v3 -= (v4 + v5 + 11) ^ ((v4 << 6) + *a2) ^ ((v4 >> 9) + a2[1]) ^ 0x20;
7    
8     v5 -= 0x458BCD42;
9   }

最终的脚本:

 1  unsigned int i = 0, j = 0, sum = 0;
 2     unsigned int a[6] = { 0xDF48EF7E ,0x20CAACF4,0,0,0,0x84F30420 };
 3     unsigned int temp[2] = { 0,0 }, date[4] = { 2,2,3,4 };
 4     char* p = (char*)&a;
 5     a[2] = 0x84A236FF / 2 + 0xFA6CB703 / 2 + 0x42D731A8 / 2 + 1;
 6     a[3] = a[2] - 0x84A236FF;
 7     a[4] = a[2] - 0x42D731A8;
 8     for (i = 0; i < 6; i++) printf("a[%d] = 0x%x \n", i, a[i]);
 9     for (i = 0; i < 5; i += 2) {
10         temp[0] = a[i]; temp[1] = a[i + 1];
11         sum = 0x458BCD42 * 64;
12 
13         for (j = 0; j < 64; j++) {
14             temp[1] -= (temp[0] + sum + 20) ^ ((temp[0] << 6) + date[2]) ^ ((temp[0] >> 9) + date[3]) ^ 0x10;
15             temp[0] -= (temp[1] + sum + 11) ^ ((temp[1] << 6) + date[0]) ^ ((temp[1] >> 9) + date[1]) ^ 0x20;
16             sum -= 0x458BCD42;
17         }
18         a[i] = temp[0];
19         a[i + 1] = temp[1];
20     }
21     putchar(10);
22     for (i = 0; i < 24; i += 4) printf("%c%c%c", p[i + 2], p[i + 1], p[i]);
23 
24     // putchar(10);
25     //for (i = 0; i < 24; i++) printf("%c", p[i]); 
26   //最开始我是按逐字符输出的虽然看起来他应该是个flag,但顺序不对:“alf r{g i_e g_s aer }!t ”
27     //putchar(10);
28     //for (i = 0; i < 24; i += 4) printf("%c%c%c%c", p[i + 3], p[i + 2], p[i + 1], p[i]); //调换大小端之后,发现好要去掉空格:“ fla g{r e_i s_g rea t!}”
29    

最后:

get flag: flag{re_is_great!}

 

posted @ 2020-06-22 18:50  批某人  阅读(203)  评论(0)    收藏  举报