buu-reverse-CrackRTF
核心知识点
本题因为是hash类型的加密,因此无法用动态调试的方法获得答案(hash不可逆,只能暴力枚举)
用到以下几个额外的必须知识点:
- rtf文件头格式:
{\rtf1\ansiHello!\parThis is some {\b bold} text.\par}
- wincrpytoAPI的加密类型:https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id
- 安装下载resource_hack软件,用于提取.exe文件
- python的hashlib的使用方法
- hash(不可逆算法)分类
password1
使用了wincrpyto库,经过查询是sha1加密,加密后要和6E32D0943418C2C33385BC35A1470250DD8923A9一致
wincrpytoAPI的加密类型:https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id
因为只有六位数字因此进行爆破即可,有两种方法:
- 用python 的hashlib进行爆破(用其他语言类似)
- 直接用网站查
但是很多网站查不到,使用hashlib进行爆破
import hashlib
# sha1的结果默认是小写表示的
goal = '6E32D0943418C2C33385BC35A1470250DD8923A9'.lower()
for i in range(100000,1000000):
s = str(i)+"@DBApp"
sha = hashlib.sha1(s.encode()) # 转成bytes类型
cnt = sha.hexdigest() # hexdigest获取hash值
if goal == cnt:
print(str(i)) # 123321
password2
关键代码分析
关键代码(本质上最外层是两个判断,这是第二个,第一个是hash判断,复杂度太高,爆破几乎没可能),资源文件使用resource_hacker打开找到AAA文件
大致含义就是把 输入的字符串每一位与AAA文件的对应位进行异或操作,结果保存到资源指针
// ipstring是输入的第二个字符串 a2是资源文件 a3是资源字节大小
unsigned int __cdecl sub_401420(LPCSTR lpString, int a2, int a3)
{
unsigned int result; // eax
unsigned int i; // [esp+4Ch] [ebp-Ch]
unsigned int v5; // [esp+54h] [ebp-4h]
v5 = lstrlenA(lpString);
for ( i = 0; ; ++i )
{
result = i;
if ( i >= a3 )
break;
*(_BYTE *)(i + a2) ^= lpString[i % v5];
}
return result;
}
其中lpString组成(_main()中调用的):password2 + password1 + @DBApp
之后在写入dbapp.rtf文件
char __cdecl sub_4014D0(LPCSTR lpString)
{
LPCVOID lpBuffer; // [esp+50h] [ebp-1Ch]
DWORD NumberOfBytesWritten; // [esp+58h] [ebp-14h]
DWORD nNumberOfBytesToWrite; // [esp+5Ch] [ebp-10h]
HGLOBAL hResData; // [esp+60h] [ebp-Ch]
HRSRC hResInfo; // [esp+64h] [ebp-8h]
HANDLE hFile; // [esp+68h] [ebp-4h]
hFile = 0;
hResData = 0;
nNumberOfBytesToWrite = 0;
NumberOfBytesWritten = 0;
hResInfo = FindResourceA(0, (LPCSTR)0x65, "AAA");
if ( !hResInfo )
return 0;
nNumberOfBytesToWrite = SizeofResource(0, hResInfo);
hResData = LoadResource(0, hResInfo);
if ( !hResData )
return 0;
lpBuffer = LockResource(hResData);
sub_401005(lpString, (int)lpBuffer, nNumberOfBytesToWrite);
hFile = CreateFileA("dbapp.rtf", 0x10000000u, 0, 0, 2u, 0x80u, 0); //看这里
if ( hFile == (HANDLE)-1 )
return 0;
if ( !WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, &NumberOfBytesWritten, 0) ) //看这里
return 0;
CloseHandle(hFile);
return 1;
}
思路分析
来仔细考虑一下这个异或内容怎么反向得到password1:
- lpString:password2 + password1 + @DBApp
- a2:AAA文件的内容可以使用resource_hack得到
- result:最后的结果要保存成rtf文件,而rtf文件前六位是固定的{\rtf1
已知二三条的数据,可以反向异或得到password2
即可 result = ipstring ^ a2 => result ^ a2 == ipstring ^ a2 ^ a2 == ipstring
因此 ipstring = result ^a2
注册机
ipstring = ''
a2 = [0x05, 0x7D, 0x41, 0x15, 0x26, 0x01]
result = "{\\rtf1"
for i in range(len(a2)):
x = ord(result[i]) ^ a2[i]
ipstring += chr(x)
print(ipstring) # ~!3a@0
得到flag
根据IDA分析_main()->sub_40100F()的内容
可以知道最后把一个内容保存进了dbapp.rtf文件,而题目提示有说flag就在一个rtf文件中。
因此运行原程序,依次输入两段password
- 123321
- ~!3a@0
打开生成的dbapp.rtf文件答案赫然在列flag为:flag{N0_M0re_Free_Bugs}