코드엔진 Basic RCE L14 Write Up

War Game

2019. 9. 29. 14:48

반응형

문제만 본다면 무언가 입력될 때 어떤 연산을 통해 시리얼이 생성된다는걸 알 수 있다.

프로그램을 실행해보자.

실행하면 이런 프로그램이 띄워진다.

아마 윗칸에 Name을 입력하고, 밑칸에 시리얼을 입력하는 것 같다.

당장은 임시로 12345로 둘다 입력해주고 CHECK를 눌러보겠다.

"You Have Enter A Wrong Serial, Please Try Again"이라는 문자열이 출력된다.

직역하면 잘못된 시리얼을 입력했으니 제발 다시 해보라는것이다.

대충 실패 문자열을 알아냈으니 성공 문자열을 출력하는 곳으로 무난하게 갈 것 같다.

디버거로 열기전에 Detect It Easy로 파일을 분석하자.

아무 패킹도 없다. 바로 디버거로 열어주자.

문자열 검색으로 실패문자열을 찾자.

"Good Job, I Wish You the Very Best"가 성공 문자열인 것 같다.

성공 문자열 구문으로 이동하자.

성공 문자열 윗쪽을 보면 무언가 반복되는 구문이 있는걸 확인할 수 있다.

MOV EDX, DWORD PTR DS:[403038]
MOV DL, BYTE PTR DS:[EAX+403037]
AND EDX, 0FF
MOV EBX, EDX
IMUL EBX, EDX
ADD ESI, EBX
MOV EBX, EDX
SAR EBX, 1
ADD ESI, EBX
SUB ESI, EDX
INC EAX
DEC ECX

해당 코드가 어떤 동작을 하는지 알아내기 위해 동적분석을 해보도록 하자.

00401304에 BP를 걸어준 뒤 프로그램을 실행해주자 EDX에는 2345가 들어가고 EAX와 ECX에는 5가 들어가게 되었다.

여기서 킹리적 갓심이 갑자기 들었다. EAX와 ECX는 NAME과 시리얼의 자릿수가 아닐까?

그래서 NAME에는 1234, 시리얼에는 12345를 입력하고 다시 실행해보았다.

아니다.

EAX와 ECX는 NAME의 자릿수였다.

EDX에는 234가 들어갔는데 NAME의 앞자리가 짤린채로 들어간 것 같다.

MOV EAX, 1

위 코드가 실행되자 EAX에 1이 들어가게 되었다.

MOV EDX, DWORD PTR DS:[403038]

위 코드가 실행되자 EDX에 있던 "234"가 사라졌다.

위 코드의 의미는 DATA영역 403038에 접근하여 4바이트 만큼의 데이터를 EDX에 저장한다는 뜻입니다.

olly의 Dump를 이용해 해당 영역에 가봅시다.

NAME에 입력했던 '1234'가 저장되어 있습니다.

MOV DL, BYTE PTR DS:[EAX+403037]

여기서 DL은 EDX의 하위 8비트입니다.

해당 코드의 의미는 DATA영역 EAX+403037에 접근하여 1바이트 만큼의 데이터를 DL에 저장한다는 뜻입니다.

이번에도 Dump를 이용해 해당 영역에 가봅시다.

'1234'가 저장되어있다.

AND EDX, 0FF

위 코드가 실행되자 EDX가 31로 변경되었고,

PF와 ZF가 0으로 설정되었다.

EDX에 저장된 값과 0FF를 AND연산해준것인데,

여기서 0FF는 10진수로 바꿀 시 255이다.

 

2진수로 변환하면 11111111인데,

여기서 기존 EDX에 저장된 34333231을 2진수로 변환했을 때 11111111110100001100110011001000110001,

이둘을 AND연산하면

10진법으론 49, 16진수론 31이 나오게 된다.

MOV EBX, EDX

위 코드는 EDX에 있는 값을 EBX에 복사해준다.

레지스터를 확인해보면 EBX에 31이 복사된걸 확인할 수 있다.

IMUL EBX, EDX

IMUL은 부호있는 정수를 곱할 때 사용됩니다.

EDX와 EBX를 곱해준다네요.

16진수로 31과 31을 곱해주면 961이 나오는데, 이 값을 EBX에 저장해준다는 의미입니다.

ADD ESI, EBX

ESI와 EBX를 더해주어서 ESI에 저장해줍니다.

MOV EBX, EDX

EDX에 있는 값을 EBX에 복사해줍니다.

SAR EBX, 1

SAR연산은 최상위 비트는 유지한 채 오른쪽으로 쉬프트 연산을 수행한다.

C언어로 표현하자면 <<와 같다.

Visual Studio로 구현해보니 18이 출력되었다.

디버거 사진에서 레지스터 항목을 보면 알겠지만 EBX에 18이 들어가있다.

ADD ESI, EBX

ESI 값에 EBX를 더해서 ESI에 저장해준다.

ESI = 961, EBX = 18

961 + 18 = 979

SUB ESI, EDX

ESI 값에 EDX 값을 뺀 후 ESI에 저장해준다.

ESI = 979, EDX = 31

979 - 31 = 948

INC EAX

EAX값을 1 증가시킵니다.

DEC ECX

ECX값을 1 감소시킵니다.

 

이런식으로 루프가 계속 진행됩니다.

정리를 해보면

!) 루프가 진행되기 전 EAX값을 1로 채워준다.

1) EDX에 저장된 값을 403038 DATA 영역으로 보내준다.

2) DL에 저장된 값을 403037 DATA 영역으로 보내준다.

3) EDX값을 0FF와 AND연산을 해준 뒤 그 값을 EDX에 저장한다.

4) EDX값을 EBX에 저장한다.

5) EBX와 EDX를 곱해준 뒤 그 값을 EBX에 저장한다.

6) ESI에 EBX값을 더해준 뒤 ESI에 그 값을 저장한다.

7) EDX값을 EBX에 저장한다.

8) EBX값을 1과 <<연산한다.

9) ESI값에 EBX값을 더해준 뒤 그 값을 ESI에 저장한다.

10) ESI값에 EDX값을 빼준 뒤 그 값을 ESI에 저장한다.

11) EAX값을 1 증가시킨다.

12) ECX값을 1 감소시킨다.

13) ECX값이 0이 될때까지 반복한다.

 

이런 구문이 반복된다.

그 아래에 있는 CMP에 BP를 걸어주고 실행해보자.

hint 영역을 보면 ESI에는 15381이, EAX에는 3039가 입력되었다.

EAX에 들어있는 3039는 12345를 16진수로 변환한 값이다.

즉, ESI에는 codeengn이 들어가 있는걸 유추할 수 있다.

둘을 비교하므로 아마 15381이 Name이 codeengn일 시 만들어지는 시리얼 값인 듯 하다.

16진수이니 10진수로 바꾼 후 입력하자.

반응형

'War Game' 카테고리의 다른 글

코드엔진 Basic RCE L16 Write Up  (0) 2019.09.29
코드엔진 Basic RCE L15 Write up  (2) 2019.09.29
코드엔진 Basic RCE L13 Write Up  (0) 2019.07.31
코드엔진 Basic RCE L12 Write Up  (0) 2019.07.16
코드엔진 Basic RCE L11 Write Up  (0) 2019.07.13