[Rev] CCE 2025 Qual - Directcalc write-up

TL;DR

콘솔에서는 Base64 문자열을 받고 이를 디코딩한 바이트 열이 메시지 prefix

프로그램이 .rdata 특정 문자열의 128바이트 suffix를 prefix뒤에 붙임

HLSL Compute Shader가 GF(256)에서 신드롬 2 t개를 계산하고 전부 0일 경우 Correct한다.

미지수 64바이트(prefix)를 구해 신드롬이 64개가 모두 0이 되게 만드는 반더몬드 해를 계산한다.

 

Correct를 띄우는 값이 Flag


바이너리 실행흐름

실행 흐름은 다음과 같다. 주요 코드들을 전체로 드리고 아래에 따로 스니펫으로 요약 정리할테니 절대로 놀리지마세요.

 

1. Direct3D 초기화 & Shader Compile

InitD3DAndCompilerShader(sub_140002060)

bool __fastcall InitD3DAndCompileShader(ID3D11Device **ppDevice)
{
  ID3D11DeviceContext **ppImmediateContext; // rbx
  ID3D11Device *v3; // rcx
  ID3D11Device *v4; // rcx
  __int64 *v5; // rax
  ID3DBlob *v7; // rbp
  ID3D11Device *v8; // r12
  ID3D11Device *v9; // rcx
  struct ID3D11DeviceVtbl *lpVtbl; // rsi
  LPVOID (__stdcall *GetBufferPointer)(ID3D10Blob *); // rbx
  __int64 v12; // rdi
  __int64 v13; // rax
  __int64 *v14; // rax
  ID3DBlob *v15; // rcx
  ID3DBlob *v16; // rcx
  ID3DBlob *v17; // rcx
  ID3DBlob *v18; // rcx
  ID3DBlob *ppCode; // [rsp+60h] [rbp-48h] BYREF
  ID3DBlob *ppErrorMsgs; // [rsp+68h] [rbp-40h] BYREF
  D3D_FEATURE_LEVEL pFeatureLevels; // [rsp+70h] [rbp-38h] BYREF
  D3D_FEATURE_LEVEL pFeatureLevel; // [rsp+74h] [rbp-34h] BYREF

  pFeatureLevels = D3D_FEATURE_LEVEL_11_0;
  ppImmediateContext = (ID3D11DeviceContext **)(ppDevice + 1);
  v3 = ppDevice[1];
  if ( v3 )
  {
    *ppImmediateContext = 0LL;
    ((void (__fastcall *)(ID3D11Device *))v3->lpVtbl->Release)(v3);
  }
  v4 = *ppDevice;
  if ( *ppDevice )
  {
    *ppDevice = 0LL;
    ((void (__fastcall *)(ID3D11Device *))v4->lpVtbl->Release)(v4);
  }
  if ( D3D11CreateDevice(
         0LL,
         D3D_DRIVER_TYPE_HARDWARE,
         0LL,
         0,
         &pFeatureLevels,
         1u,
         7u,
         ppDevice,
         &pFeatureLevel,
         ppImmediateContext) >= 0 )
  {
    ppCode = 0LL;
    ppErrorMsgs = 0LL;
    if ( D3DCompile(
           "\n"
           "// GF(256) multiplication and exponentiation tables\n"
           "static const uint exp_table[256] = {\n"
           "    1, 2, 4, 8, 16, 32, 64, 128, 45, 90, 180, 69, 138, 57, 114, 228, 229, 231, 227, 235, 251, 219, 155, 27, 5"
           "4, 108, 216, 157, 23, 46, 92, 184, 93, 186, 89, 178, 73, 146, 9, 18, 36, 72, 144, 13, 26, 52, 104, 208, 141, "
           "55, 110, 220, 149, 7, 14, 28, 56, 112, 224, 237, 247, 195, 171, 123, 246, 193, 175, 115, 230, 225, 239, 243, "
           "203, 187, 91, 182, 65, 130, 41, 82, 164, 101, 202, 185, 95, 190, 81, 162, 105, 210, 137, 63, 126, 252, 213, 1"
           "35, 35, 70, 140, 53, 106, 212, 133, 39, 78, 156, 21, 42, 84, 168, 125, 250, 217, 159, 19, 38, 76, 152, 29, 58"
           ", 116, 232, 253, 215, 131, 43, 86, 172, 117, 234, 249, 223, 147, 11, 22, 44, 88, 176, 77, 154, 25, 50, 100, 2"
           "00, 189, 87, 174, 113, 226, 233, 255, 211, 139, 59, 118, 236, 245, 199, 163, 107, 214, 129, 47, 94, 188, 85, "
           "170, 121, 242, 201, 191, 83, 166, 97, 194, 169, 127, 254, 209, 143, 51, 102, 204, 181, 71, 142, 49, 98, 196, "
           "165, 103, 206, 177, 79, 158, 17, 34, 68, 136, 61, 122, 244, 197, 167, 99, 198, 161, 111, 222, 145, 15, 30, 60"
           ", 120, 240, 205, 183, 67, 134, 33, 66, 132, 37, 74, 148, 5, 10, 20, 40, 80, 160, 109, 218, 153, 31, 62, 124, "
           "248, 221, 151, 3, 6, 12, 24, 48, 96, 192, 173, 119, 238, 241, 207, 179, 75, 150, 1\n"
           "};\n"
           "\n"
           "static const uint log_table[256] = {\n"
           "    0, 0, 1, 240, 2, 225, 241, 53, 3, 38, 226, 133, 242, 43, 54, 210, 4, 195, 39, 114, 227, 106, 134, 28, 243"
           ", 140, 44, 23, 55, 118, 211, 234, 5, 219, 196, 96, 40, 222, 115, 103, 228, 78, 107, 125, 135, 8, 29, 162, 244"
           ", 186, 141, 180, 45, 99, 24, 49, 56, 13, 119, 153, 212, 199, 235, 91, 6, 76, 220, 217, 197, 11, 97, 184, 41, "
           "36, 223, 253, 116, 138, 104, 193, 229, 86, 79, 171, 108, 165, 126, 145, 136, 34, 9, 74, 30, 32, 163, 84, 245,"
           " 173, 187, 204, 142, 81, 181, 190, 46, 88, 100, 159, 25, 231, 50, 207, 57, 147, 14, 67, 120, 128, 154, 248, 2"
           "13, 167, 200, 63, 236, 110, 92, 176, 7, 161, 77, 124, 221, 102, 218, 95, 198, 90, 12, 152, 98, 48, 185, 179, "
           "42, 209, 37, 132, 224, 52, 254, 239, 117, 233, 139, 22, 105, 27, 194, 113, 230, 206, 87, 158, 80, 189, 172, 2"
           "03, 109, 175, 166, 62, 127, 247, 146, 66, 137, 192, 35, 252, 10, 183, 75, 216, 31, 83, 33, 73, 164, 144, 85, "
           "170, 246, 65, 174, 61, 188, 202, 205, 157, 143, 169, 82, 72, 182, 215, 191, 251, 47, 178, 89, 151, 101, 94, 1"
           "60, 123, 26, 112, 232, 21, 51, 238, 208, 131, 58, 69, 148, 18, 15, 16, 68, 17, 121, 149, 129, 19, 155, 59, 24"
           "9, 70, 214, 250, 168, 71, 201, 156, 64, 60, 237, 130, 111, 20, 93, 122, 177, 150\n"
           "};\n"
           "\n"
           "// GF(256) addition (XOR)\n"
           "uint gf_add(uint x, uint y) {\n"
           "    return x ^ y;\n"
           "}\n"
           "\n"
           "// GF(256) multiplication using lookup tables\n"
           "uint gf_mul(uint x, uint y) {\n"
           "    if (x == 0 || y == 0) return 0;\n"
           "    return exp_table[(log_table[x] + log_table[y]) % 255];\n"
           "}\n"
           "\n"
           "// GF(256) power using lookup tables\n"
           "uint gf_pow(uint N, uint P) {\n"
           "    if (N == 0) return 0;\n"
           "    return exp_table[(log_table[N] * P) % 255];\n"
           "}\n"
           "\n"
           "// Structured buffer for input message\n"
           "StructuredBuffer<uint> g_MessageBuffer : register(t0);\n"
           "\n"
           "// Output buffer for syndromes\n"
           "RWStructuredBuffer<uint> g_SyndromesBuffer : register(u0);\n"
           "\n"
           "// Constant buffer for parameters\n"
           "cbuffer cbConstants : register(b0) {\n"
           "    uint g_MessageLength;\n"
           "    uint g_SupportedErrorCount;\n"
           "    uint g_TableLength;\n"
           "}\n"
           "\n"
           "// Compute shader for calculating syndromes\n"
           "[numthreads(64, 1, 1)]\n"
           "void CSMain(uint3 DTid : SV_DispatchThreadID) {\n"
           "    uint threadId = DTid.x;\n"
           "    \n"
           "    if (threadId >= g_SupportedErrorCount * 2) {\n"
           "        return;\n"
           "    }\n"
           "    \n"
           "    uint x = gf_pow(2, threadId);\n"
           "    uint syndrome = 0;\n"
           "    \n"
           "    // Calculate syndrome for this thread\n"
           "    for (uint i = 0; i < g_MessageLength; i++) {\n"
           "        uint coeff = g_MessageBuffer[g_MessageLength - i - 1];\n"
           "        if (coeff != 0) {\n"
           "            uint term = gf_mul(coeff, gf_pow(x, i));\n"
           "            syndrome = gf_add(syndrome, term);\n"
           "        }\n"
           "    }\n"
           "    \n"
           "    g_SyndromesBuffer[threadId] = syndrome;\n"
           "}\n",
           0xF09uLL,
           "GF256Compute",
           0LL,
           0LL,
           "CSMain",
           "cs_5_0",
           0x805u,
           0,
           &ppCode,
           &ppErrorMsgs) < 0 )
      goto LABEL_11;
    v7 = ppCode;
    v8 = *ppDevice;
    v9 = ppDevice[2];
    if ( v9 )
    {
      ppDevice[2] = 0LL;
      ((void (__fastcall *)(ID3D11Device *))v9->lpVtbl->Release)(v9);
    }
    lpVtbl = v8->lpVtbl;
    GetBufferPointer = v7->lpVtbl->GetBufferPointer;
    v12 = ((__int64 (__fastcall *)(ID3DBlob *))v7->lpVtbl->GetBufferSize)(v7);
    v13 = ((__int64 (__fastcall *)(ID3DBlob *))GetBufferPointer)(v7);
    if ( ((int (__fastcall *)(ID3D11Device *, __int64, __int64, _QWORD, ID3D11Device **))lpVtbl->CreateComputeShader)(
           v8,
           v13,
           v12,
           0LL,
           ppDevice + 2) >= 0 )
    {
      v17 = ppErrorMsgs;
      if ( ppErrorMsgs )
      {
        ppErrorMsgs = 0LL;
        ((void (__fastcall *)(ID3DBlob *))v17->lpVtbl->Release)(v17);
      }
      v18 = ppCode;
      if ( ppCode )
      {
        ppCode = 0LL;
        ((void (__fastcall *)(ID3DBlob *))v18->lpVtbl->Release)(v18);
      }
      return (unsigned __int8)InitPipelineAndConstants(ppDevice) != 0;
    }
    else
    {
LABEL_11:
      v14 = CheckSyndromesOnCPU(&qword_140036640, (__int64)"error");
      StreamFlush(v14);
      v15 = ppErrorMsgs;
      if ( ppErrorMsgs )
      {
        ppErrorMsgs = 0LL;
        ((void (__fastcall *)(ID3DBlob *))v15->lpVtbl->Release)(v15);
      }
      v16 = ppCode;
      if ( ppCode )
      {
        ppCode = 0LL;
        ((void (__fastcall *)(ID3DBlob *))v16->lpVtbl->Release)(v16);
      }
      return 0;
    }
  }
  else
  {
    v5 = CheckSyndromesOnCPU(&qword_140036640, (__int64)"error");
    StreamFlush(v5);
    return 0;
  }
}

D3D11CreateDevice를 통해 디바이스/컨텍스트를 새로 생성한다.

임베디드 HLSL 컴파일을 진행한다. -> D3DCompile, entry CSMain, target cs_5_0

 

또한 GF(256)용 exp_table과 log_table을 내장하는 것을 확인할 수 있다.

 

2. main

int __fastcall main(int argc, const char **argv, const char **envp)
{
  __int64 *v3; // rax
  __int64 v4; // rcx
  __int64 v5; // rcx
  __int64 v6; // rcx
  __int64 v7; // rcx
  __int64 v8; // rcx
  __int64 v9; // rcx
  ID3D11Device *v10; // rcx
  ID3D11Device *v11; // rcx
  __int64 v13; // rax
  __int64 v14; // rdx
  unsigned __int8 v15; // di
  __int64 v16; // rcx
  void (__fastcall ***v17)(_QWORD, __int64); // rax
  __int64 *v18; // rax
  void *v19; // rcx
  __int64 v20; // rcx
  __int64 v21; // rcx
  __int64 v22; // rcx
  __int64 v23; // rcx
  __int64 v24; // rcx
  __int64 v25; // rcx
  ID3D11Device *v26; // rcx
  ID3D11Device *v27; // rcx
  void *v28; // rcx
  __int64 v29; // rcx
  __int64 v30; // rcx
  __int64 v31; // rcx
  __int64 v32; // rcx
  __int64 v33; // rcx
  __int64 v34; // rcx
  ID3D11Device *v35; // rcx
  ID3D11Device *v36; // rcx
  ID3D11Device *ppDevice[2]; // [rsp+20h] [rbp-A8h] BYREF
  __int128 v38; // [rsp+30h] [rbp-98h]
  __int128 v39; // [rsp+40h] [rbp-88h]
  __int128 v40; // [rsp+50h] [rbp-78h]
  __int64 v41; // [rsp+60h] [rbp-68h]
  __int128 v42; // [rsp+70h] [rbp-58h] BYREF
  __int64 v43; // [rsp+80h] [rbp-48h]
  __int128 v44; // [rsp+88h] [rbp-40h] BYREF
  __int64 v45; // [rsp+98h] [rbp-30h]
  unsigned __int64 v46; // [rsp+A0h] [rbp-28h]

  *(_OWORD *)ppDevice = 0LL;
  v38 = 0LL;
  v39 = 0LL;
  v40 = 0LL;
  v41 = 0x8000000040LL;
  if ( InitD3DAndCompileShader(ppDevice) )
  {
    CheckSyndromesOnCPU(&ID3D11DeviceContext_Global, (__int64)"Enter Message (Base64): ");
    v44 = 0LL;
    v45 = 0LL;
    v46 = 15LL;
    LOBYTE(v44) = 0;
    *((_QWORD *)&v42 + 1) = *(_QWORD *)(*(_QWORD *)((char *)&GF256_ExpTable + *(int *)(qword_1400365B0 + 4)) + 8LL);
    (*(void (**)(void))(**((_QWORD **)&v42 + 1) + 8LL))();
    v13 = StringGetProxy((__int64)&v42);
    LOBYTE(v14) = 10;
    v15 = (*(__int64 (__fastcall **)(__int64, __int64))(*(_QWORD *)v13 + 64LL))(v13, v14);
    v16 = *((_QWORD *)&v42 + 1);
    if ( *((_QWORD *)&v42 + 1) )
    {
      v17 = (void (__fastcall ***)(_QWORD, __int64))(*(__int64 (__fastcall **)(_QWORD))(**((_QWORD **)&v42 + 1) + 16LL))(*((_QWORD *)&v42 + 1));
      if ( v17 )
        (**v17)(v17, 1LL);
    }
    StringAssignSlice(v16, &v44, v15);
    v42 = 0LL;
    v43 = 0LL;
    Base64Decode((__int64)&v42, &v44);
    if ( *((_QWORD *)&v42 + 1) - (_QWORD)v42 > 0x40uLL )
      StringShrinkToFit(&v42);
    if ( (unsigned __int8)CheckMessageWithShader(ppDevice, &v42) )
      v18 = CheckSyndromesOnCPU(&ID3D11DeviceContext_Global, (__int64)"Correct");
    else
      v18 = CheckSyndromesOnCPU(&ID3D11DeviceContext_Global, (__int64)"Wrong");
    StreamFlush(v18);
    v19 = (void *)v42;
    if ( (_QWORD)v42 )
    {
      if ( (unsigned __int64)(v43 - v42) >= 0x1000 )
      {
        v19 = *(void **)(v42 - 8);
        if ( (unsigned __int64)(v42 - (_QWORD)v19 - 8) > 0x1F )
          invalid_parameter_noinfo_noreturn();
      }
      j_j_free(v19);
    }
    v20 = v38;
    if ( (_QWORD)v38 )
    {
      *(_QWORD *)&v38 = 0LL;
      (*(void (__fastcall **)(__int64))(*(_QWORD *)v20 + 16LL))(v20);
    }
    v21 = *((_QWORD *)&v38 + 1);
    if ( *((_QWORD *)&v38 + 1) )
    {
      *((_QWORD *)&v38 + 1) = 0LL;
      (*(void (__fastcall **)(__int64))(*(_QWORD *)v21 + 16LL))(v21);
    }
    v22 = v39;
    if ( (_QWORD)v39 )
    {
      *(_QWORD *)&v39 = 0LL;
      (*(void (__fastcall **)(__int64))(*(_QWORD *)v22 + 16LL))(v22);
    }
    v23 = *((_QWORD *)&v39 + 1);
    if ( *((_QWORD *)&v39 + 1) )
    {
      *((_QWORD *)&v39 + 1) = 0LL;
      (*(void (__fastcall **)(__int64))(*(_QWORD *)v23 + 16LL))(v23);
    }
    v24 = v40;
    if ( (_QWORD)v40 )
    {
      *(_QWORD *)&v40 = 0LL;
      (*(void (__fastcall **)(__int64))(*(_QWORD *)v24 + 16LL))(v24);
    }
    v25 = *((_QWORD *)&v40 + 1);
    if ( *((_QWORD *)&v40 + 1) )
    {
      *((_QWORD *)&v40 + 1) = 0LL;
      (*(void (__fastcall **)(__int64))(*(_QWORD *)v25 + 16LL))(v25);
    }
    v26 = ppDevice[1];
    if ( ppDevice[1] )
    {
      ppDevice[1] = 0LL;
      ((void (__fastcall *)(ID3D11Device *))v26->lpVtbl->Release)(v26);
    }
    v27 = ppDevice[0];
    if ( ppDevice[0] )
    {
      ppDevice[0] = 0LL;
      ((void (__fastcall *)(ID3D11Device *))v27->lpVtbl->Release)(v27);
    }
    if ( v46 > 0xF )
    {
      v28 = (void *)v44;
      if ( v46 + 1 >= 0x1000 )
      {
        v28 = *(void **)(v44 - 8);
        if ( (unsigned __int64)(v44 - (_QWORD)v28 - 8) > 0x1F )
          invalid_parameter_noinfo_noreturn();
      }
      j_j_free(v28);
    }
    v29 = *((_QWORD *)&v40 + 1);
    if ( *((_QWORD *)&v40 + 1) )
    {
      *((_QWORD *)&v40 + 1) = 0LL;
      (*(void (__fastcall **)(__int64))(*(_QWORD *)v29 + 16LL))(v29);
    }
    v30 = v40;
    if ( (_QWORD)v40 )
    {
      *(_QWORD *)&v40 = 0LL;
      (*(void (__fastcall **)(__int64))(*(_QWORD *)v30 + 16LL))(v30);
    }
    v31 = *((_QWORD *)&v39 + 1);
    if ( *((_QWORD *)&v39 + 1) )
    {
      *((_QWORD *)&v39 + 1) = 0LL;
      (*(void (__fastcall **)(__int64))(*(_QWORD *)v31 + 16LL))(v31);
    }
    v32 = v39;
    if ( (_QWORD)v39 )
    {
      *(_QWORD *)&v39 = 0LL;
      (*(void (__fastcall **)(__int64))(*(_QWORD *)v32 + 16LL))(v32);
    }
    v33 = *((_QWORD *)&v38 + 1);
    if ( *((_QWORD *)&v38 + 1) )
    {
      *((_QWORD *)&v38 + 1) = 0LL;
      (*(void (__fastcall **)(__int64))(*(_QWORD *)v33 + 16LL))(v33);
    }
    v34 = v38;
    if ( (_QWORD)v38 )
    {
      *(_QWORD *)&v38 = 0LL;
      (*(void (__fastcall **)(__int64))(*(_QWORD *)v34 + 16LL))(v34);
    }
    v35 = ppDevice[1];
    if ( ppDevice[1] )
    {
      ppDevice[1] = 0LL;
      ((void (__fastcall *)(ID3D11Device *))v35->lpVtbl->Release)(v35);
    }
    v36 = ppDevice[0];
    if ( ppDevice[0] )
    {
      ppDevice[0] = 0LL;
      ((void (__fastcall *)(ID3D11Device *))v36->lpVtbl->Release)(v36);
    }
    return 0;
  }
  else
  {
    v3 = CheckSyndromesOnCPU(&qword_140036640, (__int64)"error");
    StreamFlush(v3);
    v4 = *((_QWORD *)&v40 + 1);
    if ( *((_QWORD *)&v40 + 1) )
    {
      *((_QWORD *)&v40 + 1) = 0LL;
      (*(void (__fastcall **)(__int64))(*(_QWORD *)v4 + 16LL))(v4);
    }
    v5 = v40;
    if ( (_QWORD)v40 )
    {
      *(_QWORD *)&v40 = 0LL;
      (*(void (__fastcall **)(__int64))(*(_QWORD *)v5 + 16LL))(v5);
    }
    v6 = *((_QWORD *)&v39 + 1);
    if ( *((_QWORD *)&v39 + 1) )
    {
      *((_QWORD *)&v39 + 1) = 0LL;
      (*(void (__fastcall **)(__int64))(*(_QWORD *)v6 + 16LL))(v6);
    }
    v7 = v39;
    if ( (_QWORD)v39 )
    {
      *(_QWORD *)&v39 = 0LL;
      (*(void (__fastcall **)(__int64))(*(_QWORD *)v7 + 16LL))(v7);
    }
    v8 = *((_QWORD *)&v38 + 1);
    if ( *((_QWORD *)&v38 + 1) )
    {
      *((_QWORD *)&v38 + 1) = 0LL;
      (*(void (__fastcall **)(__int64))(*(_QWORD *)v8 + 16LL))(v8);
    }
    v9 = v38;
    if ( (_QWORD)v38 )
    {
      *(_QWORD *)&v38 = 0LL;
      (*(void (__fastcall **)(__int64))(*(_QWORD *)v9 + 16LL))(v9);
    }
    v10 = ppDevice[1];
    if ( ppDevice[1] )
    {
      ppDevice[1] = 0LL;
      ((void (__fastcall *)(ID3D11Device *))v10->lpVtbl->Release)(v10);
    }
    v11 = ppDevice[0];
    if ( ppDevice[0] )
    {
      ppDevice[0] = 0LL;
      ((void (__fastcall *)(ID3D11Device *))v11->lpVtbl->Release)(v11);
    }
    return -1;
  }
}

 

Base64 입력을 받고 디코딩을 거친 후 정리를 한다.

 

3. Check

__int64 __fastcall CheckMessageWithShader(_QWORD *a1, unsigned __int8 **a2)
{
  unsigned __int64 v4; // rdi
  size_t v5; // rdi
  char *v6; // rbx
  void *v7; // rax
  void *v8; // rcx
  unsigned __int8 *v9; // rsi
  unsigned __int8 *i; // rdi
  int v11; // eax
  char **v12; // rdi
  int v13; // eax
  __int64 v14; // rdi
  char *v15; // rsi
  size_t v16; // rdi
  char *v17; // rbx
  void *v18; // rax
  char *v19; // rdi
  __int64 *v20; // rax
  unsigned __int8 v21; // di
  char *v22; // rax
  __int64 v23; // rcx
  char *v24; // rax
  void *v25; // rcx
  int v27; // [rsp+40h] [rbp-49h] BYREF
  void *v28; // [rsp+48h] [rbp-41h] BYREF
  void *Src[2]; // [rsp+58h] [rbp-31h] BYREF
  char *v30; // [rsp+68h] [rbp-21h]
  __int64 v31; // [rsp+70h] [rbp-19h] BYREF
  __int128 v32; // [rsp+78h] [rbp-11h]
  char *v33; // [rsp+88h] [rbp-1h]
  int v34; // [rsp+90h] [rbp+7h] BYREF
  __int64 v35; // [rsp+94h] [rbp+Bh]
  int v36; // [rsp+9Ch] [rbp+13h]
  __int64 v37; // [rsp+A0h] [rbp+17h]
  _DWORD v38[2]; // [rsp+A8h] [rbp+1Fh] BYREF
  __int64 v39; // [rsp+B0h] [rbp+27h]

  *(_OWORD *)Src = 0LL;
  v30 = 0LL;
  v4 = a2[1] - *a2 + 128;
  if ( a2[1] - *a2 == -128 )
  {
    v6 = (char *)Src[1];
  }
  else
  {
    if ( v4 > 0x3FFFFFFFFFFFFFFFLL )
      unknown_libname_4();
    v5 = 4 * v4;
    if ( v5 )
    {
      if ( v5 < 0x1000 )
      {
        v6 = (char *)operator new(v5);
      }
      else
      {
        if ( v5 + 39 < v5 )
          goto LABEL_58;
        v7 = operator new(v5 + 39);
        if ( !v7 )
          goto LABEL_59;
        v6 = (char *)(((unsigned __int64)v7 + 39) & 0xFFFFFFFFFFFFFFE0uLL);
        *((_QWORD *)v6 - 1) = v7;
      }
    }
    else
    {
      v6 = 0LL;
    }
    memcpy(v6, Src[0], (char *)Src[1] - (char *)Src[0]);
    v8 = Src[0];
    if ( Src[0] )
    {
      if ( (unsigned __int64)(4 * ((v30 - (char *)Src[0]) >> 2)) >= 0x1000 )
      {
        v8 = (void *)*((_QWORD *)Src[0] - 1);
        if ( (unsigned __int64)((char *)Src[0] - (char *)v8 - 8) > 0x1F )
          goto LABEL_59;
      }
      j_j_free(v8);
    }
    Src[0] = v6;
    Src[1] = v6;
    v30 = &v6[v5];
  }
  v9 = a2[1];
  for ( i = *a2; i != v9; ++i )
  {
    v11 = *i;
    v27 = v11;
    if ( v6 == v30 )
    {
      VecPush32_Grow(Src, v6, &v27);
      v6 = (char *)Src[1];
    }
    else
    {
      *(_DWORD *)v6 = v11;
      v6 = (char *)Src[1] + 4;
      Src[1] = (char *)Src[1] + 4;
    }
  }
  v12 = (char **)&unk_140030790;
  do
  {
    v13 = *(unsigned __int8 *)v12;
    v27 = v13;
    if ( v6 == v30 )
    {
      VecPush32_Grow(Src, v6, &v27);
      v6 = (char *)Src[1];
    }
    else
    {
      *(_DWORD *)v6 = v13;
      v6 = (char *)Src[1] + 4;
      Src[1] = (char *)Src[1] + 4;
    }
    v12 = (char **)((char *)v12 + 1);
  }
  while ( v12 != &off_140030810 );
  (*(void (__fastcall **)(_QWORD, _QWORD, _QWORD, _QWORD, void *, _DWORD, _DWORD))(*(_QWORD *)a1[1] + 384LL))(
    a1[1],
    a1[3],
    0LL,
    0LL,
    Src[0],
    0,
    0);
  v38[0] = ((char *)Src[1] - (char *)Src[0]) >> 2;
  v38[1] = *((_DWORD *)a1 + 16);
  v39 = 128LL;
  (*(void (__fastcall **)(_QWORD, _QWORD, _QWORD, _QWORD, _DWORD *, _DWORD, _DWORD))(*(_QWORD *)a1[1] + 384LL))(
    a1[1],
    a1[5],
    0LL,
    0LL,
    v38,
    0,
    0);
  (*(void (__fastcall **)(_QWORD, _QWORD, _QWORD, _QWORD))(*(_QWORD *)a1[1] + 552LL))(a1[1], a1[2], 0LL, 0LL);
  (*(void (__fastcall **)(_QWORD, _QWORD, __int64, _QWORD *))(*(_QWORD *)a1[1] + 536LL))(a1[1], 0LL, 1LL, a1 + 7);
  (*(void (__fastcall **)(_QWORD, _QWORD, __int64, _QWORD *, _QWORD))(*(_QWORD *)a1[1] + 544LL))(
    a1[1],
    0LL,
    1LL,
    a1 + 6,
    0LL);
  (*(void (__fastcall **)(_QWORD, _QWORD, __int64, _QWORD *))(*(_QWORD *)a1[1] + 568LL))(a1[1], 0LL, 1LL, a1 + 5);
  (*(void (__fastcall **)(_QWORD, _QWORD, __int64))(*(_QWORD *)a1[1] + 328LL))(
    a1[1],
    (unsigned int)(*((_DWORD *)a1 + 17) + 63) >> 6,
    1LL);
  v14 = *((unsigned int *)a1 + 17);
  v32 = 0LL;
  v15 = 0LL;
  v33 = 0LL;
  if ( v14 )
  {
    v16 = 4 * v14;
    if ( !v16 )
    {
      v17 = 0LL;
LABEL_34:
      *(_QWORD *)&v32 = v17;
      v33 = &v17[v16];
      memset(v17, 0, v16);
      v19 = &v17[v16];
      v15 = v19;
      *((_QWORD *)&v32 + 1) = v19;
      goto LABEL_36;
    }
    if ( v16 < 0x1000 )
    {
      v17 = (char *)operator new(v16);
      goto LABEL_34;
    }
    if ( v16 + 39 >= v16 )
    {
      v18 = operator new(v16 + 39);
      if ( !v18 )
        goto LABEL_59;
      v17 = (char *)(((unsigned __int64)v18 + 39) & 0xFFFFFFFFFFFFFFE0uLL);
      *((_QWORD *)v17 - 1) = v18;
      goto LABEL_34;
    }
LABEL_58:
    sub_1400013F0();
  }
  v19 = (char *)*((_QWORD *)&v32 + 1);
  v17 = (char *)v32;
LABEL_36:
  v31 = 0LL;
  v37 = 0LL;
  v34 = 4 * *((_DWORD *)a1 + 17);
  v35 = 3LL;
  v36 = 0x20000;
  if ( (*(int (__fastcall **)(_QWORD, int *, _QWORD, __int64 *))(*(_QWORD *)*a1 + 24LL))(*a1, &v34, 0LL, &v31) < 0 )
  {
    v20 = CheckSyndromesOnCPU(&qword_140036640, (__int64)"error");
    StreamFlush((__int64)v20);
LABEL_38:
    v21 = 0;
    goto LABEL_45;
  }
  (*(void (__fastcall **)(_QWORD, __int64, _QWORD))(*(_QWORD *)a1[1] + 376LL))(a1[1], v31, a1[4]);
  if ( (*(int (__fastcall **)(_QWORD, __int64, _QWORD, __int64, _DWORD, void **))(*(_QWORD *)a1[1] + 112LL))(
         a1[1],
         v31,
         0LL,
         1LL,
         0,
         &v28) >= 0 )
  {
    memcpy(v17, v28, 4LL * *((unsigned int *)a1 + 17));
    (*(void (__fastcall **)(_QWORD, __int64, _QWORD))(*(_QWORD *)a1[1] + 120LL))(a1[1], v31, 0LL);
  }
  v22 = v17;
  if ( v17 != v19 )
  {
    while ( !*(_DWORD *)v22 )
    {
      v22 += 4;
      if ( v22 == v19 )
        goto LABEL_44;
    }
    goto LABEL_38;
  }
LABEL_44:
  v21 = 1;
LABEL_45:
  v23 = v31;
  if ( v31 )
  {
    v31 = 0LL;
    (*(void (__fastcall **)(__int64))(*(_QWORD *)v23 + 16LL))(v23);
  }
  if ( v17 )
  {
    v24 = v17;
    if ( (unsigned __int64)(4 * ((v15 - v17) >> 2)) < 0x1000
      || (v17 = (char *)*((_QWORD *)v17 - 1), (unsigned __int64)(v24 - v17 - 8) <= 0x1F) )
    {
      j_j_free(v17);
      goto LABEL_51;
    }
LABEL_59:
    invalid_parameter_noinfo_noreturn();
  }
LABEL_51:
  v25 = Src[0];
  if ( Src[0] )
  {
    if ( ((v30 - (char *)Src[0]) & 0xFFFFFFFFFFFFFFFCuLL) >= 0x1000 )
    {
      v25 = (void *)*((_QWORD *)Src[0] - 1);
      if ( (unsigned __int64)((char *)Src[0] - (char *)v25 - 8) > 0x1F )
        invalid_parameter_noinfo_noreturn();
    }
    j_j_free(v25);
  }
  return v21;
}

sub_1400024E0

 

1. 입력 바이트들을 uint 배열로 push

2. suffix 128바이트를 push

3. 두 버퍼를 SRV/UAV/CB 형태로 CS 바인딩 후 Dispatch

4. 결과(staging) Map -> 모든 요소 0인지 검사

 


상세 분석

MainEntry(int __fastcall main(...))

  • ID3D11Device *ppDevice[2] -> [0]=Device, [1]=Context
  • v42, v44 -> std::string 역할의 입력 버퍼
  • qword_140036370 -> g_StdOut 출력 스트림

1. 초기화

*(_OWORD *)ppDevice = 0; v38=v39=v40=0; v41=0x8000000040; // 몇몇 iostream 내부 세팅
if ( InitD3DAndCompileShader(ppDevice) ) { ... } else { ... }

 

D3D11 디바이스와 컨텍스트를 생성하고 쉐이더 실패시 error 출력한다.

 

2. 프롬프트 출력

CheckSyndromesOnCPU(&ID3D11DeviceContext_Global, (__int64)"Enter Message (Base64): ");

 

CheckSyndromesOnCPU(sub_1400035B0)은 아래 설명 참고

 

3. 입력

v44 = "" (capacity=15);  // SSO 초기 상태
*((QWORD*)&v42+1) = *(_QWORD*)(*(_QWORD*)((char*)&unk_1400365F0 + *(int*)(qword_1400365B0+4)) + 8);
(**((QWORD**)&v42+1)+8)();             // 입력 스트림 준비
v13 = sub_140003470(&v42);             // string 프록시/포인터 취득
v15 = (**(QWORD**)v13 + 64)(v13, 10);  // 개행 위치 찾기
sub_140004240(v16, &v44, v15);         // 개행 전까지 잘라 v44로 대입
sub_1400029E0(&v42, &v44);             // ★ Base64Decode: v44 -> 디코딩 결과를 v42에
if ( size(v42) > 0x40 ) sub_1400038F0(&v42); // capacity 정리

Base64 알파벳 .rdata:140030700의 XREF가 CheckSyndromesOnCPU(sub_1400035B0)에 있으므로 디코딩을 확정한다.

 

4. GPU 검사

if ( CheckMessageWithShader(ppDevice, &v42) ) Print("Correct"); else Print("Wrong");

CheckMessageWIthShader(sub_1400024E0)가 true(모든 신드롬=0)이면 Correct이다.

 

즉, Main에서는 SSO인지 확인 후 j_j_free 함수로 v42, v44를 해제한다.

ppDevice[1] (Context) Release, ppDevice[0] (Device) Release, 중간에 사용된 임시 iostream 객체도 Release한다.

 

입력이 Base64 디코딩 후 GPU로 간다.

 

InitD3DAndCompileShader (bool __fastcall sub_140002060(ID3D11Device **ppDevice))

D3D11 디바이스/컨텍스트 생성 후 HLSL 문자열을 컴파일

 

1. 디바이스 생성

D3D_FEATURE_LEVEL req = D3D_FEATURE_LEVEL_11_0, got;
D3D11CreateDevice(nullptr, HARDWARE, nullptr, 0, &req, 1, D3D11_SDK_VERSION,
                  &Device, &got, &ImmediateContext) >= 0

 

2. HLSL 컴파일

D3DCompile(HlslSource, len=0xF09, "GF256Compute", nullptr, nullptr,
           "CSMain", "cs_5_0", 0x805, 0, &ppCode, &ppErrorMsgs)

소스에서는 다음 친구들이 정의되어있다.

exp_table[256]
log_table[256]
GF256_Add/Mul/Pow
StructuredBuffer<uint> g_MessageBuffer (t0)
RWStructuredBuffer<uint> g_SyndromesBuffer (u0)
cbuffer { uint g_MessageLength; uint g_SupportedErrorCount; uint g_TableLength; } (b0)
[numthreads(64,1,1)] void CSMain(uint3 DTid)

 

4. Compute Shader 생성

Device->CreateComputeShader(ppCode->GetBufferPointer(), ppCode->GetBufferSize(), nullptr, &ComputeShader)

 

이후 에러 메시지는 blob후 release한다.

 

5. 파이프라인 준비

return sub_1400022A0(ppDevice) != 0;

여기서 t(SupportedErrorCount), 입출력 버퍼, SRV/UAV/CB를 생성하고 저장한다.

 

CheckMessageWithShader (__int64 __fastcall sub_1400024E0(_QWORD *ctx, unsigned __int8 **inputStr))

인자 부분
a1(ctx): 내부적으로 [0]=Device, [1]=ImmediateContext, [2]=ComputeShader, [3]=MsgBuf(ID3D11Buffer*), [4]=SynBuf(ID3D11Buffer*), [5]=CB(ID3D11Buffer*), [6]=UAV(ID3D11UnorderedAccessView*), [7]=SRV(ID3D11ShaderResourceView*), *((DWORD*)a1+16)=t, *((DWORD*)a1+17)=2t

a2: std::string(Base64 디코딩 결과)의 데이터 범위 [*a2, a2[1]]

 

1. CPU 임시 벡터 준비

v4 = (a2[1] - *a2) + 128;      // 총 요소 수(입력길이 + 128 suffix)
reserve vector<uint32_t> capacity = 4 * v4 bytes (32바이트 정렬 new)

 

기존의 Src가 비어있으면 새로 할당한다. 정렬된 new를 새로 사용(+39 후 32바이트 정렬을 하고 원 포인트는 -8에 저장한다.)

 

2. 입력바이트를 32비트로 push

for (i=*a2; i!=a2[1]; ++i) {
  push_back(uint32_t(*i));     // v6 포인터에 4바이트씩 기입
  if (full) VecPush32_Grow(...);
}

 

이미 Base64 디코딩이 끝났기에 각 문자를 그 값 그대로 uint에 저장한다. 

 

3. suffix 128바이트 추가

for (p = &unk_140030790; p != &off_140030810; ++p) {
  push_back(uint32_t(*p));
}

 

.rdata:140030790의 128바이트를 같은 방식으로 이어붙힌다.

.rdata:0000000140030790 unk_140030790   db  92h                 ; DATA XREF: CheckMessageWithShader:loc_14000264A↑o
.rdata:0000000140030791                 db 0D5h
.rdata:0000000140030792                 db  31h ; 1
.rdata:0000000140030793                 db 0A5h
.rdata:0000000140030794                 db 0E5h
.rdata:0000000140030795                 db 0DFh
.rdata:0000000140030796                 db  29h ; )
.rdata:0000000140030797                 db  67h ; g
.rdata:0000000140030798                 db  37h ; 7
.rdata:0000000140030799                 db 0C8h
.rdata:000000014003079A                 db  27h ; '
.rdata:000000014003079B                 db  65h ; e
.rdata:000000014003079C                 db 0FEh
.rdata:000000014003079D                 db  66h ; f
.rdata:000000014003079E                 db  17h
.rdata:000000014003079F                 db  47h ; G
.rdata:00000001400307A0                 db  29h ; )
.rdata:00000001400307A1                 db  78h ; x
.rdata:00000001400307A2                 db 0A5h
.rdata:00000001400307A3                 db  77h ; w
.rdata:00000001400307A4                 db 0E1h
.rdata:00000001400307A5                 db 0AFh
.rdata:00000001400307A6                 db  7Dh ; }
.rdata:00000001400307A7                 db 0D5h
.rdata:00000001400307A8                 db 0E1h
.rdata:00000001400307A9                 db  5Ch ; \
.rdata:00000001400307AA                 db  7Eh ; ~
.rdata:00000001400307AB                 db  66h ; f
.rdata:00000001400307AC                 db 0C9h
.rdata:00000001400307AD                 db 0E9h
.rdata:00000001400307AE                 db  41h ; A
.rdata:00000001400307AF                 db 0BFh
.rdata:00000001400307B0                 db 0AAh
.rdata:00000001400307B1                 db 0E0h
.rdata:00000001400307B2                 db  11h
.rdata:00000001400307B3                 db 0DAh
.rdata:00000001400307B4                 db  39h ; 9
.rdata:00000001400307B5                 db  2Dh ; -
.rdata:00000001400307B6                 db  2Dh ; -
.rdata:00000001400307B7                 db  8Dh
.rdata:00000001400307B8                 db  73h ; s
.rdata:00000001400307B9                 db 0B9h
.rdata:00000001400307BA                 db 0BDh
.rdata:00000001400307BB                 db 0C9h
.rdata:00000001400307BC                 db 0E2h
.rdata:00000001400307BD                 db  86h
.rdata:00000001400307BE                 db  6Eh ; n
.rdata:00000001400307BF                 db  60h ; `
.rdata:00000001400307C0                 db  40h ; @
.rdata:00000001400307C1                 db  29h ; )
.rdata:00000001400307C2                 db  86h
.rdata:00000001400307C3                 db 0BAh
.rdata:00000001400307C4                 db  76h ; v
.rdata:00000001400307C5                 db    4
.rdata:00000001400307C6                 db  8Dh
.rdata:00000001400307C7                 db  7Ah ; z
.rdata:00000001400307C8                 db 0C0h
.rdata:00000001400307C9                 db  5Ch ; \
.rdata:00000001400307CA                 db  89h
.rdata:00000001400307CB                 db  1Dh
.rdata:00000001400307CC                 db 0FFh
.rdata:00000001400307CD                 db  3Eh ; >
.rdata:00000001400307CE                 db  5Eh ; ^
.rdata:00000001400307CF                 db  9Ch
.rdata:00000001400307D0                 db 0E9h
.rdata:00000001400307D1                 db 0ABh
.rdata:00000001400307D2                 db  45h ; E
.rdata:00000001400307D3                 db  5Ch ; \
.rdata:00000001400307D4                 db 0C1h
.rdata:00000001400307D5                 db  5Dh ; ]
.rdata:00000001400307D6                 db  64h ; d
.rdata:00000001400307D7                 db  56h ; V
.rdata:00000001400307D8                 db  46h ; F
.rdata:00000001400307D9                 db  11h
.rdata:00000001400307DA                 db  72h ; r
.rdata:00000001400307DB                 db 0CDh
.rdata:00000001400307DC                 db  8Fh
.rdata:00000001400307DD                 db  5Fh ; _
.rdata:00000001400307DE                 db  87h
.rdata:00000001400307DF                 db 0A9h
.rdata:00000001400307E0                 db 0D6h
.rdata:00000001400307E1                 db 0B7h
.rdata:00000001400307E2                 db  69h ; i
.rdata:00000001400307E3                 db 0CFh
.rdata:00000001400307E4                 db  22h ; "
.rdata:00000001400307E5                 db 0F5h
.rdata:00000001400307E6                 db 0F6h
.rdata:00000001400307E7                 db 0DBh
.rdata:00000001400307E8                 db  41h ; A
.rdata:00000001400307E9                 db  76h ; v
.rdata:00000001400307EA                 db 0CDh
.rdata:00000001400307EB                 db  3Dh ; =
.rdata:00000001400307EC                 db 0F8h
.rdata:00000001400307ED                 db  66h ; f
.rdata:00000001400307EE                 db  57h ; W
.rdata:00000001400307EF                 db 0E3h
.rdata:00000001400307F0                 db  3Eh ; >
.rdata:00000001400307F1                 db  8Fh
.rdata:00000001400307F2                 db  50h ; P
.rdata:00000001400307F3                 db 0EFh
.rdata:00000001400307F4                 db  1Eh
.rdata:00000001400307F5                 db  99h
.rdata:00000001400307F6                 db  2Ah ; *
.rdata:00000001400307F7                 db  1Ah
.rdata:00000001400307F8                 db  21h ; !
.rdata:00000001400307F9                 db  58h ; X
.rdata:00000001400307FA                 db 0A6h
.rdata:00000001400307FB                 db  39h ; 9
.rdata:00000001400307FC                 db  38h ; 8
.rdata:00000001400307FD                 db    0
.rdata:00000001400307FE                 db 0CFh
.rdata:00000001400307FF                 db  81h
.rdata:0000000140030800                 db  98h
.rdata:0000000140030801                 db  57h ; W
.rdata:0000000140030802                 db  61h ; a
.rdata:0000000140030803                 db  8Bh
.rdata:0000000140030804                 db 0C7h
.rdata:0000000140030805                 db  47h ; G
.rdata:0000000140030806                 db  18h
.rdata:0000000140030807                 db 0E3h
.rdata:0000000140030808                 db  86h
.rdata:0000000140030809                 db 0A1h
.rdata:000000014003080A                 db  5Dh ; ]
.rdata:000000014003080B                 db    9
.rdata:000000014003080C                 db 0FBh
.rdata:000000014003080D                 db 0DBh
.rdata:000000014003080E                 db 0A1h
.rdata:000000014003080F                 db  87h

 

 

4. GPU 리소스 업데이트

// 메시지 버퍼에 방금 만든 벡터를 통째로 복사
ImmediateContext->UpdateSubresource(a1[3] /*MsgBuf*/, 0, nullptr,
                                    Src[0], 0, 0);

v38[0] = ((char*)Src[1] - (char*)Src[0]) >> 2; // MessageLength(요소 수)
v38[1] = *((DWORD*)a1 + 16);                   // t
v39    = 128;                                  // TableLength (=SuffixLength)
ImmediateContext->UpdateSubresource(a1[5] /*CB*/, 0, nullptr,
                                    &v38, 0, 0);

 

5. 파이프라인 바인딩

ImmediateContext->CSSetShader(a1[2] /*ComputeShader*/, nullptr, 0);
ImmediateContext->CSSetShaderResources(0, 1, a1+7);   // t0 <- SRV(Message)
ImmediateContext->CSSetUnorderedAccessViews(0, 1, a1+6, nullptr); // u0 <- UAV(Syndromes)
ImmediateContext->CSSetConstantBuffers(0, 1, a1+5);   // b0 <- CB

groupsX = ((*((DWORD*)a1 + 17)) + 63) >> 6; // ceil((2t)/64)
ImmediateContext->Dispatch(groupsX, 1, 1);

 

 

6. 결과 맵핑

// staging 버퍼 생성 (D3D11_USAGE_STAGING, CPU read)
desc.ByteWidth = 4 * *((DWORD*)a1 + 17); // 4 * (2t)
desc.Usage = D3D11_USAGE_STAGING; desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;

Device->CreateBuffer(&desc, nullptr, &staging); // 실패 시 처리 코드
ImmediateContext->CopyResource(staging, a1[4] /*SynBuf*/);

// Map(READ) 후 memcpy -> CPU 배열(v17-v19)에 결과 DWORD들 복사
if (ImmediateContext->Map(staging, 0, D3D11_MAP_READ, 0, &pData) >= 0) {
    memcpy(v17, pData, 4 * (2t));
    ImmediateContext->Unmap(staging, 0);
}

// 검사: 하나라도 0이 아니면 실패
for (p=v17; p!=v19; p+=4) if (*(uint32_t*)p) goto fail;
success: v21=1; goto cleanup;
fail:    v21=0;
cleanup: Release(staging); free(CPU buffers); free(Src); return v21;

 

신드롬이 모두 0이면 true이다. 이 값이 main으로 이어져서 Correct, Wrong을 결정한다.

 

StreamWriteCString (__int64 *__fastcall sub_1400035B0(__int64 *ostr, __int64 cstr))

포맷팅을 포함한 래퍼이다.

 

1. 길이 체크

size_t len=0; while (cstr[len]) ++len;

 

2. 스트림 내부 포인터 확인

v6 = *(int*)(*ostr + 4);                 // iostream 내부 오프셋 베이스
streambuf = *(__int64*)((char*)ostr + v6 + 72);
fill_char = *((unsigned char*)ostr + v6 + 88);
width     = *(__int64*)((char*)ostr + v6 + 40); // 출력 폭

 

3. 출력 처리

좌우 정렬을 fmtflags로 검사 후 필요한 만큼 fill_char을 반복 출력한다.

출력은 streambuf의 sputc, sputn 으로 한다. 내부적으로 버퍼가 있으면 직접 채우고 그게 아닐 경우 sputn을 호출한다.

오류 비트가 있을 경우 throw하고 출력에 있어 많은 처리가 있지만, 중요한건많이 한다.

 

failure는 throw하고 uncaught_exception()이 아니면 ostr->copyfmt(ostr) 등으로 폭 초기화를 한다.

 

플래그가 출력 처리에 민감해서 조금 훑어보았다.

 

 


Shader 핵심

// GF(256) exp/log 테이블, gf_add/mul/pow 구현
StructuredBuffer<uint> g_MessageBuffer : register(t0);     // 계수열
RWStructuredBuffer<uint> g_SyndromesBuffer : register(u0);
cbuffer cbConstants : register(b0) {
  uint g_MessageLength;            // 전체 길이(prefix+suffix)
  uint g_SupportedErrorCount;      // t
  uint g_TableLength;              // 128(고정)
}

[numthreads(64,1,1)]
void CSMain(uint3 DTid:SV_DispatchThreadID){
  uint j = DTid.x;
  if (j >= g_SupportedErrorCount * 2) return;  // 0..(2t-1)

  uint x = gf_pow(2, j);          // a^j, a=2
  uint S = 0;
  // 뒤에서부터 사용 (g_MessageLength - i - 1)
  for (uint i=0; i<g_MessageLength; i++){
    uint c = g_MessageBuffer[g_MessageLength - i - 1];
    if (c != 0) S ^= gf_mul(c, gf_pow(x, i));
  }
  g_SyndromesBuffer[j] = S;        // S_j
}

메시지 다항식 $M(x) = \sum\limits_{i=0}^{L-1} c_ix^i$ (여기서 $c_0$은 맨 뒤 바이트)

$\alpha = 2$. 각 스레드 $j$는 $S_j = M(\alpha^j)$를 계산한다.

$S_0,...,S_{2t-1}$ 모두 0이면 Correct

 

Exploitation

$j = 0..63$에 대해 $S_j = 0$.

메시지를 prefix $X[0..n-1]$ (우측 계수)와 suffix $Y[0..127]$로 나누면

 

$$M(x) = \sum\limits_{i=0}^{n-1} X[n-1-i]x^i+ \sum\limits_{u=0}^{127} Y[127-u]x^{n+u} $$

따라서

 

$$ 0 = S_j = \sum\limits_{i=0}^{n-1} X[n-1-i] \cdot (a^j)^i + \sum\limits_{u=0}^{127} Y[127-u] \cdot (a^j)^{n+u}$$

 

이를 미지수 X에 대한 선형 $AX = b$로 변환한다.

$n$을 2t(=64)로 잡으면, 식이 정확히 64x64 $\rightarrow$ 가역

$A_{j,y} = \alpha^{j \cdot (n-1-y)}$

$b_j = \sum\limits_{u=0}^{127} Y[127-u] \cdot \alpha^{j \cdot (n+u)}$ 을 GF(256)에서 계산 후 좌변으로 넘기기

 

GF -> Shader와 동일한 exp/log 테이블 기반이다. 원시원소 2, 모듈러 255 지수

 

 

import base64

EXP = [1,2,4,8,16,32,64,128,45,90,180,69,138,57,114,228,229,231,227,235,251,219,155,27,54,108,216,157,23,46,92,184,93,186,89,178,73,146,9,18,36,72,144,13,26,52,104,208,141,55,110,220,149,7,14,28,56,112,224,237,247,195,171,123,246,193,175,115,230,225,239,243,203,187,91,182,65,130,41,82,164,101,202,185,95,190,81,162,105,210,137,63,126,252,213,135,35,70,140,53,106,212,133,39,78,156,21,42,84,168,125,250,217,159,19,38,76,152,29,58,116,232,253,215,131,43,86,172,117,234,249,223,147,11,22,44,88,176,77,154,25,50,100,200,189,87,174,113,226,233,255,211,139,59,118,236,245,199,163,107,214,129,47,94,188,85,170,121,242,201,191,83,166,97,194,169,127,254,209,143,51,102,204,181,71,142,49,98,196,165,103,206,177,79,158,17,34,68,136,61,122,244,197,167,99,198,161,111,222,145,15,30,60,120,240,205,183,67,134,33,66,132,37,74,148,5,10,20,40,80,160,109,218,153,31,62,124,248,221,151,3,6,12,24,48,96,192,173,119,238,241,207,179,75,150,1]
LOG = [0,0,1,240,2,225,241,53,3,38,226,133,242,43,54,210,4,195,39,114,227,106,134,28,243,140,44,23,55,118,211,234,5,219,196,96,40,222,115,103,228,78,107,125,135,8,29,162,244,186,141,180,45,99,24,49,56,13,119,153,212,199,235,91,6,76,220,217,197,11,97,184,41,36,223,253,116,138,104,193,229,86,79,171,108,165,126,145,136,34,9,74,30,32,163,84,245,173,187,204,142,81,181,190,46,88,100,159,25,231,50,207,57,147,14,67,120,128,154,248,213,167,200,63,236,110,92,176,7,161,77,124,221,102,218,95,198,90,12,152,98,48,185,179,42,209,37,132,224,52,254,239,117,233,139,22,105,27,194,113,230,206,87,158,80,189,172,203,109,175,166,62,127,247,146,66,137,192,35,252,10,183,75,216,31,83,33,73,164,144,85,170,246,65,174,61,188,202,205,157,143,169,82,72,182,215,191,251,47,178,89,151,101,94,160,123,26,112,232,21,51,238,208,131,58,69,148,18,15,16,68,17,121,149,129,19,155,59,249,70,214,250,168,71,201,156,64,60,237,130,111,20,93,122,177,150]

def gf_add(x,y): return x ^ y
def gf_mul(x,y):
    if x==0 or y==0: return 0
    return EXP[(LOG[x] + LOG[y]) % 255]
def gf_inv(x):
    assert x!=0
    return EXP[(255 - LOG[x]) % 255]
def gf_pow(x,p):
    if x==0: return 0
    return EXP[(LOG[x]*p) % 255]

ALPHA = 2

# .rdata:140030790
SUFFIX = [
    0x92,0xD5,0x31,0xA5,0xE5,0xDF,0x29,0x67,0x37,0xC8,0x27,0x65,0xFE,0x66,0x17,0x47,
    0x29,0x78,0xA5,0x77,0xE1,0xAF,0x7D,0xD5,0xE1,0x5C,0x7E,0x66,0xC9,0xE9,0x41,0xBF,
    0xAA,0xE0,0x11,0xDA,0x39,0x2D,0x2D,0x8D,0x73,0xB9,0xBD,0xC9,0xE2,0x86,0x6E,0x60,
    0x40,0x29,0x86,0xBA,0x76,0x04,0x8D,0x7A,0xC0,0x5C,0x89,0x1D,0xFF,0x3E,0x5E,0x9C,
    0xE9,0xAB,0x45,0x5C,0xC1,0x5D,0x64,0x56,0x46,0x11,0x72,0xCD,0x8F,0x5F,0x87,0xA9,
    0xD6,0xB7,0x69,0xCF,0x22,0xF5,0xF6,0xDB,0x41,0x76,0xCD,0x3D,0xF8,0x66,0x57,0xE3,
    0x3E,0x8F,0x50,0xEF,0x1E,0x99,0x2A,0x1A,0x21,0x58,0xA6,0x39,0x38,0x00,0xCF,0x81,
    0x98,0x57,0x61,0x8B,0xC7,0x47,0x18,0xE3,0x86,0xA1,0x5D,0x09,0xFB,0xDB,0xA1,0x87
]

def solve_prefix(t=32, n=64):
    L = n + len(SUFFIX)
    b = []
    for j in range(2*t):
        xj = gf_pow(ALPHA, j)
        s = 0
        for u in range(128):
            s = gf_add(s, gf_mul(SUFFIX[127 - u], gf_pow(xj, u)))
        b.append(s)

    A = [[0]*n for _ in range(2*t)]
    for j in range(2*t):
        xj = gf_pow(ALPHA, j)
        for y in range(n):
            A[j][y] = gf_pow(xj, L - 1 - y)

    # Gauss-Jordan over [A|B]
    for j in range(2*t):
        A[j].append(b[j])
    rows, cols = 2*t, n
    r = c = 0
    while r < rows and c < cols:
        piv = None
        for i in range(r, rows):
            if A[i][c] != 0:
                piv = i; break
        if piv is None:
            c += 1; continue
        if piv != r:
            A[r], A[piv] = A[piv], A[r]
        inv = gf_inv(A[r][c])
        for k in range(c, cols+1):
            A[r][k] = gf_mul(A[r][k], inv)
        for i in range(rows):
            if i == r: continue
            if A[i][c] != 0:
                factor = A[i][c]
                for k in range(c, cols+1):
                    A[i][k] = gf_add(A[i][k], gf_mul(factor, A[r][k]))
        r += 1; c += 1

    X = [A[y][n] for y in range(n)]

    def calc_syndromes(msg_bytes, t):
        L = len(msg_bytes)
        S = []
        for j in range(2*t):
            xj = gf_pow(ALPHA, j)
            s = 0
            for i in range(L):
                c = msg_bytes[L-1-i]
                if c:
                    s = gf_add(s, gf_mul(c, gf_pow(xj, i)))
            S.append(s)
        return S

    msg = X + SUFFIX
    S = calc_syndromes(msg, t)
    assert all(s == 0 for s in S), "not all zero"

    return base64.b64encode(bytes(X)).decode()

if __name__ == "__main__":
    print(solve_prefix())

 

 


cce2025{/0RSaoB7Wx/1CkP3G7ElEmZomDizSxK8A7gXCtGoqVvyLuzigr9Syl0RxT7owWjE8rkXAiBHMc1/kiguDSl0ww==}