Hideit
巨恶心的SMC,先逐步锁定主函数:
由于地址是随机加载的,所以就通过行数来找吧,




在最后这个176行步入
进入到TestEvil.dll中,但是没法反编译
跟着汇编走,发现在call后停下来接收输入,发现这样一个函数
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
| __int64 __fastcall sub_1F60E221BB0(__int64 a1) { __int64 v2; unsigned int v3; int v4; unsigned int v5; unsigned int v6; unsigned int v7; __int64 v8; __int64 v10; char v11; __int64 v12; int v13[4]; __int128 v14[2]; char v15; char v16[48]; __int64 v17; int v18; int v19; char v20[512]; char v21[560]; int v22; int v23; __int64 v24;
v2 = 0i64; v15 = 0; v14[0] = 0i64; v24 = 0i64; v14[1] = 0i64; if ( !(unsigned int)off_1F60E223000(-2147483646i64, aSoftwareClasse, &v24) ) { v23 = 0; ((void (__fastcall *)(char *, _QWORD, __int64))unk_1F60E222A0C)(v21, 0i64, 520i64); v22 = 66; if ( !(unsigned int)off_1F60E223008(v24, aKeysSecret, 0i64, &v23, v21, &v22) ) off_1F60E223020(0i64, 0i64, v21, 0xFFFFFFFFi64, v14, 260, 0i64, 0i64); } off_1F60E2230F8(aFirstSecretHer); v10 = 0i64; v11 = 0; ((void (__fastcall *)(void *, __int64 *))unk_1F60E221B50)(&unk_1F60E22324C, &v10); v12 = 0i64; strcpy((char *)&v12, (const char *)&v10); v13[0] = 114; v13[1] = 514; v13[2] = 19; v13[3] = 19; ((void (__fastcall *)(char *, _QWORD, __int64))unk_1F60E222A0C)(v20, 0i64, 512i64); v3 = HIDWORD(v12); v4 = 32; v5 = v12; v6 = HIDWORD(v12); v7 = 0; do { v7 -= 1640531527; v8 = (v7 >> 2) & 3; v5 += ((v7 ^ v3) + (v6 ^ v13[v8])) ^ (((16 * v6) ^ (v3 >> 3)) + ((v6 >> 5) ^ (4 * v3))); v3 += ((v7 ^ v5) + (v5 ^ v13[v8 ^ 1])) ^ (((16 * v5) ^ (v5 >> 3)) + ((v5 >> 5) ^ (4 * v5))); v6 = v3; --v4; } while ( v4 ); if ( v5 == 288407067 && v3 == 1668576323 ) { v17 = 0i64; v18 = (unsigned __int8)v10 | ((BYTE1(v10) | (WORD1(v10) << 8)) << 8); v19 = BYTE4(v10) | ((BYTE5(v10) | (HIWORD(v10) << 8)) << 8); ((void (__fastcall *)(char *, __int64))unk_1F60E221000)(v16, a1); ((void (__fastcall *)(char *, __int128 *, char *, _QWORD))unk_1F60E221150)(v16, v14, v20, (unsigned int)(v4 + 32)); while ( byte_1F60E2231D0[v2] == v20[v2] ) { if ( ++v2 >= 32 ) return off_1F60E2230F8(aYouFindLastSec); } } return 0i64; }
|
最后显然是验证完毕后return了一个正确,同时也有FirstSecret,所以这是我们要找的main函数。
由于有右移2与3,和TEA KEY,但是不是XXTEA,因为轮数又是确定的,所以只能写解密函数

解密函数还是很简单的
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
| #include <stdio.h>
int main(int argc, char *argv[]) { unsigned int v15[4] = {}; v15[0] = 114; v15[1] = 514; v15[2] = 19; v15[3] = 19; unsigned int v5, v6, v7, v8, v9, v10; v5 = (unsigned int)1668576323; v6 = 32; v7 = (unsigned int)288407067; v8 = 0; v9 = (unsigned int)0x9E3779B9 * 32; do {
v10 = (v9 >> 2) & 3; v5 -= ((v9 ^ v7) + (v7 ^ v15[v10 ^ 1])) ^ (((16 * v7) ^ (v7 >> 3)) + ((v7 >> 5) ^ (4 * v7))); v8 = v5; v7 -= ((v9 ^ v5) + (v8 ^ v15[v10])) ^ (((16 * v8) ^ (v5 >> 3)) + ((v8 >> 5) ^ (4 * v5))); v9 -= 0x9E3779B9; --v6; } while ( v6 ); unsigned int a[] = {v7,v5, 0}; puts((char *) a); }
|
得到dotitsit
第二个算法里,由于expand…知道是chacha20加密,解密即可

1 2 3 4 5 6 7
| from Crypto.Cipher import ChaCha20 import struct key = b"0N3@aYI_M3l0dy_KurOm1_W_Suk1dqy0" enc = bytes([0xEB, 0x8E, 0x5C, 0xA5, 0x62, 0xB4, 0x1C, 0x84, 0x5C, 0x59, 0xFC, 0x0D, 0x43, 0x3C, 0xAB, 0x20, 0xD8, 0x93, 0x33, 0x13, 0xA1, 0x9E, 0x39, 0x00, 0x76, 0x14, 0xB5, 0x04, 0x58, 0x9D, 0x06, 0xB8])
flag = ChaCha20.new(key=key, nonce=b"dotitsit").decrypt(enc) print(flag)
|
Shell
这个题涉及傀儡进程,并且根据进程的返回值控制进程的控制流(RIP),质量很高。
dump子进程的方法可以用任务管理器、火绒剑转储,https://github.com/glmcdona/Process-Dump这个也可以。
总之弄下来之后,首先看主函数

用了一个waitfordebugevent,结合子进程中的int 3,猜测是接收中断信号,然后进行操作。
在结合main函数里的这个

得知base这个变量是子进程的基址(我这里重命名了)
这里整体是对什么东西进行0x78异或

这里通过读取RIP+1,设置RIP为两个地方

在子进程中:一个是0x1035,这里和int3连在一起了,需要先undefined再创建code

0x1242

那我们结合子进程的main函数

int 3之后 mov对应的是0x48,所以是到0x1242处进行处理,代码实际上在1035也跳转了(但是不知道为什么),1035转成代码是这样
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| def enc(i, a): m = a n = i ax = m & n ax = ax ^ 0xff J = ax ax = ax & m ax = ax ^ 0xff k = ax ax = J & n ax = ax ^ 0xff ax = ax & K ax = ax ^ 0xff return ax
|
异或1是取反,而与非是异或,实际上代码可以简化成
1 2 3 4 5 6
| def enc(i, a): m = a n = i ax = m ^ n ^ n ^ m ^ n ^ m return ax
|
其实就是下标异或
所以代码为
1 2 3 4 5 6
| key = [0x1E, 0x15, 0x1B, 0x1C, 0x07, 0x4D, 0x1F, 0x1B, 0x12, 0x17, 0x4B, 0x44, 0x47, 0x58, 0x12, 0x47, 0x58, 0x58, 0x47, 0x5F, 0x54, 0x54, 0x58, 0x42, 0x59, 0x57, 0x50, 0x01, 0x49, 0x51, 0x53, 0x57, 0x3D, 0x6B, 0x3E, 0x6F, 0x3D, 0x6D, 0x6C, 0x3E, 0x69, 0x2C]
flag = [] for i in range(42): flag.append(chr(key[i] ^ 0x78 ^ i)) print(''.join(flag))
|