稍微……有那么一点离谱
程序无壳,可以直接放入IDA,通过字符串找到如下函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 __int64 sub_4009C6() { __int64 result; // rax int i; // [rsp+Ch] [rbp-114h] __int64 v2; // [rsp+10h] [rbp-110h] __int64 v3; // [rsp+18h] [rbp-108h] __int64 v4; // [rsp+20h] [rbp-100h] __int64 v5; // [rsp+28h] [rbp-F8h] __int64 v6; // [rsp+30h] [rbp-F0h] __int64 v7; // [rsp+38h] [rbp-E8h] __int64 v8; // [rsp+40h] [rbp-E0h] __int64 v9; // [rsp+48h] [rbp-D8h] __int64 v10; // [rsp+50h] [rbp-D0h] __int64 v11; // [rsp+58h] [rbp-C8h] char v12[13]; // [rsp+60h] [rbp-C0h] BYREF char v13[4]; // [rsp+6Dh] [rbp-B3h] BYREF char v14[19]; // [rsp+71h] [rbp-AFh] BYREF char v15[32]; // [rsp+90h] [rbp-90h] BYREF int v16; // [rsp+B0h] [rbp-70h] char v17; // [rsp+B4h] [rbp-6Ch] char v18[72]; // [rsp+C0h] [rbp-60h] BYREF unsigned __int64 v19; // [rsp+108h] [rbp-18h] v19 = __readfsqword(0x28u); qmemcpy(v12, "Iodl>Qnb(ocy", 12); v12[12] = 127; qmemcpy(v13, "y.i", 3); v13[3] = 127; qmemcpy(v14, "d`3w}wek9{iy=~yL@EC", sizeof(v14)); memset(v15, 0, sizeof(v15)); v16 = 0; v17 = 0; sub_4406E0(0LL, v15, 37LL); v17 = 0; if ( sub_424BA0(v15) == 36 ) { for ( i = 0; i < (unsigned __int64)sub_424BA0(v15); ++i ) { if ( (unsigned __int8)(v15[i] ^ i) != v12[i] ) { result = 4294967294LL; goto LABEL_13; } } sub_410CC0("continue!"); memset(v18, 0, 0x40uLL); v18[64] = 0; sub_4406E0(0LL, v18, 64LL); v18[39] = 0; if ( sub_424BA0(v18) == 39 ) { v2 = sub_400E44(v18); v3 = sub_400E44(v2); v4 = sub_400E44(v3); v5 = sub_400E44(v4); v6 = sub_400E44(v5); v7 = sub_400E44(v6); v8 = sub_400E44(v7); v9 = sub_400E44(v8); v10 = sub_400E44(v9); v11 = sub_400E44(v10); if ( !(unsigned int)sub_400360(v11, off_6CC090) ) { sub_410CC0("You found me!!!"); sub_410CC0("bye bye~"); } result = 0LL; } else { result = 4294967293LL; } } else { result = 0xFFFFFFFFLL; } LABEL_13: if ( __readfsqword(0x28u) != v19 ) sub_444020(); return result; }
通过分析,我们可以把函数名修正为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 v19 = __readfsqword(0x28u); qmemcpy(v12, "Iodl>Qnb(ocy", 12); v12[12] = 127; qmemcpy(v13, "y.i", 3); v13[3] = 127; qmemcpy(v14, "d`3w}wek9{iy=~yL@EC", sizeof(v14)); memset(v15, 0, sizeof(v15)); v16 = 0; v17 = 0; read(0LL, v15, 37LL); v17 = 0; if ( strlen(v15) == 36 ) { for ( i = 0; i < strlen(v15); ++i ) { if ( (v15[i] ^ i) != v12[i] ) { result = 4294967294LL; goto LABEL_13; } } printf("continue!"); memset(v18, 0, 0x40uLL); v18[64] = 0; read(0LL, v18, 64LL); v18[39] = 0; if ( strlen(v18) == 39 ) { v2 = base64encode(v18); v3 = base64encode(v2); v4 = base64encode(v3); v5 = base64encode(v4); v6 = base64encode(v5); v7 = base64encode(v6); v8 = base64encode(v7); v9 = base64encode(v8); v10 = base64encode(v9); v11 = base64encode(v10); if ( !sub_400360(v11, off_6CC090) ) { printf("You found me!!!"); printf("bye bye~"); } result = 0LL; } else { result = 4294967293LL; } } else { result = 0xFFFFFFFFLL; } LABEL_13: if ( __readfsqword(0x28u) != v19 ) sub_444020(); return result; }
有一处9层base64加密的字符串存在
1 2 3 4 5 6 7 8 9 10 11 12 13 .rodata:00000000004A23A8 aVm0wd2vhuxhtwg db 'Vm0wd2VHUXhTWGhpUm1SWVYwZDRWVll3Wkc5WFJsbDNXa1pPVlUxV2NIcFhhMk0xV' .rodata:00000000004A23A8 ; DATA XREF: .data:off_6CC090↓o .rodata:00000000004A23A8 db 'mpKS1NHVkdXbFpOYmtKVVZtcEtTMUl5VGtsaVJtUk9ZV3hhZVZadGVHdFRNVTVYVW' .rodata:00000000004A23A8 db '01T2FGSnRVbGhhVjNoaFZWWmtWMXBFVWxSTmJFcElWbTAxVDJGV1NuTlhia0pXWWx' .rodata:00000000004A23A8 db 'ob1dGUnJXbXRXTVZaeVdrWm9hVlpyV1hwV1IzaGhXVmRHVjFOdVVsWmlhMHBZV1ZS' .rodata:00000000004A23A8 db 'R1lWZEdVbFZTYlhSWFRWWndNRlZ0TVc5VWJGcFZWbXR3VjJKSFVYZFdha1pXWlZaT' .rodata:00000000004A23A8 db '2NtRkhhRk5pVjJoWVYxZDBhMVV3TlhOalJscFlZbGhTY1ZsclduZGxiR1J5VmxSR1' .rodata:00000000004A23A8 db 'ZXSlZjRWhaTUZKaFZqSktWVkZZYUZkV1JWcFlWV3BHYTFkWFRrZFRiV3hvVFVoQ1d' .rodata:00000000004A23A8 db 'sWXhaRFJpTWtsM1RVaG9hbEpYYUhOVmJUVkRZekZhY1ZKcmRGTk5Wa3A2VjJ0U1Ex' .rodata:00000000004A23A8 db 'WlhTbFpqUldoYVRVWndkbFpxUmtwbGJVWklZVVprYUdFeGNHOVhXSEJIWkRGS2RGS' .rodata:00000000004A23A8 db 'nJhR2hTYXpWdlZGVm9RMlJzV25STldHUlZUVlpXTlZadE5VOVdiVXBJVld4c1dtSl' .rodata:00000000004A23A8 db 'lUWGhXTUZwell6RmFkRkpzVWxOaVNFSktWa1phVTFFeFduUlRhMlJxVWxad1YxWnR' .rodata:00000000004A23A8 db 'lRXRXTVZaSFVsUnNVVlZVTURrPQ==',0
解码后得到:
“https://bbs.pediy.com/thread-254172.htm ”
看来没有那么简单
1 2 3 4 5 qmemcpy(v12, "Iodl>Qnb(ocy", 12); v12[12] = 127; qmemcpy(v13, "y.i", 3); v13[3] = 127; qmemcpy(v14, "d`3w}wek9{iy=~yL@EC", sizeof(v14));
这里还有一个显然特殊的字符串
v12、v13、v14在内存中是连续的,通过第二和第四行的赋值操作将‘\0’抹去,使得他们连成一整个字符串(但本来是‘\0’的地方现在被填充了,所以字符串增加了两个字节)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 BYTE ke1[14] = "Iodl>Qnb(ocy"; char ke2[5] = "y.i"; char ke3[20] = "d`3w}wek9{iy=~yL@EC"; for (int i = 0; i < 13; i++) { ke1[i] ^= i; if (i == 12) ke1[12] = 127 ^ i; } cout << ke1; for (int i = 0; i < 4; i++) { ke2[i] ^= (i + 13); if (i == 3) { ke2[3] = 127 ^ (i + 13); } } cout << ke2; for (int i = 0; i < 19; i++) { ke3[i] ^= (i + 17); } cout << ke3;
解密之后得到:
Info:The first four chars are `flag`
现在暂时无法理解它的意义,好像什么都没说一样,但实际上是个必要的提示
自以上分析,sub_4009C6函数似乎已经没有其他信息可以获取了
这个体量的函数列表显然也不太能够一个个去检查
再次从字符串搜索入手:
1 2 3 4 5 6 7 8 9 10 .data:00000000006CC090 off_6CC090 dq offset aVm0wd2vhuxhtwg .data:00000000006CC090 ; DATA XREF: sub_4009C6+31B↑r .data:00000000006CC090 ; "Vm0wd2VHUXhTWGhpUm1SWVYwZDRWVll3Wkc5WFJ"... .data:00000000006CC098 align 20h .data:00000000006CC0A0 ; char byte_6CC0A0[3] .data:00000000006CC0A0 byte_6CC0A0 db 40h, 35h, 20h, 56h, 5Dh, 18h, 22h, 45h, 17h, 2Fh, 24h .data:00000000006CC0A0 ; DATA XREF: sub_400D35+95↑r .data:00000000006CC0A0 ; sub_400D35+C1↑r ... .data:00000000006CC0A0 db 6Eh, 62h, 3Ch, 27h, 54h, 48h, 6Ch, 24h, 6Eh, 72h, 3Ch .data:00000000006CC0A0 db 32h, 45h, 5Bh
从那个9层base64的字符串向上查找,来到此处,发现在下面还有一个特殊的数组(没做成数组之前很是明显,我将它们打成组了)
这个函数通过sub_402080,也就是init函数中的函数数组来初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 unsigned __int64 sub_400D35() { unsigned __int64 result; // rax unsigned int v1; // [rsp+Ch] [rbp-24h] int i; // [rsp+10h] [rbp-20h] int j; // [rsp+14h] [rbp-1Ch] unsigned int v4; // [rsp+24h] [rbp-Ch] unsigned __int64 v5; // [rsp+28h] [rbp-8h] v5 = __readfsqword(050u); v1 = sub_43FD20(0LL) - qword_6CEE38; for ( i = 0; i <= 1233; ++i ) { sub_40F790(v1); sub_40FE60(); sub_40FE60(); v1 = sub_40FE60() ^ 0x98765432; } v4 = v1; if ( ((unsigned __int8)v1 ^ byte_6CC0A0[0]) == 0x66 && (HIBYTE(v4) ^ byte_6CC0A0[3]) == 0x67 ) { for ( j = 0; j <= 24; ++j ) sub_410E90(byte_6CC0A0[j] ^ *((_BYTE *)&v4 + j % 4)); } result = __readfsqword(0x28u) ^ v5; if ( result ) sub_444020(); return result; }
第一个for循环对v1变量进行初始化,得到一个定值;
第二个for循环中将上述的特殊数组做循环一次异或;
至于sub_410E90、sub_40F790、sub_40FE60函数则由于过于复杂,或许是系统函数,便不做分析,选择性忽视过去
同时,第二个for循环中的异或数是 v4的某个BYTE位,而v4是一个int类型的4BYTE数据
那么我们现在需要做的应该是获取这个v4或v1
在if条件中,我们可以发现:
v1的第一个BYTE与byte_6CC0A0[0]异或结果位‘f’;
v4的最后一个BYTE与byte_6CC0A0[3]异或结果位‘g’
根据:
Info:The first four chars are `flag`
可以猜测v1的四个BYTE与byte_6CC0A0的前四个异或后结果应该分别位‘f’、’l’、‘a’、‘g’
以此获得v1之后再做第二个for循环运算得到结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 char k[] = { 0x40, 0x35, 0x20, 0x56, 0x5D, 0x18, 0x22, 0x45, 0x17, 0x2F, 0x24,0x6E, 0x62, 0x3C, 0x27, 0x54, 0x48, 0x6C, 0x24, 0x6E, 0x72, 0x3C,0x32, 0x45, 0x5B }; BYTE f[4]; f[0] = 0x66 ^ k[0]; f[1] = 108 ^ k[1]; f[2] = 97 ^ k[2]; f[3] = 0x67 ^ k[3]; for (int i = 0; i <= 24; i++) { k[i] ^= f[i % 4]; } for (int i = 0; i <= 24; i++) { cout << (char)k[i]; }
从此得到flag
这次我该吸取的教训是:不要因为事情看起来复杂就认为考点不在这里
插画ID : 90097136