1. 문제
CodeEngn 이름의 키 값을 찾으면 된다
패킹은 따로 안되어있는것 같다
2. 접근방법
키젠 하는 부분을 찾고, 코드로 포팅해서 풀어도 되고 생성된 키 값이랑 입력한 키 값이랑 비교하는 부분을 찾는 방법도 있다.
...
dword_408CF0 = GetDlgItemTextA(hWnd, 1001, String, 512);// return Name size
v9 = GetDlgItemTextA(hWnd, (int)aXspD3rRedCrew, byte_4086F0, 512);
sub_403F80((int)byte_4086F0, v9); // v9=0
sub_404058((unsigned int *)String, byte_4088F0);
v10 = sub_404820(byte_4088F0, dword_408CF0, byte_408AF0);
v11 = 0x524544;
LOBYTE(v11) = *((_BYTE *)sub_404768 + (_DWORD)v10);
wsprintfA(
key_gen,
"%.8X%.8X",
0x407AF0 * (v11 + LOBYTE(byte_4088F0[0])) + v11,
0x407AF0 * (v11 + LOBYTE(byte_4088F0[0])) - 5796720);
wsprintfA((LPSTR)byte_4088F0, "%.8X%.8X", dword_407AF0[1] ^ dword_407AF0[0], v12);
GetDlgItemTextA(hWnd, 1004, serial, 512);
if ( !lstrcmpiA(serial, key_gen) )
return MessageBoxA(hWnd, "Your serial is correct\r\n now you know what 2 do :p", aG0od, 0x40u);
MessageBoxA(hWnd, Text, Caption, 0x10u);
break;
case 0x3EA:
...
strcmp로 입력한 serial과 생성된 key를 비교한다. 사실 저 key_gen 이 정답이다. 너무 쉬우니까 어떻게 키젠을 하는지 추가로 확인해보자
3. 풀이
...
dword_408CF0 = GetDlgItemTextA(hWnd, 1001, String, 512);// return Name size
v9 = GetDlgItemTextA(hWnd, (int)aXspD3rRedCrew, byte_4086F0, 512);
sub_403F80((int)byte_4086F0, v9); // v9=0
sub_404058((unsigned int *)String, byte_4088F0);
v10 = sub_404820(byte_4088F0, dword_408CF0, byte_408AF0);
v11 = 0x524544;
LOBYTE(v11) = *((_BYTE *)sub_404768 + (_DWORD)v10);
wsprintfA(
key_gen,
"%.8X%.8X",
0x407AF0 * (v11 + LOBYTE(byte_4088F0[0])) + v11,
0x407AF0 * (v11 + LOBYTE(byte_4088F0[0])) - 5796720);
wsprintfA((LPSTR)byte_4088F0, "%.8X%.8X", dword_407AF0[1] ^ dword_407AF0[0], v12);
GetDlgItemTextA(hWnd, 1004, serial, 512);
if ( !lstrcmpiA(serial, key_gen) )
return MessageBoxA(hWnd, "Your serial is correct\r\n now you know what 2 do :p", aG0od, 0x40u);
MessageBoxA(hWnd, Text, Caption, 0x10u);
break;
case 0x3EA:
...
key_gen 변수는 wsprintfA를 이용하여 생성한다. 총16바이트 사이즈이며 공백은 0으로 채운다.
상위 8바이트는 v11
, byte_4088F0
변수를 이용하여 계산하게 되는데 저 두 변수가 어떠한 값을 같는지만 확인해보면 키젠을 쉽게 이해할 수 있다.
우선 byte_4088F0 은 총 2번 이용되는데 처음 sub_404058
함수에서 어떠한 값이 들어가는지 확인해보자. 처음에는 널 값으로 채워져 있던 공간이
해당 함수가 호출되고 나면 8바이트의 값이 써진다. 이는 해당 함수 내부에서 xor 연산들이 계산된 결과이다
그다음 sub_404820
함수에서 byte_4088F0 이 어떻게 쓰이는지 봐보자
값의 변화가 없다. 따라서 byte_4088F0
는 최종적으로 위 8바이트 값이다.
이제 v11이 뭔지 확인해보자.
v11 = 0x524544;
LOBYTE(v11) = *((_BYTE *)sub_404768 + (_DWORD)v10);
이렇게 나오는데 그냥 어셈으로 보는게 더 편하다
ecx는 0이여서 eax는 결국 아까 그 8바이트 중 첫바이트값인 0xCD가 들어간다.
그다음 [ebx+404768] 에 들어있는 한바이트를 dl 로 복사한다. 여기서 ebx는 0x10이다
마지막으로 eax와 edx를 더한다. 이 값이 바로 v11이다.
키젠은 이제 v11
과 byte_4088F0
를 이용해서 간단한 연산으로 생성된다
.text:0040117F imul eax, 407AF0h
.text:00401185 add edx, eax
.text:00401187 sub eax, 587370h
4. 몰랐던 개념
'워게임 > CodeEngn' 카테고리의 다른 글
[CodeEngine] Basic RCE L20 (0) | 2021.01.18 |
---|---|
[CodeEngine] Basic RCE L19 (0) | 2021.01.13 |
[CodeEngine] Basic RCE L17 (0) | 2021.01.11 |
[CodeEngine] Basic RCE L16 (0) | 2021.01.04 |
[CodeEngine] Basic RCE L14 (0) | 2021.01.02 |
Uploaded by Notion2Tistory v1.1.0