【KCTF2020秋季赛】异常信号 WriteUp


这道题做出来的时候还是非常激动的,不枉费本菜鸡从中午肝到半夜/(ㄒoㄒ)/~~

这道题的壳是出题方自己写的,强度其实是非常不错的,这里我投机取巧了,直接dump内存后转静态分析,这壳子直接木大

后面的哥隆尺算法卡了我好久,最后只能去找金牌爷了= =


下面是照搬的发在看雪的WriteUp:

肝了个一血出来哈哈哈

直接运行,然后x32dbg附加,注意开启sharpod的anti anti attach,然后ollydumpex,点search image,选择module、binary(virtual),dump下来,用ida打开,定位到sub_2F12B0函数

int sub_2F12B0()
{
  int v0; // esi
  char v1; // al
  char *v2; // ecx
  unsigned __int8 *v3; // ecx
  unsigned __int8 v4; // al
  signed int v5; // eax
  signed int v6; // ecx
  signed int length; // ebx
  unsigned __int8 v8; // al
  char v9; // al
  signed int v10; // edx
  int v11; // esi
  char v12; // cl
  char v13; // al
  char v14; // cl
  signed int v15; // eax
  __int16 v16; // ax
  signed int half_len; // ebx
  int v18; // edi
  int v19; // ecx
  signed int v20; // esi
  signed int v21; // esi
  int v22; // eax
  int v23; // eax
  __int16 v24; // ax
  int v25; // esi
  int v26; // eax
  int v27; // ecx
  int v28; // edx
  int v29; // eax
  __int16 v31; // [esp+Ch] [ebp-514h]
  int v32; // [esp+10h] [ebp-510h]
  int v33; // [esp+14h] [ebp-50Ch]
  unsigned __int16 v34; // [esp+18h] [ebp-508h]
  __int16 v35; // [esp+18h] [ebp-508h]
  int v36; // [esp+1Ch] [ebp-504h]
  int v37; // [esp+20h] [ebp-500h]
  unsigned __int8 input; // [esp+23h] [ebp-4FDh]
  int v39[100]; // [esp+24h] [ebp-4FCh]
  char flag[400]; // [esp+1B4h] [ebp-36Ch]
  char table[256]; // [esp+344h] [ebp-1DCh]
  __int16 dest[50]; // [esp+444h] [ebp-DCh]
  char v43[100]; // [esp+4A8h] [ebp-78h]
  char v44; // [esp+50Ch] [ebp-14h]
  int v45; // [esp+50Dh] [ebp-13h]
  int v46; // [esp+511h] [ebp-Fh]
  int v47; // [esp+515h] [ebp-Bh]
  __int16 v48; // [esp+519h] [ebp-7h]
 
  v0 = *(_DWORD *)&unk_314474;
  memset(*(_DWORD *)&unk_314474, 0, 256);
  v1 = *(_BYTE *)&unk_3138B0;
  if ( *(_BYTE *)&unk_3138B0 )
  {
    v2 = (_BYTE *)&unk_3138B0;
    do
    {
      *(++v2 - 1) = v1 ^ 0xE4;
      v1 = *v2;
    }
    while ( *v2 );
  }
  sub_2F5D70(v0, 0x3138B0, strlen((const char *)&unk_3138B0) + 1);// Correct
  v45 = 0x9091948A;
  v46 = 0x9681B7C4;
  v3 = (unsigned __int8 *)&v44;
  v47 = 0xDE88858D;
  v4 = 0xADu;
  v48 = 0xEE;
  do
  {
    *(++v3 - 1) = v4 ^ 0xE4;
    v4 = *v3;
  }
  while ( *v3 );                                // Input Serial:\n
  v36 = **(_DWORD **)(*(_DWORD *)(*(_DWORD *)&unk_314478 + 0x3C) + *(_DWORD *)&unk_314478 + 0x28);
  printf(&v44);
  memset(v39, 0, 400);
  memset(dest, 0, 200);
  memset(flag, 255, 400);
  memset(table, 255, 256);
  v5 = 0;
  do
  {
    table[v5 + '0'] = v5;
    ++v5;
  }
  while ( v5 <= 9 );
  v6 = 0;
  do
  {
    table[v6 + 'A'] = v6 + 10;
    ++v6;
  }
  while ( v6 <= 5 );
  input = 0;
  length = 0;
  scanf(0x310CDC, &input, 1);                   // %c
  v8 = input;
  if ( input != 10 )
  {
    while ( length < 360 )
    {
      v9 = table[v8];
      if ( v9 == -1 )
      {
LABEL_52:
        printf(0x310C6C);
        printf(0x310C80);                       // 一个礼貌的开场白还是要的
        return 0;
      }
      flag[length++] = v9;
      scanf(0x310CDC, &input, 1);               // %c
      v8 = input;
      if ( input == '\n' )
        goto LABEL_14;
    }
LABEL_32:
    printf(0x310C6C);
    printf(0x310C70);                           // \f换页
    return 0;
  }
LABEL_14:
  v10 = 0;
  if ( length > 0 )
  {
    v11 = *(_DWORD *)&unk_31446C;
    while ( v11 )
    {
      v12 = flag[v10];
      if ( v12 == -1 )
        goto LABEL_52;
      v13 = flag[v10 + 1];
      if ( v13 == -1 )
        goto LABEL_52;
      v14 = v13 + 16 * v12;
      v15 = v10 >> 1;
      v10 += 2;
      *((_BYTE *)dest + v15) = v14;             // 4个输入构成一个int16
      if ( v10 >= length )
        goto LABEL_20;
    }
    goto LABEL_32;
  }
LABEL_20:
  v16 = 0;
  half_len = length >> 2;
  v18 = 0;
  v33 = 0;
  if ( half_len <= 0 )
    goto LABEL_57;
  v19 = 0;
  v32 = 0;
  do
  {
    v34 = -v16;
    sub_2F6305(v19);
    v20 = 0x65;
    do
    {
      v31 = sub_2F62E4();
      --v20;
    }
    while ( v20 );
    sub_2F6305(v34);
    v21 = 0x65;
    do
    {
      v35 = sub_2F62E4();
      --v21;
    }
    while ( v21 );
    v22 = (*(int (__stdcall **)(_DWORD))&unk_30B144)(0);// GetActiveWindow(0)
    if ( v22 )
    {
      v23 = (*(int (__stdcall **)(int))&unk_30B148)(v22);// GetWindowLongA(v22,GWL_STYLE)
      if ( v23 == 0x17CF0000 || v23 == 0x16CF0000 || v23 == 0x97CF0000 )
        goto LABEL_51;
    }
    v24 = dest[v32];                            // v32是满足条件v31的输入的index
    if ( v31 == v24 )
    {
      v39[v18++] = v32;                         // 将满足条件的index入队
    }
    else if ( v35 != v24 )
    {
      goto LABEL_52;
    }
    v16 = v33++ + 1;
    v19 = (unsigned __int16)v33;
    v32 = (unsigned __int16)v33;
  }
  while ( (unsigned __int16)v33 < half_len );
  if ( v18 < 12 )
  {
LABEL_57:
    printf(0x310C6C);
    printf(0x310C9C);                           // 行星太少了
    return 0;
  }
  if ( v39[1] - v39[0] > *(&v37 + v18) - *(&v36 + v18) )
  {
    printf(0x310C6C);
    printf(0x310CA8);                           // 穿越虫洞还得讲个顺序
    return 0;
  }
  memset(v43, 0, 100);
  v25 = 0;
  if ( v18 - 1 <= 0 )
  {
LABEL_49:
    if ( !*(_DWORD *)&unk_314470 )
      return 0;
    printf(*(_DWORD *)&unk_314474);             // Correct
    return 0;
  }
  v26 = v36;
  while ( 1 )
  {
    if ( !v26 )
    {
      printf(0x310C6C);
      printf(0x310C80);                         // 一个礼貌的开场白还是要的
LABEL_47:
      v26 = v36;
      goto LABEL_48;
    }
    v27 = v25 + 1;
    if ( v25 + 1 < v18 )
      break;
LABEL_48:
    if ( ++v25 >= v18 - 1 )
      goto LABEL_49;
  }
  v28 = v39[v25];
  while ( 1 )
  {
    v29 = v39[v27] - v28;                       // v29每次必须不一样
    if ( v43[v29] )                             // 队列中的indexes,两两的差必须唯一
      break;
    ++v27;
    v43[v29] = 1;
    if ( v27 >= v18 )
      goto LABEL_47;
  }
LABEL_51:
  printf(0x310C6C);
  printf(0x310CC0);                             // 有人说这题根本无解,你信吗
  return 0;
}

遇到30xxxx的地址,从x32dbg里查看到底是啥内容

解密脚本:

int gl;
 
int sub_2F62E4()
{
    unsigned int v1;
 
    v1 = 214013 * gl + 2531011;
    gl = v1;
    return (v1 >> 16) & 0x7FFF;
}
 
void sub_2F6305(int a1)
{
    gl = a1;
}
 
int main()
{
    int list[] = { 0,2,6,24,29,40,43,55,68,75,76,85 };
    __int16 v16, v31, v35;
    unsigned __int16 v34;
    int v18, v19, v20, v21, v32;
    int n = 85;
    v16 = 0;
    v19 = 0;
    v32 = 0;
    do
    {
        v34 = -v16;
        sub_2F6305(v19);
        v20 = 0x65;
        do
        {
            v31 = sub_2F62E4();
            --v20;
        } while (v20);
        sub_2F6305(v34);
        v21 = 0x65;
        do
        {
            v35 = sub_2F62E4();
            --v21;
        } while (v21);
        bool isin = false;
        for (size_t i = 0; i < 12; i++)
        {
            if (list[i] == v16)
            {
                isin = true;
                break;
            }
        }
        if (isin)
        {
            if ((v31 / 16 & 0xF) < 10)
                cout << (v31 / 16 & 0xF);
            else
                cout << char((v31 / 16 & 0xF) - 10 + 'A');
            if ((v31 & 0xF) < 10)
                cout << (v31 & 0xF);
            else
                cout << char((v31 & 0xF) - 10 + 'A');
            if ((v31 / 4096 & 0xF) < 10)
                cout << (v31 / 4096 & 0xF);
            else
                cout << char((v31 / 4096 & 0xF) - 10 + 'A');
            if ((v31 / 256 & 0xF) < 10)
                cout << (v31 / 256 & 0xF);
            else
                cout << char((v31 / 256 & 0xF) - 10 + 'A');
        }
        else
        {
            if ((v35 / 16 & 0xF) < 10)
                cout << (v35 / 16 & 0xF);
            else
                cout << char((v35 / 16 & 0xF) - 10 + 'A');
            if ((v35 & 0xF) < 10)
                cout << (v35 & 0xF);
            else
                cout << char((v35 & 0xF) - 10 + 'A');
            if ((v35 / 4096 & 0xF) < 10)
                cout << (v35 / 4096 & 0xF);
            else
                cout << char((v35 / 4096 & 0xF) - 10 + 'A');
            if ((v35 / 256 & 0xF) < 10)
                cout << (v35 / 256 & 0xF);
            else
                cout << char((v35 / 256 & 0xF) - 10 + 'A');
        }
        v16++;
        v19++;
        v32++;
    } while (n--);
    return 0;
}

list中的值要满足的条件是:从[0,89]中选择12个互不相同的数,使它们任意两个数之差都不相同,这里我问了4位ACM金牌爷,2个多小时后有人把结果弄出来了

程序执行的思路就是,读入至多360个字符,只能0-9、A-F,把每4个输入组合成一个类似0x1234这样的short,如果与v31一样,则把下标加入v39队列,如果与v35一样,则继续,如果都不一样,则结束程序。如果v39的元素小于12则结束程序。之后会判断v39里面的数(也就是满足v31的输入的下标)是否两两之差唯一,是的话就输出Correct。

生成v31和v35的算法是可以本地写代码跑出来的,只要输入的满足“下标不在list里的输入等于v35,否则等于v31”的就是flag

补充金牌爷算法:

#include <stdio.h>
 
int c[100];
int a[100];
int abs(int x)
{
    return x <0?-x:x;
}
 
void work(int x,int n,int k)
{
    for(int i=0;i<n;i++)
        c[x-a[i]]+=k;
}
 
int check(int x,int n)
{
    for(int i=0;i<n;i++)
    {
        if(c[x-a[i]] > 0)
            return 0;
    }
    return 1;
}
 
void dfs(int now,int n)
{
    if(n == 12)
    {
        for(int i=0;i<n;i++)
        {
            printf("%d,",a[i]);
        }
        printf("\n");
    }
    if(90-now < 12-n) return ;
    for(int i=now;i<=89;i++)
    {
        if(check(i,n))
        {
            work(i,n,1);
            a[n] = i;
            dfs(i+1,n+1);
            work(i,n,-1);
        }
    }
}
int main()
{
    dfs(0,0);
    return 0;
}

注意,这段代码能跑出多组解,但是其余解不满足程序的要求,会输出“穿越虫洞要讲究顺序”,因此上面那组解应该是唯一满足题目限制的解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值