REVERSE-如影随形

ISCC2026 WriteUp 提交模板

REVERSE-如影随形

解题思路

1.打开ida看函数
看main函数最后,有比较逻辑

image.png

是个硬编码

image.png

就是c&U.zG<uILF9m0 Y

2.第一关

image.png

// For each source permutation entry, finds its target position and calls the per-cell transform with horizontal/vertical distances.
void __fastcall apply_permutation_distance_transforms(unsigned __int8 (*a1)[4])
{
  char *p_M; // r14
  int n4; // r15d
  __int64 i; // r13
  char v4; // di
  int n4_1; // esi
  char *p_M_target; // rbx
  __int64 v7; // r9
  int v8; // r9d
  int n4_2; // edx

  p_M = (char *)&g_source_permutation_matrix;
  n4 = 4;
  do
  {
    for ( i = 0; i != 4; ++i )
    {
      v4 = p_M[i];
      n4_1 = n4 - 4;
      p_M_target = (char *)&g_target_identity_matrix;
LABEL_4:
      while ( 2 )
      {
        v7 = 0;
        while ( v4 != p_M_target[v7] )
        {
          if ( ++v7 == 4 )
          {
            ++n4_1;
            p_M_target += 4;
            if ( n4 != n4_1 )
              goto LABEL_4;
            goto LABEL_8;
          }
        }
        v8 = v7 - i;
        n4_2 = -n4_1;
        if ( n4_1 > 0 )
          n4_2 = n4_1;
        if ( v8 <= 0 )
          v8 = -v8;
        ++n4_1;
        p_M_target += 4;
        transform_matrix_cell_by_distance(a1, 4 - n4, i, v8, n4_2);
        if ( n4 != n4_1 )
          continue;
        break;
      }
LABEL_8:
      ;
    }
    p_M += 4;
    --n4;
  }
  while ( n4 );
}

会遍历两个 4x4 表:

M_target = 0  1  2  3
           4  5  6  7
           8  9  a  b
           c  d  e  f

M =        7  8  c  9
           e  3  5  2
           0  f  d  b
           a  4  1  6

它对 M 中每个元素,去 M_target 里找对应位置,然后得到当前位置与目标位置之间的横向距离和纵向距离,再调用 0x1400018A0 做一次“整串变换 + 单点变换”。

0x1400018A0 的逻辑分两段:

  1. 先把 4x4 矩阵按行拍平成 16 字节字符串。
  2. 对整个 16 字节做一次 printable 区间上的链式 mod95 位移。
    公式可以写成:
y = (shift + x - 32) % 95 + 32
shift = y - 32

这里初始 shift 是刚才求出来的横向距离。

  1. 然后只修改某一个格子,修改次数等于纵向距离。
    这里用了一个伪装得很像 flag 的字符串:
    iscc_{this_is_not_flag}

它其实只是 key,不是答案。另一个表 cfg::kMapXor 会先整体异或 0x60 还原成一个 95 字节置换表,再配合这个 key 做单点替换。

这两个步骤都是可逆的,所以我们只要把 16 次操作倒着跑一遍就能拿回原串

image.png

ISCC{8,Fu}@V$s2sSt8y}

Exp

TARGET_BYTES = b"c&U.zG<uILF9m0 Y"
KEY_BYTES = b"iscc_{this_is_not_flag}"

TRANSFORM_STEPS = [
    (0, 0, 3, 1), (0, 1, 1, 2), (0, 2, 2, 3), (0, 3, 2, 2),
    (1, 0, 2, 2), (1, 1, 2, 1), (1, 2, 1, 0), (1, 3, 1, 1),
    (2, 0, 0, 2), (2, 1, 2, 1), (2, 2, 1, 1), (2, 3, 0, 0),
    (3, 0, 2, 1), (3, 1, 1, 2), (3, 2, 1, 3), (3, 3, 1, 2),
]

ENCODED_SBOX_BYTES = bytes([
    0x43, 0x6F, 0x2E, 0x5E, 0x7F, 0x5F, 0x59, 0x39, 0x6D, 0x62, 0x73, 0x6B, 0x52, 0x51, 0x47, 0x27,
    0x31, 0x45, 0x42, 0x24, 0x2F, 0x74, 0x58, 0x32, 0x75, 0x63, 0x5D, 0x7C, 0x71, 0x79, 0x2B, 0x29,
    0x2A, 0x68, 0x22, 0x44, 0x23, 0x5A, 0x7B, 0x6E, 0x28, 0x7D, 0x67, 0x60, 0x3C, 0x65, 0x30, 0x21,
    0x2C, 0x4F, 0x4A, 0x3B, 0x48, 0x6A, 0x55, 0x4D, 0x70, 0x41, 0x57, 0x49, 0x3D, 0x69, 0x20, 0x5B,
    0x37, 0x36, 0x3E, 0x7A, 0x66, 0x26, 0x4E, 0x2D, 0x77, 0x54, 0x4B, 0x3A, 0x4C, 0x76, 0x7E, 0x61,
    0x25, 0x50, 0x5C, 0x78, 0x34, 0x53, 0x38, 0x72, 0x33, 0x64, 0x56, 0x40, 0x35, 0x46, 0x6C,
])

decoded_sbox = bytes(value ^ 0x60 for value in ENCODED_SBOX_BYTES)
inverse_sbox = [0] * 95
for source_index, mapped_value in enumerate(decoded_sbox):
    inverse_sbox[mapped_value] = source_index


def reverse_chain_shift(byte_values, initial_shift):
    restored_values = []
    rolling_shift = initial_shift % 95

    for encoded_value in byte_values:
        normalized_value = encoded_value - 32
        original_value = (normalized_value - rolling_shift) % 95 + 32
        restored_values.append(original_value)
        rolling_shift = normalized_value

    return restored_values


def reverse_cell_transform(byte_values, row_index, column_index, repeat_count):
    if repeat_count == 0:
        return byte_values

    flat_index = row_index * 4 + column_index
    current_value = byte_values[flat_index] - 32
    key_offset = KEY_BYTES[repeat_count % len(KEY_BYTES)] % 95

    for _ in range(repeat_count):
        current_value = inverse_sbox[(current_value - key_offset) % 95]

    byte_values[flat_index] = current_value + 32
    return byte_values


working_values = list(TARGET_BYTES)

for row_index, column_index, horizontal_shift, vertical_shift in reversed(TRANSFORM_STEPS):
    working_values = reverse_cell_transform(
        working_values,
        row_index,
        column_index,
        vertical_shift,
    )
    working_values = reverse_chain_shift(working_values, horizontal_shift)

print("ISCC{" + bytes(working_values).decode() + "}")


posted @ 2026-05-19 16:32  MillionMind  阅读(6)  评论(0)    收藏  举报