HelloWorld.exe
Reversing/Reverse Engineering

HelloWorld.exe

◾ 실습환경: VisualStudio 2015, IDA pro 7.0


[C] HelloWorld.exe

helloworld.c (Visual Studio)

#include <stdio.h>
int main() {
    puts("hello world!\n");
    return 0;
}

Visual Studio에서 위의 코드를 작성하고 64bit Release 버전으로 컴파일(빌드)했다.


HelloWorld.exe (IDA)

디스어셈블 할 HelloWorld.exe 위치

앞의 단계와 같이 빌드하고나면 "프로젝트 폴더 > x64 > Release에 HelloWorld.exe" 실행파일이 생성된다.

IDA pro 64bit에 해당 실행 파일(HelloWorld.exe)를 넣고 실행하면 아래와 같은 창을 볼 수 있다.

Options > General > Disassembly > Number of Opcode Bytes: 10 를 설정해줘야 Opcode(machine code)를 볼 수 있다.

Graph view
Text view

IDA에서 main 함수의 retn 영역에 breakpoint를 설정하고 Local Windows debugger 로 디버깅[F9]했다.

디버깅

  1. Local Windows debugger
  2. IDA View-RIP : retn 영역에 breakpoint를 설정하고 디버깅을 하면 소스코드 창과 RIP 창이 나타나는데 이 때 RIP 창을 선택하면 어셈블리 코드를 볼 수 있다.
  3. 주소 : 해당 어셈블리 코드의 시작주소가 출력된다.
  4. Opcode(machine code)
  5. 어셈블리어 : 비교적 사람이 이해하기 쉬운 형태인 어셈블리어 코드로 나타난다.

 

디스어셈블 결과 분석

sub rsp, 28h

⇒ rsp = rsp - 0x28 : 함수 내부에서 사용할 스택 공간 0x28byte를 확보한다.

보통 함수에서 지역변수로 선언한 값들을 스택에 저장하고, 이를 위한 공간을 컴파일러가 미리 계산하여 함수 시작 부분(함수 프롤로그)에서 확보해둔다

하지만 현재 코드에서는 지역변수를 사용하는 곳이 전혀 없음에도 0x28만큼 스택을 확보한다. 왜냐하면 컴파일러가 shadow space/home space라는 공간을 미리 확보하고 성능향상을 위한 메모리 사용 최적화가 적용되기 때문이다.

lea rcx, Str ; "hello world!\n"

⇒ rcx = *(Str) : rcx에 Str(주소)의 값을 저장한다. IDA에서는 바로 그 옆에 Str에 저장되어 있는 문자열을 보여준다.

이 때 puts함수의 첫번째 인자로 RCX 레지스터를 넣은 이유는 x64 Windows의 Calling Convention (함수 호출 규약)때문이다.

call cs:__imp_puts

⇒ puts 함수를 호출한다.

xor eax, eax

⇒ eax = eax^eax : eax 레지스터는 함수의 리턴값을 반환받는 역할을 하며, eax의 값을 0으로 만든다.

서로 같은 값으로 xor 연산을 하게 될 경우 결과값은 1이 된다. eax 레지스터의 값을 0으로 만들어서 return 0; 를 할 수 있도록 한다.

이 때 xor이 아니라 "mov eax, 0"으로 써도 되는데, xor을 사용함으로써 명령어의 길이가 짧아지면서 CPU에서 좀 더 빠르게 실행시킬 수 있게된다.

add rsp, 28h

⇒ rsp = rsp + 0x28 : 함수를 시작할 때 확보해뒀던 스택을 정리한다.

ret

⇒ 함수의 실행을 마치고 리턴한다.


[참고]

SMALL

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

패킹과 언패킹  (0) 2021.05.18
어셈블리 코드 변환  (0) 2021.04.06
Instruction (명령어)  (0) 2021.03.30
리버싱을 위한 기초 지식(구조)  (0) 2021.03.28
[dreamhack] 리버싱 엔지니어링이란  (0) 2021.03.27