Reverse Engineering

Exercise: Helloworld

박연준 2023. 7. 2. 15:27
  • 이번 코스에서는 간단한 예제인 HelloWorld.exe을 분석해보는 실습을 할 것이다.
  • 예제는 1초를 대기하고 Hello, world!를 출력하는 프로그램이다.
/*
    File: hello-world.cpp
    Build opts:
      - /MT -> Library Static Linking
      - /DYNAMICBASE:NO -> Disable ASLR
      - /od -> Disable Optimization
*/
#include <Windows.h>
#include <stdio.h>
char* str;
int main() {
  int delay = 1000;
  Sleep(delay);  // 1000ms(1초)를 대기합니다.
  str = (char*)"Hello, world!\\n";
  printf(str);
  return 0;
}

 

정적 분석

  • 신뢰할 수 없는 프로그램을 분석할 때는 악성 프로그램일 가능성을 대비하여 정적 분석을 먼저 시도해보는 것이 바람직하다.
  • IDA를 실행하고, HelloWorld.exe를 끌어넣는다.

main 함수 찾기

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

문자열 검색

  • 프로그램을 정적 분석할 때, 많이 사용되는 정보 중 하나가 프로그램에 포함된 문자열이다.
  • 프로그래머는 디버깅 메세지를 출력하거나 로그 파일을 생성하는 등의 목적으로 여러 문자열을 프로그램에 포함시키는데, 이 문자열들은 유용한 정보를 제공할 때가 많다.
    1. Shift + F12를 눌러 Strings 창을 연다.
    2. 많은 문자열 중 Hello, world! 라는 문자열이 보인다.
    3. 문자열을 더블 클릭하여 따라간다.

 

상호 참조

  • 정적 분석을 하다가 ,어떤 수상한 값이나 함수를 찾았다면, 이를 참조하는 함수를 분석하고 싶을 것이다.
  • 많은 정적 분석 도구들은 상호 참조(XRef)라는 기능을 통해 이를 지원한다.
  • Hello world! 라는 수상한 문자열이 어디서 사용되는지 추적해 볼 것이다.
  • aHelloWorld를 클릭하고 상호 참조의 단축키 X를 누르면 xrefs 창에 나타난다. 이 창에는 해당 변수를 참조하는 모든 주소가 출력된다.

 

 

main 함수 분석

  • main 함수를 찾아 F5를 눌러 디컴파일한다.
    • 인자 분석
      • IDA는 argc, argv, envp로 3개의 인자를 받는다고 해석했다.
    • 동작
      1. Sleep 함수를 호출하여 1초 대기한다.
      2. qword_14001DBE0에 “Hello, world!\n” 문자열의 주소를 넣는다.
      3. sub_140001060에 “Hello, world!\n” 를 인자로 전달하여 호출한다.
      4. 0을 반환다.

sub_140001060 함수 분석

  • 먼저 va_start 함수를 통해 가변 인자를 처리하는 함수임을 알 수 있다.
  • __acrt_iob_func 함수는 스트림을 가져올 때 사용되는 함수인데, 인자로 들어가는 1은 stdout 을 의미한다.
  • 따라서 문자열 인자를 받고 stdout 스트림을 내부적으로 사용하는 가변 함수임을 알 수 있다.
  • 이러한 모든 정황을 통해 sub_140001060 함수는 printf 함수로 추정할 수 있다.

 

 

 

동적 분석

main 함수 진입

  • 이번에는 앞에서 분석한 내용을 동적 분석으로 살펴보며, 정적 분석이 정확했는지, 앞에서 배운 함수의 호출 규약이 어떻게 구현되는지 분석해 볼 것이다.

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

  • 이 예제에서는 main 함수가 유일한 관심 대상이다.
    1. main 함수에 F2를 눌러 중단점을 설정한다.
    2. F9로 디버깅을 시작하여 main 함수까지 실행한다. 디버깅을 고르라는 창이 나타나면 Local Windows debugger를 선택한다.
    3. 동적 분석을 위한 준비가 끝났다.

한 단계 실행(Step Over, F8)

  • 앞서 살펴본 중단점과 실행이 필요한 실행 과정을 생략하는 기능이라면, Step Over은 관심있는 부분의 코드를 정밀하게 분석하기 위해 사용하는 기능이다. F8을 눌러 동작을 분석해본다.
    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으로 원래 실행 흐름으로 돌아다.

 

 

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

  • Step Over는 함수의 내부로 진입하지 않는다.
  • Step Into는 그 함수가 호출하는 다른 함수까지 정밀하게 분석할 수 있다.
  • 이번엔 printf() 에 중단점을 설정하고, 해당 함수의 내부로 진입할 것이다.
    1. 디버깅을 중단**(Ctrl-F2)**하고, printf를 호출하는 0x14000110b에 중단점을 설정한다.

          2. 디버깅을 다시 시작하고, Continue(F9)를 클릭하여, printf 함수에 도달한다.

 

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

 

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

  • IDA를 이용하면 실행중인 프로세스의 메모리를 조작할 수 있다.
  • 기존 코드에서 Sleep(delpay=1000)을 호출하여 1초 동안 프로세스를 정지시켰다. 이번에는 delay의 값을 1000000으로 조작하여 1000초 동안 프로세스를 정지시킬 것이다.
    1. delay를 Sleep함수의 인자로 전달하는 부분에 중단점을 설정하고, 프로세스를 재시작한다.

        2. 스택을 보면 rsp+0x20에 delay의 값인 0x3e8이 저장되어 있습니다.

      3. 해당 값을 클릭하고, F2를 누른 뒤 0xf4240(=1000000)을 입력한다. 그리고 다시 F2를 눌러서 값을 저장합니다. delay의 값이 변경된 것을 확인할 수 있다.

       4. 이제 F9를 눌러서 Sleep함수를 호출한다. 아까와 달리 한참을 기다려도 프로세스가 재개되지 않는다. 1000초는 대략 20분이므로, 20분 정도를 대기해야 프로세스가 재개된다.

 

'Reverse Engineering' 카테고리의 다른 글

Tools: IDA  (0) 2023.07.02
x86 Assembly: Essential Part(2)  (0) 2023.07.02
x86 Assembly: Essential Part(1)  (0) 2023.07.02
Background: Windows Memory Layout  (0) 2023.07.02
Background: Computer Architecture  (0) 2023.07.02