目錄
just reverse it

IDA打开程序,查看start函数C伪代码。

首先来看第一个for循环,它将输入的16个字符分成4部分。v12占20字节,用来存放大小为16字节的str,sub_402573是MD5计算函数,将4个部分的MD5值存放在64字节大小的v6中。具体对应关系如下图(每一格表示一个字节)。

如何看出sub_402573函数是MD5算法,进入该函数,看到两个函数,进入第一个,有一些初始赋值的操作,猜测为MD5。再返回来看v6,v6占64个字节,分成四部分就是16字节,每个字节包含两个十六进制,刚好每部分可以存一个MD5值,进一步猜测为MD5算法。于是动态调试进行验证。

将程序丢入od,在call sub_402573的地方下断点,运行程序,输入“1234567890123456”,继续运行,跟踪v6所在的内存,如下图,发现与“1234”、“5678”、“9012”、“3456”的MD5值相同,验证猜测。

接着到了strtol函数,这是一个C语言库函数。这里的意思是将v12的值转化为十六进制,中间的参数‘0’表示不返回非法字符串,意味着输入的每个字符应该是十六进制字符,否则每一部分可能就少于4个字符。由图2可知v12[3]+3、v12[2]+2、v12[1]+1、v12刚好对应每一部分字符串。

sub_4025b1函数,v12[3]+3 > v12[2]+2 > v12[1]+1 > v12 > 999,保证输入顺序。

sub_402513函数,是这道题最复杂的地方。首先来看传参,a1为输入值的一部分,a2为该部分的MD5值。关于小头位序存储方式,例如1234存为0x 34 12。因此,a2>>4即为MD5值的第一个字符,a2&0xF为第二字符,(a2+1)>>4为第三个字符,(a2+1)&0xF为第四个字符,这里只取MD5前四个字符作比较。

数字+48和字母+87是将十六进制转为assic码(ord(‘0’-0)=48,ord(‘a’-a)=87)。

v3是int型,占四个字节,分别为LOBYTE、BYTE1,、BYTE2、BYTE3。因此是将MD5值的3241与原字符串1234作比较,相等则为真。

最后和固定字符串进行异或得到flag,编写脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import hashlib
import sys
from Crypto.Util.strxor import *
for i in "0123456789abcdef":
for j in "0123456789abcdef":
for k in "0123456789abcdef":
for l in "0123456789abcdef":
md5=hashlib.md5()
md5.update((i+j+k+l).encode('utf8'))
if md5.hexdigest()[:4]==l+j+i+k:
sys.stdout.write(i+j+k+l)

v3 = "d\x01@flQAizAST\biTB"
a = "31795a469327c6e6"
flag = strxor(v3,a)

print "\nflag{%s}"%flag

输入字符串为”31795a469327c6e6”,flag为:flag{W0w_Y0u_Crack_1t}

文章作者: kangel
文章鏈接: https://j-kangel.github.io/2018/12/10/reverse/
版權聲明: 本博客所有文章除特別聲明外,均採用 CC BY-NC-SA 4.0 許可協議。轉載請註明來自 KANGEL