2023CISCN华中赛区re
阅读原文时间:2023年08月15日阅读:1

2023CISCN华中赛区re

当时出的题

找so文件,加密过程也不复杂

每三个一组进行加密

这里就是先每个减去65

然后

大概是

y1=(31_x1)%26+65

y2=(31_x1+39_x2)%26+65

y3=(31_x1+39_x2+52_x3)+65

y1,y2,y3为密文存储

我一开始想法是爆出来,没想到组合很多。

但是x1是可以确定的

key=[6, 24, 1, 13, 16, 10, 20, 17, 15]
enc=[0x42, 0x55, 0x5A, 0x53, 0x58, 0x52, 0x4D, 0x4E, 0x41, 0x49, 0x4A, 0x4B, 0x4E, 0x48, 0x49, 0x57, 0x41, 0x59, 0x52, 0x5A, 0x4E, 0x58, 0x43, 0x41, 0x4C, 0x57, 0x58, 0x48, 0x46, 0x4D, 0x4D, 0x4E, 0x4F]
from gmpy2 import*
flag_head=''
for i in range(0,len(enc),3):
    x1=((enc[i]-65)*invert(31,26))%26+65
    flag_head+=chr(x1)
print(flag_head)#VOSMNUTPXRS

这里发现flag的3个一组为加密的第一个字符全是大写字母

所以推测flag全是大写字母

#include<stdio.h>

unsigned int key[9] = {
    0x00000006, 0x00000018, 0x00000001, 0x0000000D, 0x00000010, 0x0000000A, 0x00000014, 0x00000011,
    0x0000000F
};

char enc[] = "BUZSXRMNAIJKNHIWAYRZNXCALWXHFMMNO";
int __fastcall hill_encrypt(char* a1,int x)
{
    bool v2; // [rsp+7h] [rbp-49h]
    int m; // [rsp+8h] [rbp-48h]
    int v4; // [rsp+Ch] [rbp-44h]
    int k; // [rsp+10h] [rbp-40h]
    int j; // [rsp+14h] [rbp-3Ch]
    int i; // [rsp+18h] [rbp-38h]
    int v8; // [rsp+1Ch] [rbp-34h]
    unsigned __int64 v10; // [rsp+48h] [rbp-8h]

        int s[3] = {0}; // [rsp+3Ch] [rbp-14h] BYREF
        for (j = 0;j<3 ; ++j)
        {

            s[j] = a1[j] - 65;
        }
        for (k = 0; k < 3; ++k)
        {
            v4 = 0;
            for (m = 0; m < 3; ++m)
                v4 += s[m] * key[3 * k + m];
            a1[k] = v4 % 26 + 65;
        }
        if( (a1[0] == enc[x]) && (a1[1] == enc[x+1])&& (a1[2] == enc[x+2]))
        {
            return 1;
        }

    return 0;

}
int main()
{

    int i, j, kl, l;
    for (int x = 0; x < 33; x += 3)
    {
        int flag = 0;
        for (int i = 65; i <=65+26; i++)
        {
            for (int j = 65; j < 65 + 26-1; j++)
            {
                for (int k = 65; k < 65 + 26-1; k++)
                {
                    char temp[3];
                    temp[0] = i;
                    temp[1] = j;
                    temp[2] = k;
                    if (hill_encrypt(temp, x))
                    {
                        printf("%c%c%c",i, j, k);
                        flag = 1;

                    }
                    if (flag)
                    {
                        break;
                    }

                }
                if (flag)
                {
                    break;
                }
            }
            if (flag)
            {
                break;
            }
        }

    }

}

这里flag第一位和上面对不上不知道为啥,纯misc脑洞题

这个flag是对的

上来就混淆,我原本准备的去混淆脚本,但是电脑前端时间换了环境,python库没安装,寄掉了,还好d810救了一命

这里使用ollvm

这里去得比较清楚,这里盲猜base64

没想到直接对了,拿了波一血。

同样去混淆,d810去混淆时间要好久

复盘

拿到题看到混淆,去混淆脚本直接寄了,报错没办法解决。

主要是去混淆输入的地址感觉是错的。

还是用d810

但是d810没改汇编,我copy下来自己跑下

显然我们可以简化一下

#include<stdio.h>
#include"defs.h"
int unk_3D030 = 0;
int  main()
{
    int v3; // [rsp+BCh] [rbp-10E4h]
    __int64 s2[4]; // [rsp+D0h] [rbp-10D0h] BYREF
    char s[32]; // [rsp+F0h] [rbp-10B0h] BYREF
    char v6[24]; // [rsp+110h] [rbp-1090h] BYREF
    char v7[4168]; // [rsp+128h] [rbp-1078h] BYREF
    unsigned __int64 v8; // [rsp+1170h] [rbp-30h]

    strcpy(v6, "i_am_a_fish_man");
    memset(s, 0, sizeof(s));
    s2[0] = 0xBCB6C065E9B49472LL;
    s2[1] = 0xDBD7F8723B1F9F9CLL;
    s2[2] = 0x925740C949C6E3CDLL;
    s2[3] = 0x6B18711A0CF70D06LL;
    puts("Pls input flag");
    //read(0, s, 0x20uLL);
    scanf("%s", s);
    v3 = 0;
    memcpy(v7, "fishrman", 8LL);
    while (v3 < 4)
    {

      //sub_167F0(v7, &s[8 * v3], &s[8 * v3 + 4]);

        ++v3;
    }
    //sub_30990(s, 32LL, v6, 15LL);
    if (!memcmp(s, s2, 0x20uLL))
    {
        puts("you get the flag");
        _exit(0);
    }
    puts("flag is error");
    _exit(0);
}

接下来就是继续优化sub_167F0和sub_30990了

这里使用对应的优化后copy到vs里面,速度很慢,这里不在赘述

这里也不知道着加密算法

最后用插件找到了

接着把d810优化过的函数,放到vs里面,利用编译器优化。

直接copy进去,不透明谓词一般是全局变量,我们置为0

不过我们为了消除它的影响,设置为局部变量为0,同时开启release

这样经过vs编译出来的,我们可以看个大概了

下面的函数

还原地有问题,但可以分辨出这是RC4初始化盒子的地方,但是对密文操作没有了,不知道为啥优化没了

这里找到初始的函数猜了一波

void __stdcall init_sbox(_BYTE *s_box, int a2, _BYTE *key, int a4, unsigned __int64 a5)
{
  int v5; // esi
  int i; // ebx
  int j; // eax
  unsigned __int8 v8; // bl
  char v9[256]; // [esp+14h] [ebp-104h] BYREF

  v5 = 0;
  memset(v9, 0, sizeof(v9));
  for ( i = 0; i < 256; ++i )
  {
    s_box[i] = i;
    v9[i] = key[i % a5];
  }
  for ( j = 0; j < 256; ++j )
  {
    v8 = s_box[j];
    v5 = (v8 + v9[j] + v5) % 256;
    s_box[j] = s_box[v5];
    s_box[v5] = v8;
  }
}

init_sbox(...)
j=0
index=0
for(int i=0;i<32;i++)
{
  j+=1;
  j%=256;
  index=(index+s_box[j])%256
  swap(&s_box[j],&s_box[index]);
  index2=(s_box[index]+s_box[j])%256
  //这里魔改了
  input[i]=(input[i]+s_box[index2]+16-394991376)

}

可以发现16-394991376是没用的

input[i]=(input[i]+s_box[index2])



enc=[0x72, 0x94, 0xB4, 0xE9, 0x65, 0xC0, 0xB6, 0xBC, 0x9C, 0x9F, 0x1F, 0x3B, 0x72, 0xF8, 0xD7, 0xDB, 0xCD, 0xE3, 0xC6, 0x49, 0xC9, 0x40, 0x57, 0x92, 0x06, 0x0D, 0xF7, 0x0C, 0x1A, 0x71, 0x18, 0x6B]

a=[0]*256
key="i_am_a_fish_man"
for i in range(256):
    a[i]=i
v6 = 0
for j in range(256):
    v6=(ord(key[j%len(key)])+v6+a[j])%256
    v3 = a[j]
    a[j] = a[v6]
    a[v6] = v3
v7 = 0
v8 = 0
for k in range(32):
    v8 = (v8 + 1) % 256
    v7 = (v7 + a[v8]) % 256
    temp = a[v8]
    a[v8] = a[v7]
    a[v7] = temp
    x=(a[(a[v7] + a[v8]) % 256])&0xff
    enc[k]-=x
    enc[k]&=0xff
print(enc)
#[122, 73, 76, 203, 209, 228, 164, 144, 213, 221, 151, 124, 19, 36, 165, 83, 113, 87, 165, 82, 153, 183, 185, 34, 211, 49, 31, 211, 162, 151, 214, 194]

BLOWFISH解密 脚本:https://www.cnblogs.com/iBinary/p/14883752.html#25完成代码

int main()
{
    char enc[] = { 122, 73, 76, 203, 209, 228, 164, 144, 213, 221, 151, 124, 19, 36, 165, 83, 113, 87, 165, 82, 153, 183, 185, 34, 211, 49, 31, 211, 162, 151, 214, 194 ,0};
    BLOWFISH_CTX ctx;
    char key[] = "fishrman";
    size_t len = strlen("fishrman");
    BlowFishInit(&ctx, (unsigned char*)key, len);
    for (int i = 0; i < 4; i++)
    {
        BlowFish_Decrypt(&ctx, (unsigned int*)(&enc[8 * i]), (unsigned int*)(&enc[8 * i + 4]));
    }
    puts(enc);
}

总结一下思路,先用deflat.py脚本报错->d810插件去除部分混淆->findcrypt插件找到加密算法BLOWFISH(猜第一组加密是它)->利用编译器优化找到部分RC4特征猜RC4(发现魔改了一点 异或改加法了)

ps:当时第一个安卓题浪费太多了时间了,这个题之前发现是BLOWFISH+RC4,一把梭哈没出来。上午离比赛结束还有20分钟,当时太急了,魔改没找到。

剩下2个题暂时没思路,未完待续。