攻防世界-逆向(elrond32、re2-cpp-is-awesome、hackme、流浪者)

张开发
2026/4/20 6:03:03 15 分钟阅读

分享文章

攻防世界-逆向(elrond32、re2-cpp-is-awesome、hackme、流浪者)
幻想成为ctf糕手的第四天elrond3232位无壳找到主函数并没有发现特别的还是得进入别的函数看int __cdecl main(int a1, char **a2) { if ( a1 1 sub_8048414(a2[1], 0) ) { puts(Access granted); sub_8048538((int)a2[1]); } else { puts(Access denied); } return 0; }这段函数的作用是验证输入的密钥将sub_8048414函数直接丢给ai就可以得到密钥isengardint __cdecl sub_8048414(_BYTE *a1, int a2) { int result; // eax switch ( a2 ) { case 0: if ( *a1 105 ) goto LABEL_19; result 0; break; case 1: if ( *a1 101 ) goto LABEL_19; result 0; break; case 3: if ( *a1 110 ) goto LABEL_19; result 0; break; case 4: if ( *a1 100 ) goto LABEL_19; result 0; break; case 5: if ( *a1 97 ) goto LABEL_19; result 0; break; case 6: if ( *a1 103 ) goto LABEL_19; result 0; break; case 7: if ( *a1 115 ) goto LABEL_19; result 0; break; case 9: if ( *a1 114 ) LABEL_19: result sub_8048414(a1 1, 7 * (a2 1) % 11); else result 0; break; default: result 1; break; } return result; }这段函数中则是主要的加密部分了循环密钥的字符和unk_8048760所存字符异或unk_8048760位小端序后三个字节是没用的删的时候需要注意有的一整个小端序中全为0x00int __cdecl sub_8048538(int a1) { int v2[33]; // [esp18h] [ebp-A0h] BYREF int i; // [esp9Ch] [ebp-1Ch] qmemcpy(v2, unk_8048760, sizeof(v2)); for ( i 0; i 32; i ) putchar(v2[i] ^ *(char *)(a1 i % 8)); return putchar(10); }最后使用代码得到flagdata1[0x0F,0x1F,0x04,0x09,0x1C,0x12,0x42,0x09,0x0C,0x44,0x0D,0x07,0x09,0x06,0x2D,0x37,0x59,0x1E,0x00,0x59,0x0F,0x08,0x1C,0x23,0x36,0x07,0x55,0x02,0x0C,0x08,0x41,0x0A,0x14]keybisengarddecrypted[]foriinrange(33):decrypted.append(data1[i]^key[i%8])print(bytes(decrypted).decode())#flag{s0me7hing_S0me7hinG_t0lki3n}re2-cpp-is-awesome64位无壳找到主函数主要内容在if中sub_400B56()是报错的地方所以要使if成立off_6020A0 双击可以知道是L3t_ME_T3ll_Y0u_S0m3th1ng_1mp0rtant_A_{FL4G}_W0nt_b3_3X4ctly_th4tdword_6020C0 是索引数组双击进入可以发现是小端序主要用处就是逐字符检查输入是否匹配off_6020A0中的特定字符__int64 __fastcall main(int a1, char **a2, char **a3) { char *v3; // rbx __int64 v4; // rax __int64 v5; // rdx __int64 v6; // rax __int64 v7; // rdx _BYTE *v8; // rax __int64 v10[2]; // [rsp10h] [rbp-60h] BYREF char v11[47]; // [rsp20h] [rbp-50h] BYREF char v12; // [rsp4Fh] [rbp-21h] BYREF __int64 v13; // [rsp50h] [rbp-20h] BYREF int v14; // [rsp5Ch] [rbp-14h] if ( a1 ! 2 ) { v3 *a2; v4 std::operatorstd::char_traitschar(std::cout, Usage: , a3); v6 std::operatorstd::char_traitschar(v4, v3, v5); std::operatorstd::char_traitschar(v6, flag\n, v7); exit(0); } std::allocatorchar::allocator(v12, a2, a3); std::string::basic_string(v11, a2[1], v12); std::allocatorchar::~allocator(v12); v14 0; v10[0] std::string::begin(v11); while ( 1 ) { v13 std::string::end(v11); if ( !(unsigned __int8)sub_400D3D(v10, v13) ) break; v8 (_BYTE *)sub_400D9A(v10); if ( *v8 ! off_6020A0[dword_6020C0[v14]] ) sub_400B56(); v14; sub_400D7A(v10); } sub_400B73(); std::string::~string(v11); return 0LL; }按下方代码解释就是取str[list]0除外然后连接起来这里没有选择删除0而是用计数的方式跳过0list[36,0,0,0,0,0,0,0,5,0,0,0,54,0,0,0,101,0,0,0,7,0,0,0,39,0,0,0,38,0,0,0,45,0,0,0,1,0,0,0,3,0,0,0,0,0,0,0,13,0,0,0,86,0,0,0,1,0,0,0,3,0,0,0,101,0,0,0,3,0,0,0,45,0,0,0,22,0,0,0,2,0,0,0,21,0,0,0,3,0,0,0,101,0,0,0,0,0,0,0,41,0,0,0,68,0,0,0,68,0,0,0,1,0,0,0,68,0,0,0,43,0,0,0]strL3t_ME_T3ll_Y0u_S0m3th1ng_1mp0rtant_A_{FL4G}_W0nt_b3_3X4ctly_th4t_345y_t0_c4ptur3_H0wev3r_1T_w1ll_b3_C00l_1F_Y0u_g0t_1tx0foriinlist:ifx4:x0ifx0:print(str[i],end)#ALEXCTF{W3_L0v3_C_W1th_CL45535}x1hackme64位无壳主函数__int64 __fastcall sub_400F8E(__int64 a1, int a2, int a3, int a4, int a5, int a6) { int v6; // edx int v7; // ecx int v8; // r8d int v9; // r9d int v10; // ecx int v11; // r8d int v12; // r9d char v14; // [rsp0h] [rbp-C0h] char v15; // [rsp0h] [rbp-C0h] char v16[136]; // [rsp10h] [rbp-B0h] BYREF int v17; // [rsp98h] [rbp-28h] char v18; // [rsp9Fh] [rbp-21h] int v19; // [rspA0h] [rbp-20h] unsigned __int8 v20; // [rspA6h] [rbp-1Ah] char v21; // [rspA7h] [rbp-19h] int v22; // [rspA8h] [rbp-18h] int v23; // [rspACh] [rbp-14h] int v24; // [rspB0h] [rbp-10h] int v25; // [rspB4h] [rbp-Ch] _BOOL4 v26; // [rspB8h] [rbp-8h] int i; // [rspBCh] [rbp-4h] sub_407470((unsigned int)Give me the password: , a2, a3, a4, a5, a6, a2); sub_4075A0((unsigned int)%s, (unsigned int)v16, v6, v7, v8, v9, v14); for ( i 0; v16[i]; i ) ; v26 i 22; v25 10; do { v10 (int)sub_406D90() % 22; v22 v10; v24 0; v21 byte_6B4270[v10]; v20 v16[v10]; v19 v10 1; v23 0; while ( v23 v19 ) { v23; v24 1828812941 * v24 12345; } v18 v24 ^ v20; if ( v21 ! ((unsigned __int8)v24 ^ v20) ) v26 0; --v25; } while ( v25 ); if ( v26 ) v17 sub_407470((unsigned int)Congras\n, (unsigned int)v16, v24, v10, v11, v12, v15); else v17 sub_407470((unsigned int)Oh no!\n, (unsigned int)v16, v24, v10, v11, v12, v15); return 0LL; }这题比较简单主函数丢给ai他会给我们这么一串代码接着只需要把byte_6B4270中的内容按位置丢进去运行就好了defcalculate_v24(i):v240for_inrange(i1):v24(1828812941*v2412345)0xFFFFFFFFreturnv24 byte_6B4270[...]# 替换为实际的 22 字节passwordbytes([byte_6B4270[i]^(calculate_v24(i)0xFF)foriinrange(22)])print(Password:,password.decode())#flag{d826e6926098ef46}流浪者32位无壳找到主函数函数大致作用是找到KanXueCTF2019JustForhappy在aAbcdefghiabcde中的位置。例如K在字符串中在第19个即是19以此类推。aAbcdefghiabcde双击进去可以看到如下abcdefghiABCDEFGHIJKLMNjklmn0123456789opqrstuvwxyzOPQRSTUVWXYZBOOL __cdecl sub_4017F0(int a1) { char Str1[28]; // [espD8h] [ebp-24h] BYREF int v3; // [espF4h] [ebp-8h] int v4; // [espF8h] [ebp-4h] v4 0; v3 0; while ( *(_DWORD *)(a1 4 * v4) 0x3Du ) { Str1[v4] aAbcdefghiabcde[*(_DWORD *)(a1 4 * v4)]; v4; } Str1[v4] 0; if ( !strcmp(Str1, KanXueCTF2019JustForhappy) ) return sub_401770(); else return sub_4017B0(); }刚开始以为过程是这样使用以下代码最后将列表转化为数组提交发现不行无奈之下使用od动态调试aAbcdefghiabcdeabcdefghiABCDEFGHIJKLMNjklmn0123456789opqrstuvwxyzOPQRSTUVWXYZtargetKanXueCTF2019JustForhappyindices[aAbcdefghiabcde.index(c)forcintarget]print(indices)#[19, 0, 27, 59, 44, 4, 11, 55, 14, 30, 28, 29, 37, 18, 44, 42, 43, 14, 38, 41, 7, 0, 39, 39, 48]调试过程中发现他会逐个读取19会分开取1和9这样就导致取到了b和A后来看大佬wp时发现最终flag有字母我当时居然没想到字母。。。。。。尝试字母后发现a对应的是字符串中BA则对应8位置这一看这不就是按0-9a-zA-Z排序吗于是修改代码得到flagaAbcdefghiabcdeabcdefghiABCDEFGHIJKLMNjklmn0123456789opqrstuvwxyzOPQRSTUVWXYZkey0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZtargetKanXueCTF2019JustForhappyindices[aAbcdefghiabcde.index(c)forcintarget]print(indices)foriinindices:print(key[i],end)#j0rXI4bTeustBiIGHeCF70DDM可能是刚开始光顾着判断数字发现能到下一步后就跳过了剩下代码的判断就不知道在字母的范围内会发生什么去ida中寻找也可以发现一段类似的代码int __thiscall sub_401890(CWnd *this) { CWnd *DlgItem; // eax int v2; // eax struct CString *v4; // [esp-4h] [ebp-C4h] int v5[26]; // [esp4Ch] [ebp-74h] BYREF int i; // [espB4h] [ebp-Ch] char *Str; // [espB8h] [ebp-8h] CWnd *v8; // [espBCh] [ebp-4h] v8 this; v4 (CWnd *)((char *)this 100); DlgItem CWnd::GetDlgItem(this, 1002); CWnd::GetWindowTextA(DlgItem, v4); v2 sub_401A30((char *)v8 100); Str CString::GetBuffer((CWnd *)((char *)v8 100), v2); if ( !strlen(Str) ) return CWnd::MessageBoxA(v8, byte_4035DC, 0, 0); for ( i 0; Str[i]; i ) { if ( Str[i] 57 || Str[i] 48 ) { if ( Str[i] 122 || Str[i] 97 ) { if ( Str[i] 90 || Str[i] 65 ) sub_4017B0(); else v5[i] Str[i] - 29; } else { v5[i] Str[i] - 87; } } else { v5[i] Str[i] - 48; } } return sub_4017F0((int)v5); }

更多文章