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