2011.07.16 21:45 WarGame

[+] Introduction

 


 이번에 소개할 문제는 VM 관련 문제 입니다.

VM을 이용한 기술은 VCP [ Virtualized Code Protection ] 이 있으며 해당 기술은 Protector 에 많이 쓰이곤 합니다.

언뜻 봐도 " Code를 Virtualize 하여 Protect 한다 " 라는것을 의미한다는거라고 쉽게 추측 할 수 있죠.

상용 Packer 인 Themida에 실제로 쓰이고 있는 기술이기도 하구요.

물론 Themida에는 VCP 뿐만 아니라 여러가지 Anti Reversing 기술들이 들어가있습니다만..

 이 포스팅에서는 VM만을 다루도록 하겠습니다.

 * VM이 적용되면 Reversing 하는 입장에서는 상당히 귀찮아집니다.

뒤에서 설명하겠지만 Assembly Language 로 한줄씩 실행되기 떄문에 

전체적인 구조를 살펴보려면 Script를 짜거나 손으로 직접 모아야 하기 떄문이죠.

디버거로 열어봤는데...


<Fig 0. VM이 딱 ! >


 <Fig0-1. 5초후에 빡침이 딱!>



[+] Problem


<Fig1. Bin500을 실행 시켰을 때 >

 

먼저 Debugger로 문자열을 확인해보면

key File로 짐작되는 문자열 'codegate.key' 를 찾을 수 있습니다.

적당히 아무내용이나 집어넣어서 재실행 시켜보면

역시 유효하지 않은 파일이라고 하는군요.

<Fig2. 해당 파일이 올바르지 않을 때 메세지> 

이런 류의 문제라면 해당 Key 파일을 검사하는 부분을 우회해도 

암호가 나오지 않고 그 파일을 가지고 연산을 하기 떄문에

해당 파일의 내용을 정확히 복구를 해야 합니다.

 파일을 열어 Verify 하는 부분을 찾으려 해도 도통 보이지 않는군요.

이 문제의 핵심인 Verify 부분이 VM에 의해 실행되기 때문이죠.


[+] Analysis

 
그렇다면 Debugger로 확인을 해봅시다. 

<Fig3. VirtualAlloc을 통해 특정 메모리 영역을 할당받는 모습>

 해당 영역을 확인해보면 아시겠지만

애초에 VM 영역에서 시작하네요.

후에 VirtualAlloc 을 호출하고 특정 영역에  RWE 권한을 모두 줍니다.

계속 따라가보면 VirtualAlloc을 한번 더 호출하고 .. [ 같은 크기, 다른 위치에 RWE 권한을 줍니다 ] 

이 할당한 영역에 특정 명령어를 수행하는 것을 확인 할 수 있습니다.

<Fig4. VirtualAlloc에 할당된 영역에서 코드를 실행하고 있는 모습>
 
그 후에 다시 0x40ABBD로 Return해서 특정 루틴을 반복합니다.


<Fig5. Code를 가져와 Decrypt하는 부분>

0x0040A94A를 호출함으로써 실행할 Code를 복호화 하는데

해당 함수를 살펴보면 다음과 같습니다.


<Fig6. Fig5의 Decrypt함수 내부>

 

사실 위 함수가 문제를 푸는데 큰 도움이 되는 건 아닙니다.

CPU가 해석 할 수 있는 일반 기계어로 복호화 하는 과정이지

Key 파일의 내용을 확인하는 과정이 아니기 떄문이죠.

하지만 VM의 동작 방식은 확인을 하고 갑시다.

대략적인 VM의 구현은 다음과 같습니다.

<Fig7. VM의 동작 방식>

실제 문제 파일을 Debugging 해보면 아시겠지만

text 영역과 VM 영역이 번갈아 가며 실행되는 것을 볼 수 있습니다.

Sensitive 한 곳은 VM 처리가 되어있는거죠.



즉 우리가 원하는 것은 ' Codegate.key 파일을 입력 받고 난 후 실패 메세지가 나오기 전까지의 연산 과정 ' 입니다.

이것은 1Byte 씩 검사하여 다르면 바로 실패로 return 하는 과정일수도 있고

전체 내용을 모두 검사한 후 최종적으로 실패를 판단할 수도 있습니다.

물론 전자가 훨씬 까다로워집니다. 실행중에 비교 값을 바꿔야하니까요.

ReadFile에 BP를 걸고 해당 파일을 읽어 온 후에 Buffer에 접근 하는 부분을 잡아보면

최종 Code가 실행되는 곳을 잡을 수 있습니다.

이곳을 보면 Fig4에서 할당한 곳과는 다른 공간임을 알 수 있습니다.

즉, 복호화된 Code가 실행 되는 부분은 2군데이며 

1. 일반 적인 Code가 실행되는 부분

2. Key 파일의 내용을 검사하는 부분


이 되겠습니다.

두 부분을 모두 BP 걸고 확인해보면 아시겠지만 Call , JMP 문을 찾아 볼 수 없다는걸 알 수 있습니다.

Call이나 JMP문이 가고자 하는 곳은 VM에서는 외부 , 즉 원본 프로그램의 text 영역입니다.

이 부분으로 가려면 해당 주소에 맞는 연산이 또 별도로 필요하죠.

문제 풀이엔 별로 중요한 내용이 아닙니다만,

'VM은 이런식으로 구현되고 있다' 라는 것은 염두해두시는게 좋습니다.



[+] Solution



이 다음부턴 딱히 설명 드릴게 없습니다.

Script를 짜거나 손으로 직접 코드를 바꾸시면서 진행을 하셔야 합니다.

운이 나쁘게도 앞서 설명드린 1Byte 씩 검사하고 아닐 경우 실패로 간주하는 타입이군요.

Script로 모으기 짜증 + 1  이 되었습니다.

아무튼 해당 Code를 모으면 다음과 같은 모습입니다.

Pydbg의 HardWare BP를 이용한건데 가변길이라 그런지 

다음 명령어까지 받아오더군요.. 쩝..


<Fig8. Xor, Cmp 부분 중 일부를 긁어온 모습>

이 부분을 예로 들자면

al 로 가져온 값을 xor 0x46 하고 이 값을 cmp 합니다.

xor  [ Data  ] , 0x46

cmp ( [ Data ] ^ 0x 46 )  , 0xf0

즉 Data 의 값은 0x46 과 Xor를 했을 때 0xF0 가 나오는 0xB6 이 되겠네요.

이런 식으로 Codegate.key 값을 하나씩 복원합니다.

Codegate key 값이 총 100 Byte 니 벼..별거 아니군요.

Xor 부분과 cmp 부분을 parsing 매 Byte마다 바꿔주면

다음과 같은 원본 데이터를 얻을 수 있습니다.

<Fig9. 원본 Key File >

이를 codegate.key 에 저장하면 


<Fig10. 해독된 Key File>

이게 정답은 아니겠죠?

100Byte의 16진수가 뭘 의미 할까요.

흠 분포도를 보면 문자를 의미하는건 아닌거 같습니다.

그리고 저 출력 방식도 의심해볼만 하죠

4 * 25 형식입니다.

또, 0x80 0x00 이 유독 눈에 많이 띄는걸 볼 수 있는데..

일단 이를 binary 값으로 바꿔보았습니다.


<Fig11. Binary 값으로 바꾼 모습>



<Fig11-1. !?>
왜 4 * 25 형식으로 출력했는지 알겠네요.

0x80이 binary 값으로 1000 0000 이니까

뒤의 0을 떼버리면 25 * 25 형식의 값이 완성됩니다.

여기에 모서리 부분을 보면 1과 0이 규칙적으로 나열되어있는데

전 이걸 QR 코드라고 판단했고 이를 만들어보면..



QR Code Reader로 읽어보니

I_am_in_C0d3gat3_2011!!

이라는 답이 나오는군요.















Posted by LinkC

블로그 이미지
LinkC

태그목록

Tistory Cumulus Flash tag cloud by BLUEnLIVE requires Flash Player 9 or better.

공지사항

Yesterday32
Today19
Total315,771

달력

 « |  » 2018.08
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

최근에 받은 트랙백

글 보관함


. .