본문 바로가기

리버싱

[리버싱] IDA 사용해보기

IDA란?

Hex-Rays사에서 제작한 디스어셈블러

IDA의 메인 기능은 디스어셈블이지만 이 외에도 여러환경에서의 디버깅과

다양한 아키텍처 디컴파일과 같이 여러가지 기능을 제공

 

 

 

 

Helloworle.exe 파일 정적 분석해보기

우선 메인함수를 찾아보도록 하겠습니다.

메인 함수를 찾는데에는 크게 두가지 방법이 있는데요

첫번째는 프로그램의 시작 지점인 진입점(Entry Point, EP)부터 분석을 시작하여

원하는 함수를 찾을 때까지 탐색하는 것이고,

다른 하나는 대상 함수의 특성이나 프로그램의 여러 외적인 정보를 이용하여 탐색하는 방법입니다.

 

오늘은 후자의 방법을 이용하여 분석해보도록 하겠습니다.

 

Shift+F12를 눌러 String창을 불러옵니다.

 

 

Helloworld 문자열을 찾아줍니다.

저는 Ctrl+F를 이용해 검색해주었습니다.

 

 

찾은 문자열을 더블클릭하여 따라갑니다.

 

 

 

 

이제 이 'Helloworld\n'문자열이 어디에 사용되는지를

상호참조(cross reference, Xref)라는 기능을 통해 알아보도록 하겠습니다.

 

“aHelloWorld”를 클릭하고 상호 참조의 단축키 X를 누르면 문자열 xref 모습와 같이 

xrefs(cross reference) 창이 나타납니다.

이 창에는 해당 변수를 참조하는 모든 주소가 출력됩니다.

 

 

첫번째 항목을 더블클릭하여 따라가면 메인 함수를 찾을 수 있습니다.

 

 

 

이제 메인함수를 찾았으니 메인함수를 분석해 보도록 하겠습니다.

 

 

F5를 눌러서 디컴파일 해줍니다.

인자분석

argc, argv, envp 세가지로 인자를 받는다고 분석하였습니다.

 

동작

1. Sleep 함수를 호출하여 1초 대기

2. qword_14001BE0 에 "Hello, world!\n" 문자열의 주소를 넣음

3. sub_140001060에 "Hello, world!\n"를 인자로 전달하여 호출

4. 0을 반환

 

생각해보기

 qword_14001BE0은 값이 변경될 수 있는 전역변수이기 때문에 data 섹션에 위치함

"Hello, world!\n"문자열은 실행 도중 값이 변경될 일이 없는 상수이기 때문에 rodata 섹션에 위치함

 

sub_140001060 함수를 분석해보도록 하겠습니다.

 

sub_140001060를 디컴파일한 결과입니다.

먼저 va_start 함수를 통해 가변 인자를 처리하는 함수임을 알 수 있습니다.

 __acrt_iob_func 함수는 스트림을 가져올 때 사용되는 함수인데, 인자로 들어가는 1은 stdout 을 의미합니다. 따라서 문자열 인자를 받고 stdout 스트림을 내부적으로 사용하는 가변 함수임을 알 수 있습니다.

이러한 모든 정황을 통해 sub_140001060 함수는 printf 함수로 추정할 수 있습니다.

 

 

 

 

 

 

 

Helloworle.exe 파일 동적 분석해보기

동적분석이란 프로그램을 실행하면서 분석하는 방법입니다.

진입점부터 메인함수까지 코드를 한줄 씩 실행시켜 메인함수에 도달하는 것은 효율적인 분석방법이 아니므로

중단점과 실행이라는 기능을 사용하여 효율적으로 메인함수에 접근해보도록 하겠습니다.

 

 

F2를 눌러 메인함수에 중단점을 설정해줍니다.

 

 

디버깅 단축키인 F9를 사용해 디버깅을 시작하여 main함수까지 실행합니다.

 디버거를 고르라는 창이 나타나면 Local Windows debugger를 선택합니다.

 

이제 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으로 원래 실행 흐름으로 돌아갑니다.

 

Hello, world!가 실행된 것을 볼 수 있습니다

이렇게 F8을 사용하여 한단계씩 관찰하는 방법을 Step Over라고 합니다.