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==}
'CTF' 카테고리의 다른 글
[Forensic] CCE 2025 Qual - something from a friend write-up (0) | 2025.08.16 |
---|---|
[Crypto] Linear congruential generator(LCG) Recovery (2) | 2025.08.09 |
[Crypto] SASCTF 2025 - blindspot write-up (0) | 2025.05.26 |
[Crypto] SASCTF 2025 - bigbabycode write-up (0) | 2025.05.26 |
[Network Forensic] MISC 풀어보기 (0) | 2024.05.20 |