-
-
[原创]KCTF 2025 第4题 血色试炼wp
-
发表于: 2025-8-26 08:11 4679
-
先看main函数:
发现其中调用了LoadStringA从资源中加载字符串; 用7zip将exe文件作为压缩包打开, 拿出.rsrc/2052/strings.txt:
之后分析string_init为字符串结构体初始化函数, 在其中对参数右键Create new struct type..., 分析字符串结构为:
同时看到string_init引用了一个全局变量, 查找引用发现在TlsCallback函数中初始化为字符串"ThisEncAndDecKey";
同时TlsCallback函数中还初始化了变体base64表, aes_sbox, aes_inv_sbox, "tweakKey_2024521";
之后在Ntdll中查找了某些函数, 后续使用decrypt函数解密了资源中的字符串, 又有类似查找函数的系统调用号进行系统调用等操作, 感觉和算法关系不大先放一下, 先分析decrypt.
分析decrypt函数主要逻辑为:
首先用变体base64解码, 分成16byte每组用aes解密, 每组再与xorstream(组号+0x24D67344, "tweakKey_2024521")的结果进行异或;
xorstream逻辑为:
先将gidx+1重复4次小端序存入data_ptr, 然后:
用tweakey对data进行aes加密, 最后返回加密结果.
整合一下decrypt逻辑:
发现解密结果对不上, 判断AES的实现被更改过, 故将之前使用的Crypto.Cipher.AES换成了 2f3K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6T1L8%4A6Z5N6g2)9J5c8V1q4q4f1#2)9J5k6q4m8&6N6r3S2G2L8R3`.`. 的版本准备对照分析调整, 但是之后发现了其它解题方式.
回到main函数, 函数后续调用了AddVectoredExceptionHandler通过tiggerfault的方式在ExceptionHandler进行加解密操作, 分析发现其中天然存在decrypt的逆函数encrypt, 就不用分析AES的实现更改再自己写encrypt函数了.
在main函数中, 会将用户名加密3次与序列号解密一次的结果做对比; 则在对比处下断点, 输入用户名KCTF可以拿到KCTF被加密3次的结果l/SxsR0BCjRZTmc7XWscrMv38iYuoiUECvi9Tuvi+ZiJZmdR5EcvVnTZOZvrnOrw
将其作为序列号输入可以拿到KCTF被加密2次的结果8g+JjodOZ4bcaurrKobFVzxuSGA2uDFJFyXqAlnTlKI=
再作为序列号输入一次可以拿到KCTF被加密1次的结果vCF5nc2wC5/sVISvceXVkY==
再作为用户名输入, 就可以拿到KCTF被加密4次的结果即用户名KCTF的序列号tSzQkyqcvZLgkwDltPF9RpInibA5fTpH/bJni2yvLzTKao2uL5eLZ5QIxPj8bsYWe48ZohC5/Jw3cNNAaX8/rA==
...ModuleHandleW_0 = GetModuleHandleW_0(0LL);StringA = LoadStringA(ModuleHandleW_0, 104u, r104, 200);// IRq9quEgngSgKTq+M5+3038imAv9HEVFLeDEREYUoQG=v58[1] = v59;v5 = string_init((struct_somestr *)v59, (struct_somestr *)ThisEncAndDecKey);v6 = createstr(&v60, r104, &r104[StringA]);decr104 = (void **)decrypt(v6, v5);v8 = (char *)sub_140004468(&decr104_1, *decr104, decr104[1]);decr104_2 = v8;if ( *((_QWORD *)v8 + 3) > 0xFuLL )decr104_2 = *(char **)v8;memset(&decr104_3, 0, sizeof(decr104_3));v10 = strlen(decr104_2);sub_14000269C(&decr104_3, decr104_2, v10);qword_14000D000 = *(int *)(*find_syscalln(v11, v58, &decr104_3) + 64LL);......ModuleHandleW_0 = GetModuleHandleW_0(0LL);StringA = LoadStringA(ModuleHandleW_0, 104u, r104, 200);// IRq9quEgngSgKTq+M5+3038imAv9HEVFLeDEREYUoQG=v58[1] = v59;v5 = string_init((struct_somestr *)v59, (struct_somestr *)ThisEncAndDecKey);v6 = createstr(&v60, r104, &r104[StringA]);decr104 = (void **)decrypt(v6, v5);v8 = (char *)sub_140004468(&decr104_1, *decr104, decr104[1]);decr104_2 = v8;if ( *((_QWORD *)v8 + 3) > 0xFuLL )decr104_2 = *(char **)v8;memset(&decr104_3, 0, sizeof(decr104_3));v10 = strlen(decr104_2);sub_14000269C(&decr104_3, decr104_2, v10);qword_14000D000 = *(int *)(*find_syscalln(v11, v58, &decr104_3) + 64LL);...102 SUCCESS103 FAILED104 IRq9quEgngSgKTq+M5+3038imAv9HEVFLeDEREYUoQG=105 xn9aMR6l940QYqEQkCjRGQ==106 KfeXm13d+R+hqh6T/TUN3QCibwL4dz3/JyO9Bo2dnSM=107 UserName: 108 Serial: 109 Pause102 SUCCESS103 FAILED104 IRq9quEgngSgKTq+M5+3038imAv9HEVFLeDEREYUoQG=105 xn9aMR6l940QYqEQkCjRGQ==106 KfeXm13d+R+hqh6T/TUN3QCibwL4dz3/JyO9Bo2dnSM=107 UserName: 108 Serial: 109 Pause00000000 struct struct_somestr // sizeof=0x2000000000 { // XREF: TlsCallback_0/r main/r ...00000000 __int64 ptr_or_data; // XREF: TlsCallback_0+BBE/r00000000 // TlsCallback_0+CB5/r ...00000008 // padding byte00000009 // padding byte0000000A // padding byte0000000B // padding byte0000000C // padding byte0000000D // padding byte0000000E // padding byte0000000F // padding byte00000010 _QWORD len;00000018 _QWORD size; // XREF: TlsCallback_0+BB6/r00000018 // TlsCallback_0+CA5/r ...00000020 };00000000 struct struct_somestr // sizeof=0x2000000000 { // XREF: TlsCallback_0/r main/r ...00000000 __int64 ptr_or_data; // XREF: TlsCallback_0+BBE/r00000000 // TlsCallback_0+CB5/r ...00000008 // padding byte00000009 // padding byte0000000A // padding byte0000000B // padding byte0000000C // padding byte0000000D // padding byte0000000E // padding byte0000000F // padding byte00000010 _QWORD len;00000018 _QWORD size; // XREF: TlsCallback_0+BB6/r00000018 // TlsCallback_0+CA5/r ...00000020 };v3 = string_init((struct_somestr *)v45, arg1);decoded_a1 = (struct_str *)b64decode(v3);...do { v21 = (const void *)(decoded_a1_ptr + i_1); memset(&arg1, 0, sizeof(arg1)); v22 = i_1 + 16 - (__int64)i_1; Size = v22; if ( v22 ) { allocstr(&arg1, v22); v23 = arg1.ptr; memmove((void *)arg1.ptr, v21, Size); arg1.cur = v23 + Size; v18 = v37; } v24 = aes_decrypt(&arg1, v13); v25 = string_init(&v46, (struct_somestr *)&tweakKey_2024521); v26 = (void **)xorstream(v18 + 0x24D67344, v25); for ( i = 0LL; i < 16; ++i ) *(_BYTE *)(i + v40 + v14->ptr) = *((_BYTE *)*v26 + i) ^ *(_BYTE *)(v24->ptr + i); release(v26); release((void **)v24); v37 = ++v18; i_1 = v38 + 16; v38 += 16; v40 += 16LL; pinp = inpstr->ptr; } while ( (unsigned __int64)v18 < (inpstr->cur - inpstr->ptr) >> 4 ); thiskey_1 = v43; inpc = inpstr;...v3 = string_init((struct_somestr *)v45, arg1);decoded_a1 = (struct_str *)b64decode(v3);...do { v21 = (const void *)(decoded_a1_ptr + i_1); memset(&arg1, 0, sizeof(arg1)); v22 = i_1 + 16 - (__int64)i_1; Size = v22; if ( v22 ) { allocstr(&arg1, v22); v23 = arg1.ptr; memmove((void *)arg1.ptr, v21, Size); arg1.cur = v23 + Size; v18 = v37; } v24 = aes_decrypt(&arg1, v13); v25 = string_init(&v46, (struct_somestr *)&tweakKey_2024521); v26 = (void **)xorstream(v18 + 0x24D67344, v25); for ( i = 0LL; i < 16; ++i ) *(_BYTE *)(i + v40 + v14->ptr) = *((_BYTE *)*v26 + i) ^ *(_BYTE *)(v24->ptr + i); release(v26); release((void **)v24); v37 = ++v18; i_1 = v38 + 16; v38 += 16; v40 += 16LL; pinp = inpstr->ptr; } while ( (unsigned __int64)v18 < (inpstr->cur - inpstr->ptr) >> 4 ); thiskey_1 = v43;