攻防世界逆向高手题之dmd-50
继续开启全栈梦想之逆向之旅~
这题是攻防世界逆向高手题的dmd-50
下载附件,照例扔入exeinfope中查看信息:
64位ELF文件,无壳,照例扔入IDA64位中查看伪代码,有main函数看main函数:
看到一堆变量,一堆系统函数,我知道系统函数通常不是考点,可这系统函数多到我都差点找不到主要代码:
突然看见字符串Enter the valid key!\n 猜测题型是与用户输入相关的判断型flag。
代码分析:
v43 = __readfsqword(0x28u); //一个内存段偏移,无用
std::operator<<<std::char_traits<char>>(&std::cout, "Enter the valid key!\n", envp);
std::operator>><char,std::char_traits<char>>(&edata, v42);
std::allocator<char>::allocator(&v38);
std::string::string(v39, v42, &v38); // v42 输入复制给 v39。这里借鉴了别人的博客,这里犯下第一个错误,因为系统函数太多了,我也就只注意到了下面的md5,没去查这个函数用法,结果这个函数是赋值函数,也是关键
md5((MD5 *)v40, (const std::string *)v39); //一个md5加密函数, 把 v39 进行 MD5 后保存在 v40,我记得C语言没有md5函数的,这里可能是调用了外部的库函数
v41 = std::string::c_str((std::string *)v40);
std::string::~string((std::string *)v40);
std::string::~string((std::string *)v39);
std::allocator<char>::~allocator(&v38);
继续分析判断语句:
if ( *(_WORD *)v41 == 0x3837 //这里犯下第二个错误,这里本来是14390的整数的,这里类型是16位WORD,后面都是8位的BYTE,也就是这里应该分出一个*(_BYTE *)v41和*(_BYTE *)(v41 + 1)的,可是我不会分,想起数在内存中是小端的十六进制数,就改为了十六进制,那么前面(_BYTE *)v41就是0x37,后面*(_BYTE *)(v41 + 1)就是0x38了。
&& *(_BYTE *)(v41 + 2) == 0x30
&& *(_BYTE *)(v41 + 3) == 0x34
&& *(_BYTE *)(v41 + 4) == 0x33
&& *(_BYTE *)(v41 + 5) == 0x38
&& *(_BYTE *)(v41 + 6) == 0x64
&& *(_BYTE *)(v41 + 7) == 0x35
&& *(_BYTE *)(v41 + 8) == 0x62
&& *(_BYTE *)(v41 + 9) == 0x36
&& *(_BYTE *)(v41 + 10) == 0x65
&& *(_BYTE *)(v41 + 11) == 0x32
&& *(_BYTE *)(v41 + 12) == 0x39
&& *(_BYTE *)(v41 + 13) == 0x64
&& *(_BYTE *)(v41 + 14) == 0x62
&& *(_BYTE *)(v41 + 15) == 0x30
&& *(_BYTE *)(v41 + 16) == 0x38
&& *(_BYTE *)(v41 + 17) == 0x39
&& *(_BYTE *)(v41 + 18) == 0x38
&& *(_BYTE *)(v41 + 19) == 0x62
&& *(_BYTE *)(v41 + 20) == 0x63
&& *(_BYTE *)(v41 + 21) == 0x34
&& *(_BYTE *)(v41 + 22) == 0x66
&& *(_BYTE *)(v41 + 23) == 0x30
&& *(_BYTE *)(v41 + 24) == 0x32
&& *(_BYTE *)(v41 + 25) == 0x32
&& *(_BYTE *)(v41 + 26) == 0x35
&& *(_BYTE *)(v41 + 27) == 0x39
&& *(_BYTE *)(v41 + 28) == 0x33
&& *(_BYTE *)(v41 + 29) == 0x35
&& *(_BYTE *)(v41 + 30) == 0x63
&& *(_BYTE *)(v41 + 31) == 0x30 )
后面判断后的结果按照以前经验转成ASCII字符,发现都是成功失败类的字符串,那这里的系统函数作用应该只是简单的赋值和输出吧,就不用深究了:
所以思路清晰了,对用户输入进行md5加密后一位一位比较,那么我们用md5后的值在在线工具中反向解密即可。
脚本:
key1=[0x37,0x38,0x30,0x34,0x33,0x38,0x64,0x35,0x62,0x36,0x65,0x32,0x39,0x64,0x62,0x30,0x38,0x39,0x38,0x62,0x63,0x34,0x66,0x30,0x32,0x32,0x35,0x39,0x33,0x35,0x63,0x30]
md=""
for i in key1:
md+=chr(i)
print(len(md))
print(md)
md5结果:
在线解密网址:
https://www.cmd5.com/
额,我们不需要两次解密,一次就可以了,所以对grape再加密一次:
结果:b781cbb29054db12f88f08c6e161c199
。
。
。
。
。
PS:我在修改14390整数时突然发现我的IDA7.5有撤销功能!!(狂喜.jpg),快捷键一样是Ctrl+Z:
看见没,这里有个undo,是撤销!!太棒了!,不知道是那一版本IDA开始新增的功能!
。
。
。
总结:
1:
这里犯下第一个错误,因为系统函数太多了,我也就只注意到了下面的md5,没去查这个函数用法,结果这个函数是赋值函数,也是关键。
2:
这里犯下第二个错误,这里本来是14390的整数的,这里类型是16位WORD,后面都是8位的BYTE,也就是这里应该分出一个*(_BYTE
)v41和(_BYTE *)(v41 + 1)的,可是我不会分,想起数在内存中是小端的十六进制数,就改为了十六进制,那么前面(_BYTE )v41就是0x37,后面(_BYTE *)(v41 + 1)就是0x38了。
解毕!敬礼!