본문 바로가기

0x00 /0x01 Reversing

- C 프로그래밍 의사코드 연습 1

# Reversing Study

- printf 함수 & 함수 호출 규약에 대한 C 코드를 어셈블리어로 디버깅하여 의사코드 작성하기.

- Study 내용 : 간단한 C 코드 작성 후 컴파일한 파일을 Study 원들에게 배포.

                     Ollydbg 등으로 디버깅한 내용으로 C 의사코드 작성.




함수호출규약에 대해서 잘 모르시는 분들은 아래 링크 참고하시길.

http://yokang90.tistory.com/9



총 5가지 파일을 가지고, 의사코드를 작성.

1. RS_1.exe (지훈이)

2. re_printf.exe (현민이)

3. reversing1.exe (건이)

4. reversing2.exe (혁재)

5. taeyoul.exe (태열이)





1.1. RS_1.exe 실행 모습

- 간단하게 4줄에 걸쳐 printf 함수를 이용하여 그림과 같은 문자열을 출력




1.2. Ollydbg를 이용하여 디버깅

- 우선 처음 EP가 00D71B90 으로 함수를 2개 호출하고 종료되는 식의 간단한 구조를 가지고 있는 것으로 확인했다.

- 첫 번째 함수에서 C 코드로 작성된 main 함수에 대한 내용이 없었으며, 두 번째 함수에서 main 함수를 찾을 수 있었다.

- 아래의 사진이 두 번째 함수에서 찾은 main 함수 부분이다.

- 아주 세세하게는 분석하지 못하였으며, 간단하게 흐름을 살펴보았다.

- 일단 메인함수 내에서 행위

  1. 지역변수 하나를 선언하고 3이란 값으로 초기화

  2. 그 외엔 printf 함수를 호출시에 사용되는 인자를 사용하여 문자열을 인자로 printf 함수에 전달

      (1) 첫번째 : 예상 - printf("Hello World\n");     = 인자 1개

(2) 두번째 : 예상 - printf("Number %d is good\n", num);    = 인자 2개   (지역변수명을 num이라고 가정)

(3) 세번째 : 예상 - printf("What's your name?");

(4) 네번째 : 예상 - printf("Ha-Ha-Ha!!\n");

- Caller(main 함수)에서 인자들을 정리하는 것으로 확인되고,인자 전달 순서 또한 오른쪽에서 왼쪽으로 전달된다.

   따라서 cdecl 방식의 함수호출규약을 사용하는 것으로 판단된다.



1.3. 예상 의사코드

- 생각해본 예상 의사코드.



1.4 결론 

- 아직 원본 코드를 받아보지 못했으나, 코드를 작성한 친구의 말에 의하면, fastcall 함수호출규약을 사용했다고 함.

- 그런데 fastcall은 인자 전달을 할 때, ECX와 EDX 레지스터를 우선적으로 사용하고, 호출된 함수(Callee)에서 인자를 정리하는 것으로

   알고 있는데, 이 부분이 애매하다. 어셈코드가 왜 저렇게 나왔는지, 다시 원본 코드를 받아서 컴파일 후 디버깅해봐야겠음.






2.1. re_printf.exe 실행 모습

- 역시 따로 설명할 필요가 없을듯.




2.2. Ollydbg를 이용하여 디버깅

- 메인 함수에서 지역변수를 선언하고 610 입력.

- 지역변수 하나를 더 선언 문자열 주소를 입력.

   (이부분에서 실수를 했음. OFFSET으로 주소를 넘겨주는 것은 포인터 자료형으로 생각해야하는데, 배열로 생각해버림. 참고로 배열은 그냥 주소가 

   아닌 문자열 데이터가 들어감)

- 나머지는 다 무난하게, printf 함수 이용

(1) 첫번째 : 예상 - printf("hello 2014 unknown\n");

(2) 두번째 : 예상 - printf("%d\n", num);            - int형 지역변수명을 num으로 가정

(3) 세번째 : 예상 - printf("%s\n", string);         - char형 배열을 사용했다고 생각했음. 이부분이 잘못됬었지. (char형 포인터형을 사용한것임)




2.3. 예상 의사코드 및 실제 코드


- 예상 의사코드


- 실제 코드




2.4 결론 

- 생각했던 것 처럼 cdecl 함수호출규약이였으며, 틀린 부분은 포인터를 사용했는데 배열이라고 생각했던 점.

- 포인터형은 OFFSET으로 주소를 저장하고, 배열은 그 문자열의 데이터를 직접 저장했음.






3.1 re_printf.exe 실행 모습



3.2. Ollydbg를 이용하여 디버깅

- 메인 함수 내에 지역변수 선언이 없었으며, printf 함수만을 이용하여 문자열을 출력.



3.3. 예상 의사코드 및 실제 코드


- 예상 의사코드


- 실제 코드


3.4 결론 

- 함수의 자료형이 틀렸음.






4.1 reversing2.exe 실행 모습



4.2. Ollydbg를 이용하여 디버깅

- [EBP-18]까지 지역 변수를 사용한 것으로 보이는데, [EBP-18]에 십진수 90을 대입하고, 안되겠다. 

   헷갈리네 그려봐야겠다. 아래 사진이 메인 함수에서부터 스택 구조를 그려본 모습이다. 확실하게 맞는진 모르겠지만...

   대충 그려보니 변수 a,b,c는 4byte씩이니까 int형 포인터 자료형으로 생각된다. 

   (사실 처음 분석할땐 그리지않고 대강해서, 포인터인줄도 몰랐음...)

   대충 3개의 int형 포인터 변수와 [EBP-18]에 90을 대입하고, printf 함수에 인자로 넘겨주어 출력을 하게 된다.

   포인터 변수 3개 아래에는 다시봐도 어떤 변수의 자리인지 잘 파악이 안된다...



- 그 다음 코드 부분인데, 여기에선 앞에서 선언했던 즉, 포인터 변수뒤에 선언되었던 변수에다가 값들을 대입하고 마찬가지로 

   printf 함수의 인자로 주어 출력하는 내용이다.



4.3. 예상 의사코드 및 실제 코드


- 예상 의사코드


- 실제 코드



4.4 결론 

- 지역변수 선언시 자료형 파악이 제대로 되지 않고 있으며, 특히 포인터, 배열에 대해서 정확하게 파악하지 못했음.

   그리고, 어셈코드를 좀 더 자세하게 분석해 볼 필요가 있는 것으로 판단.






5.1 taeyoul.exe 실행 모습



5.2 Ollydbg를 이용하여 디버깅

- "adult"라는 문자열이 있는 주소를 EBP-10에 넘겨주고 있다. 배열일 것으로 판단했으며, 그다음 EBP-1C엔 1E(십진수30)을 

    대입. 그리고 그 아래에서 배열을 인자로 주어 printf 함수 호출.



- 이 부분의 코드는 주석으로 충분한 설명이 됬을거라 생각된다.






5.3 예상 의사코드 및 실제 코드


- 예상 의사코드


- 실제 코드


5.4 결론

- 의사코드로 작성한 샘플들 중에 가장 비슷하게 작성한 샘플이다.

  이 샘플을 통해서는 배열의 주소를 이용할때 연산을 하지 않더라도, 그 해당 주소를 찾기 위해서

  어셈 코드에서는 곱셈, 쉬프트 연산 등을 사용한다는 점을 알 수 있었다.