buuctf 逆向 crackrtf
首先查壳,没壳。ida打开,发现主函数
代码如下
int __cdecl main_0()
{
DWORD v0; // eax
DWORD v1; // eax
CHAR String; // [esp+4Ch] [ebp-310h]
int v4; // [esp+150h] [ebp-20Ch]
CHAR String1; // [esp+154h] [ebp-208h]
BYTE pbData; // [esp+258h] [ebp-104h]
memset(&pbData, 0, 0x104u);
memset(&String1, 0, 0x104u);
v4 = 0;
printf("pls input the first passwd(1): ");
scanf("%s", &pbData);
if ( strlen((const char *)&pbData) != 6 )
{
printf("Must be 6 characters!\n");
ExitProcess(0);
}
v4 = atoi((const char *)&pbData);
if ( v4 < 100000 )
ExitProcess(0);
strcat((char *)&pbData, "@DBApp");
v0 = strlen((const char *)&pbData);
sub_40100A(&pbData, v0, &String1);
if ( !_strcmpi(&String1, "6E32D0943418C2C33385BC35A1470250DD8923A9") )
{
printf("continue...\n\n");
printf("pls input the first passwd(2): ");
memset(&String, 0, 0x104u);
scanf("%s", &String);
if ( strlen(&String) != 6 )
{
printf("Must be 6 characters!\n");
ExitProcess(0);
}
strcat(&String, (const char *)&pbData);
memset(&String1, 0, 0x104u);
v1 = strlen(&String);
sub_401019((BYTE *)&String, v1, &String1);
if ( !_strcmpi("27019e688a4e62a649fd99cadaafdb4e", &String1) )
{
if ( !sub_40100F(&String) )
{
printf("Error!!\n");
ExitProcess(0);
}
printf("bye ~~\n");
}
}
return 0;
}
看主函数,输入两次密码,然后进行加密对比。
先看第一个,首先判断输入的是数字,并且要求是个六位数,然后
把第一个数据和"@DBApp"拼接,然后传入函数sub_40100A()
进入函数,查看反汇编代码
int __cdecl sub_401230(BYTE *pbData, DWORD dwDataLen, LPSTR lpString1)
{
int result; // eax
DWORD i; // [esp+4Ch] [ebp-28h]
CHAR String2; // [esp+50h] [ebp-24h]
BYTE v6[20]; // [esp+54h] [ebp-20h]
DWORD pdwDataLen; // [esp+68h] [ebp-Ch]
HCRYPTHASH phHash; // [esp+6Ch] [ebp-8h]
HCRYPTPROV phProv; // [esp+70h] [ebp-4h]
if ( !CryptAcquireContextA(&phProv, 0, 0, 1u, 0xF0000000) )
return 0;
if ( CryptCreateHash(phProv, 0x8004u, 0, 0, &phHash) )
{
if ( CryptHashData(phHash, pbData, dwDataLen, 0) )
{
CryptGetHashParam(phHash, 2u, v6, &pdwDataLen, 0);
*lpString1 = 0;
for ( i = 0; i < pdwDataLen; ++i )
{
wsprintfA(&String2, "%02X", v6[i]);
lstrcatA(lpString1, &String2);
}
CryptDestroyHash(phHash);
CryptReleaseContext(phProv, 0);
result = 1;
}
else
{
CryptDestroyHash(phHash);
CryptReleaseContext(phProv, 0);
result = 0;
}
}
else
{
CryptReleaseContext(phProv, 0);
result = 0;
}
return result;
}
可以看出是一个hash加密过程,判断对比字符串6E32D0943418C2C33385BC35A1470250DD8923A9
判断sh1加密,然后利用穷举法,得到输入参数
import hashlib
flag="@DBApp"
for i in range(100000,999999):
s=str(i)+flag
x=hashlib.sha1(s.encode())
cnt=x.hexdigest()
if ""in cnt:
print(cnt)
print(str(i)+flag)
得到第一个密码:123321
然后输入第二个密码,根据对比数据27019e688a4e62a649fd99cadaafdb4e
是32位,进入函数内部,大概可以猜测是md5加密,但是因为这个数据的限制条件是要求六位,穷举法不太靠谱,所以当时没思路了,之后注意到数据对比之后还用了sub_40100F()函数判断,然后进去瞅瞅,然后发现读取文件AAA内容
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;
}
把读取文件的内容和原本输入的第二个密码放入sub_401005(),打开函数发现加密,就是简单的异或,然后上图看出,生成了.rtf文件,突然有了思路,百度搜索.rtf的文件头,异或之后一定生成的是.rtf的文件头内容,查到.rtf文件头的前六位是"{\rtf1",现在关键是找到AAA这个文件的内容,最后看大佬博客,找到一个工具resource_hacker,把exe文件拖入,发现AAA内容,取前六位异或操作,得到第二次输入的密码
贴上脚本
s='{\\rtf1'
a=[0x05,0x7d,0x41,0x15,0x26,0x01]
flag=''
for i in range(6):
flag+=chr(ord(s[i])^a[i])
print(flag)
最后得到第二个密码:~!3a@0
最后执行文件,把两个密码依次输入,生成.rtf文件,打开文件,文件内容为flag.