2. 목차
• 리버싱이란?
• 리버싱 개념
• 리버싱을 위한 툴
• 올리 디버거
• 헥사 에디터(HxD)
• 리버싱 맛보기
• CodeEngn basic 1
• CodeEngn basic 2
• Lena’s Reversing for Newbies 1
• 주요 개념 소개
• PE File Format
• 실행압축
• DLL/Code injection
• API Hooking
• 앞으로 할 것
• 과제
• 실습 보고서 쓰기
• 부록
• 참고 사이트
8. 리버싱을 위한 기초적인 툴
• Ollydbg
• 디버거 : 다른 대상 프로그램을 테스트하고 디버그 하는 데 쓰이는 프로그램
• EXE에 적혀 있는 명령어(숫자로 되어있음)를 disassemble 해준다.
• 숫자로 적혀 있는 명령어들을 어셈블리어로 해석하여 표시
• 무료 프로그램
• 다운 링크(환경설정 되어있는 것)
• http://ladybug.tistory.com/entry/%EC%98%AC%EB%A6%AC%EB%94%94%EB%B2%84%EA%B1%B0Ollydbg-%EC%84%A4%EC%B9%98-%EB%B0%8F-
%EC%82%AC%EC%9A%A9%EB%B2%95
• Hex Editor
• Binary파일을 편집하는 편집기
• 메모장과 비슷하다
• 다운 링크(HxD)
• https://mh-nexus.de/en/downloads.php?product=HxD
14. Run한 뒤 다시 시작하고 싶다면
아이콘을 누르거나 단축키 Ctrl + F2로
프로그램을 Restart
Ollydbg – 아이콘/단축키
아이콘을 누르거나
단축키 F9로
프로그램을 Run
일시정지
단축키 F12
디버깅중인
프로그램 끄기
단축키로 Alt + F2
15. 함수를 Call했을 시
함수의 코드까지 들어 감
한 번에 한 줄 실행
단축키는 F7
함수를 Call했을 시
함수의 코드까지 들어 감
계속 한 줄 씩 실행
단축키는 Ctrl + F11
Trace into
함수를 Call했을 시
함수의 코드는 들어가지 않음
계속 한 줄 씩 실행
단축키는 Ctrl + F12
Trace over
함수를 Call했을 시
함수의 코드는 들어가지 않음
한 번에 한 줄 실행
단축키는 F8
Ollydbg – 아이콘/단축키
17. Ollydbg
• 이외에도 여러 기능이 있음
• 플러그인을 설치하는 등 기능 확장 가능
• 기초 단축키
• F2 : Breakpoint
• F7 : Step into (Entering function) - VS의 F11과 유사
• F8 : Step over (Executing function calls at once) - VS의 F10과 유사
• Ctrl + F7 / Ctrl + F8 : 자동으로 진행됨 (Animate into/Animate over) -> 어느 코드를 실행하는지 볼 수 있음
• Ctrl + F11 / Ctrl + F12 : 자동으로 진행됨 (Trace into/Trace over) -> 어느 코드를 실행하는지는 보여주지 않음
• F9 : Run
• Ctrl + F2 : Restart
• F12 또는 ESC : 일시정지
18. 헥사 에디터 - HxD
• 메모장과 유사하다.
• 오른쪽에 아스키 문자로 쓸 수 있고,
왼쪽에서 16진수 숫자로 쓸 수도 있다.
• 2자리 16진수 수는 1 바이트를 의미한다.
끊어진 숫자 각각이 1바이트이다.
23. Reversing example – CodeEngn basic 1
이 줄을 실행하니
원하지 않는 창이 뜬다.
이 명령어는 어느 경로로
실행하게 되는가?
다시 차근차근 실행해보자.
24. Reversing example – CodeEngn basic 1
위에서 점프하지 않으면
실패 문장을 Push하고
Message Box를 띄운다.
점프를 하면
실패 문장을 띄우지
않을 것 같다.
25. Reversing example – CodeEngn basic 1
JE일 때 점프하지 않았으니
JNE로 바꿔 보았다
(JNE로 바꾸니 JNZ로 바뀌었다.
이 둘은 같은 기계어를
사용하므로 같은 의미이다.)
26. Reversing example – CodeEngn basic 1
성공!
하지만 점프만을 이용한 풀이는 좋지 않다.
리버싱을 어렵게 하기 위해서 점프 코드를 많이 넣었다면 그 코드를 전부 바꾸어야 한다.
->조금 더 근본적으로 문제를 해결할 필요가 있다.
27. Reversing example – CodeEngn basic 1
JE일 때 점프하지
않은 것이 문제였다.
무엇을 비교한 것인가?
그 값은 어디서 나왔나?
28. Reversing example – CodeEngn basic 1
JE위에 CMP가 있다. 점프를 할지 안 할지 결정하는 레지스터가 EAX와 ESI라는 것을 알았다.
EAX와 ESI에 들어있는 값의 근원을 찾아보자.
29. Reversing example – CodeEngn basic 1
GetDriveTypeA 함수를 실행하면 EAX가 3으로 설정된다.
ESI는 처음부터 0이였다.
30. Reversing example – CodeEngn basic 1
GetDriveTypeA 함수와 CMP코드 사이의 코드이다.
ESI를 총 3만큼 더하고, EAX를 총 2만큼 뺀다.
중간의 점프는 바로 아래 있는 코드로 점프한다.
(리버서를 헷갈리게 만드는 쓰레기 코드이다.)
그러면 EAX값을 설정해주는 GetDriveTypeA 함수를 살펴보자.
코드를 잘 보니 GetDriveTypeA함수는 Kernel(OS)과 관련이 있어 보인다.
31. Reversing example – CodeEngn basic 1
GetDriveTypeA함수가 Kernel(OS)과 관련이 있어 보여 인터넷 검색을
했다.
그러자 Return value에 대한 정보를 찾을 수 있었다.
CDROM이면 return값은 5가 되어야 한다.
GetDriveTypeA 함수를 호출하기 전에 인자로 “C:”라는 string을
넣어주고 있다.
C드라이브의 타입으로 3을 반환하고 있다. 그래서 EAX가 3으로
설정되었다.
여러가지 방법이 가능하겠다.
1. 점프문 수정/삽입
2. 함수 인자를 CDROM의 경로로 수정
3. 함수를 나온 뒤 eax가 5로 설정되도록 수정
4. 값에 상관 없이 ESI == EAX가 되도록 수정
5. … 무엇이든 마음대로
32. Reversing example – CodeEngn basic 1
Cmp하기 전에 ESI에 EAX의 값을 넣도록 코드를 수정했다.
코드를 수정할 때, 파일 크기가 정해져 있다는 점에 주의해야 한다.
코드의 크기가 수정하는 원본 코드보다 크면 다음 코드를 침범하게 된다.
다음 코드를 침범하면 코드가 깨지게 되어 원치 않는 행동을 할 수 있다.
35. Reversing example – CodeEngn basic 2
• Ollydbg로 열리지 않는다. 문제에서 말한 것처럼, 실행파일이 손상되어 실행이 안 된다.
실행이 안 되니
바이너리를 뜯어보자.
36. Reversing example – CodeEngn basic 2
Hex Editor인 HxD로 열어보았다.
앞부분은 EXE를 실행하기 위한 헤더이다. 이 부분이
손상되어 파일이 실행되지 않는 것이다.
하지만 이번 문제의 초점은 이게 아니다.
파일에는 여러 정보가 들어있다. 프로그램에서 사용하는
문자열은 데이터 영역에 저장되어 있다.
파일에 무엇이 들어있는지 한 번 훑어보자.
37. Reversing example – CodeEngn basic 2
딱 봐도 수상해 보이는 문장이 있다.
맞다. 떡 하니 써 있는 JK3FJZh가 비밀번호다.
38. • 다운로드 링크
• https://tuts4you.com/download.php?view.122
Reversing example – Lena’s Reversing for Newbies 1
39. Reversing example – Lena’s Reversing for Newbies 1
실행하면 뜨는 창이다.
라이선스를 획득하여 이 창이 뜨지 않도록 만들고 싶다.
40. Reversing example – Lena’s Reversing for Newbies 1
올리 디버거로 실행했다.
문자열 찾기로 에러메시지를 출력하는 루틴을 찾았다.
에러 메시지를 출력하고 싶지 않다. 어딘가 에러메시지를 내지 않게 하는 분기문이 있을 것 같다.
41. Reversing example – Lena’s Reversing for Newbies 1
에러메시지 바로 위에는 점프로 분기하여 에러메시지를 실행하지 않고 지나가는 코드가 있다.
점프하여 도달한 위치에서는 ReadFile 함수를 위한 인자를 push하고 호출한다.
어디서 분기하는 지 알아냈으니, 무엇으로 플래그를 세팅하는지 알아낼 차례다.
42. Reversing example – Lena’s Reversing for Newbies 1
점프의 바로 위에서 EAX와 -1을 비교한다. EAX와 -1이 같지 않다면 점프하여 에러메시지 출력을 생략한다.
Cmp 바로 위에서 CreateFileA 함수가 호출된다. 올리 디버거로 이 함수를 실행해 보면 EAX의 값이 변한다는 사실을 알 수 있다.
따라서 EAX의 값은 CreateFileA 함수의 반환 값이다.
43. Reversing example – Lena’s Reversing for Newbies 1
CreateFileA 함수의 인자로 Mode는 OPEN_EXISTING이다. 파일이 있다면 연다는 의미이다. 파일이 없다면 -1을 반환한다.
EAX 를 -1과 비교하고 분기하는 코드는 파일 열기를 실패했을 시 에러를 처리하는 코드였다.
그렇다면 “Keyfile.dat”라는 이름의 파일이 EXE가 있는 폴더에 있다면 이 에러 메시지를 띄우지 않겠다.
(경로가 이름 뿐이기 때문에 같은 폴더에 있어야 한다.)
CreateFile 함수가 궁금하다면 부록의 참고 사이트를 보자.
44. Reversing example – Lena’s Reversing for Newbies 1
동명의 파일을 만들어 다시 실행해 보았다.
이전과는 다른 에러 메시지가 나온다. 일단 첫 번째 에러는 넘겼다.
45. Reversing example – Lena’s Reversing for Newbies 1
같은 방식으로 에러 메시지를 내는 코드를 찾았다.
에러 메시지로 분기하는 점프문도 찾았다.
위의 JNZ에서 점프하지 않으면 에러 메시지를
띄우는 코드로 무조건 jmp 한다.
즉, 에러 메시지를 띄우지 않기 위해서는 JNZ에서
점프해야 한다.
그 위에는 ReadFile 함수와 TEST EAX, EAX라는
코드가 있다.
ReadFile 함수가 궁금하다면 부록 참고
46. Reversing example – Lena’s Reversing for Newbies 1
• test 명령어는 주어진 인자를 &연산 하는 명령어이다. 이 때, &된 계산 결과는
저장하지 않고 버린다. &연산을 하며 flag를 세팅한다.
• test 명령어는 보통 인자로 같은 레지스터를 넣어 값이 0인지 아닌지 판단할 때
많이 쓰인다. (&연산을 하여 0이 나오는 경우는 두 인자 모두가 0인 경우
뿐이다. )
• Ex ) test eax, eax
• eax가 0이면 zf 플래그가 1로 설정된다.
• 0이 아니면 0으로 설정된다.
• 부록 참고
47. Reversing example – Lena’s Reversing for Newbies 1
• ReadFile은 파일을 읽는다. 읽기에 성공한다면
TRUE(0보다 큰 값), 실패한다면 FALSE를
return한다.
• Test eax, eax를 통해 0을 체크한다. 0이면
에러를 출력한다.
• 즉 읽기에 실패하면 에러메시지를 출력한다.
• ->이 루틴은 일단 파일이 있으면 내용이 있든
없든 잘 통과한다.
48. Reversing example – Lena’s Reversing for Newbies 1
위의 에러문을 통과하고 나서의 루틴을
따라가보니 에러 메시지를 내는 코드를 찾았다.
에러 메시지로 분기하는 점프문도 찾았다.
바로 위에는 cmp가 있다.
402173 주소에 저장되어 있는 값과
0x10(디스어셈블리 창에 적힌 수는
16진수이다.)를 비교하고, 0x10보다 작을 경우
에러메시지를 출력한다.
->402173 위치에 저장되는 변수를 추적해 보자
Conditional jump 조건은 부록에 있다.
49. Reversing example – Lena’s Reversing for Newbies 1
402173 주소에 저장되어 있는 값이 무엇인지 알아보았다.
조금 이전에 지나간 코드를 보면, ReadFile함수에 인자로
402173를 넣는 것을 볼 수 있다. 주석을 보면
pByteRead이다.
즉 402173는 파일에서 실제로 읽어온 바이트 수가
저장되는 주소이다.
->파일에 0x10(십진수로 16)글자보다 많이 쓰고
실행했더니 이 에러메시지 루틴도 넘어갔다.
50. Reversing example – Lena’s Reversing for Newbies 1
하지만 아직도 에러메시지를 출력한다.
에러 메시지로 가는 코드를 찾았다. 바로
위에서 cmp esi, 8한다. ESI값이 8보다
같거나 커야 에러메시지를 내지 않는다.
이 루틴은 주석에 자세히 적었다.
Equal or larger
51. Reversing example – Lena’s Reversing for Newbies 1
파일에 ‘G’를 8개 이상 쓰고, 파일 크기는
0x10보다 크게 하면 성공 메시지가 뜬다.
성공!
52. 주요 개념 소개
• PE File Format
• 실행압축
• DLL/Code injection
• API Hooking
• 앞으로 할 것
53. PE File Format
• PE란?
• Portable Executable File Format의 약자
• 파일이(File) 다른 곳에 옮겨져도(Portable) 실행이 가능하도록(Executable) 만들어 놓은 구성 방식(Format)
• 다른 OS와의 이식성을 높이려는 의도이지만 실제로는 Windows 계열에서만 사용
• UNIX는 또 다른 File Format을 이용
• 32비트 형태의 실행파일은 PE 또는 PE32, 64비트는 PE+ 또는 PE32+라고 함
• PE 헤더 : 실행 파일을 실행하기 위한 각종 정보들
54. PE File Format
종류 주요 확장자
실행계열 EXE, SCR
라이브러리 계열 DLL, OCX, CPL, DRV
드라이버 계열 SYS, VXD
오브젝트 파일 계열 OBJ
55. PE header
• 코드가 실행되기 전 PE 헤더의 정보를 읽음
• PE헤더 내용에 따라 메모리/리소스 할당
• PE가 잘못되면 실행하는 데 필요한 정보를 불러오지 못 함
• 로딩 단계부터 실패
• 파일을 수정하기 위해서는 수정된 상황이 반영된 PE헤더로 바꾸어야 한다.
• 예를 들어, 더 큰 데이터 영역을 사용하도록 바꾸었다면 PE 헤더에 바뀐 데이터 영역 사이즈를 적
어주어야 한다.
56. 실행 압축
• 실행(PE) 파일을 대상으로 파일 내부에 압축 해제 코드를 포함
• 실행되는 순간에 메모리에서 압축을 해제시킨 후 실행시키는 기술
• 실행 압축된 파일 역시 PE파일
• 내부에 원본 PE파일과 decoding 루틴이 존재
• 패킹(Packing)이라고도 함
• 패커 : 실행 파일 압축기
• Anti-Reversing 기술에 특화된 패커는 “프로텍터”라 함
57. 실행 압축
항목 일반 압축 실행 압축
대상 파일 모든 파일 PE 파일(exe, dll, sys 등)
압축 결과물 압축(zip, rar 등) 파일 PE 파일(exe, dll, sys 등)
압축해제 방식 전용 압축해제 프로그램 내부의 decoding 루틴
파일 실행 여부 자체 실행 불가 자체 실행 가능
장점 모든 파일에 대해
높은 압축률로 압축 가능
별도의 해제 프로그램 없이
바로 실행 가능
단점 전용 압축해제 프로그램이 없으면
사용할 수 없음
실행때마다 decoding 루틴이 호출되기 때
문에 실행시간이 미세하게 느려 짐
58. 실행 압축
• 패커
• 사용 목적
• 파일 크기를 줄이기 위해
• 내부 코드와 리소스를 감추기 위해
• 프로텍터
• 사용 목적
• 크래킹 방지
• 코드 및 리소스 보호
• 오히려 파일 크기가 커질 수도 있다
59. DLL/Code injection
• DLL : Dynamic-Link Library
• MS에서 구현된 동적 라이브러리
• DLL injection
• 다른 프로세스(실행 중인 프로그램)에 특정 DLL 파일을 강제로 넣어 원하는 동작을 하게 만든다
• Code injection
• 다른 프로세스(실행 중인 프로그램)에 임의의 코드를 강제로 넣어 원하는 동작을 하게 만든다
• 위와 같은 기법을 이용하는 방법과, 위의 기법이 적용된 프로그램을 리버싱하는 방
법을 알아본다.
60. API hooking
• Hooking
• 정보 가로채기, 실행 흐름 변경, 원래와는 다른 기능 제공
• API Hooking
• Win32 API 호출을 중간에서 가로채서 제어권을 얻어내는 것
• 예) 다른 프로그램이 printf를 호출하면 printf가 아닌 임의의 코드가 실행되게 함
• 위와 같은 기법을 이용하는 방법과, 위의 기법이 적용된 프로그램을 리버싱하는 방
법을 알아본다.
61. 앞으로 할 것
• 리버싱 기초
• 고급언어를 컴파일하여 만들어진 어셈블리어 패턴에 익숙해진다.
• Executable 파일이 어떤 형식으로 써 있는지 알아본다.
• 패킹이 적용된 파일을 분석해본다.
• 리버싱 심화
• DLL/Code injection, API hooking 기법을 실습한다.
• 64비트 프로그램을 리버싱 한다.
• 커널(OS) 부분을 리버싱 한다.
• 안티 리버싱 기법을 공부하고 우회한다.
63. 실습 보고서 쓰기
• CodeEngn Basic 1번과 2번, Lena’s reversing for newbies 1번을 푼다.
• 푼 방법을 간단히 설명하는 문서를 만들어주세요! 중요한 부분 스크린샷 찍어 넣을 것
• 구글에 치면 답과 풀이과정이 나온다. 잘 안 풀릴 때는 참고해도 좋지만 반드시 직접 따라해 보아야 한다.
• 문제는 이 곳에서 받을 수 있다.
• CodeEngn
• http://codeengn.com/challenges/
• 심심하면 사이트에 답을 제출해보자.
• Lena’s reversing for newbies
• https://tuts4you.com/download.php?list.17
65. 참고 사이트
• CreateFileA
• https://www.joinc.co.kr/w/man/4200/CreateFile
• http://irontooth.tistory.com/75
• ReadFile
• https://msdn.microsoft.com/ko-kr/library/windows/desktop/aa365467(v=vs.85).aspx
• https://www.joinc.co.kr/w/man/4200/ReadFile
• Conditional Jump 조건 목록
• http://unixwiz.net/techtips/x86-jumps.html
• Test 명령어
• https://ko.wikipedia.org/wiki/TEST_(x86_%EB%AA%85%EB%A0%B9%EC%96%B4)