DreamHack Reversing RoadMap

챠챠비둘기·2023년 4월 5일
0

리버싱😎☠️

목록 보기
6/7

HelloWorld

로드맵에 따라 리버싱 실습을 해 보도록 하겠다. 계속 이론만 공부하다 보면 중간에 늘어지고 집중도 제대로 안 될테니 이렇게 실습하고 정리하면 좀 더 리버싱을 자세히 익힐 수 있도록 생각한다...😊
일단 파일을 다운받는다.(HelloWorld.exe)

파일의 구조
1초를 대기하고 Hello, world!를 출력하는 파일이다.

정적 분석

신뢰할 수 없는 프로그램 -> 악성 프로그램일 가능성을 대비하여 정적 분석을 먼저 시도해보는 것이 바람직하다.
ida를 실행하고, 위에서 다운받은 파일을 넣어보자.

들어가기 앞서
정적 분석은 주로 main 함수를 찾고, 이를 분석하며 시작된다.
바이너리에서 어떤 함수를 찾는 방법은 크게 두 가지가 있다. 하나는 프로그램의 시작 지점인 진입점(Entry Point, EP)부터 분석을 시작하여 원하는 함수를 찾을 때까지 탐색하는 것이고, 다른 하나는 대상 함수의 특성이나 프로그램의 여러 외적인 정보를 이용하여 탐색하는 방법이다.


그냥 ok 누르면 된다. 웬만하면 ida가 알아서 잘 분석해서 해 준다.

(참고로, 나는 text view로 보는게 더 편해서 text view로 항상 설정해 놓는다. graph가 더 보기 편하다면 마우스 우클릭으로 변경할 수 있다.)

문자열 검색

프로그램을 정적 분석할 때, 많이 사용되는 정보 중 하나가 프로그램에 포함된 문자열이다.(매우 중요!!)
프로그래머는 디버깅 메세지를 출력하거나, 로그 파일을 생성하는 등의 목적으로 여러 문자열을 프로그램에 포함시키는데, 이 문자열들은 특성상 유용한 정보를 제공할 때가 많다. 예를 들어 프로그램의 로그와 관련된 문자열은 로그를 생성하는 함수의 이름과 인자가 적혀 있기도 한다. 이 문자열이 어느 함수에서 사용되는지 알 수 있다면, 원하는 함수를 쉽게 찾을 수도 있고, 함수의 이름과 인자를 통해 기능을 유추할 수도 있다.
IDA는 바이너리에 포함된 문자열을 쉽게 찾을 수 있도록 “문자열 탐색” 기능을 제공하고 있다.

  1. 먼저 Shift + F12를 누르기.
    다음과 같이 바이너리에 포함된 문자열이 열거된 Strings 창이 나타난다.
  1. 많은 문자열 중에 'Hello, world!'라는 문자열이 보인다. 컴파일 과정에서 다양한 문자열이 바이너리에 추가되는데, 이 문자열은 그런 종류가 아니라 프로그래머가 넣었을 것으로 추측할 수 있다.

    Ctrl +f 로 더 빠르게 찾을 수 있다.

  2. 이 문자열을 더블 클릭하여 따라가 보자.

상호 참조

정적 분석을 하다가, 어떤 수상한 값이나 함수를 찾았다면, 우리는 이를 참조하는 함수(동일한 값을 가리키는 함수)도 분석할 수 있다. 많은 정적 분석 도구들은 상호 참조(Cross Reference, XRef)라는 기능을 통해 이를 지원한다. 앞에서 찾은 “Hello, world!\n”라는 수상한 문자열이 어디서 사용되는지 찾아보자.

“aHelloWorld”를 클릭하고 상호 참조의 단축키 X를 누르면 xrefs(cross reference) 창이 뜬다. 이 창에는 해당 변수를 참조하는 모든 주소가 출력된다.

첫 번째 항목을 더블 클릭하여 이를 따라가면 main함수를 찾을 수 있다.

(F5를 누르면 디컴파일 된 결과값을 볼 수 있다.)

디컴파일 결과값.
Ctrl + F5를 누르면 전체 디컴파일 가능하다.

🤷‍♂️ main 함수를 찾는 일반적인 방법
일반적으로 main함수는 C계열 언어에서 프로그래머가 작성한 코드 중 가장 먼저 실행되는 함수이다. 그래서 리버싱을 처음 공부할 때는 프로그램에서 가장 먼저 실행되는 코드가 main함수의 코드라고 생각하기 쉽다. 하지만 운영체제는 바이너리를 실행할 때, 바이너리에 명시된 진입점부터 프로그램을 실행한다. 진입점이 main함수인게 불가능한 것은 아니지만, 일반적으로는 그렇지 않다.
진입점과 main함수의 사이를 채우는 것은 컴파일러의 몫다. 대부분의 컴파일러는 둘 사이에 여러 함수를 삽입하여 바이너리가 실행될 환경을 먼저 구성하고, 그 뒤에 main함수가 호출되게 한다. 잠시 편의상 진입점에 위치한 함수를 start함수라고 하겠다. 만약, main함수를 쉽게 찾고 싶다면 컴파일러가 작성하는 start함수블 수없이 분석해봐야 한다. start함수를 여러 번 분석하다 보면 나중에는 start함수를 보고 main함수가 어디서 호출될지를 쉽게 찾아낼 수 있다.


한번 분석해보자!
IDA로 디컴파일 한 결과, 메인함수는 argc, argv, envp 매개변수로 3개의 인자를 받는다.
그 후, Sleep함수를 호출하여 1초 대기한다.

qword_14001DBE0에 “Hello, world!\n” 문자열의 주소를 넣는다.

sub_140001060에 “Hello, world!\n” 를 인자로 전달하여 호출한다. (대충 함수로 추정된다)

0을 반환하고 끝

간단하게 Dreamhack 퀴즈를 풀어보았다.


rodata = read only data, 즉 읽기 전용 데이터라는 의미이다.

동적 분석

프로그램을 실행하면서 분석하는 방법

중단점 설정(Break Point, F2) 및 실행(Run, F9)

특정 주소에 중단점을 설정(주소 클릭 후 f2누르기)하고, 디버깅을 시작하면 프로그램은 중단점까지 멈추지 않고 실행한다(디버깅 시작 단축키: F9)
IDA에서는 디버거를 고를 수도 있을 텐데, 왠만하면 Local Windows debugger를 선택하는게 좋다.

한단계 실행(Step over, F8)

관심이 있는 부분의 코드를 정밀하게 분석하기 위해 사용하는 기능
IDA로 실행해보고자 하였으나, 내가 가지고 있는 IDA는 사실 불법복제본이라서 뭐가 빠진건지 디버깅이 되지 않았다...F8의 경우 ollydebugger나 win64에서도 동일하게 쓰이는 기능이므로 여기서 실행화면을 보도록 하겠다.😊😅

  1. sub rsp, 38을 통해 main 함수가 사용할 스택 영역을 확보한다.

  2. rsp+0x20에 4 바이트 값인 0x000003e8을 저장한다.

  3. rsp+0x20에 저장된 값을 ecx에 옮긴다. 이는 함수의 첫 번째 인자를 설정하는 것이다.

  4. Sleep함수를 호출한다. ecx가 0x3e8이므로, Sleep(1000)이 실행되어 1초간 실행이 멈춘다.

  5. “Hello, world!\n” 문자열의 주소를 rax에 옮긴다.

  6. 아래의 메모리 덤프 창을 이용하여 0x14001a140의 데이터를 보면 실제로 해당 문자열이 저장되어 있음을 확인할 수 있다.

  7. rax의 값을 data세그먼트의 주소인 0x14001dbe0에 저장한다.

  8. 0x14001dbe0에 저장된 값을 rcx에 옮긴다. 이는 다음 호출할 함수의 첫번째 인자로 사용될 것이다.

  9. 0x140001060함수를 호출한다. 앞에서 한 정적 분석을 통해 이 함수를 printf함수라고 추측해볼 수 있다.

  10. 프로그램을 확인하면, Hello, world!가 출력되어 있다. 정적 분석을 할 때는 함수의 기능을 추측하기 어려웠지만, 동적 분석으로는 프로그램 실행을 통해 문자열을 출력하는 함수라는 사실을 쉽게 알 수 있다.

  11. 시작할 때 확장한 스택 영역을 add rsp, 38을 통해 다시 축소하고, ret으로 원래 실행 흐름으로 돌아간다.


retn을 BP로 설정하고 실행하면, 위의 Hello world 창이 뜬 것을 확인할 수 있다.

함수 내부로 진입하기(Step Into, F7)

앞의 Step Over는 함수의 내부로 진입하지 않는다. 하지만 여러 함수를 분석하다 보면 그 함수가 호출하는 다른 함수까지 정밀하게 분석해야 할 때가 있다. 그런 상황을 대비하여 Step Into(F7)라는 편리한 기능이 존재한다. F7을 통해 함수 내부로 진입하여 호출되는 다른 함수를 분석할 수 있다.

  1. printf를 호출하는 0x14000110b에 중단점을 설정한 후, 디버깅을 시작하여, printf 함수에 도달한다.

  2. F7 단축키를 통해 함수 내부로 들어간다. 함수 내부로 RIP가 이동한 것을 확인할 수 있다.

Appendix, 실행 중인 프로세스 조작하기

IDA를 이용할 경우, 실행중인 프로세스 메모리를 조작할 수 있다.
아쉽게도 x64 debugger에는 이러한 기능을 아직까지 발견하지 못했다. 추후에 발견하게 되면 추가하겠슴돠.

profile
개발 + 보안

0개의 댓글