2024 强网拟态Re(全解)
1315609050541697 发表于 湖北 CTF 262浏览 · 2024-10-20 03:39

serv1ce

#include<stdio.h>

int main()
{
    char enc[] = { 0xB9, 0x32, 0xC2, 0xD4, 0x69, 0xD5, 0xCA, 0xFB, 0xF8, 0xFB,
  0x80, 0x7C, 0xD4, 0xE5, 0x93, 0xD5, 0x1C, 0x8B, 0xF8, 0xDF,
  0xDA, 0xA1, 0x11, 0xF8, 0xA1, 0x93, 0x93, 0xC2, 0x7C, 0x8B,
  0x1C, 0x66, 0x01, 0x3D, 0xA3, 0x67 };
    //bArr[i3] = (byte)(((str.charAt(i3 % str.length()) - 'w') ^ 23) & 255);
    char key_arry[64] = {0};
    char key[] = "1liIl11lIllIIl11llII";
    for (int i = 0; i < 64; i++) {
        key_arry[i] = ((key[i % 20] - 'w') ^ 23) % 256;
    }

    int num = 11;
    char flag[36] = {0};
    for (int i = 0; i < 36; i++) {
        for (int j = 0; j < '}'; j++) {
            if ((char)(num * (j ^ key_arry[i])) == enc[i]) {
                flag[i] = j;
            }
        }
    }
    printf("%s", flag);
}

easyre

Tracecode,比较长度0x38

两处数据获取

输入测试数据 'A' * 0x38 密文如下

8字节相同,说明加密时8字节一组
先猜一个TEA算法,trace里搜 9E3779B9
执行次数 714 次,714 / 7 = 102,每组执行了102轮
搜到指令 shr r8d,B ,对应XTEA算法中的 (sum>>11),找到KEY读取的代码
0xEF6FD9DB, 0xD2C273D3, 0x6F97E412, 0x72BFD624

测试发现输入前对密文 xor 0xBF

#include <stdio.h>
#include <stdint.h>

/* take 64 bits of data in v[0] and v[1] and 128 bits of key[0] - key[3] */

void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
    unsigned int i;
    uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
    for (i=0; i < num_rounds; i++) {
        v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
        sum += delta;
        v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
    }
    v[0]=v0; v[1]=v1;
}

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) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
        sum -= delta;
        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
    }
    v[0]=v0; v[1]=v1;
}

int main()
{
    uint32_t v[]={0x9851E3A1, 0x49765686, 0x812B6B6F, 0x9612CECF, 0x3C3570A2, 0xF15C6231, 0xAA6B77FA, 0xBE056D9E,
 0xF8A424E8, 0x0B3A23DB, 0x03CC2016, 0xA92BB5AD, 0x1D789F34, 0x9EF9B92E,0};
    uint32_t const k[4]={0xEF6FD9DB, 0xD2C273D3, 0x6F97E412, 0x72BFD624};
    unsigned int r=102;//num_rounds建议取值为32
    // v为要加密的数据是两个32位无符号整数
    // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
    for(int i = 0; i< 7;i++){
        decipher(r, (v + i * 2), k);
    }
    for(int i = 0;i<14;i++){
        v[i] ^= 0xbfbfbfbf;
    }
    for(int i = 0;i< 0x38 ;i++){
        printf("%.2x ", *((char* )(v)+i) & 0xff);
    }
    printf("\n");
    printf("%s\n",v);
    return 0;
}
66 6c 61 67 7b 75 5f 61 72 b3 5f 72 65 40 b1 b1 79 5f 67 b0 b0 64 5f 40 74 5f b0 b1 b1 76 6d 5f 64 65 b0 62 66 5f 61 6e 64 5f 61 6e 74 69 5f 64 65 62 75 67 67 65 72 7d

发现仍有乱码,bx,这些转成数字 3x

A_game

有个调试器检测,判断其不是被powershell或者正常打开的就会退出,这里patch了

首先通过读写文件的api定位到关键函数,其中该函数会在退出游戏时调用。

把game.tmp解密产生了game.ps1

ps1是个混淆的powershell脚本,每段脚本最前面是个iex 执行,去掉后运行一下,可直接解密出下一段脚本,
继续运行,得到真正的加密脚本。

对照其加密逻辑解密即可

enc = [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]

key2 = [0x70, 0x30, 0x77, 0x65, 0x72]
for i in range(len(enc)):
    enc[i] -= key2[i % len(key2)]

for i in range(len(enc)):
    enc[i] -= key2[i % len(key2)]

key3 = [0x70, 0x30, 0x77, 0x33, 0x72]
for i in range(len(enc)):
    enc[i] = int(enc[i] / key3[i % len(key3)])

for i in range(len(enc)):
    enc[i] -= key2[i % len(key2)]

for i in range(len(enc)):
    enc[i] -= key2[i % len(key2)]

for i in range(len(enc)):
    enc[i] -= key2[i % len(key2)]

def rc4(key, plaintext):
    S = list(range(256))
    j = 0
    for i in range(256):
        j = (j + S[i] + key[i % len(key)]) % 256
        S[i], S[j] = S[j], S[i]
    i = 0
    j = 0
    ciphertext = []

    for k in range(len(plaintext)):
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        t = (S[i] + S[j]) % 256
        ciphertext.append(plaintext[k] ^ S[t])

    return ciphertext

def enenenenene1_decrypt(encrypted_data):
    key = [0x70, 0x6f, 0x77, 0x65, 0x72]
    plaintext = ""
    for _ in range(36):
        current_encrypted_text = encrypted_data[:-len(key)]
        current_key = rc4(current_encrypted_text,encrypted_data[-len(key):])
        current_encrypted_text = rc4(current_key, current_encrypted_text)
        plaintext = current_encrypted_text
    return plaintext

decrypted_plaintext = enenenenene1_decrypt(enc)
for c in decrypted_plaintext:
    print(chr(c),end="")

babyre

标准AES,KEY 35 77 40 2E CC A4 4A 3F 9A B7 21 82 F9 B0 1F 35

不过这里是无填充的

后面是转成二进制然后求z3

z3转太麻烦了,不如直接爆破

#include <stdio.h>
int check(int a1[])
{
    int v1;          // r8d
    int v2;          // ecx
    int v3;          // ecx
    int ANS[12];     // [rsp+8h] [rbp-38h]
    int i;           // [rsp+38h] [rbp-8h]
    unsigned int v7; // [rsp+3Ch] [rbp-4h]

    v7 = 1;
    for (int i = 0; i < 12; i++)
    {
        ANS[i] = a1[11 - i];
    }

    v1 = ANS[2] & ANS[3] & ANS[4] & (ANS[6] == 0) & (ANS[7] == 0) & ANS[8] & ((ANS[9] | ANS[10] | ANS[11]) == 0) & (ANS[5] == 0) & (ANS[1] == 0) | ANS[2] & ANS[4] & ANS[6] & (ANS[8] == 0) & (ANS[9] == 0) & ANS[11] & (ANS[10] == 0) & (ANS[7] == 0) & (ANS[5] == 0) & (ANS[3] == 0) & (ANS[1] == 0) | ANS[1] & (ANS[3] == 0) & (ANS[4] == 0) & (ANS[5] == 0) & ANS[6] & ANS[7] & (unsigned int)(ANS[9] & ANS[10] & (ANS[11])) & (ANS[8] == 0) & (ANS[2] == 0);
    v2 = ANS[0] & ANS[1] & ANS[3] & ANS[4] & ANS[5] & ANS[6] & ANS[7] & (ANS[9] == 0) & (unsigned int)(ANS[10] & (ANS[11])) & (ANS[8] == 0) & (ANS[2] == 0) | (ANS[1] == 0) & (ANS[2] == 0) & ANS[3] & ANS[4] & ANS[5] & ANS[7] & ANS[8] & ANS[10] & (ANS[11] == 0) & (ANS[9] == 0) & (ANS[6] == 0) & (ANS[0] == 0) | ANS[0] & (ANS[2] == 0) & ANS[3] & ANS[5] & ANS[7] & ANS[8] & ANS[9] & ANS[11] & (ANS[10] == 0) & (ANS[6] == 0) & (ANS[4] == 0) & (ANS[1] == 0) | ANS[0] & ANS[2] & ANS[3] & ANS[5] & ANS[6] & ANS[8] & ANS[9] & (ANS[10] == 0 & ANS[11] == 0) & (ANS[7] == 0) & (ANS[4] == 0) & (ANS[1] == 0) | (v1 | ANS[1] & ANS[2] & (ANS[4] == 0) & ANS[5] & (ANS[7] == 0) & ANS[8] & ANS[9] & ANS[11] & (ANS[10] == 0) & (ANS[6] == 0) & (ANS[3] == 0)) & (ANS[0] == 0);
    v3 = ANS[0] & ANS[1] & (ANS[3] == 0) & (ANS[4] == 0) & ANS[5] & (ANS[7] == 0) & (ANS[8] == 0) & (ANS[9] == 0) & (unsigned int)(ANS[10] & (ANS[11])) & (ANS[6] == 0) & (ANS[2] == 0) | (ANS[1] == 0) & (ANS[2] == 0) & (ANS[3] == 0) & (ANS[4] == 0) & ANS[5] & (ANS[7] == 0) & ANS[8] & ((ANS[9] | ANS[10] | ANS[11]) == 0) & (ANS[6] == 0) & (ANS[0] == 0) | ANS[0] & ANS[1] & ANS[2] & (ANS[4] == 0) & (ANS[5] == 0) & ANS[6] & ANS[7] & (ANS[9] == 0) & ANS[10] & (ANS[11] == 0) & (ANS[8] == 0) & (ANS[3] == 0) | ANS[0] & ANS[2] & (ANS[4] == 0) & (ANS[5] == 0) & ANS[6] & ((ANS[7] | ANS[8] | ANS[9] | ANS[10] | ANS[11]) == 0) & (ANS[3] == 0) & (ANS[1] == 0) | ANS[0] & (ANS[2] == 0) & (ANS[3] == 0) & ANS[4] & ANS[5] & ANS[6] & ANS[7] & (ANS[9] == 0) & ANS[11] & (ANS[10] == 0) & (ANS[8] == 0) & (ANS[1] == 0) | v2;
    if (!(ANS[1] & ANS[3] & ANS[5] & ANS[7] & (ANS[9] == 0) & ANS[10] & (ANS[11] == 0) & (ANS[8] == 0) & (ANS[6] == 0) & (ANS[4] == 0) & (ANS[2] == 0) & (ANS[0] == 0) | ANS[0] & ANS[1] & ANS[2] & ANS[3] & (ANS[5] == 0) & (ANS[6] == 0) & ANS[7] & (ANS[9] == 0) & ANS[10] & (ANS[11] == 0) & (ANS[8] == 0) & (ANS[4] == 0) | v3 | ANS[1] & ANS[2] & ANS[3] & ANS[5] & ANS[7] & ((ANS[8] | ANS[9] | ANS[10] | ANS[11]) == 0) & (ANS[6] == 0) & (ANS[4] == 0) & (ANS[0] == 0)))
        v7 = 0;

    return v7;
}

int main()
{
    int ANS[12];
    for (int i = 0; i < 16; i++)
    {
        ANS[8] = i & 0x8 ? 1 : 0;
        ANS[9] = i & 0x4 ? 1 : 0;
        ANS[10] = i & 0x2 ? 1 : 0;
        ANS[11] = i & 0x1 ? 1 : 0;
        for (int x = 0; x < 256; x++)
        {
            for (int j = 0; j < 8; j++)
            {
                ANS[j] = (x >> (7 - j) & 1) ? 1 : 0;
            }
            // Check
            // for (int q = 0; q < 12; q++)
            // {
            //     printf("%d", ANS[q]);
            // }
            // printf("\n");
            if (check(ANS))
            {
                printf("%.2x\n", x);
            }
        }
    }
    return 0;
}

得到AES后的密文 128fecc28504b24c5bba4acf11360a48

应输入 4d87ef03-77bb-491a-80f5-4620245807c4

0 条评论
某人
表情
可输入 255
目录