정적 분석

IDA로 파일 열기

신뢰할 수 없는 프로그램을 분석할 때는 악성 프로그램일 가능성을 대비하여 정적 분석을 먼저 시도해보는 것이 바람직합니다.

 

main 함수 찾기

정적 분석은 주로 main 함수를 찾고, 이를 분석하며 시작됩니다. 이 예제에서는 IDA가 이를 자동으로 찾아주지만, IDA와 익숙해질 겸, IDA의 도움을 받지 않고 main함수를 찾아보겠습니다.

바이너리에서 어떤 함수를 찾는 방법은 두 가지가 있다.

  1. 프로그램 시작 지점인 Entry Point 부터 분석을 시작하여 원하는 함수를 찾을 때까지 탐색
  2. 대상 함수의 특성이나 프로그램의 여러 외적인 정보를 이용하여 탐색

첫 번째 방법은 프로그램 규모가 조금만 커져도 시간이 오래 걸리는 방법이다. 따라서 2번이 바람직하다.

 

문자열 검색

정적 분석을 할 떄, 많이 사용되는 정보 중 하나가 프로그램에 포함된 문자열입니다.

  1. Shift + F12를 누릅니다. 바이너리에 포함된 문자열이 열거된 string 창이 나타납니다.
  2. 문자열 중에 찾고 싶은 문자열을 찾아 더블 클릭하여 따라갑니다.

상호 참조

정적 분석을 하다가, 어떤 수상한 값이나 함수를 찾았다면, 우리는 이를 참조하는 함수를 분석하고 싶을 것입니다. 앞에서 찾은 “Hello world\n”라는 수상한 문자열이 어디서 사용되는지 추적해봅시다.

“aHelloWorld”를 클릭하고 상호 참조의 단축키 X를 누르면 Figure 2와 같이 xrefs(cross reference) 창이 나타납니다. 이 창에는 해당 변수를 참조하는 모든 주소가 출력됩니다.

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

 

main 함수 분석

이제 main 함수를 찾았으므로, F5를 눌러 이를 디컴파일합니다. 디컴파일된 코드를 통해 함수의 주요 정보를 살펴보겠습니다.

int __cdecl main(int argc, const char **argv, const char **envp)
{
  Sleep(0x3E8u);
  qword_14001DBE0 = (__int64)"Hello, world!\n";
  sub_140001060("Hello, world!\n");
  return 0;
}

IDA는 argc , argv ,envp 로 3개의 인자를 받는다고 해석했습니다.

동작

  1. Sleep 함수를 호출하여 1초 대기합니다.
  2. qword_14001DBE0 에*“Hello, world!\n”* 문자열의 주소를 넣습니다.
  3. sub_140001060에 “Hello, world!\n” 를 인자로 전달하여 호출합니다.

sub_140001060 함수 분석

_int64 sub_140001060(__int64 a1, ...)
{
  FILE *v1; // rax
  va_list va; // [rsp+58h] [rbp+10h] BYREF

  va_start(va, a1);
  v1 = _acrt_iob_func(1u);
  return (unsigned int)sub_140001010(v1, a1, 0i64, (__int64 *)va);
}

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

 

스트림이란?

스트림은 데이터가 조금씩 흘러들어온다는 의미에서 명명되었습니다. 데이터는 스트림의 형식으로 한 프로세스에서 다른 프로세스로, 또는 한 프로세스에서 다른 파일 등으로 이동합니다.

운영체제는 stdin (standard input), stdout (standard output), stderr (standard error)와 같은 기본 스트림들을 프로세스마다 생성해줍니다. 이들은 일반적으로 사용자와 프로세스를 연결해주기 위해 사용됩니다. printf 함수는 stdout 을 통해 출력 데이터를 우리가 볼 수 있게 해 주며, scanf 함수는 우리의 키보드 입력을 stdin으로 받아서 프로세스에 전달해 줍니다.

이런 기본 스트림외에, 프로그래머는 필요에 따라 스트림을 생성할 수도 있습니다. 예를 들어, 프로그래머가 dream.txt라는 텍스트 파일에 데이터를 저장하고 싶다면, 이 파일과 스트림을 형성하여 내용을 작성할 수 있습니다.

 

동적 분석

main 함수 진입

Break Point F2

Run F9

동적 분석은 프로그램을 실행하면서 분석하는 방법입니다. 그런데 우리는 전체 프로그램 중 아주 일부분의 동작에만 관심이 있씁니다. main 함수에 도달하기 위해 한 줄씩 실행시켜서 도달한다면, 효율적인 방법이 아닐 것입니다.

 

한 단계 실행 F8

함수 내부로 진입하기 F7

 

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

IDA를 이용하면 실행중인 프로세스의 메모리를 조작할 수 있습니다.

기존의 코드 Sleep(delay=1000)을 호

출하여 1초동안 프로세스를 정지시켰습니다. 이번에는 delay의 값을 조작하여 정지시켜보겠습니다.

delay를 Sleep함수의 인자로 전달하는 부분에 중단점을 설정하고, 프로세스를 재시작합니다.

 

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

 

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

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

실제로 어떤 함수의 동작을 모를 떄는 인자를 적절히 봄으로써 함수의 동작과 인자의 역할들을 유추해볼 수 있습니다.

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

Exercise: rev-basic-0  (0) 2022.02.18
IDA 사용법  (0) 2022.02.18
x86 Assembly🤖: Essential Part(2)  (0) 2022.02.18
x86 Assembly🤖: Essential Part  (0) 2022.02.18
Windows Memory Layout  (0) 2022.02.18