Solution

И снова не понятно, что за файл. В diec его:

Info:
    File name: /spbctf_rev/cosy/cosy
    Size: 16384
    File type: ELF64
    String: ELF(AMD64)
    Extension: so
    Operation system: Debian Linux(ABI: 3.2.0)
    Architecture: AMD64
    Mode: 64-bit
    Type: DYN
    Endianness: LE

Анализ main

Пойду смотреть main.

  int32_t main(int32_t argc, char** argv, char** envp)

  {
      puts("Give me the key: ");
      char buf[0x100];
      fgets(&buf, 0xff, stdin);
      int32_t rax = strlen(&buf);
      buf[(uint64_t)(rax - 1)] = 0;
      
      if (strlen(&buf) != 0x16)
      {
          puts("Incorrect length");
          exit(0xffffffff);
          /* no return */
      }
      
      int64_t var_138;
      __builtin_memset(&var_138, 0, 0x16);
      int32_t var_198;
      __builtin_memcpy(&var_198, 
          "\x11\x0c\x00\x00\xbb\x25\x00\x00\xae\x00\x00\x00\x09\x27\x00\x00\xb7\x0c\x00\x00\xe9\x26\x00"
      "00\xf4\x16\x00\x00\xce\x22\x00\x00\x0b\x18\x00\x00\x02\x27\x00\x00\x1e\x11\x00\x00\xc8\x1e\x"
      "00\x00\xc2\x04\x00\x00\xd4\x21\x00\x00\xb7\x0c\x00\x00\x2a\x22\x00\x00\x0b\x18\x00\x00\x35\x"
      "26\x00\x00\x87\x13\x00\x00\xef\x24\x00\x00\xc2\x04\x00\x00\x33\x1f\x00\x00", 
          0x58);
      int32_t var_c = 0;
      
      while (true)
      {
          if (rax - 1 <= var_c)
          {
              puts("Correct!");
              exit(0);
              /* no return */
          }
          
          int32_t rax_9 = toRad(buf[(int64_t)var_c]);
          
          if (rax_9 < 0)
          {
              puts("Internal error");
              exit(0xffffffff);
              /* no return */
          }
          
          int32_t temp0_1;
          int32_t temp1_1;
          temp0_1 = HIGHD((int64_t)var_c);
          temp1_1 = LOWD((int64_t)var_c);
          uint32_t rdx_3 = temp0_1 >> 0x1f;
          
          if (modify(rax_9, ((temp1_1 + rdx_3) & 1) - rdx_3) != (&var_198)[(int64_t)var_c])
              break;
          
          var_c += 1;
      }
      
      puts("Wrong input");
      exit(0xffffffff);
      /* no return */
  }

Слишком много букаф. Ну да ладно. Флаг у нас имеет длину 22.

Анализ toRad

Мда. Переводим символ в число. Пон)

  uint64_t toRad(char arg1)
  {
      if (arg1 > '`' && arg1 <= 'z')
          return (uint64_t)((int32_t)arg1 - 'a');
      
      if (arg1 > '/' && arg1 <= '9')
          return (uint64_t)((int32_t)arg1 - '\x16');
      
      if (arg1 == '{')
          return '$';
      
      if (arg1 == '}')
          return '%';
      
      if (arg1 != '_')
          return 4294967295;
      
      return '&';
  }

Анализ modify

Опять немного математики.

  uint64_t modify(int32_t arg1, int32_t arg2)
  {
      double zmm0 = 3.141 * (double)arg1 / 180.0;
      
      if (!arg2)
          return (uint64_t)(int32_t)(sin(zmm0) * 10000.0);
      
      if (arg2 != 1)
          return 0;
      
      return (uint64_t)(int32_t)(cos(zmm0) * 10000.0);
  }

Написание декодера

Разбирать многое то и не нужно. Каждый символ ключа преобразуется вот в такие значения:

    mem2[0] = 0xc11;
    mem2[1] = 0x25bb;
    mem2[2] = 0xae;
    mem2[3] = 0x2709;
    mem2[4] = 0xcb7;
    mem2[5] = 0x26e9;
    mem2[6] = 0x16f4;
    mem2[7] = 0x22ce;
    mem2[8] = 0x180b;
    mem2[9] = 0x2702;
    mem2[10] = 0x111e;
    mem2[11] = 0x1ec8;
    mem2[12] = 0x4c2;
    mem2[13] = 0x21d4;
    mem2[14] = 0xcb7;
    mem2[15] = 0x222a;
    mem2[16] = 0x180b;
    mem2[17] = 0x2635;
    mem2[18] = 0x1387;
    mem2[19] = 0x24ef;
    mem2[20] = 0x4c2;
    mem2[21] = 0x1f33;

Есть 2 возможных логичных решения:

  • повторить код и брутить значения;
  • написать обратные функции;

Первый вариант проще, поэтому его и сделаю. Меньше шансов ошибиться. Да и можно закинуть код в гпт и попросить его навоять такое же. Мы же тут реверсом занимаемся, а не разработкой. Еще предложите переменные адекватно называть, психи…

import math


def toRad(arg1: str) -> int:
    c = arg1

    if '`' < c <= 'z':  # 'a'..'z'
        return ord(c) - ord('a')

    if '/' < c <= '9':  # '0'..'9'
        return ord(c) - 0x16  # '\x16' == 22

    if c == '{':
        return ord('$')  # '$' == 36

    if c == '}':
        return ord('%')  # '%' == 37

    if c == '_':
        return ord('&')  # '&' == 38

    return 0xFFFFFFFF  # 4294967295 (uint32_t -1)


def modify(arg1: int, arg2: int) -> int:

    zmm0 = 3.141 * float(arg1) / 180.0

    if arg2 == 0:
        val = math.sin(zmm0) * 10000.0
        return int(val) & 0xFFFFFFFF
    elif arg2 == 1:
        val = math.cos(zmm0) * 10000.0
        return int(val) & 0xFFFFFFFF
    else:
        return 0


if __name__ == '__main__':
    mem2 = [0] * 22
    mem2[0] = 0xc11
    mem2[1] = 0x25bb
    mem2[2] = 0xae
    mem2[3] = 0x2709
    mem2[4] = 0xcb7
    mem2[5] = 0x26e9
    mem2[6] = 0x16f4
    mem2[7] = 0x22ce
    mem2[8] = 0x180b
    mem2[9] = 0x2702
    mem2[10] = 0x111e
    mem2[11] = 0x1ec8
    mem2[12] = 0x4c2
    mem2[13] = 0x21d4
    mem2[14] = 0xcb7
    mem2[15] = 0x222a
    mem2[16] = 0x180b
    mem2[17] = 0x2635
    mem2[18] = 0x1387
    mem2[19] = 0x24ef
    mem2[20] = 0x4c2
    mem2[21] = 0x1f33

    for i, target in enumerate(mem2):
        for c in "abcdefghijklmnopqrstuvwxyz_{}0123456789":
            n = toRad(c)
            n = modify(n, i % 2)
            if n == target:
                print(c, end='')
                break
    print('\n')

Запущу код:

root@2972fc48b804:/rev# python3 solver.py
spbctf{1_d0_h4t3_m4th}

Проверю в оригинальном бинаре:

root@2972fc48b804:/rev# ./cosy
Give me the key:
spbctf{1_d0_h4t3_m4th}
Correct!