首页
社区
课程
招聘
[原创]KCTF 2025 第4题 血色试炼wp
发表于: 2025-8-26 08:11 4679

[原创]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 SUCCESS
103 FAILED
104 IRq9quEgngSgKTq+M5+3038imAv9HEVFLeDEREYUoQG=
105 xn9aMR6l940QYqEQkCjRGQ==
106 KfeXm13d+R+hqh6T/TUN3QCibwL4dz3/JyO9Bo2dnSM=
107 UserName:
108 Serial:
109 Pause
102 SUCCESS
103 FAILED
104 IRq9quEgngSgKTq+M5+3038imAv9HEVFLeDEREYUoQG=
105 xn9aMR6l940QYqEQkCjRGQ==
106 KfeXm13d+R+hqh6T/TUN3QCibwL4dz3/JyO9Bo2dnSM=
107 UserName:
108 Serial:
109 Pause
00000000 struct struct_somestr // sizeof=0x20
00000000 {                                       // XREF: TlsCallback_0/r main/r ...
00000000     __int64 ptr_or_data;                // XREF: TlsCallback_0+BBE/r
00000000                                         // TlsCallback_0+CB5/r ...
00000008     // padding byte
00000009     // padding byte
0000000A     // padding byte
0000000B     // padding byte
0000000C     // padding byte
0000000D     // padding byte
0000000E     // padding byte
0000000F     // padding byte
00000010     _QWORD len;
00000018     _QWORD size;                        // XREF: TlsCallback_0+BB6/r
00000018                                         // TlsCallback_0+CA5/r ...
00000020 };
00000000 struct struct_somestr // sizeof=0x20
00000000 {                                       // XREF: TlsCallback_0/r main/r ...
00000000     __int64 ptr_or_data;                // XREF: TlsCallback_0+BBE/r
00000000                                         // TlsCallback_0+CB5/r ...
00000008     // padding byte
00000009     // padding byte
0000000A     // padding byte
0000000B     // padding byte
0000000C     // padding byte
0000000D     // padding byte
0000000E     // padding byte
0000000F     // padding byte
00000010     _QWORD len;
00000018     _QWORD size;                        // XREF: TlsCallback_0+BB6/r
00000018                                         // 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;

传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2025-8-26 08:11 被tacesrever编辑 ,原因:
收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回