逆向 十二月 04, 2019

从一道简单的逆向题到入门

文章字数 7.5k 阅读约需 7 mins. 阅读次数 0

从一道简单的逆向题到入门

前言:

Blog重建,丢失好多帖子,找个机会补一篇Linux的逆向分析入门,给小白入门学习用,大佬绕过。

朋友喊帮忙看看,就顺手写下一篇逆向入门教程吧
聊天记录

分析

初步分析

文件信息:

file-info

可以看到从命令行里传入两个参数,第一个就是该执行文件的当前path,第二个就是传入另一个文件,如果存在能打开那么就将输入重定向到infile, 否则重定向到stdin,也就是标准输入。
ida1

补充:

变量 信息
stdin 0 标准输入
stdout 1 标准输出
stderr 2 标准错误

initialize_bomb

此函数设置一个信号量
initialize_bomb函数

read_line

read_line函数就对输入做一下简单的处理,读取一行。因为之前有输入有可能是从文件获取,同时获取一下环境变量GRADE_BOMB的值。
read_line

phase_1

这个就拿输入和aWhyMakeTrillio全局变量做了一个比较so我们直接去拿下来就行了
phase1.1

phase_1

如果不等于这个值就会执行explode_bomb函数,直接退出程序
explode

phase_2

读入6个数,然后前三个等于后个不相等则退出
phase_2

read_six_numbers

so 我们输入1 2 3 1 2 3就可以了

phase_3

是不是看着很吓人,实际上不要慌,他就一张switch表,我们先倒着看
phase_3

这里比较了var_11和al不相等则结束,
phase3.1

这里赋值了eax为’q’,也就控制了刚才的al,同时修改了var_10为84,但是进入条件是case 1
phase3.3

这里进行输入赋值由于是64位的,通常顺序是rdi, rsi, rdx, rcx, r8, r9, 栈
phase3.2

结合上面的简单分析,我们需要输入 1 q 84就能通过,实际上还可以看看其他表是做啥都差不多

phase4

就是输入一个数,然后经过一个func4计算后和这个0x375F00比较不相等就退出,
phase4

我们看看func4函数
实际上就一个递归计算阶乘很简单,imul指令是相乘嘛。
我们爆破一下就知道了
func4

可以看到结果就是10
result

phase5

就把我们的输入当作索引取这个数组里面取值然后做比较需要等于ravens
phase5

phase5.1

这是结果但这里有个坑,只能输入如6个字符,11是两个字符了,所以这里我们可以借pwntools来简单处理一下,比较方便
phase5.2

phase5.3

phase5.4

phase6

继续看这个函数用func6计算一个node后结果在循环加8,总共加8次。
phase6

我们看看func6函数,看上去计算有点点复杂,不过这里有个小技巧,我们的输入没有去参加计算,而是直接比较,so我们直接动态下个断点,dump出计算好的值就可以了,在上面那个图我们可以看见计算好的结果指针放在rax里面。
func6

so,解决问题
phase6.1

crack

到这里我们以及成功完成了6个函数的破解,但有个细节
phase_defused看第一张图,我们发现有这个函数存在,跟进去看发现可能是个隐藏关卡
phase_defused

phase_defused

进入此函数需要该全局变量等于6
phase_defused.1

我们在回头仔细去看一下read_line函数
read_line2

read_line里面把读入的字符串存放在这个input_strings全局变量里面,也就是每次最多读入80个字节,也就是num_strings_input就是用来计入第几次读入,也就是第6关结束,我们总的输入了6次就进入了这个隐藏关卡。

我们在来看看隐藏关卡:
default_parse

先补充一些sscanf函数:

int sscanf(const char *buffer, const char *format, [ argument ] ...);
// 其实很简单,就是把buffer的字符串,按照format指定的格式,解析到参数argument里面去

所以也就是把a1地址处的字符串,解析出一个整数,和一个字符串,其中字符串必须要等于austinpowers,
我们在看看a1的地址:0x6031B0
a1_addr

在看看read_line函数处理的input_strings的地址:0x6030C0
input_strings_addr

按照read_line函数的计算,(0x1B0-0xC0)/0x50=3,从0开始算起,也就是我们需要在第四次输入的时候,得多输入一个austinpowers这里前面有个空格,因为要满足%d %s的格式,而第四次输入整好是第四关,而他的答案也正好只是一个整数,这样我们就能进入secret_phase函数。

secret_phase函数:
secret_phase

补充:

long int strtol(const char *nptr,char **endptr,int base);
//就是将一个字符数字,转成一个长整型

也就是输入一个整数,通过func7来与n1地址处的值进行计算结果等于0就能过关

看看func7:
func7

其实很简单就是我们输入的数不等于0,同时等于n1即可。
n1:0x24
n1

Perfect result:
perfect_result

附上EXP:

from pwn import *
#
context.log_level = "DEBUG"
#
io = process("./bomb8")
io.recv()
io.sendline("Why make trillions when we could make... billions?")
io.recv()
io.sendline("1 2 3 1 2 3")
io.recv()
io.sendline("1 q 84")
io.recv()
io.sendline("10 austinpowers")
io.recv()
io.sendline("2534\x0b1")
io.recv()
# gdb.attach(io)
# io.interactive()
io.sendline(str(0x70000008d))
io.recv()
io.sendline(str(0x24))
io.recv()

题目下载

bomb8

0%