
0x00 前言
- 题目是
TWCTF-reverse_box,题目下载链接如下:
0x01 程序分析
- 主要由两个函数来解题。
1 | int __cdecl main(int a1, char **a2) |
1 | int __cdecl sub_804858D(_BYTE *a1) |
题目提示如果传入正确的Flag则会输出
95eeaf95ef94234999582f722f492f72b19a7aaf72e6e776b57aee722fe77ab5ad9aaeb156729676ae7a236d99b1df4但是分析题目, 题目会取当前时间作为随机数种子,然后取一堆随机数执行一堆操作。
由于当前时间在不断变化,所以这个随机数种子是不固定的,所取的随机数也不固定,这就对解题产生了很大的困难。
但是查看这个算法函数
sub_804858D的汇编代码,发现了惊喜!

- 所取的随机数最后会跟
0xFF进行按位与运算,这就会使此时eax的值只能取0-255其中一个,也就是说我们的v10只能取0-255中的一个,这就为我们执行爆破提供了可能。
0x02 写脚本前的分析
既然我们想进行爆破,但因为由于时间的变化随机数种子一直变会,
v10也会一直变,所以我们直接控制v10。那么该如何控制
v10呢?我们可以通过gdb脚本来在每次给v10赋值的时候进行暗箱操作。

而这个赋值的时候通过IDA能够找到,就是图中
0x080485B1的位置,因此我们需要在这个位置下个断点。该如何暗箱操作? 既然赋值是通过eax寄存器来实现的,那么我们可以通过
set $eax 计数器的形式来改变eax的值,计数器的范围就是0~255。而且根据要求,还需要满足首先输出
0x95(因为题中用的printf("%02x", *((unsigned __int8 *)&v4 + a2[1][i]));,所以输出出来只有95)。我们来看
printf这附近的汇编代码。

- 依然是用eax寄存器来传值,又因为
printf是在一个for循环里面,如果第一次输出的是95,则爆破成功,否则就让计数器+1 再来一遍~

- 爆破成功以后我们就能得到这个
a2[1][?]里面的内容了,从而就能逆出flag。
0x03 脚本的实现
1 |
|

- 通过
define 脚本名称来新建一个脚本。 - 通过
脚本名称来调用一个脚本。

- 运行脚本得到如下结果

得出flag
- 通过结果再结合题意逆出flag,脚本如下(Python)
1 | # -*- coding: UTF-8 -*- |

