buu-SimpleRev
unsigned __int64 Decry()
{
char cChar; // [rsp+Fh] [rbp-51h]
int v2; // [rsp+10h] [rbp-50h]
int v3; // [rsp+14h] [rbp-4Ch]
int i; // [rsp+18h] [rbp-48h]
int keyLength; // [rsp+1Ch] [rbp-44h]
char src[8]; // [rsp+20h] [rbp-40h]
__int64 v7; // [rsp+28h] [rbp-38h]
int v8; // [rsp+30h] [rbp-30h]
__int64 v9; // [rsp+40h] [rbp-20h]
__int64 v10; // [rsp+48h] [rbp-18h]
int v11; // [rsp+50h] [rbp-10h]
unsigned __int64 v12; // [rsp+58h] [rbp-8h]
v12 = __readfsqword(0x28u);
*(_QWORD *)src = 'SLCDN';
v7 = 0LL;
v8 = 0;
v9 = 'wodah';
v10 = 0LL;
v11 = 0;
text = join(key3, (const char *)&v9); // killshadow
strcpy(key, key1);
strcat(key, src); // ADSFKNDCLS
v2 = 0;
v3 = 0;
getchar();
keyLength = strlen(key);
for ( i = 0; i < keyLength; ++i )
{
if ( key[v3 % keyLength] > '@' && key[v3 % keyLength] <= 'Z' )
key[i] = key[v3 % keyLength] + 32;
++v3;
}
printf("Please input your flag:", src);
while ( 1 )
{
cChar = getchar();
if ( cChar == '\n' )
break;
if ( cChar == ' ' )
{
++v2;
}
else
{
if ( cChar <= '`' || cChar > 'z' ) // 不属于a-z的范围
{
if ( cChar > '@' && cChar <= 'Z' ) // 如果出现大写字母
str2[v2] = (cChar - 39 - key[v3++ % keyLength] + 'a') % 26 + 'a';
}
else
{
str2[v2] = (cChar - 39 - key[v3++ % keyLength] + 'a') % 26 + 'a';
}
if ( !(v3 % keyLength) )
putchar(' ');
++v2;
}
}
if ( !strcmp(text, str2) )
puts("Congratulation!\n");
else
puts("Try again!\n");
return __readfsqword(0x28u) ^ v12;
}
这里需要注意大小端存储的问题。例如src由于是小端存储的,因此需要倒过来。其他的顺着原来的代码分析逆向即可。exp中flag的每一位都进行枚举判断即可。
key = list("adsfkndcls")
text = list("killshadow")
ll="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
a=0
flag=''
while(a<len(text)):
for i in ll:
if((ord(i)-39-ord(key[a])+ord('a'))%26+ord('a')==ord(text[a])):
flag+=i
a+=1
break
print(flag)
buuoj CrackRTF
int main_0()
{
DWORD v0; // eax
DWORD StringLen; // 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 ) // pbData=123321
{
printf("Must be 6 characters!\n");
ExitProcess(0);
}
v4 = atoi((const char *)&pbData);
if ( v4 < 100000 )
ExitProcess(0);
strcat((char *)&pbData, "@DBApp"); // pbData=123321@DBApp
v0 = strlen((const char *)&pbData);
sub_40100A(&pbData, v0, &String1);
if ( !_strcmpi(&String1, "6E32D0943418C2C33385BC35A1470250DD8923A9") )// String1 = 6E32D0943418C2C33385BC35A1470250DD8923A9 (sha1)
{
printf("continue...\n\n");
printf("pls input the first passwd(2): ");
memset(&String, 0, '\x01\x04');
scanf("%s", &String);
if ( strlen(&String) != 6 )
{
printf("Must be 6 characters!\n"); // String : Pwd Target
ExitProcess(0);
}
strcat(&String, (const char *)&pbData); // String = Pwd+'123321@DBApp'
memset(&String1, 0, 0404u);
StringLen = strlen(&String);
sub_401019((BYTE *)&String, StringLen, &String1);// calc md5 val(String) -> String1
if ( !_strcmpi("27019e688a4e62a649fd99cadaafdb4e", &String1) )
{
if ( !sub_40100F(&String) )
{
printf("Error!!\n");
ExitProcess(0);
}
printf("bye ~~\n");
}
}
return 0;
}
要求两个密码,第一个字符串有40位。先进入sub_401230看看,传入的String参数是第二组的密码+"123321@DBApp"的值,继续分析:
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;
}
可以看到是一堆内置好的加密函数,其中CryptCreateHash函数的第二个参数是0x8004,找到官方文档,是sha1。
https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id


由此可以推断,6E32D0943418C2C33385BC35A1470250DD8923A9就是第一组密码+"@DBApp" 的sha1值,由于只有六位,爆破即可,得到123321.
第二个加密是md5,但是爆破失败。先继续往下分析。sub_40100F传入的参数是
char __cdecl sub_4014D0(LPCSTR TarString)
{
LPCVOID rtfFile; // [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;
rtfFile = LockResource(hResData);
sub_401005(TarString, (int)rtfFile, nNumberOfBytesToWrite);
hFile = CreateFileA("dbapp.rtf", 0x10000000u, 0, 0, 2u, 0x80u, 0);
if ( hFile == (HANDLE)-1 )
return 0;
if ( !WriteFile(hFile, rtfFile, nNumberOfBytesToWrite, &NumberOfBytesWritten, 0) )
return 0;
CloseHandle(hFile);
return 1;
}
/*
以下为sub_401005的关键代码:
/*
v5 = lstrlenA(TarString);
for ( i = 0; ; ++i )
{
result = i;
if ( i >= rtfFileLength )
break;
*(_BYTE *)(i + rtfFile) ^= TarString[i % v5];
}
return result;
使用Resource Hacker打开这个文件,得到:

根据代码,程序会最终输出一个dbapp.rtf的文件,并将其与传入的String异或。
由于rtf文件头已知({\rtf1)因此,可以计算出String的前六位,即第二组6位密码。
exp:
lockedrtf=[0x05,0x7d,0x41,0x15,0x26,0x01]
rtfhead=list("{\\rtf1")
ff=""
for i in range(0,len(rtfhead)):
ff+=chr(lockedrtf[i]^ord(rtfhead[i]))
print(ff)
得到第一组密码~!3a@0,输入程序,即可在生成的rtf文件中找到flag。

Comments | NOTHING