此次比賽就作了這一道逆向題,看到隊友的WP,下面的對v10的加密方式爲RC4,從我提取的v4數組就可以察覺出這是CR4了,本身傻乎乎的用OD調試,跟蹤數據半天才作出來,仍是見得的少了... ...下面有幾篇不錯的RC4的文章:html
C語言實現:https://zhoujianshi.github.io/articles/2016/RC4%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95/index.htmlc++
Python實現:https://specters.top/2019/03/01/Python%E5%AE%9E%E7%8E%B0RC4/git
文件下載:https://www.lanzous.com/i76vcne數組
獲取信息app
int __cdecl main(int argc, const char **argv, const char **envp) { _DWORD *v4; // [esp+1Ch] [ebp-A0h] int v5; // [esp+20h] [ebp-9Ch] int v6; // [esp+24h] [ebp-98h] int v7; // [esp+28h] [ebp-94h] int v8; // [esp+2Ch] [ebp-90h] char v9; // [esp+30h] [ebp-8Ch] int v10; // [esp+50h] [ebp-6Ch] int v11; // [esp+70h] [ebp-4Ch] sub_402620(); v5 = 1701148529; v6 = 101; v7 = 0; v8 = 0; v4 = malloc(0x408u); puts("Plz solve the puzzle:"); sub_40ED00("%32s", &v9); if ( (unsigned __int8)sub_401C70(&v9) && (sub_401B60((int)&v10, &v9), sub_401850(v4, (int)&v5, strlen((const char *)&v5)), sub_4018D0(v4, &v10, 8), (unsigned __int8)sub_401950(&v10)) ) { sub_401BA0(&v9, (int)&v11); sub_40ED20("Congrats!\n%s\n", &v11); } else { puts("Failed!"); } return 0; }
經過分析,要獲得flag,則須要if中的條件成立ide
if ( (unsigned __int8)sub_401C70(&v9) && (sub_401B60((int)&v10, &v9), sub_401850(v4, (int)&v5, strlen((const char *)&v5)), sub_4018D0(v4, &v10, 8), (unsigned __int8)sub_401950(&v10)) )
打開sub_401C70(&v9)函數函數
int __cdecl sub_401C70(char *a1) { char *v2; // edx if ( strlen(a1) != 16 ) return 0; v2 = a1; while ( (unsigned __int8)(*v2 - 58) > 38u && (unsigned __int8)(*v2 - 48) <= 54u )// 輸入的字符串每一個字符都是'a'~'f'或者'0'~'9'之間 { if ( ++v2 == a1 + 16 ) // 遍歷到字符串末尾結束,輸入字符串長度爲16 return 1; } return 0; }
由於&&符號後面是( func1, func2, func3)形式的判斷條件,所以我先直接看func3便可(func3決定條件是否成立),打開sub_401950(&v10)函數加密
bool __cdecl sub_401950(_BYTE *a1) { _BYTE *v1; // ecx bool result; // al v1 = a1; while ( 2 ) { switch ( *v1 ) { case 0: dword_40F028 &= dword_40F038; dword_40F02C *= dword_40F028; goto LABEL_4; case 1: if ( !dword_40F02C ) goto LABEL_6; dword_40F028 /= dword_40F02C; dword_40F024 += dword_40F034; goto LABEL_4; case 2: dword_40F030 ^= dword_40F034; dword_40F03C += dword_40F020; goto LABEL_4; case 3: dword_40F03C -= dword_40F030; dword_40F030 &= dword_40F024; goto LABEL_4; case 4: dword_40F034 *= dword_40F020; dword_40F02C -= dword_40F038; goto LABEL_4; case 5: dword_40F020 ^= dword_40F02C; dword_40F038 -= dword_40F03C; goto LABEL_4; case 6: if ( !dword_40F03C ) goto LABEL_6; dword_40F034 |= dword_40F024 / dword_40F03C; dword_40F024 /= dword_40F03C; goto LABEL_4; case 7: dword_40F038 += dword_40F028; dword_40F034 |= dword_40F024; goto LABEL_4; case 8: dword_40F020 *= dword_40F02C; dword_40F030 -= dword_40F03C; goto LABEL_4; case 9: dword_40F028 += dword_40F034; dword_40F02C ^= dword_40F030; LABEL_4: if ( ++v1 != a1 + 8 ) continue; result = (dword_40F038 == 231) + (dword_40F034 == 14456) + (dword_40F030 == 14961) + (dword_40F02C == -13264) + (dword_40F028 == 16) + (dword_40F024 == 104) + (dword_40F020 == -951) == 7; if ( dword_40F03C != -239 ) goto LABEL_6; break; default: LABEL_6: result = 0; break; } return result; } }
經過分析,這就是將v10的每一位進行switch選擇,對一組數據進行更改,最後要知足要求,才能返回1。spa
所以,獲得v10的值成爲了這道題的關鍵,又由於v10的每一個數都是0~9之間,且長度爲8,我直接暴力求解。
#include <bits/stdc++.h> #pragma warning(disable:4996) #define _DWORD unsigned int #define _BYTE char using namespace std; bool __cdecl sub_401950(_BYTE* a1) { _BYTE* v1; // ecx bool result; // al int val_0 = 0x0A; int val_1 = 0x8A; int val_2 = 0x1A1; int val_3 = 0x12A; int val_4 = 0x269; int val_5 = 0x209; int val_6 = 0x68; int val_7 = 0x39F; int val_8 = 0x2C8; v1 = a1; while (2) { switch (*v1-48) { case 0: val_3 &= val_7; val_4 *= val_3; goto LABEL_4; case 1: if (!val_4) goto LABEL_6; val_3 /= val_4; val_2 += val_6; goto LABEL_4; case 2: val_5 ^= val_6; val_8 += val_1; goto LABEL_4; case 3: val_8 -= val_5; val_5 &= val_2; goto LABEL_4; case 4: val_6 *= val_1; val_4 -= val_7; goto LABEL_4; case 5: val_1 ^= val_4; val_7 -= val_8; goto LABEL_4; case 6: if (!val_8) goto LABEL_6; val_6 |= val_2 / val_8; val_2 /= val_8; goto LABEL_4; case 7: val_7 += val_3; val_6 |= val_2; goto LABEL_4; case 8: val_1 *= val_4; val_5 -= val_8; goto LABEL_4; case 9: val_3 += val_6; val_4 ^= val_5; LABEL_4: if (++v1 != a1 + 8) continue; result = (val_7 == 231) + (val_6 == 14456) + (val_5 == 14961) + (val_4 == -13264) + (val_3 == 16) + (val_2 == 104) + (val_1 == -951) == 7; if (val_8 != -239) goto LABEL_6; break; default: LABEL_6: result = 0; break; } return result; } } int main() { char* s = (char*)malloc(10); for (long i = 10000000; i < 100000000; ++i) { sprintf(s, "%08ld", i); //cout << s << endl; if (sub_401950(s)) { cout << i << endl; system("PAUSE"); } } system("PAUSE"); return 0; }
獲得v10的值
獲得v10值後,不能得到有關輸入字符串的相關信息,打開前面的函數sub_401B60(&v10, &v9)
int __cdecl sub_401B60(int a1, _BYTE *a2) { _BYTE *v2; // ebx int i; // esi char v4; // ST08_1 _BYTE *v5; // ST00_4 int result; // eax v2 = a2; for ( i = a1; *v2; result = sub_40ED40(v5, "%02X", v4) ) { v4 = i; v5 = v2; v2 += 2; ++i; } return result; }
可以猜想到,v9加密爲十六進制,存儲到v10中,(若是v9="0123456789abcdef",則v10=0x0123456789abcdef。經過後面OD調試,也可以發現。)
打開sub_401850(v4, &v5, strlen((const char *)&v5))函數
int __cdecl sub_401850(_DWORD *a1, int a2, int a3) { int v3; // eax int v4; // edi unsigned int *v5; // ebx int v6; // ecx int result; // eax unsigned int v8; // esi char v9; // dl unsigned int *v10; // edx v3 = 0; v4 = (int)(a1 + 2); *a1 = 0; a1[1] = 0; do { *(_DWORD *)(v4 + 4 * v3) = v3; ++v3; } while ( v3 != 256 ); v5 = a1 + 2; v6 = 0; LOBYTE(result) = 0; do { v8 = *v5; v9 = *(_BYTE *)(a2 + v6++) + *v5; result = (unsigned __int8)(v9 + result); v10 = (unsigned int *)(v4 + 4 * result); *v5 = *v10; *v10 = v8; if ( v6 >= a3 ) v6 = 0; ++v5; } while ( v5 != a1 + 258 ); return result; }
這裏在生成V4數組,我從OD中提取出來
0x00, 0x00, 0x71, 0x12, 0x62, 0x31, 0x4D, 0x97, 0x14, 0x0D, 0xED, 0xA3, 0xD6, 0xFC, 0xF1, 0x3B, 0x3C, 0x33, 0xB5, 0x22, 0xA2, 0x1A, 0x17, 0x1D, 0x98, 0x91, 0x06, 0x2A, 0x8B, 0x23, 0xE6, 0x55, 0x46, 0x3A, 0x65, 0x28, 0x30, 0x39, 0xD4, 0x0C, 0x01, 0x2D, 0x25, 0x10, 0x09, 0x8F, 0x6A, 0x3F, 0x44, 0xD8, 0x6D, 0xC5, 0xA6, 0x72, 0x07, 0x83, 0x40, 0xC6, 0x8E, 0x1F, 0x77, 0x61, 0x96, 0x4A, 0x08, 0xFE, 0x53, 0x5A, 0xA1, 0xDF, 0xB6, 0x67, 0x66, 0x5C, 0x57, 0xB8, 0xD3, 0x11, 0x52, 0x21, 0xCC, 0x56, 0x2E, 0xC2, 0x88, 0xAA, 0xF9, 0x20, 0x7A, 0x6F, 0x4E, 0x76, 0xE8, 0xC1, 0xD5, 0xBD, 0xCE, 0x9E, 0x38, 0x95, 0x50, 0xF2, 0x9F, 0xB2, 0x9A, 0x0B, 0x47, 0x16, 0x60, 0xBF, 0xFD, 0x92, 0x35, 0x89, 0xDA, 0xFF, 0x9B, 0xBA, 0x13, 0xAB, 0xF4, 0x79, 0x87, 0xAC, 0x8C, 0x73, 0x84, 0xB3, 0x0E, 0xC8, 0x26, 0xA5, 0xE7, 0x15, 0xE9, 0xC3, 0x69, 0x70, 0xE0, 0x68, 0x42, 0x81, 0xCD, 0xEB, 0xDE, 0x7D, 0xEF, 0xD0, 0x24, 0x00, 0xF0, 0x41, 0xA0, 0xEE, 0x05, 0x94, 0x85, 0xBB, 0x43, 0x02, 0xF7, 0xC0, 0xD1, 0x1B, 0x7F, 0x5B, 0xEC, 0xF6, 0x2B, 0x1E, 0xE2, 0x27, 0xFB, 0x78, 0x54, 0x58, 0xE4, 0x32, 0xDB, 0xB7, 0xC7, 0x90, 0x7C, 0xF8, 0x5D, 0x5F, 0x63, 0xBE, 0x2C, 0x0A, 0xDD, 0x9C, 0x75, 0x19, 0xC4, 0xA8, 0x86, 0x36, 0xBC, 0x8D, 0xD7, 0x7B, 0xB4, 0x5E, 0x3E, 0xA7, 0xB1, 0xE1, 0x59, 0x82, 0xB9, 0xAE, 0xD9, 0x7E, 0xAF, 0xCF, 0x9D, 0xF5, 0xFA, 0x48, 0x4F, 0xA9, 0x6C, 0x64, 0x6E, 0x49, 0x4B, 0x6B, 0x29, 0x45, 0xE5, 0x04, 0xA4, 0x4C, 0x34, 0x80, 0xD2, 0x3D, 0xE3, 0x99, 0x37, 0xDC, 0x93, 0xC9, 0xCA, 0xCB, 0xEA, 0xB0, 0x0F, 0x03, 0x8A, 0xF3, 0x51, 0x1C, 0xAD, 0x74, 0x18, 0x2F
打開 sub_4018D0(v4, &v10, 8)函數
_DWORD *__cdecl sub_4018D0(_DWORD *a1, _BYTE *a2, int a3) { int v3; // edx int v4; // ecx int v5; // esi _BYTE *v6; // ebx int v7; // edi unsigned int *v8; // eax int v9; // edx _DWORD *v10; // ebp _DWORD *v11; // ST00_4 unsigned int v12; // ebp _DWORD *result; // eax v3 = *a1; v4 = a1[1]; v5 = (int)(a1 + 2); if ( a3 > 0 ) { v6 = a2; v7 = *a1; do { v7 = (unsigned __int8)(v7 + 1); v8 = (unsigned int *)(v5 + 4 * v7); v9 = *v8; v4 = (unsigned __int8)(*v8 + v4); v10 = (_DWORD *)(v5 + 4 * v4); v11 = v10; v12 = *v10; *v8 = v12; *v11 = v9; *v6++ ^= *(_DWORD *)(v5 + 4 * (unsigned __int8)(v9 + v12)); } while ( v6 != &a2[a3] ); v3 = v7; } result = a1; *a1 = v3; a1[1] = v4; return result; }
這裏利用v4數組,對v10的每一位進行異或運算。
這個函數執行後,就是最後一個函數,剛剛咱們暴力解出了61495072,v10 = '\x06\x01\x04\x09\x05\x00\x07\x02',所以咱們可以對v10的每一位進行異或,獲得v10加密前的值。
原本是準備利用提取出的v4,代入函數計算出v10的值,可是沒成功,哈哈哈!後面發現v4的值其實是固定的,不會受到輸入的影響而且我只須要知道*v6異或的值便可。所以,我在OD中調試,記錄異或的值。
0x7c, 0x0AB, 0x2D, 0x91, 0x2F, 0x98, 0x0ED, 0xA9
咱們可以寫出腳本
num = [0x7c, 0x0AB, 0x2D, 0x91, 0x2F, 0x98, 0x0ED, 0xA9] v10 = '\x06\x01\x04\x09\x05\x00\x07\x02' flag = [] n = 0 for i in v10: flag.append(hex(ord(i) ^ num[n])) n = n + 1 print(flag)
['0x7a', '0xaa', '0x29', '0x98', '0x2a', '0x98', '0xea', '0xab']
組合起來,獲得v9通過十六進制加密後的v10=0x7aaaa29982a98eaab
所以咱們可以獲得v9="7aaa29982a98eaab",輸入到程序中獲得flag。
flag{5cb92582-66a8-e5b7-d3bf-3b99df8ac7f0}