CodeEngn Write Up/Basic

CodeEngn Basic RCE L20 Write Up

서원근양학계정 2022. 5. 18. 09:29

이 프로그램은 Key파일을 필요로 하는 프로그램이다.
'Cracked by: CodeEngn!' 문구가 출력 되도록 하려면 crackme3.key 파일안의 데이터는 무엇이 되어야 하는가
Ex) 41424344454647
(정답이 여러개 있는 문제로 인증시 맞지 않다고 나올 경우 Contact로 연락주시면 확인 해드리겠습니다)

https://ch.codeengn.com/

 

CodeEngn.com [코드엔진]

코드엔진은 국내 리버스엔지니어링 정보공유를 위해 2007년 부터 리버스엔지니어링 컨퍼런스 및 세미나, 워크숍을 현업 실무자들과 함께 운영하고 있는 비영리 커뮤니티입니다.

ch.codeengn.com

 

Basic단계의 최후의 문제네요.

먼저 문제 파일을 실행시켜보겠습니다.

 

아무것도 뜨지 않네요.

PEiD를 이용한 정적 분석을 진행해보겠습니다.

 

딱히 특이한 것은 보이지 않습니다.

OllyDBG를 이용한 동적 분석을 진행해보겠습니다.

이 문제는 이전에 풀었던 문제들과는 다르게 Key파일이라는 것을 필요로 하는 문제입니다.

따라서 파일과 관련된 함수들을 집중적으로 확인했습니다.

 

함수의 이름이 상당히 중요할 것 같다는 생각을 가지게 만듭니다.

그냥 실행시키니 함수의 리턴값을 받는 EAX에 0xFFFFFFFF, 10진수로 -1이 들어가게 되고 약간 더 실행시키면

 

중요해 보이는 ReadFile함수를 건너뛰게 됩니다.

CreateFileA함수에서 FileName = "CRACKME3.KEY"라는 것이 보여서 문제 파일이 있는 폴더에 CRACKME3.KEY라는 파일을 만들어보았습니다.

 

그랬더니 EAX에 0x000000E8이라는 값이 들어가고 이 부분에서 점프를 하면서 ReadFile함수를 거쳐가게 됩니다.

 

그리고 ReadFile함수를 실행시켰더니

 

4021A0의 값과 0x12를 비교하고 좋지 않은 쪽으로 점프하게 됩니다.

따라서 우리는 4021A0의 값을 0x12로 만들어야만 합니다.

ReadFile함수를 자세히 보면 pBytesRead = 20.004021A0이라는 부분이 있습니다.

4021A0에는 파일의 크기가 Byte단위로 들어간다고 추측할 수 있습니다.

CRACKME3.KEY의 값을 바꾸어 가면서 확인해본 결과 4021A0에는 파일의 글자 수가 들어간다는 사실을 알게 되었습니다.

따라서 CRACKME3.KEY의 내용을 0x12를 10진수로 바꾼 값인 18글자로 채워주었습니다.

그랬더니 좋지 않은 쪽으로 점프하지 않고 뭔가 중요한 부분으로 들어서게 되었습니다.

 

그리고 0x00401074에 있는 함수를 실행시키니 문자열이 바뀝니다.

 

 

따라서 0x00401074에 있는 함수가 중요하다는 사실을 알 수 있습니다.

이 함수를 분석해보겠습니다.

아래는 이 함수의 코드입니다.

 

먼저 XOR ECX, ECX와 XOR EAX, EAX를 해줍니다.

XOR은 배타적 논리합 연산으로 값이 같으면 0이 되고 값이 다르면 1이 됩니다.

따라서 동일한 레지스터를 XOR 연산하면 그 레지스터의 값은 0이 됩니다.

간단히 말해서 XOR EAX, EAX는 MOV EAX, 0입니다.

 

그리고 ESI에 key파일에 있는 문자열이 있는 주소를 넣고 BL에 0x41을 넣어줍니다.

그리고 본격적인 루프가 시작됩니다.

 

먼저 AL에 ESI가 가리키는 주소의 값을 Byte단위로 받아옵니다.

ESI는 문자열이 있는 주소를 가지고 있으므로 문자열의 첫 글자가 AL에 들어갑니다.

 

AL과 BL를 XOR연산 해줍니다.

 

그리고 그 값을 ESI가 가리키는 주소에 Byte단위로 넣어줍니다.

 

ESI와 BL를 1씩 늘려줍니다.

ESI가 1 늘어나면 다음번에 반복할 때는 두 번째 글자를 가져오게 됩니다.

 

0x4020F9에 EAX의 값을 더해줍니다.

 

그리고 AL의 값과 0을 비교하고 JE을 실행시킵니다.

이 부분은 문자열이 끝났는지 확인하고 끝났다면 루프를 탈출하기 위한 코드입니다.

 

CL의 값을 1 늘려주는데 이 부분은 큰 의미는 없는 것 같습니다.

 

마지막으로 BL을 0x4F와 비교해서 같으면 루프의 첫 부분으로 점프하고 아니면 루프를 빠져나옵니다.

처음에 BL에 0x41을 넣어주었으므로 총 14번 반복하게 됩니다.

 

이 부분을 C언어로 구현해보겠습니다.

 

#define _CRT_SECURE_NO_WARNINGS

#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
	char key[19] = { "123456789012345678" };
	int _4020F9 = 0;
	int _402149 = 0;
	int AL, BL, CL;
	int ESI = 0;

	CL = 0;
	AL = 0;
	BL = 0x41;

	while (1)
	{
		AL = key[ESI];
		AL ^= BL;
		key[ESI] = AL;
		ESI++;
		BL++;
		_4020F9 += AL;
		if (AL == 0)
		{
			break;
		}
		CL++;
		if (BL == 0x4F)
		{
			break;
		}
	}

	_402149 = CL;

	printf("key: %s\n", key);
	printf("_4020F9: %d\n", _4020F9);
	printf("_402149: %d\n", _402149);

	return 0;
}

 

이 코드가 0x00401311 함수를 C언어로 구현한 코드입니다.

 

 

이어서 코드를 분석해보겠습니다.

0x00401311 함수에서 만들어진 값인 0x4020F9 주소에 있는 값과 0x12345678을 XOR 연산해줍니다. 

그리고 0x0040133C함수를 호출합니다.

이 함수도 안으로 들어가서 자세히 분석해보겠습니다.

 

복잡한 함수는 아니고 0x00401311 함수에서 만들어진 문자열의 마지막 4글자의 아스키코드값을 EAX에 넣는 간단한 코드였습니다.

 

5, 6, 7, 8의 아스키코드값인 0x35, 0x36, 0x37, 0x38이 EAX에 오른쪽부터 순서대로 들어간 모습입니다.

 

EAX와 0x4020F9의 값을 비교합니다.

EAX에는 입력한 문자열의 마지막 4글자의 아스키코드값이 들어가고 4020F9에는 0x00401074함수에서 만들어진 값과 0x12345678을 XOR 한 값이 들어갑니다.

그리고 그 값이 같으면 AL을 1로 바꾸고 아니면 0이 됩니다.

만약 EAX가 0이면 JE을 통해서 점프하게 되고 특별한 것이 없는 창이 뜨게 됩니다.

따라서 그 두 값을 같게 만들어주어야 합니다.

 

지금은 값이 같지 않지만 임의로 값을 변경해보겠습니다.

그리고 F9를 이용해서 실행하니 이런 창이 뜹니다.

 

뒤에 느낌표가 추가되는 것을 확인할 수 있습니다.

 

이제 0x00401074를 거쳐서 문자열이 CodeEngn이 되도록 해보겠습니다.

입력한 문자의 아스키코드값과 0x41을 XOR 연산해서 'C'가 나와야 하므로 

'C'의 아스키코드값인 0x43과 0x41을 XOR 하면 0x2

'o'의 아스키코드값인 0x6F와 0x42를 XOR하면 0x2D

이런 식으로 해주면 

0x2, 0x2D, 0x27, 0x21, 0x0, 0x28, 0x20, 0x26이 나옵니다.

그리고 문자열의 끝을 알리는 0x0이 들어가야 하므로 

0x49와 0x0을 XOR 한 값인 0x49를 뒤에 더해서 key파일의 문자열의 아스키코드값이 0x2, 0x2D, 0x27, 0x21, 0x0, 0x28, 0x20, 0x26, 0x49가 되면 CodeEngn이 만들어집니다.

 

그리고 문구가 출력되는 창을 띄우기 위해서는 0x00401093에서 진행하는 비교에서 EAX와 4020F9에 같은 값이 들어가 있게 해야 합니다.

위에 있는 아스키코드값을 넣고 0x00401074 함수를 실행시키면 4020F9에는 771이 들어가게 됩니다.

그리고 그 값에 0x12345678과 XOR 연산해줍니다.

그러면 0x1234557B가 나오게 됩니다.

EAX에는 key파일에 있는 마지막 4글자의 아스키코드값이 들어가므로 key파일의 마지막 4글자를 0x7B, 0x55, 0x34, 0x12를 아스키코드값으로 가지는 것으로 해주면 됩니다.

 

이제 지금까지 알아낸 값을 key파일에 넣어주면 됩니다.

하지만 일반적인 메모장을 이용해서는 0x2나 0x0 같은 값을 아스키코드값으로 가지는 문자를 입력할 수 없습니다.

따라서 파일의 내용을 16진수를 이용해서 수정할 수 있게 해주는 HxD라는 프로그램을 이용해서 값을 수정해보겠습니다.

 

HxD를 실행시킨 모습입니다.

 

값을 모두 수정했습니다.

중간에 16진수 값이 0xFF로 되어있는 부분이 있는데 이 부분은 어떤 값이 들어가더라도 상관이 없는 부분입니다.

이제 이 key파일을 저장하고 문제 파일을 실행시켜보겠습니다. 

 

Flag: -'!�( &Iÿÿÿÿÿ{U4

0x02 0x2D 0x27 0x21 0x00 0x28 0x20 0x26 0x49 0xFF 0xFF 0xFF 0xFF 0xFF 0x7B 0x55 0x34 0x12

CRACKME3.KEY
0.00MB

'CodeEngn Write Up > Basic' 카테고리의 다른 글

CodeEngn Basic RCE L19 Write Up  (1) 2022.05.13
CodeEngn Basic RCE L18 Write Up  (2) 2022.05.12
CodeEngn Basic RCE L17 Write Up  (1) 2022.04.22
CodeEngn Basic RCE L16 Write Up  (0) 2022.03.31
CodeEngn Basic RCE L15 Write Up  (3) 2022.03.11