Basic RCE L20
이 프로그램은 Key파일을 필요로 하는 프로그램이다.
'Cracked by: CodeEngn!' 문구가 출력 되도록 하려면 crackme3.key 파일안의 데이터는 무엇이 되어야 하는가
Ex) 41424344454647
(정답이 여러개 있는 문제로 인증시 맞지 않다고 나올 경우 Contact로 연락주시면 확인 해드리겠습니다)
가장 먼저 실행시켜보면
이런 화면이 뜨네요.
이 윈도우 창을 띄우는 것 이외에는 하는 일이 없어보이는데 Ollydbg로 열어봅시다.
Ollydbg로 열어보면
이런 화면이 나오는데 대충 읽어보면 CRACKME3.KEY라는 파일이 있다면 읽어들이는 것 같네요, 일단 해당 이름의 파일을 만들어 봅시다.
( 확장자명은 .KEY로 해 주어야 합니다. )
그럼 이제 아래로 쭉쭉 가봅시다. 일단 비교문 CMP위주로 읽어볼게요.
가장 먼저 봐야 할 부분입니다.
ReadFile을 실행한 뒤의 함수에 12( 18 )와 어떤 주소의 값과 비교를 하는 부분이 있는데 아마 이 부분이 읽어들인 CRACKME3.KEY 파일의 길이인 것 같네요. 일단 똑같이 메모장으로 CRACKME3.KEY파일을 열어서 A를 18개 채워 넣읍시다.
이렇게 내용을 18byte로 넣어준 뒤에 실행을 시키면 JNZ문을 건너뛸 수 있게 됩니다.
다음 점프문 부분을 봅시다.
대충 보니 AL이 중요한 듯 하네요. AL는 EAX의 한 부분이니 EAX를 봐야합니다.
근처에서 EAX의 값을 주는 명령은 위에 있는 CALL 함수에서의 호출밖에 없으니 해당 호출함수에서 무슨일이 일어나는지 보러 갑시다.
요런 함수에 진입해보니 적은 양의 코드가 보이네요.
해석을 해보자면...
MOV ESI, DWORD PTR SS : [ ESP+4 ] | ESI에 우리가 만든 CRACKME3.KEY파일의 값을 넣는다. ( ESP + 4 = 함수 호출 전 PUSH를 통해 받은 값 ) |
ADD ESI, 0E | ESI += 14 |
MOV EAX, DWORD PTR DS : [ ESI ] | ESI주소에 있는 값을 EAX에 저장 |
RETN | 종료 |
축약을 하자면 CRACKME3.KEY 파일의 마지막 4byte값을 EAX에 저장하고 끝내게 됩니다.
이제 점프문을 넘어가기 위해서 자세히 들여다보면
CMP EAX, DWORD PTR DS:[ 4020F9 ] | EAX와 4020F9 ( 78563412 )의 값을 비교한다. |
SETE AL | ZF가 1이면 바이트형 레지스터를 1로 set |
PUSH EAX | 스택에 EAX 저장 |
TEST AL, AL | AL이 0인지 검사 |
JE SHORT 20.00401037 | AL이 0이면 점프 |
이렇게 해석됩니다. CMP부분에서 78563412의 값과 CRACKME3.KEY의 마지막 4byte의 값을 비교하는데 이 값만 같으면 모두 해결될 듯 하니 CRACKME3.KEY의 마지막 4byte의 값을 78563412로바꿔줍시다.
하지만 그냥 78563412를 그대로 넣으면 크기가 커지고 값이 제대로 안들어가니 HxD라는 프로그램을 이용해서 값을 바꿔줬습니다.
내용을 이렇게 바꿔준뒤에 실행을 시켜보면
성공! .... 인줄 알았으나..
문제의 내용을 자세히 보니 CodeEngn이라는 문자열이 출력되어야 하는데 !만 출력한다... 왜 이렇게 출력되는지 확인해봤더니
메세지박스를 출력하기 전에 REP이라는 것을 통해서 문자열을 삽입해주는데 우선 REP은 반복문과 비슷한 역할을 합니다.
그런데 EDI 그러니까 !앞에 부분에 문자열을 삽입하는데 ESI 주소에 있는 값( 00402008 )부터 삽입을 하는데 첫 부분이 0이라서 바로 종료하는 듯 했다.
원래는 41이라는 값이 들어있었는데 바뀐걸 보니 어디선가 값을 조작하는듯 했다. 그래서 찾아봤더니 의외로 초반 부분에 있었다.
ReadFile함수 밑에 함수를 하나 호출하는데 이 부분에서 값의 수정이 이루어졌네요. 해당 함수에 진입해봅시다.
첫 부분 XOR ECX, ECX 이 부분들은 모두 값을 0으로 만들어주는 부분이기 때문에 제외하고, 반복을 하는 부분을 해석 해봅시다.
MOV AL,BYTE PTR DS:[ESI] | AL에 ESI주소에 있는 값 저장 ( CRACKME3.KEY 내용의 첫 부분부터 ) |
XOR AL, BL | AL에 BL을 XOR연산 |
MOV BYTE PTR DS:[ESI],AL | XOR연산된 값을 ESI주소에 저장 ( CRACKME3.KEY 내용의 첫 부분부터 ) |
INC ESI | ESI += 1 ( CRACKME3.KEY 의 다음 값 ) |
INC EBX | EBX += 1 |
ADD DWORD PTR DS:[4020F9],EAX | 4020F9주소의 값 += EAX |
CMP AL, 0 | AL과 0을 비교 |
JE SHORT 00401335 | 같으면 반복문 종료 |
이 정도만 알아도 문제를 풀기에는 충분하다.
어떻게 흘러가는지 풀어서 말해보자면, 만약 CRACKME3.KEY의 내용이 AA라면
AL ( 41 ) XOR BL ( 41 )
AL ( 41 ) XOR BL ( 42 )
을 한다는 의미이다 하지만 여기서 XOR을 했을 때 AL이 0이 되면 끝나기 떄문에 우리가 원하는 CodeEngn을 삽입하려면 BL값과 XOR했을 때 CodeEngn의 값이 나오도록 해주어야 한다.
여기에서 알아둬야 할 점은 BL의 값은 XOR 할 때마다 1씩 늘어나서 BL은 41, 42, 43... 이렇게 변하기 때문에 이 값에 맞춰서 XOR을 해주어야 한다는 점을 생각해서 XOR할 값을 저장해야 한다.
그리고 우리가 원하는 문자열인 CodeEngn을 만들어내고 0이라는 값을 넣어줘야 문자열을 끊기 때문에 마지막 9번째에는 끝내기 위해서 49라는 값을 삽입해줘야 한다.
( 9번째 XOR을 할 때의 BL이 49 )
여기까지 알면 풀기는 쉬울거라 생각한다.
'Hacking > Reversing' 카테고리의 다른 글
CodeEngn_basic_19 (0) | 2020.08.02 |
---|---|
CodeEngn_basic_18 (0) | 2020.07.24 |
CodeEngn_basic_17 (0) | 2020.07.24 |
CodeEngn_basic_16 (0) | 2020.07.18 |
CodeEngn_basic_15 (0) | 2020.07.13 |