농소

바이너리 분석 연습 본문

Security/System Hacking

바이너리 분석 연습

농소 2018. 1. 29. 03:33

리버싱을 통해 해당 실행파일의 패스워드를 찾기위한 연습을 진행한다.



실행을 해 보았더니 패스워드를 입력하라는 input이 호출되고

 아무번호나 입력했더니 wrong password라는 false를 반환한다.

true값을 반환받기 위해 이 파일을 분석해 보겠다.



우선 gdb로 바이너리를 asm로 변환시킨 모습이다.




자 이제부터 처음부터 차근차근 분석 해 보겠다.


1



우선 프롤로그를 설정해 주었고, printf를 calll하고 있는걸 봐선 앞에 push값은

 주소값을 보아 segment영역 일 것이고 전역변수인 것을 알 수 있다.


확인해 보았더니 Input password: 라는 문자열이 나왔다.


이 과정을 c로 변환해 보면


int main()

{

  printf("Input password: ");


  return 0;

}


자료형은 아직 알순없다. 더 추가적인 정보가 있어야 확인가능하다 또 변수이름은 확인 불가능하다.




2




[ebp-1024]주소를 eax레지스터 에 선언하고 그 값을 push, gets함수를 call하고

 입력받은 문자열을 ebp-1024에 초기화 하였다.

그리고 입력받은 값을 strlen함수를 돌려 길이를 반환하여 그것을 ebp-1036에 초기화 하였다.


c언어


int main()

{

  char buffer[1024]; or 256 or 128    // [ebp-1024]

  ?  unknown  // [ebp-1028 ~ 1032]

  int len;    // [ebp-1036]


  fgets(buffer);

  len = strlen(buffer);

  return 0;

}


아직 지역변수들의 자료형은 알 수 없고, strlen을 1036에 받는걸로 보아 자료형이 int임을 알 수 있다.




3



cmp 가 들어가는것을 봐선 분기나 조건중 하나 일 것이다. 

허나 jmp로 되돌아가는게 없는걸로 봐선 이 cmp는 조건문에 쓰이는 것을 알 수있다. 

그리고 조건문이 2개나 되는데 조건실행후 동작하는 내용과 jmp가

 동일한 위치에서 떨어지는걸 봐선 다중조건임을 알 수 있다.

 조건문이 끝나고 해당 문자열 주소를 ebp-1028에 넣고 어떠한 값을 ebp-1032에 넣고 있다.

 이 값이 무엇인지 확인해 보면



실제 패스워드를 ebp-1032에 넣고있다. 아마 이것을 입력해야 true를 뱉고 아니라면 false를 반환할 것이다. 


c언어


char buffer[1024]    // [ebp-1024]

???* a;    // [ebp-1028]

???* b;    // [ebp-1032]

int len;    // [ebp-1036]

  

if(len > 0 && buffer[len-1] == '\n') {

    buffer[len-1] = 0;

a = buffer;

b = pwd;


1바이트씩 읽어 나감을 확인 했으므로 buffer의 자료형은 char일 것이고,

 주소값을 변수에 넣는걸로봐선 포인터변수임을 알 수 있다.




4



cmp명령어가 여러개가 있고 끝에 다시 되돌아오는 jmp문이 존재하기 때문에 반복문임을 알 수있다.

또 jmp문이 모두 하나로 이어지므로 다중조건임을 알 수 있다.

 [ebp-1028] 과 [ebp-1032] 를 서로 비교할때 al로 변환 한것을 보면 자료형이 char인것을 알 수 있다.


c언어


while( *a != 0 && *b != 0 && *a == *b)

{

  a++;

  b++;

}


입력한 buffer와 pwd를 1 바이트씩 비교해나가고 있다.

buffer와 pwd가 일치하면 결과적으로 a와b 에 0이 담겨있을 것이고

다르면 해당 주소에 서로 다른 문자가 들어있을 것이다.




5



 두번의 cmp가 있는데 각각 cmp 마다 전역변수를 push하는데 그 값을 알아보면



*a와 *b를 각각 0과 비교하여 같지않으면 false레이블로 jmp하고 같다면 true레이블로 jmp 한다.

이번에도 cmp가 같은위치로 jmp하고 있으므로 다중구문 이고

 중간에 false를 피하기위해 jmp 하므로 if~else구문일 것임을 알 수 있다. 


c언어


if( *a == 0 && *b == 0 )

{

  printf("Congratulations! You got it!\n"

} else if

  {

    printf("Oops! wrong password! : -P\n"

  }




결과


#include <stdio.h>


char pwd[] = "th3p4ssw0rd";


int main()

{

  char buffer[1024]; // ebp-1024

  char* a;  //  ebp-1028

  char* b;  //  ebp-1032

  int len;  // ebp-1036


  printf("Input password: ");

  fgets(buffer);

  len = strlen(buffer);


  if(len > 0 && buffer[len-1] == '\n') {

    buffer[len-1] = 0;

  }


  a = buffer;

  b = pwd;


  while( *a != 0 && *b != 0 && *a == *b ) {

    a++;

    b++;

  }


  if (*a == 0 && *b == 0){

    printf("Congratulations! You got it!\n");

  }else {

     printf("Oops! wrong password! :-P\n");

   }


  return 0;

}

<해당 실행파일을 c로 변환해본 모습>



올바른 패스워드를 입력했더니 true값을 반환받았다.