SMC + 摩斯密码 + SM4 + RC5

一个很好的题目 出题人很有水平 拿到题目先运行 这个先运行 其实没啥大问题 除了有些出题人脑残做了个勒索或者一个病毒放在里面 需要你来解密那种不能运行 不过一般都有提醒的 说多了都是痛 给我电脑整重装系统了

image

好了言归正传 简单玩了一下能看到 要求输入了一个翻译 能看出来这个只有两个字 而且有分割 所以猜测是摩斯 解密出来真是摩斯

image

喵呜喵呜/呜喵/喵/呜呜喵喵呜喵/呜呜/喵呜/呜呜喵喵呜喵/喵呜呜喵/呜呜喵喵呜喵/呜喵喵喵喵/喵喵喵喵呜/呜呜喵喵呜喵/喵呜喵喵/呜呜喵喵呜喵/呜呜呜喵喵/喵喵喵喵呜

喵 \ - 呜 \ . / =

-.-. .- - ..--.- .. -. ..--.- -..- ..--.- .---- ----. ..--.- -.-- ..--.- ...-- ----.
CAT_IN_X_19_Y_39

image

到下一个路径 也就是要找key

image

ida打开 我们能看到是 有很多提示的 有flag

image

我们去找key 看看哪里调用了 发现无法反编译 往下看看 能看到一团不能反编译的东西 再往下还有

image

我们再往下看是谁调用了下面一坨东西

int sub_401ED0()
{
  int i; // [esp+D0h] [ebp-20h]
  int flOldProtect[2]; // [esp+E8h] [ebp-8h] BYREF

  __CheckForDebuggerJustMyCode(&unk_46401A);
  if ( unk_462A40 == 32 )
  {
    VirtualProtect(dword_402780, 0x7C5u, 0x40u, (PDWORD)flOldProtect);
    for ( i = 0; i < 1989; ++i )
      *((_BYTE *)dword_402780 + i) ^= unk_462A40;
  }
  return 0;
}

这里进行了一个SMC 解密就可以了

s=0x402780
for i in range(1989):
    patch_byte(s+i,get_wide_byte(s+i)^32)

解密出来的是真的迷宫图 也就是我们刚刚看到的所玩的游戏 里面还有一个假的图 有兴趣的可以看看

int sub_402780()
{
  char v1; // [esp+3DFh] [ebp-82Dh]
  char v2; // [esp+3EBh] [ebp-821h]
  int v3; // [esp+454h] [ebp-7B8h]
  int v4; // [esp+460h] [ebp-7ACh]
  int i; // [esp+46Ch] [ebp-7A0h]
  int j; // [esp+46Ch] [ebp-7A0h]
  char Buffer[42]; // [esp+478h] [ebp-794h] BYREF
  __int16 v8; // [esp+4A2h] [ebp-76Ah]
  _WORD v9[22]; // [esp+4A4h] [ebp-768h] BYREF
  _WORD v10[22]; // [esp+4D0h] [ebp-73Ch] BYREF
  _WORD v11[22]; // [esp+4FCh] [ebp-710h] BYREF
  _WORD v12[22]; // [esp+528h] [ebp-6E4h] BYREF
  _WORD v13[22]; // [esp+554h] [ebp-6B8h] BYREF
  _WORD v14[22]; // [esp+580h] [ebp-68Ch] BYREF
  _WORD v15[22]; // [esp+5ACh] [ebp-660h] BYREF
  _WORD v16[22]; // [esp+5D8h] [ebp-634h] BYREF
  _WORD v17[22]; // [esp+604h] [ebp-608h] BYREF
  _WORD v18[22]; // [esp+630h] [ebp-5DCh] BYREF
  _WORD v19[22]; // [esp+65Ch] [ebp-5B0h] BYREF
  _WORD v20[22]; // [esp+688h] [ebp-584h] BYREF
  _WORD v21[22]; // [esp+6B4h] [ebp-558h] BYREF
  _WORD v22[22]; // [esp+6E0h] [ebp-52Ch] BYREF
  _WORD v23[22]; // [esp+70Ch] [ebp-500h] BYREF
  _WORD v24[22]; // [esp+738h] [ebp-4D4h] BYREF
  _WORD v25[22]; // [esp+764h] [ebp-4A8h] BYREF
  _WORD v26[22]; // [esp+790h] [ebp-47Ch] BYREF
  _WORD v27[22]; // [esp+7BCh] [ebp-450h] BYREF
  char v28[1060]; // [esp+7E8h] [ebp-424h] BYREF

  __CheckForDebuggerJustMyCode(&unk_46401A);
  printf("@为冒险者,请在迷宫中寻找笨橘猫吧!!\n");
  strcpy(Buffer, "00000000000000000000000000000000000000000");
  v8 = 0;
  strcpy((char *)v9, "0 0 0 0!    0     0 0 0 0 0*    0     0 0");
  v9[21] = 0;
  strcpy((char *)v10, "0 0 0 00000 00000 0 0 0 0 00000 00000 0 0");
  v10[21] = 0;
  strcpy((char *)v11, "0 0               0 0 0               0 0");
  v11[21] = 0;
  strcpy((char *)v12, "0 000 000 0 000 0 0 0 000 000 0 000 0 0 0");
  v12[21] = 0;
  strcpy((char *)v13, "0 0     0 0 0   0 0 0 0     0 0 0   0 0 0");
  v13[21] = 0;
  strcpy((char *)v14, "0 0 0 00000 000 000 0 0 0 00000 000 000 0");
  v14[21] = 0;
  strcpy((char *)v15, "0 0 0     0   0 0     0 0     0   0 0   0");
  v15[21] = 0;
  strcpy((char *)v16, "0 000 0 0 000 0 0 0 0 000 0 0 000 0 0 0 0");
  v16[21] = 0;
  strcpy((char *)v17, "0     0 0 0 0 0 0 0 0     0 0 0 0 0 0 0 0");
  v17[21] = 0;
  strcpy((char *)v18, "0 00000 000 000 0 0 0 00000 000 000 0 0 0");
  v18[21] = 0;
  strcpy((char *)v19, "0     0       0   0 0     0       0   0 0");
  v19[21] = 0;
  strcpy((char *)v20, "000 0 0 0 000 0 0 0 000 0 0 0 000 0 0 0 0");
  v20[21] = 0;
  strcpy((char *)v21, "0 0 0 0 0 0   0 0 0 0 0 0 0 0 0   0 0 0 0");
  v21[21] = 0;
  strcpy((char *)v22, "0 0000000 0 000 00000 0000000 0 000 00000");
  v22[21] = 0;
  strcpy((char *)v23, "0@  0   0 0         0   0   0 0         0");
  v23[21] = 0;
  strcpy((char *)v24, "0 0 0 0 0 00000000000 0 0 0 0 00000000000");
  v24[21] = 0;
  strcpy((char *)v25, "0 0 0 0             0 0 0 0             0");
  v25[21] = 0;
  strcpy((char *)v26, "000 0 00000 0 000 00000 0 00000 0 000 000");
  v26[21] = 0;
  strcpy((char *)v27, "0         0 0   0   0         0 0   0   0");
  v27[21] = 0;
  strcpy(v28, "00000000000000000000000000000000000000000");
  memset(&v28[42], 0, 1014);
  v1 = 0;
  v4 = 15;
  v3 = 1;
  for ( i = 0; i <= 40; ++i )
    puts(&Buffer[44 * i]);
  while ( v4 != 7 || v3 != 40 )
  {
    if ( v4 == 1 && v3 == 7 )
    {
      printf("当你寻找到这里的时候,你发现它是可恶的偷猫人!?\n");
      printf("你被抓起来了...\n");
      Sleep(0x1388u);
      _loaddll(0);
    }
    if ( v4 == 1 && v3 == 27 )
    {
      printf("好耶!!!你终于找到了笨橘猫\n");
      printf("她的毛上都沾满了污泥,毛发都结成了一块一块\n");
      printf("原本灵动皎洁的眼睛都变得黯淡无光\n");
      printf("你非常的心疼,你想立马上去带她回家\n");
      printf("但是她好像有话和你说,你能解出她的话语嘛...\n");
      printf(
        "笨橘猫:喵呜喵呜/呜喵/喵/呜呜喵喵呜喵/呜呜/喵呜/呜呜喵喵呜喵/喵呜呜喵/呜呜喵喵呜喵/呜喵喵喵喵/喵喵喵喵呜/呜呜喵喵呜喵/喵呜喵喵/呜呜喵喵呜喵/呜呜呜喵喵/喵喵喵喵呜\n");
      sub_402F60();
      v1 = 1;
      HIBYTE(v27[19]) = (unsigned __int8)"T";
    }
    if ( v4 == 19 && v3 == 39 && v1 == 1 )
    {
      printf("你找到了这只可怜的流浪小猫\n");
      printf("但是你们不知道怎么逃出这个迷宫\n");
      printf("小猫经常在这片区域流浪\n");
      printf("这时小猫告诉你,他知道出口在哪里\n");
      printf("但是需要你先找到开启出口的钥匙,你能找到它嘛!!!\n");
      sub_402410();
      LOBYTE(v15[20]) = (unsigned __int8)" ";
    }
    ((void (__thiscall *)(int (***)()))**off_46200C)(off_46200C);
    v2 = _getch();
    ((void (__thiscall *)(int (***)()))**off_46200C)(off_46200C);
    switch ( v2 )
    {
      case 's':
        if ( Buffer[44 * v4 + 44 + v3] != 48 )
        {
          Buffer[44 * v4++ + v3] = 32;
          Buffer[44 * v4 + v3] = 64;
        }
        break;
      case 'w':
        if ( Buffer[44 * v4 - 44 + v3] != 48 )
        {
          Buffer[44 * v4-- + v3] = 32;
          Buffer[44 * v4 + v3] = 64;
        }
        break;
      case 'a':
        if ( Buffer[44 * v4 - 1 + v3] != 48 )
        {
          Buffer[44 * v4 + v3--] = 32;
          Buffer[44 * v4 + v3] = 64;
        }
        break;
      default:
        if ( v2 == 100 && Buffer[44 * v4 + 1 + v3] != 48 )
        {
          Buffer[44 * v4 + v3++] = 32;
          Buffer[44 * v4 + v3] = 64;
        }
        break;
    }
    sub_42AD51((int)"cls");
    for ( j = 0; j <= 40; ++j )
      puts(&Buffer[44 * j]);
  }
  sub_42AD51((int)"cls");
  Sleep(0x1F4u);
  printf("感谢你找到了笨橘猫并且带小猫咪跑了出来\n");
  printf("为了奖励你flag就是CatCTF{第一段翻译+_+第二段key}\n");
  printf("非常感谢你的爱心,让我们一起爱护流浪猫吧!!!\n");
  printf("其中笨橘猫的那段话语彩蛋你发现了嘛!?\n");
  sub_42AD51((int)"pause");
  return 0;
}

但是还是不行啊 这个图我们解过了 对不对 这个时候我们要回到我们一开始的地方 也就是显示key对不对的地方 能够发现能显示了

int sub_402410()
{
  int j; // [esp+D0h] [ebp-1A0h]
  unsigned __int8 v2; // [esp+DFh] [ebp-191h]
  char v3; // [esp+EBh] [ebp-185h]
  int v4[6]; // [esp+10Ch] [ebp-164h] BYREF
  int v5[6]; // [esp+124h] [ebp-14Ch]
  int v6[13]; // [esp+13Ch] [ebp-134h] BYREF
  char v7[24]; // [esp+170h] [ebp-100h] BYREF
  int v8[28]; // [esp+188h] [ebp-E8h] BYREF
  int v9[28]; // [esp+1F8h] [ebp-78h] BYREF
  int i; // [esp+268h] [ebp-8h]

  __CheckForDebuggerJustMyCode(&unk_46401A);
  v5[0] = -1821724372;
  v5[1] = -310169419;
  v5[2] = -295936376;
  v5[3] = -519352180;
  sub_401AB0(v7, dword_462018);
  sub_4021B0((int)v7, v9);
  for ( i = 0; i < 26; ++i )
    v8[i] = v9[i];
  v3 = 0;
  v2 = 0;
  printf("请输入你找到的key\n");
  while ( v3 != 10 )
  {
    v3 = j___fgetchar();
    *((_BYTE *)&v6[6] + v2++) = v3;
  }
  if ( v2 > 0x11u )
  {
    printf("长度错误");
    Sleep(0x1388u);
    _loaddll(0);
  }
  for ( j = 0; j < 4; ++j )
    v6[j] = SHIBYTE(v6[j + 6]) | (SBYTE2(v6[j + 6]) << 8) | (SBYTE1(v6[j + 6]) << 16) | (SLOBYTE(v6[j + 6]) << 24);
  sub_401950(v6, v4, v8);
  for ( i = 0; i < 4; ++i )
  {
    if ( v4[i] != v5[i] )
    {
      printf("这把钥匙好像打不开大门\n");
      Sleep(0x1388u);
      _loaddll(0);
    }
  }
  return printf("成功了,大门已经打开,快点跑出去吧!!!\n");
}

发现是一个RC5 看着并没有魔改 从网上找一个解密脚本就可以了

int __cdecl sub_4021B0(int a1, _DWORD *a2)
{
  int result; // eax
  unsigned int v3; // [esp+Ch] [ebp-13Ch]
  unsigned int v4; // [esp+Ch] [ebp-13Ch]
  int v5[6]; // [esp+D4h] [ebp-74h]
  int v6; // [esp+ECh] [ebp-5Ch]
  unsigned int v7; // [esp+F8h] [ebp-50h]
  unsigned int v8; // [esp+104h] [ebp-44h]
  unsigned int v9; // [esp+110h] [ebp-38h]
  int v10; // [esp+11Ch] [ebp-2Ch]
  int i; // [esp+128h] [ebp-20h]
  int v12; // [esp+134h] [ebp-14h]
  int v13; // [esp+140h] [ebp-8h]

  __CheckForDebuggerJustMyCode(&unk_46401A);
  v13 = 0xB7E15163;
  v12 = 0x9E3779B9;
  v10 = dword_462010 / 8;
  v6 = 0;
  v7 = 0;
  v8 = 0;
  v9 = 0;
  *a2 = 0xB7E15163;
  for ( i = 1; i < dword_46201C; ++i )
    a2[i] = v12 + a2[i - 1];
  for ( i = 0; i < dword_462020; ++i )
    v5[i] = 0;
  for ( i = dword_462018 - 1; i != -1; --i )
    v5[i / v10] = *(unsigned __int8 *)(i + a1) + (v5[i / v10] << 8);
  for ( i = 0; ; ++i )
  {
    result = 3 * dword_46201C;
    if ( i >= 3 * dword_46201C )
      break;
    v3 = ((v6 + v7 + a2[v9]) >> (dword_462010 - ((dword_462010 - 1) & 3))) | ((v6 + v7 + a2[v9]) << ((dword_462010 - 1) & 3));
    a2[v9] = v3;
    v7 = v3;
    v9 = (v9 + 1) % dword_46201C;
    v4 = ((v6 + v3 + v5[v8]) >> (dword_462010 - ((dword_462010 - 1) & (v6 + v3)))) | ((v6 + v3 + v5[v8]) << ((dword_462010 - 1) & (v6 + v3)));
    v5[v8] = v4;
    v6 = v4;
    v8 = (v8 + 1) % dword_462020;
  }
  return result;
}

exp

import math

MASK = 0xffffffff
P = 0xB7E15163
Q = 0x9E3779B9

w = 32
r = 12
b = 16
c = 4
t = 26

def rol(x, n):
    n &= 31
    x &= MASK
    return ((x << n) | (x >> (32 - n))) & MASK

def ror(x, n):
    n &= 31
    x &= MASK
    return ((x >> n) | (x << (32 - n))) & MASK

key = [0] * 16
key[0] = 3
for i in range(1, 16):
    key[i] = int(math.pow(3.0, float(i))) % (255 - i)

L = [0] * 4
for i in range(15, -1, -1):
    L[i // 4] = (key[i] + (L[i // 4] << 8)) & MASK

S = [0] * t
S[0] = P
for i in range(1, t):
    S[i] = (S[i - 1] + Q) & MASK

A = B = 0
i = j = 0
for _ in range(3 * t):
    A = S[i] = rol((S[i] + A + B) & MASK, 3)
    B = L[j] = rol((L[j] + A + B) & MASK, A + B)
    i = (i + 1) % t
    j = (j + 1) % c

def decrypt_block(A, B):
    for i in range(r, 0, -1):
        B = ror((B - S[2 * i + 1]) & MASK, A) ^ A
        A = ror((A - S[2 * i]) & MASK, B) ^ B
        A &= MASK
        B &= MASK

    B = (B - S[1]) & MASK
    A = (A - S[0]) & MASK
    return A, B

cipher = [
    -1821724372 & MASK,
    -310169419 & MASK,
    -295936376 & MASK,
    -519352180 & MASK,
]

plain_words = []
for i in range(0, 4, 2):
    a, b = decrypt_block(cipher[i], cipher[i + 1])
    plain_words.append(a)
    plain_words.append(b)

flag = b''.join(x.to_bytes(4, 'big') for x in plain_words)

print(flag.decode())

解出来第二段key

LIKE_OR_LOVE_CAT

所以我们的flag就是

CatCTF{CAT_IN_X_19_Y_39_LIKE_OR_LOVE_CAT}

其实这题的正常解密就是这样 当然还有不正常的 哈哈哈

当你没有看到哪个谜语是摩斯的时候 你就要去找请输入你的翻译了

int sub_402F60()
{
  char v1[27]; // [esp+D0h] [ebp-114h]
  unsigned __int8 v2; // [esp+EBh] [ebp-F9h]
  char v3; // [esp+F7h] [ebp-EDh]
  unsigned int i; // [esp+100h] [ebp-E4h]
  char v5[140]; // [esp+10Ch] [ebp-D8h] BYREF
  char v6[28]; // [esp+198h] [ebp-4Ch] BYREF
  char v7[28]; // [esp+1B4h] [ebp-30h] BYREF
  char v8[20]; // [esp+1D0h] [ebp-14h] BYREF

  __CheckForDebuggerJustMyCode(&unk_46401A);
  qmemcpy(v8, "wuwuwuyoucatchme", 16);
  v3 = 0;
  v2 = 0;
  printf("请输入你的翻译\n");
  while ( v3 != 10 )
  {
    v3 = j___fgetchar();
    v7[v2++] = v3;
  }
  v1[0] = -74;
  v1[1] = 117;
  v1[2] = -31;
  v1[3] = 121;
  v1[4] = 112;
  v1[5] = -63;
  v1[6] = 39;
  v1[7] = 72;
  v1[8] = 9;
  v1[9] = 11;
  v1[10] = -74;
  v1[11] = 77;
  v1[12] = 2;
  v1[13] = -68;
  v1[14] = 6;
  v1[15] = 25;
  sub_403DF0(v5, v8);
  sub_403630(v5, 1, 16, v7, v6);
  for ( i = 0; i < 0x10; ++i )
  {
    if ( v6[i] != v1[i] )
    {
      printf("笨橘猫好像不是这个意思,再想想吧!!");
      Sleep(0x1388u);
      _loaddll(0);
    }
  }
  printf("你终于弄懂笨橘猫在说什么了\n");
  printf("原来是这样,笨橘猫看见了可怜的小猫咪流浪街头\n");
  printf("而且这时有可怕的偷猫人想要偷走小猫,笨橘猫带着小猫逃跑\n");
  printf("跑进了下水管道,但是下水道太黑和小猫失散了..\n");
  return printf("快去找到小猫吧,她已经在地图上出现了\n");
}

然后找到了这句话 发现前面有一个字符串 应该是key 然后进去到加密函数里面 发现是一个SM4 byte_4531F0 是 SM4 S-box byte_4532F0 是 FK byte_453300 是 CK 然后找一下魔改点 发现没有 我们直接去解密

image

然后接着去解