- 来源:Root-Me
- 题型:Cracking
- 题目:ELF - CrackPass
- 分数:30 Points
前言
【Cracking : ELF - Ptrace】的进阶版,区别在于:无法从静态源码中查看代码地址了~
其实除了不方便打断点之外,逆向流程还是一样的,不算太难。
不过两题的知识点还是共通的,建议先做【Cracking : ELF - Ptrace】。
试错
开启挑战后下载压缩包 ch8.zip ,解压后得到脚本 Crack 。
放到 Linux 上直接运行,发现给定不同的密码有不同的提示:
- 若无密码,如执行命令
./Crack, 提示You must give a password for use this program ! - 若密码有特殊字符,如执行命令
./Crack exp-blog.com, 提示Bad password ! - 若密码无特殊字符,如执行命令
./Crack exp, 提示Is not the good password !

执行命令 gdb Crack 开启调试器,但是输入命令 layout asm 后却没有显示汇编源码。

执行命令 r 开始调试代码,此时才显示汇编源码,但是提示 Don't use a debuguer ! 。
至此我们获得三个信息:
- 源码地址只有在代码运行时才能查看,增加了打断点调试的难度
- 程序被加壳了,需要绕过调试器检测
- 一个常量字符串
Don't use a debuguer !

绕过壳
由于我们看不到代码的静态地址,因此就无法在 Don't use a debuguer ! 之前打断点进行绕过,此时要换个思路。
输入命令 info file 可以列出文件每个段的入口地址,其中 .text 是代码段的入口,亦即 main 函数的入口。
可以看到代码段的地址范围为 0x08048440 - 0x0804877c

执行命令 break *0x08048440 在入口地址打个断点,然后输入命令 r exp 开始调试 。
此处随便使用一个无特殊字符的密码
exp,是为了绕过Bad password !分支,后面用 IDA 一看源码时就知道为什么要这样做了。此处直接用无特殊字符的密码只是为了简化调试过程。
明显程序在入口位置中断了,我们看到了 main 函数入口 __libc_start_main@plt ,且还没有提示 Don't use a debuguer ! ,说明我们在检测点之前刹车了。问题是,检测点在哪 ?

此时同步在 Windows 下用 IDA 打开 Crack 文件。
找到 main 函数的代码附近有一个 jns short loc_804869F 跳转语句 (补全地址为 0x0804869F),该语句的其中一个分支就是 Don't use a debuguer ! 。
因此现在的目标就是在 Linux 的 dbg 下找到这个位置进行绕过。
在 dbg 下通过键盘 ↓ 滚动代码,很快找到 jns 0x804869f 语句,由于这是要绕过的语句,因此在其前一条语句 test %eax,%eax 打断点。
因其地址为 0x804868a ,输入命令 break *0x804868a 。

执行命令 c 让代码继续运行,在语句 test %eax,%eax 处中断。
此时输入命令 info reg 查看寄存器 eax 的值为,得知为 -1 。
若如常执行,由于 test 的结果为负数,即 SF 符号位会被置 1 ,jns 判断后必定会流转到 Don't use a debuguer ! 分支。
要改变分支走向,就需要在此时通过修改寄存器 eax 的值,间接改变 SF 符号位。
输入命令 set $eax=0 即可绕过。
找到密码
修改寄存器后,先不忙着执行代码,否则即使绕过了 debuguer 判定,由于密码是错的,程序还是会直接执行到 Is not the good password ! 的分支。
现在的目标是找到密码判定的位置,让程序中断在那里。
从 IDA 查看代码,接下来应该是会流转到 call sub_80485A5 模块,双击可以跳转到这个模块。

在这个模块里,很快就发现 call _strcmp 语句,以及其后的正确 / 错误密码的分支。
虽还有一个
Bad password !分支,但综合前面分析已经知道,因为这次调试输入的密码没有特殊字符,所以不用管这个分支。
唯一的问题是,没有这个语句的地址,不能直接打断点。
但是我们找到在其前面不远处的子模块入口地址 loc_80485E8 ,即 0x080485E8 。

回到 Linux 的 gdb ,输入命令 break *0x080485E8 打上断点,然后执行命令 c 让程序继续运行。
此时从 gdb 的源码已经可以直接看到密码比较语句 call 0x804842c <strcmp@plt> 了,其地址为 0x8048617 。
执行命令 break *0x8048617 在此处打上断点,然后执行命令 c 让程序运行到此处。
剩下的事情就简单,只需要查看比较函数 strcmp 的两个入参即可,必定有一个是正确密码。
须知道函数是存储在栈空间的,而栈指针为 esp ,因此先执行命令 x/8wx $esp 可以查到 esp 指针所指向栈顶的前 8 个地址。
在通过 x/s 地址 命令逐个地址查看,发现前两个地址就是 strcmp 函数入参。
其中一个是输入的密码,另一个是真正的密码,完成挑战。


答案下载
flag 下载后的 flagzip 的文件需要手动更改后缀为
*.zip,然后解压即可(为了避免直接刷答案)