1. IDA 打开程序,main 函数反汇编,大概逻辑是输入三次的字符串到 s 中。前两次只可以输入 2 个字符和4 个,第三次输入的是拼接在前两次后面。
下面会经过一个判断,通过之后就会将 data 中的数据经过输入异或之后的运算,写入到 flag.jpg 中。
data:
通过判断,输入的传入到 hash 函数里:
v3 =( v9 == 20 &&hash(s) == 3522040383264150944LL);
hash 函数:
__int64 __fastcall hash(char *a1) { char *v1; // rax char *v3; //[rsp+0h] [rbp-18h] signed __int64 v4;// [rsp+10h] [rbp-8h] v3 = a1; v4 = 5381LL; while ( *v3 ) { v1 = v3++; v4 = 33 * v4 + *v1; } return v4; }
第一种思路
所以第一种思路就是逆向这个算法,找到这个原来的字符串,但是我这垃圾逆向功底完全就搞不定这个算法。只能用取巧的方法来做了。
这里也可以使用 Z3 来约束求解,但是貌似也跑不出结果。
第二种思路
因为已知程序程序输出会错误输出是两个不同的提示,所以可以尝试一下使用 angr 来通过符号执行的方法来解题。
if ( stream ){ ... puts("yougot my secret photo"); }else{ puts("hakerhaker go away"); }
直接载入,添加 find 路径和 avoid 路径,开始跑。。
这里没跑出来,应该是没有限制路径和一些约束条件,但这不妨是一种思路。
第三种思路
因为发现到最后是将输入的 s 在长度值(v9)的偏移和 data 异或,然后输出到 jpg 文件中。因为我们知道最后的结果是 jpg 文件,那么可以通过 JPG 的文件头部特征,和 data 进行异或,就可以得到原始的 s 的值。
例如,我们知道 jpg 文件头的 magic number 为:FFD8FFE0,和这里的 data 开头:8CB28B95 进行异或,就可以得到前四位为 "sjtu"
以此类推,我们找到一个正常的 jpg 文件,对他的头部 20 个字节和 data 的 20 个字节进行异或就行了,最后得到的 s 的值为:
sjtu93hechangeschina
直接输入就会在当前目录下生成一个 flag.jpg 文件。
打开就可以得到最后的 flag。