open-source write up
前两道逆向的题目,我们已经尝试使用了一些逆向必备工具,如IDA Pro、Ollydbg等等,但是在二进制逆向学习除了灵活使用工具外,强大的代码分析能力也是必备的技能之一。那么今天这道非常简单基础的逆向题目open-source,就是一道不需要使用太多工具,直接考察代码分析能力的题目。
本题需要的技巧:
- 简单C语言代码阅读能力
- 简单python脚本书写能力(二进制学习需要对python有基础了解,有基本脚本书写能力,会让你的做题速度提升很多)
- 一颗细致的心嘿嘿嘿
那么我们直接来看看今天的题目。
下载附件拿到一段C语言源代码:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
if (argc != 4) {
printf("what?\n");
exit(1);
}
unsigned int first = atoi(argv[1]);
if (first != 0xcafe) {
printf("you are wrong, sorry.\n");
exit(2);
}
unsigned int second = atoi(argv[2]);
if (second % 5 == 3 || second % 17 != 8) {
printf("ha, you won't get it!\n");
exit(3);
}
if (strcmp("h4cky0u", argv[3])) {
printf("so close, dude!\n");
exit(4);
}
printf("Brr wrrr grr\n");
unsigned int hash = first * 31337 + (second % 17) * 11 + strlen(argv[3]) - 1615810207;
printf("Get your key: ");
printf("%x\n", hash);
return 0;
}
代码不多,运行之后程序打印“what?”,没有什么用处。那么我们仔细看一下代码。
通常来说我们拿到一段代码,都先从main函数开始分析,
int main(int argc, char *argv[]) {
if (argc != 4) {
printf("what?\n");
exit(1);
}
这时候我们发现这一段是迷惑代码,char 根本没有使用。那么关键代码到底在哪儿呢。
printf("Get your key: ");
printf("%x\n", hash);
看到这最后一段,它告诉我们Key就是hash。那我们找到hash。
unsigned int hash = first * 31337 + (second % 17) * 11 + strlen(argv[3]) - 1615810207;
现在得知我们要想知道hash
,需要求到first
,second
和strlen(argv[3])
的值。我们再往上看看代码,有提到那三个变量。
求first的源代码:
unsigned int first = atoi(argv[1]);
if (first != 0xcafe) {
printf("you are wrong, sorry.\n");
exit(2);
}
如此我们可以知道,first就是0xcafe。注意,一定要看清楚不是cafe,而是一个16进制的数字,它才是first的值。
求second的源代码:
unsigned int second = atoi(argv[2]);
if (second % 5 == 3 || second % 17 != 8) {
printf("ha, you won't get it!\n");
exit(3);
}
看到了如果(second % 5 == 3 || second % 17 != 8)
,则输出“ha, you won’t get it!”。也就是说,需要second % 5 != 3 && second % 17 != 8
。我们可以暂时取一个值second==25
(随便取了一个满足条件的最小的数)。
求strlen(argv[3])的源代码:
if (strcmp("h4cky0u", argv[3])) {
printf("so close, dude!\n");
exit(4);
}
直接可以知道argv[3]==“h4cky0u”,strlen(argv[3])=7。
三个值都知道了,我们就可以计算hash了。注意:计算过程中可以有比较大的数字出现,使用C语言可能导致溢出得到错误答案,我们在这里使用python脚本进行运算。
为什么用python不会溢出而C语言会?
在python3后,统一使用了长整型,长整型不存在溢出问题,即可以存放任意大小的整数。这也是吸引科研人员的一部分了,适合大数据运算,不会溢出,也不会有其他语言那样还分短整型,整型,长整型…而在C 语言中,整型所表示的大小是有范围的,但是 python 代码是保存到文本文件中的。
那么就可以写python脚本啦:
first = 0xcafe
second = 25
argv = "h4cky0u"
hash = first * 31337 + (second % 17) * 11 + len(argv) - 1615810207
print(hash)
运行得到结果:12648430,但是这不是flag。为什么呢?
关注一下这一行代码:
printf("%x\n", hash);
明白了,%x需要我们以16进制的方式输出,我们可以直接在网上转化,也可以在python中使用 print(hex(hash))
,得到结果长得就很像flag的flag:0xc0ffee。
注意:结果中的0xc0ffee的0x说明这个数是16进制的数字,并不是数字部分。