개요


최근에 들어 포렌식 공부를 하고 있는데 나중에 취업을 생각하면 내가 공부한 것을 증명할 수 있어야 할 것 같다. 비전공자인 나로써는 아무런 정보도 없이 독학하는 편인데 흔히 컴공을 졸업하면 그 동안에 만들었던 프로그램들을 하나의 포트폴리오로 제출할 수가 있겠구나라는 생각이 들면서 이젠 나도 그러한 준비를 해야겠다는 생각이 들어서 무엇이든 간에 직접 만들어보자라는 마음으로 헥사뷰어를 만들고자 다짐했다.

리버싱으로 보안 공부를 시작한 내 입장에선 가장 먼저 접한 툴이 바로 OllyDBG와 HxD인데 디버거를 구현하기엔 프로그래밍 실력이 너무나 허접할 것 같기에 HxD의 기능을 가진 프로그램을 만들어보게 되었다. 그래서 그 과정에서 어떠한 생각을 하고 어떻게 프로그래밍을 했는지 담아보고자 이렇게 문서로 작성하여 본다.


고뇌의 시작


우선 그나마 친한 프로그래밍 언어가 파이썬이기에 파이썬으로 프로그래밍을 하고자 하였다. 먼저 헥사뷰어의 기능을 생각해보았을 때 어떻게 코드가 구성이 될지를 생각해보았다.  f=open(file,'rb'), f.read()...음....답이 없었다. 큰 흐름이 보이지 않았다. 결국 구글링을 통해 다른 사람이 만들어놓은 코드를 한번 직접 보고 실행해보자라는 결정에 이르게 되었다. 그렇게 해서 찾게 된것이 아래의 코드였다.

출처 : http://mwultong.blogspot.com/2007/04/python-hex-viewer-file-dumper.html


우선 소스코드를 한번 읽어본 다음에 바로 실행하였다. 그 결과 아래와 같은데 이를 보자마자 들었던 생각은 "오....!!이거다 이거"라는 생각이였다. 따라서 이를 토대로 한번 직접 코드를 수정해서 '백문이불여일타'라는 어느 프로그래밍 책에서 보았던 말을 실천해보기로 하였다.


고뇌의 연속


우선 전체적인 코드를 읽어봤을 때 내용은 쉬웠다. 하지만 딱 한 곳 이해가 잘 안되는 곳이 있었는데 바로, 위의 코드에서 30번째 라인이다. 한 줄에 비트씩 기록이 되는데 그 길이가 16이 아닐 경우 공백으로 채우는 것이다. 하지만 for i in range( ((16 - bufLen) *3 ) + 1): 에서 곱하기 3이 쫌 불편해보였다. 단순한걸 좋아하는데 곱셈이라니.. 그래서 결국 해당 공백을 채우는 목적만 같으면 되므로 저 부분만 수정을 하고 거의 대체적으로 비슷하게 코드가 완성되었다. (거의 빼껴씀..)

위에서 말했던 부분을 그냥 for i in range(16-len_data) : result+='   '과 같이 그냥 공백을 세칸으로 주었다. 그 외에는 너무 유사(모방은 창조의 어머니)하다. 하지만 직접 코드를 따라 쓰고 실행을 했을 때 결과는 똑같았다. 하지만 문제가 있었다. 헥사뷰어를 통해서 보통 exe파일을 보던 사람임으로 실제 exe파일을 넣고 해보았더니 아래와 같이 되었다.

해당 exe파일의 시그니처를 보고자 했는데 CMD로는 용량이 어느정도 이상으로 넘어가면 더 이상 윗부분을 볼 수가 없는 것이였다..!!!이는 치명적이였다. 물론 리다이렉션을 통해서 메모장으로 넘긴다음에 볼 수도 있지만 기분이 정말 나빳다. 내가 저딴 CMD에게 굴복하는 듯한 치욕감이 들었다.  그래서 다시 고뇌에 잠기게 되었다.


고뇌의 완화


저걸 어찌해야하나 고민하다가 문득 생각 난것이 그렇다면 특정 오프셋을 지정해주면 그에 해당하는 오프셋으로부터 일정부분만 출력하도록 하는 것은 어떨까라는 생각이였다. 정말 기특했다. 자 이제 이를 어떻게 구현할까 생각해보았다. 고려해야할 사항은 다음과 같았다.

- 원래의 기능이 손상되면 안되었다. 원래의 기능은 유지한채 추가적인 기능을 넣을 것

- 사용자가 해당 오프셋을 지정하기 위해서는 인자를 통해 주는 것이 아무래도 편리

이렇게 초점을 맞추고 구상을 해보았다. 하지만 이렇게 하기에는 앞에 코드가 너무 난잡하였다. 그래서 한번 다시 깔끔하게 정리를 해보기로 하였다. 정말 웬만한건 다 제외시켜 버렸다. 그 결과는 아래와 같다.

오...이렇게 다시 작성을 해보니 뭔가 내 자신이 대단해보였다. 원래 참고했던 코드보다도 간결해보여서 뿌듯했다. 이제 이를 토대로 추가적인 기능을 구현해보고자 했다. 

- 인자가 주어지지 않을 경우에는 원래의 기능으로 동작

- 인자가 주어질 경우 새로 추가할 기능으로 동작

이렇게 정리가 되는데, 떠오른 것이 if와 try였다. 근데 왠지 if는 뭔가 느낌이 좋지 않았다. 따라서 try를 통해서 sys.argv[2]가 존재할 경우를 기술하고 만약 sys.argv[2]가 존재하지 않아 프로그램이 except로 진행이 될 때는 원래의 기능이 실행되도록 하였다. 이를 머리로 생각해보았을 때 대체로 아래와 같은 큰 그림이 그려진다.

위의 그림을 가지고 대체적인 코드를 짜보았다. 그 과정에서 많은 에러가 있었지만 결국 완성하긴 했다. 하지만 뭔가 코드가 쓸 때 없이 반복되고 너무 길었다. 매우 비효율적인 것만 같았다. 

결국 이 또한 수정을 하기로 마음 먹었다. 하지만 여기까지하고 학교 강의로 인하여 중단을 해야만했다. 그래서 수업중에 노트에 한번 구상을 해보기로 했다. 일단 기존 코드에 중첩되는 부분을 def를 통하여 함수로 만들어 뺀 후에 필요한 부분만 좀 수정해주면 될 것 같다는 결론에 이르었다.


완성




이렇게 하여 뭔가 깔끔하게 완성이 되었다. 사실 별로 보잘 것 없는 프로그래밍이지만 비전공자인 나에겐 프로그램 하나를 만들 때마다 매우 흥미롭다. 그렇기에 한번 쯤은 이러한 과정을 담아보고 싶었고, 이 후 다시 어떠한 프로그램을 만들어볼까라는 생각이 들기 전까지는 다시 포렌식 공부를 열심히 할 것 같다.


'Programming > Python' 카테고리의 다른 글

Prefetch Parser 제작기  (4) 2015.12.26
Windows Timestamp Convert 64bit  (0) 2015.12.12
Upgrade - Hex_Viewer.py  (0) 2015.11.03
Simple - Hex_View.py  (0) 2015.11.02
Python API  (0) 2015.10.06