'Windows API'에 해당되는 글 1건

  1. 2010.05.07 [Reversing With Lena] lena's tutorial 13 풀이
1. 개 요
예제 문제 및 강의 내용 출처 : http://www.tuts4you.com/download.php?view.134

이번 Lena의 13장 강의에서는 Windows API를 이용한 프로그램의 흐름 분석 및 디버깅 방법에 대하여 설명한다.


2. 사용도구
Ollydbg :
http://www.ollydbg.de


3. 분 석
이번 Lena의 강의에서는 windows API를 이용한 디버깅 방법을 보여준다. 그렇다면 Windows API(Application Programming Interface)란 무엇일까?
API(Application Programming Interface)란 우리말로 풀어본다면 운영체제가 응용 프로그램을 위해 제공하는 함수의 집합이라고 정의할 수 있다.
운영체제는 하드웨어와 응용 프로그램 사이에 위치하며 응용 프로그램을 대신하여 하드웨어를 관리하고 메모리를 관리하는 시스템 소프트웨어이다. 특정 운영체제에서 실행되는 응용 프로그램은 운영체제에 종속적일 수 밖에 없으며 운영체제가 규정한 바대로 하드웨어를 액세스해야 한다. 또한 윈도우즈와 같은 멀티 태스킹 운영제체의 경우 응용 프로그램간 상호작용을 할 때도 운영체제의 규정을 따라야만 한다.
그러나 현실적으로 응용 프로그램 개발자들이 이러한 운영체제의 내부 동작까지 속속들이 이해하고 있을 수는 없다. 그래서 운영체제는 가장 기본적인 동작을 할 수 있는 함수의 집합을 응용 프로그램에게 제공할 의무를 지며 응용 프로그램 개발자들은 운영체제가 제공하는 함수들을 사용할 권리와 의무를 가진다. 윈도우즈도 응용 프로그램을 위한 함수 집합을 제공하는데 이를 API라고 하며 좀 더 정확하게 표현하자면 윈도우즈 API라고 한다. API는 특정 시스템(운영체제든 하드웨어든)을 위한 함수 집합을 이므는 일반명사이며 그 중의 하나가 윈도우즈 API이다. API는 운영체제의 중요한 한 부분이며 운영체제 그 자체라고도 할 수 있다.

출처 :
http://winapi.co.kr/

○ 주요 API 함수
① Dialog Box 관련 함수
 - DialogBoxParam : dialog box template rosource로 부터 modal dialog box를 생성한다.
 - GetDlgItem : 특정 dialog box를 제어하는 핸들을 반환한다.
 - GetDlgItemInt : 특정 dialog box를 제어하는 텍스트 형식의 핸들을 integer 값으로 변환한다.
 - GetDlgItemText : 특정 dialog box를 제어와 관련된 타이틀이나 텍스트를 반환한다.
 - GetWindowText : 특정 윈도위의 title bar를 버퍼에 저장한다.
 - GetWindowWord : 특정 윈도우의 extra window memory의 특정 오프셋을 16-bit(word) 형태로 반환한다.

② 메시지 관련 함수
 - MessageBeep : 지정한 사운드를 연주한다.
 - MessageBox : 메시지 박스를 생성, 출력한다.
 - MessageBoxEx : 응용 프로그램에서 지정한 특정 메시지 박스를 생성, 출력한다.
 - SendMessage : 특정 메시지를 윈도우에게 보낸다.
 - SendDlgItemMessage : 특정 메시지를 특정 dialog box의 control에게 전송

③ 레지스트리 관련 함수
 - RegCreateKey : 레지스트리에 특정 키를 생성한다.
 - RegDeleteKey : 레지스트리의 특정 키를 삭제한다.
 - RegQueryValue : 레지스트리 특정 키의 값을 읽어온다.
 - RegQueryValueEx : 레지스트리 키의 타입과 데이터를 읽어온다.
 - RegCloseKey : 특정 키에 대한 핸들을 release한다.
 - RegOpenKey : 특정 키를 오픈한다.

④ 파일 입출력 관련 함수
 - ReadFile : file pointer가 가르키는 부분부터 파일의 데이터를 읽는다.
 - WriteFile : file pointer가 가르키는 부분부터 데이터를 파일에 기록한다.
 - CreateFile : 파일, 파이프, 통신 자원, 디스크 디바이스, 콘솔 등을 생성하거나, 열거나, 잘라낸다. 

⑤ INI file 관련 함수
 - GetPrivateProfileString : INI 파일의 특정 섹션의 stirng을 읽어 온다.
 - GetPrivateProfileInt : INI 파일의 특정 섹션의 int형 key 값을 읽어 온다.
 - WritePrivateProfileString : INI 파일의 특정 섹션에 특정 문자열을 복사한다.

⑥ 문자열 관련 함수
 - LoadString : 특정 모듈의 실행 파일과 관련된 string resource를 읽어온다.
 - lstrcmp : 두 개의 스트링 값을 비교한다.
 - MultiByteToWideChar : character string을 wide-character(unicode) string으로 변환한다.
 - WideCharToMultiByte : MultiByteToWideChar 함수와 반대의 역할
 - wsprintf : 특정 캐릭터 값을 버퍼에 저장한다.

⑦ 시간과 날짜 관련 함수
 - GetFileTime : 파일의 생성 일자, 마지막 접근 일자, 마지막 수정 일자를 반환한다.
 - GetLocalTime : 현재 local 날짜와 시간을 반환한다.
 - GetSystemTime : 현재 시스템의 날짜와 시간을 반환한다.
 - GetSystemTimeAsFileTime : 현재 시스템의 날짜와 시간을 반환한다.
 - SetTimer : 특정 time-out 값의 타이머를 생성한다.
 - SystemTimeToFileTime : 시스템 시간을 파일 시간으로 변환한다.

⑧ 윈도우 생성 관련 함수
 - CreateWindowEx : overlapped, pop-up, child-window 형식의 윈도우를 생성한다.
 - ShowWindow : 특정 윈도우의 show state(SW_HIDE, SW_MAXIMIZE...)를 설정한다.
 - UpdateWindow : 윈도우의 특정 client area에 WM_PAINT를 보냄으로써 업데이트 한다.

⑨ 메시지 박스 텍스트 관련 함수
 - SendDlgItemMessage : 특정 dialog box에 메시지를 전달한다.
 - SendMessage : 특정 윈도우에 특정 메시지를 전달한다.
 - SetDlgItemText : 특정 dialog box에 타이틀이나 문자열을 설정한다.
 - SetWindowText : 특정 윈도위 title bar의 텍스트를 변경한다.

위의 함수들은 리버싱시에 유의깊게 보아야할 함수들이며, 프로그램을 실행의 흐름을 보면 대충 위의 함수 중 어떤 함수들이 사용되었는지 예측이 가능할 것이다. 그렇다면 본격적으로 Windows API를 이용하여 샘플 프로그램을 리버싱 해보자.

예제로 사용되는 프로그램인 Xoftspy를 Ollydbg를 이용하여 로딩한 뒤 실행(F9)한 뒤 About 탭을 보면 "Enter Registration Code"라눈 부분이 있는 것을 볼 수 있다. 사용자로부터 값을 입력받아 등록여부를 검사하는 것을 알 수 있다. 따라서 유추하건데 GetWindowText 함수를 사용했을 것으로 추리할 수 있다.

위와 같이 임의의 값을 입력한 뒤 다시 OllyDbg로 이동한다.

사용된 함수들을 보기위해 Ctrl+N을 입력한 뒤 GetWindowText 함수를 찾아본다.
위와 같이 GetWindowText 함수에서 마우스 우클릭 후 "Set breakpoint on every reference"를 선택하면 해당 함수를 사용하는 곳에 모두 BP(Break Point)가 설정되는 것을 볼 수 있다. OllyDbg 하단의 메시지를 보면 총 3곳에 BP가 설정되는 것을 볼 수 있다.

이 후 다시 예제 프로그램을 선택하면 첫번째 BP에서 실행이 멈추는 것을 볼  수 있다. 따라서 첫번째 BP는 registration과 상관없는 부분이라는 것을 알 수 있으므로, BP를 해제한다. F9를 눌러 프로그램 다시 실행한 뒤 아까 입력해 놓은 부분의 "OK"을 클릭한다. Ollydbg를 보면 아래 부분에서 프로그램 흐름이 멈추는 것을 볼 수 있다.
GetWindowTextA 함수에 대해서 좀 더 자세히 알아보자.
int GetWindowText(
    HWND
  hWnd, // handle of window or control with text
    LPTSTR  lpString, // address of buffer for text
    int  nMaxCount  // maximum number of characters to copy
   ); 
- hWnd : Identifies the window or control containing the text.
- lpString : Points to the buffer that will receive the text.
- nMaxCount : Specifies the maximum number of characters to copy to the buffer. If the text exceeds this limit, it is truncated.
위와 같이 hWnd로부터 nMaxcount 만큼 읽어들여 lpString에 저장하는 것을 알 수 있다.

F8(Step-Over)을 눌러가면서 특이한 점을 발견할 때 까지 진행해 보자.
위와 같이 인증을 통과시 메시지를 찾을 수 있다. Bad Boy와 Good Boy(Lena의 강의에서와 동일하게 Bad Boy, Good Boy로 칭하겠다.)를 결정하는 조건 분기문은 어디에 있을까? ①번 체크루틴과 ②번 체크루틴에서 동일한 검사문이 2번 나타나는 것을 볼 수 있다. JNZ 분기문 전에 TEST AL, AL 구문을 통해서 AL 레지스터의 값이 1인지 검사한 뒤 분기하게 된다. AL 값이 1이라면 Good Boy 쪽으로 분기하게 될 것이다.
따라서 ①번 체크루틴에서 Good Boy 쪽으로 분기를 하게되면 라이센스 인증 검사가 성공하는 것을 알 수 있다. ①번 체크루틴과 ②번 체크루틴의 함수 호출 부분에 BP를 설정한 뒤 ①번 체크루틴의 CALL 함수 안으로 Step-in(F7)해보자.

호출된 함수 안에서 위와 같은 부분을 찾을 수 있다. ③번에서 AL 레지스터가 1로 설정된 후에 ④번에서 리턴되는 것을 볼 수 있다. ①번과 ②번에서는 조건분기문이 모두 ④번 이후로 분기하게 되며, 그 이후의 코드에는 XOR AL, AL 구문에 의해서 AL 레지스터의 값이 0으로 설정되는 것을 볼 수 있다. 따라서 ①번과 ②번 조건 분기문의 JMP 구문으로 변경하거나 NOP 처리하면 AL 레지스터의 값이 1로 설정된채로 리턴되는 것을 알 수 있다.

위와 같이 정상적으로 프로그램이 등록되는 것을 볼 수 있다.
하지만 예제 프로그램의 About을 확인해 보면 위와 같이 "This XoftSpy license has not been registered"라는 구문과 함께 등록되지 않은 것을 알 수 있다. 다시 OllyDbg를 열어 마우스 우클릭 -> Search for -> All referenced text strings을 선택하면 맨 윗부분에서 위의 구문을 찾을 수 있다. 더블클릭하여 해당 주소로 이동한다.

위와 같이 ①번에서 AL 레지스터의 값을 비교후 ②번 JE 구문에서 ③번 또는 ④번으로 분기할 것이지 결정이 된다. 따라서 AL 레지스터의 값이 결정되는 곳은 ①번 명령어 바로 위의 CALL 구문에 의해 호출되는 함수인 것을 알 수 있다. 해당 CALL 구문에 BP를 설정한 뒤 Step-in해보자.

위와 같이 리턴하기 전에 MOV AL, BL(이전에 BL의 값은 0으로 셋팅) 명령어 구문에 의해서 AL 레지스터가 0으로 설정되는 것을 알 수 있다. 따라서 MOV AL, BL 구문을 MOV AL, 1로 변경하면 AL 레지스터의 값이 항상 1인 것을 알 수 있다.

이후 BP를 모두 제거한 뒤 프로그램을 다시 실행하면 위와 같이 정상적으로 등록된 것을 볼 수 있다.

4. 결 론
이번 lena의 13장 tutorial에서는 Windows API를 이용한 리버싱 방법을 보여주고 있다. Windows API로 만들어진 응용 프로그램을 리버싱할 시에는 이처럼 Windows API에 익숙하면 보다 수월할 수 있다. 단순한 리버싱 기술 뿐만 아니라 Windows API에 대한 이해와 자주 사용되어 지는 함수들에 대한 지식을 갖추는 것이 필수인 듯 하다. 앞으로 Windows API 뿐만 아니라 Windows System Programming등 갈길이 멀다. 더 고급 리버서가 되는 그날까지 Keep going ~!

ps. 이 포스팅에 있는 기술들을 악용하여 상용 프로그램의 라이센스 인증 과정을 크랙하는 우를 범하지 않았으면 한다.

                                                                                                    +---------------------------------+
                                                                                                    | Infinite Flow..                              |
                                                                                                    | mail : geekspark@gmail.com         |
                                                                                                    | Blog : http://sinun.tistory.com       |
                                                                                                    | twitter : @unpacker                      |
                                                                                                    | CISSP                                        |
                                                                                                    +----------------------------------+
저작자 표시 비영리 변경 금지
신고
Posted by By. PHR34K