---
# System prepended metadata

title: '2024 强网拟态 Writeups '

---

## ez_re

直接各种调试/Trace。输入长度是 0x38, 输入经过三次变换，第一次为 +0x40(其中存在反调试使用 x64dbg 隐藏PEB即可）
![](https://md.buptmerak.cn/uploads/e4fe69d6-8134-4bc3-9726-84df5b641a64.png)
第二轮 Trace 结果是这样，看起来很复杂，其实就是三个 xor 的定义式，0xE9FCF789 ^ 0xB62DD00 ^ 0xE29E2AF6 = 0x7f，就是xor 0x7f
![](https://md.buptmerak.cn/uploads/df3b077f-0698-4ca2-a587-fa4123db64c4.png)
第三轮是一个XTEA每一步多了个 xor，轮数为 102 轮，密钥是0xEF6FD9DB, 0xD2C273D3, 0x6F97E412, 0x72BFD624，三轮加密之后在最后的cmp那把每一次要对比的值拿到，使用下面的算法解密即可
```C
void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
    unsigned int i;
    uint32_t v0 = v[0], v1 = v[1], delta = 0x9E3779B9, sum = delta * num_rounds;
    for (i = 0; i < num_rounds; i++) {
        v1 -= (((((((v0 << 4) ^ 0x770A8C91) ^ ((v0 >> 5) ^ 0x66527758)) ^ 0x1158FBC9) + v0) ^ 0xBB111015) ^
               ((sum + key[(sum >> 11) & 3]) ^ 0x4B1C1A2)) ^ 0xBFA0D1B7;
        sum -= delta;
        v0 -= (((((((v1 << 4) ^ 0xB7ECF4CD) ^ ((v1 >> 5) ^ 0x2B530BC8)) ^ 0x9CBFFF05) + v1) ^ 0xE323445C) ^
               ((sum + key[sum & 3]) ^ 0x6C6EBD5F)) ^ 0x8F4DF903;
    }
    v[0] = v0;
    v[1] = v1;
}

int main(void) {
    uint32_t key[4] = {
            0xEF6FD9DB, 0xD2C273D3, 0x6F97E412, 0x72BFD624
    };


    uint8_t final_data[0x38] = {0xFFFFFFA1, 0xFFFFFFE3, 0x51, 0xFFFFFF98, 0xFFFFFF86, 0x56, 0x76, 0x49, 0x6F, 0x6B, 0x2B, 0xFFFFFF81, 0xFFFFFFCF, 0xFFFFFFCE, 0x12, 0xFFFFFF96, 0xFFFFFFA2, 0x70, 0x35, 0x3C, 0x31, 0x62, 0x5C, 0xFFFFFFF1, 0xFFFFFFFA, 0x77, 0x6B, 0xFFFFFFAA, 0xFFFFFF9E, 0x6D, 0x5, 0xFFFFFFBE, 0xFFFFFFE8, 0x24, 0xFFFFFFA4, 0xFFFFFFF8, 0xFFFFFFDB, 0x23, 0x3A, 0xB, 0x16, 0x20, 0xFFFFFFCC, 0x3, 0xFFFFFFAD, 0xFFFFFFB5, 0x2B, 0xFFFFFFA9, 0x34, 0xFFFFFF9F, 0x78, 0x1D, 0x2E, 0xFFFFFFB9, 0xFFFFFFF9, 0xFFFFFF9E};
    for (int i = 0; i < 0x38; ++i) {
        printf("%02X ", final_data[i]);
    }
    printf("\n");
    for (int i = 0; i < 0x38; i += 8) {
        decipher(102, (uint32_t *) (final_data + i), key);
        for (int j = 0; j < 8; ++j) {
            final_data[i + j] ^= 0x7f;
            final_data[i + j] -= 0x40;
        }
    }

    for (int i = 0; i < 0x38; ++i) {
        printf("%02X ", final_data[i]);
    }
    printf("\n");

    puts(final_data);

    return 0;
}
```
## A_game
在 0x1b 对应的逻辑中，存在字符串加密，使用如下脚本解密即可
```Python
from idaapi import *
from idautils import *
import ida_xref

for xref in XrefsTo(0x7FF6D7B2419A, ida_xref.XREF_ALL):
    if xref.type == 17 and 'rcx' in print_operand(xref.frm - 7, 0):
        str_addr = get_operand_value(xref.frm - 7, 1)
        print(hex(str_addr))
        while True:
            t = get_byte(str_addr)
            if t == 0:
                break
            patch_byte(str_addr, (t ^ 0x11) - 34)
            str_addr += 1
```
解密后发现从game.data里解密出来了一个game.ps1使用pwoershell执行
![](https://md.buptmerak.cn/uploads/bfdfa361-1a0b-4db1-96f7-9fe558c9686e.png)
解密算法一眼丁真 ChaCha20 直接使用如下脚本解密：
```python
from Crypto.Cipher import ChaCha20

chacha = ChaCha20.new(key=b'powerpowerpowerpowerpowerpowerpo', nonce=b'powerpowerpo')

with open('game.data', 'rb') as f:
    data = chacha.decrypt(f.read())

with open('game.ps', 'wb') as f1:
    f1.write(data)
```
PowerShell 脚本有三层 iex 姑且算是混淆吧，改一下脚本执行一下即可得到最终的脚本，分析后解密脚本如下：
```python
def de3(e):
    key = [0x70, 0x30, 0x77, 0x33, 0x72]  # Another key 'p0w3r' in hex
    for k in range(len(e)):
        e[k] = e[k] // key[k % len(key)]
    return e


def de2(e):
    key = [0x70, 0x30, 0x77, 0x65, 0x72]  # Different key 'p0wer' in hex
    for k in range(len(e)):
        e[k] = e[k] - key[k % len(key)]
    return e


def de1(e):
    print(e)
    m = bytes(e[:-5])
    key = bytes(e[-5:])
    # for i in range(len(m)):
    key = ARC4.new(m).decrypt(key)
    m = ARC4.new(key).decrypt(m)
    return m


result = [38304, 8928, 43673, 25957 , 67260, 47152, 16656, 62832 , 19480 , 66690, 40432, 15072 , 63427 , 28558 , 54606, 47712 , 18240 , 68187 , 18256, 63954 , 48384, 14784, 60690 , 21724 , 53238 , 64176 , 9888 , 54859 , 23050 , 58368 , 46032 , 15648 , 64260 , 17899 , 52782 , 51968 , 12336 , 69377 , 27844 , 43206 , 63616]

flag = de1(de2(de2(de2(de3(de2(de2(result)))))))
print(flag)
```

## baby_re

前面就一标准AES没什么可说的，后面把AES的输出每字节输出为 12 个二进制数，前 8 个是字节的二进制表示，后面的4个是idx，因为后4位已经知道，前八位可以爆破
```python
code = """
8b45f84863d04889d04801c04801d048c1e0044889c2488b45104801d08b008945f48b45f84863d04889d04801c04801d048c1e0044889c2488b45104801d08b40048945f08b45f84863d04889d04801c04801d048c1e0044889c2488b45104801d08b40088945ec8b45f84863d04889d04801c04801d048c1e0044889c2488b45104801d08b400c8945e88b45f84863d04889d04801c04801d048c1e0044889c2488b45104801d08b40108945e48b45f84863d04889d04801c04801d048c1e0044889c2488b45104801d08b40148945e08b45f84863d04889d04801c04801d048c1e0044889c2488b45104801d08b40188945dc8b45f84863d04889d04801c04801d048c1e0044889c2488b45104801d08b401c8945d88b45f84863d04889d04801c04801d048c1e0044889c2488b45104801d08b40208945d48b45f84863d04889d04801c04801d048c1e0044889c2488b45104801d08b40248945d08b45f84863d04889d04801c04801d048c1e0044889c2488b45104801d08b40288945cc8b45f84863d04889d04801c04801d048c1e0044889c2488b45104801d08b402c8945c8837dc8000f94c00fb6d08b45f42345f02345ec89c1837de8000f94c00fb6c021c82345e42345e089c1837ddc000f94c00fb6c021c1837dd8000f94c00fb6c021c1837dd4000f94c00fb6c021c1837dd0000f94c00fb6c021c82345cc89c1837df0000f94c00fb6c02345f44189c0837dec000f94c00fb6c04121c0837de8000f94c00fb6c04121c0837de4000f94c00fb6c04421c02345e04189c0837ddc000f94c00fb6c04421c02345d84189c0837dd4000f94c00fb6c04421c02345d04189c0837dcc000f94c00fb6c04421c009c14189c88b45f40b45f00b45ec85c00f94c00fb6c02345e889c1837de4000f94c00fb6c021c1837de0000f94c00fb6c021c1837ddc000f94c00fb6c021c82345d82345d42345d089c1837dcc000f94c00fb6c021c84109c0837df0000f94c00fb6c02345f42345ec2345e889c1837de4000f94c00fb6c021c1837de0000f94c00fb6c021c82345dc89c1837dd8000f94c00fb6c021c1837dd4000f94c00fb6c021c82345d02345cc4409c089d121c18b45f40b45f085c00f94c00fb6c02345ec2345e889c2837de4000f94c00fb6c021d02345e02345dc89c2837dd8000f94c00fb6c021d02345d42345d089c2837dcc000f94c00fb6c021d02345c809c1837df0000f94c00fb6c02345f42345ec2345e82345e489c2837de0000f94c00fb6c021d02345dc89c2837dd8000f94c00fb6c021d02345d489c2837dd0000f94c00fb6c021c2837dcc000f94c00fb6c021d02345c809c1837df4000f94c00fb6c02345f089c2837dec000f94c00fb6c021d02345e82345e489c2837de0000f94c00fb6c021d02345dc2345d82345d489c2837dd0000f94c00fb6c021c2837dcc000f94c00fb6c021c2837dc8000f94c00fb6c021d009c18b45f42345f089c2837dec000f94c00fb6c021c2837de8000f94c00fb6c021d02345e42345e02345dc2345d82345d489c2837dd0000f94c00fb6c021d02345cc2345c809c1837df0000f94c00fb6c02345f489c2837dec000f94c00fb6c021c2837de8000f94c00fb6c021d02345e42345e02345dc2345d889c2837dd4000f94c00fb6c021c2837dd0000f94c00fb6c021c2837dcc000f94c00fb6c021d02345c809c18b45f40b45f00b45ec0b45e80b45e485c00f94c00fb6c02345e089c2837ddc000f94c00fb6c021c2837dd8000f94c00fb6c021c2837dd4000f94c00fb6c021d02345d089c2837dcc000f94c00fb6c021d02345c809c1837df4000f94c00fb6c02345f089c2837dec000f94c00fb6c021c2837de8000f94c00fb6c021d02345e42345e089c2837ddc000f94c00fb6c021c2837dd8000f94c00fb6c021c2837dd4000f94c00fb6c021d02345d02345cc2345c809c18b45f40b45f00b45ec85c00f94c00fb6c02345e889c2837de4000f94c00fb6c021c2837de0000f94c00fb6c021d02345dc89c2837dd8000f94c00fb6c021c2837dd4000f94c00fb6c021c2837dd0000f94c00fb6c021c2837dcc000f94c00fb6c021c2837dc8000f94c00fb6c021d009c18b45f42345f089c2837dec000f94c00fb6c021c2837de8000f94c00fb6c021c2837de4000f94c00fb6c021c2837de0000f94c00fb6c021d02345dc89c2837dd8000f94c00fb6c021c2837dd4000f94c00fb6c021c2837dd0000f94c00fb6c021d02345cc2345c809c1837df4000f94c00fb6c02345f089c2837dec000f94c00fb6c021c2837de8000f94c00fb6c021d02345e489c2837de0000f94c00fb6c021c2837ddc000f94c00fb6c021c2837dd8000f94c00fb6c021d02345d42345d02345cc2345c809c1837df4000f94c00fb6c02345f089c2837dec000f94c00fb6c021c2837de8000f94c00fb6c021d02345e489c2837de0000f94c00fb6c021d02345dc89c2837dd8000f94c00fb6c021d02345d489c2837dd0000f94c00fb6c021d02345cc89c2837dc8000f94c00fb6c021d009c18b45f40b45f00b45ec0b45e885c00f94c00fb6c02345e489c2837de0000f94c00fb6c021d02345dc89c2837dd8000f94c00fb6c021d02345d42345d02345cc89c2837dc8000f94c00fb6c021d009c8
"""

code = bytes.fromhex(code)

from unicorn import *
from unicorn.x86_const import *
import struct

mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(0x100000, 0x2000)
mu.mem_map(0x200000, 0x2000)
mu.mem_map(0x400000, 0x10000)
mu.mem_write(0x402116, code)

rbp_val = 0x100100
bool_arr_addr = 0x200000
# mu.reg_write(UC_X86_REG_RIP, 0x402116)
mu.reg_write(UC_X86_REG_RBP, rbp_val)
# 参数
mu.mem_write(rbp_val + 16, struct.pack("<Q", bool_arr_addr))
# idx
mu.mem_write(rbp_val - 8, b'\x00' * 4)

# 写入参数值
# mu.mem_write()
arr = [0] * 16
for i in range(16):
    for j in range(256):
        for k in range(8):
            mu.mem_write(bool_arr_addr + 4 * k, struct.pack("<I", (j >> (7 - k)) & 1))
        for k in range(4):
            mu.mem_write(bool_arr_addr + 4 * k + 32, struct.pack("<I", (i >> (3 - k)) & 1))
        mu.emu_start(0x402116, 0x402116 + len(code))
        if 1 == mu.reg_read(UC_X86_REG_EAX):
            print(i, j)
            arr[i] = j
            break
print(arr)
from Crypto.Cipher import AES
flag = AES.new(bytes.fromhex('3577402ECCA44A3F9AB72182F9B01F35'), AES.MODE_ECB).decrypt(bytes(arr))
print('-'.join([f'{i:02x}' for i in flag]))
# 4d87ef03-77bb-491a-80f5-4620245807c4
```