Search

[CodeEngine] Basic RCE L17

Tags
reversing
Category
CodeEngn
Last Edited time
2022/01/07 12:50
Visibility
Public

1. 문제

Key 값이 BEDA-2F56-BC4F4368-8A71-870B 일때 Name은 무엇인가 힌트 : Name은 한자리인데.. 알파벳일수도 있고 숫자일수도 있고.. 정답인증은 Name의 MD5 해쉬값(대문자)
Plain Text
복사
이번엔 반대로 키에 해당하는 Name을 구해야한다
패킹은 따로 안돼있고 델파이로 만들어진 바이너리이다
int __usercall TForm1_Button1Click@<eax>(int a1@<eax>, int a2@<ebx>) { ... Controls::TControl::GetText(*(Controls::TControl **)(a1 + 872)); v15 = v16; // v16=&Name v3 = v16; if ( v16 ) // Name 값이 참이면 v3 = *(_DWORD *)(v16 - 4); if ( v3 >= 3 ) // Name 사이즈가 3보다 크거나 같으면 { Controls::TControl::GetText(*(Controls::TControl **)(a1 + 872)); v15 = v14; v4 = v14; if ( v14 ) v4 = *(_DWORD *)(v14 - 4); if ( v4 <= 0x1E ) // len(Name) <= 0x1E { Controls::TControl::GetText(*(Controls::TControl **)(a1 + 0x374)); v7 = v13; // v13=serial Controls::TControl::GetText(*(Controls::TControl **)(a1 + 0x368)); sub_45B850(v11, (int)&v12); // v11=Name System::__linkproc__ LStrCmp(v7, v12); if ( v5 ) Forms::TApplication::MessageBox(*(Forms::TApplication **)off_45E9C0[0], "Well done!", "Good Boy!!!", 0x40u); else Sleep_0(0x14Du); .... }
C
복사
Name에 입력한 사이즈를 검사한다. 문제에서는 한글자라고 했지만 여기서는 3바이트보다 크거나 같아야지만 된다. 저기는 1로 패치해서 디버깅하면 될듯
그리고 0x1E보다는 작아야한다. 힌트에서 한글자라고 했으니 여기는 걍 통과될 것이다.
키젠을 어디서 하는지를 찾는게 관건이다

2. 접근방법

디버깅 결과
sub_45B850(v11, (int)&v12); // v11=Name
여기서 키젠을 하는것을 확인할 수 있다. v11에는 입력한 Name이 들어가고 v12에는 생서된 키 값이 들어간다
// bad sp value at call has been detected, the output may be wrong! int __fastcall sub_45B850(void *a1, int a2) { ... v34 = a2; v36 = a1; System::__linkproc__ LStrAddRef(a1); v22 = &savedregs; v21 = &loc_45BAAA; v20 = NtCurrentTeb()->NtTib.ExceptionList; __writefsdword(0, (unsigned int)&v20); v2 = 0; v3 = 0; v33 = 0; v4 = (char *)v36; if ( v36 ) v4 = (char *)*((_DWORD *)v36 - 1); if ( (int)v4 > 0 ) { v5 = 1; do { v6 = 0x772 * (v2 + (unsigned __int8)*((char *)v36 + v5 - 1)); v3 = 0x8E8 * (v6 * v6 + v6); v2 = v3; ++v5; --v4; } while ( v4 ); } v7 = (int)v36; if ( v36 ) v7 = *((_DWORD *)v36 - 1); if ( v7 >= 1 ) { do v33 += 0x93C84 * ((unsigned __int8)*((char *)v36 + --v7) + 12); while ( v7 ); } System::__linkproc__ LStrCat3((int)&v31, v36, &str_w09__720_______[1]); sub_45B54C(v31, (int)&v35); v8 = 0; v9 = 0; v10 = (int)v36; if ( v36 ) v10 = *((_DWORD *)v36 - 1); if ( v10 >= 1 ) { do { v8 = 33682 * (v9 + (unsigned __int8)*((char *)v36 + v10 - 1) + v8 + 4240); v9 = v8 + v8 * (v8 - 51); --v10; } while ( v10 ); } v11 = 0; v12 = (char *)v36; if ( v36 ) v12 = (char *)*((_DWORD *)v36 - 1); if ( (int)v12 > 0 ) { v32 = 1; do { v13 = 2 * ((unsigned __int8)*((char *)v36 + v32 - 1) + v11); v14 = (unsigned __int8)*((char *)v36 + v32 - 1) + 883 * ((v13 * v13 * v13) ^ 0x10 | 0x44) + 1091; v11 = v14 * v14; ++v32; --v12; } while ( v12 ); } Sysutils::IntToHex(v3, 4); System::__linkproc__ LStrCopy((int)&v30, (int)v20); v20 = (_EXCEPTION_REGISTRATION_RECORD *)v30; Sysutils::IntToHex(v33, 0); System::__linkproc__ LStrCopy((int)&v29, (int)&str___13[1]); v19 = v29; System::__linkproc__ LStrCopy((int)&v28, (int)&str___13[1]); v18 = v28; Sysutils::IntToHex(v8, 0); System::__linkproc__ LStrCopy((int)&v27, (int)&str___13[1]); v17 = v27; Sysutils::IntToHex(v11, 0); System::__linkproc__ LStrCopy((int)&v26, (int)&str___13[1]); System::__linkproc__ LStrCatN(v34, 9, v15, v23, v22, v21, v20, v19, v18, v17, v26); __writefsdword(0, v24); v26 = (int)&loc_45BAB1; System::__linkproc__ LStrArrayClr(&v25, 10); return System::__linkproc__ LStrArrayClr(&v35, 2); }
C
복사
맨 마지막 StrCat 을 통해 생성한 키 값을 이어붙인다. 중간중간 하이픈으로 연결한다.
키 사이즈는 Name에 상관없이 고정 사이즈이다
ex) 0000-0000-00000000-0000-0000
초반 부분을 보면
v3=0 v5=0 if ( (int)v4 > 0 ) { v5 = 1; do { v6 = 0x772 * (v3 + (unsigned __int8)*((char *)v36 + v5 - 1)); v3 = 0x474 * (v6 * v6 + v6); v3 = v3+v3; ++v5; --v4; } while ( v4 ); }
C
복사
다음과 같이 계산되는데 Name의 한바이트를 가지고 연산을 진행한다. 연산결과는 4바이트 이상의 값이 나오지만 4바이트까지만 저장된다. 생성되는 키 값을 확인해보면 위 연산 결과의 상위 2바이트 인것을 알 수 있다
따라서 위 로직을 파이썬 코드로 포팅하여 BEDA-2F56-BC4F4368-8A71-870B 키 값중 첫 4바이트가 나오는 것을 Name으로 하면 된다

3. 풀이

import hashlib v6 = 0 v2 = 0 for i in range(0x21, 0x7F): v6 = (v2 + i) * 0x772 tmp = (v6 * v6) & 0xFFFFFFFF tmp = ((tmp + v6) * 0x474) & 0xFFFFFFFF tmp = (tmp + tmp) & 0xFFFFFFFF if (tmp >> (8 * 2)) == 0xBEDA: print("Name is " + chr(i)) enc = hashlib.md5() enc.update(chr(i).encode("utf-8")) encText = enc.hexdigest() print("md5 hash is " + str(encText)) break ============================================================ Name is F md5 hash is 800618943025315f869e4e1f09471012
Python
복사

4. 몰랐던 개념