zj3t

email: euntaejang@gmail.com

Latest Posts

Global API Hooking-ntdll!ZwResumeThread() API

By 오후 11:31 ,

프로세스를 생성하는 API에 대해서 생각해봅시다.
프로세스를 생성하는 API는 kernel32!CreateProcess() API가 가장 유명합니다.
CreateProcess() API의 디버깅을 위하여 다음과 같이 간단한 프로그램을 만들어보겠습니다.



이 코드를 빌드해서 cptest.exe를 생성합니다. 이 파일을 디버깅해보면 프로세스 생성과 관련된 API들의 호출 흐름을 할 수 있습니다.

-코드
  1. #include "Windows.h"
  2. #include "tchar.h"
  3. void main()
  4. {
  5. STARTUPINFO si={0,};
  6. PROCESS_INFORMATION pi={0,};
  7. TCHAR szCmd[MAX_PATH]={0,};

  8. si.cb=sizeof(STARTUPINFO);
  9. _tcscpy(szCmd, L"notepad.exe"); //notepad.exe의 실행정보를 szCmd에 저장

  10. if(!CreateProcess(NULL, 
  11.  szCmd,NULL,           //lpCommandLine
  12.  NULL,FALSE,
  13.  NORMAL_PRIORITY_CLASS,
  14.  NULL,NULL,&si,&pi)
  15.  )

  16. return;

  17. if(pi.hProcess !=NULL)
  18. CloseHandle(pi.hProcess);
  19. }

CreateProcess() API를 보실 수가있습니다.



kernel32.CreateProcessW() 내부로 따라 들어가면(F7) 위와 같이 kernel32.CreateProcessInternalW() 호출 코드를 볼 수 있습니다. 그리고 notepad.exe가 그대로 넘어와서 세번 째 인자가 된다는 것을 볼 수강 있습니다.

CreateProcessInternalW() 내부를 살펴보도록 하겠습니다.


이렇게 긴 코드가 나옵니다. CreateProcessInternalW() 함수는 상당히 큰 함수라는 것을 알 수 있습니다. 아래로 쭉 스크롤 해보면 


ntdll.ZwCreateUserProcess()를 호출하는 코드가 나옵니다.


이번 그림에서 아래쪽의 스택을 보면 위 그림처럼 인자를 알려주는 스택형태와 많이 다른 형태인 것을 알 수 있습니다. 2번째 파라미터(Arg2)는 어떤 구조체인데 왼쪽의 Hex dump창을 보면 구조체 멤버 중에 19F9EC주소에  0019FD30가 쓰여있는 것이 확인됩니다.

이 주소로 이동해보겠습니다.


밑에 보이시죠?? notepad.exe 문자열을 확인할 수가 있었습니다. 그럼 ntdll.ZwCreateUserProcess를 한번 실행시켜보겠습니다.


notepad.exe화면은 보이지 않지만 프로세스는 생성되었습니다. 즉 아직 EP(Entry Point)코드가 실행되지 않은 상태라고 볼 수 있습니다.



위의 ntdll.ZwCreateUserProcess을 실행시킨 후 계속 아래로 진행하면...............
ntdll.ZwResumeThread() API 호출 코드를 볼 수 있습니다. ntdll.ZwResumeThread()는 함수 이름 그대로 스레드를 Resume해줍니다. 이 스레드가 바로 자식 프로세스(notepad.exe)의 메인 스레드입니다. 따라서 이 API가 호출되면 비로소 자식 프로세스의 EP코드가 실행되는 것 입니다.

보시는 것처럼 notepad.exe가 EP코드가 실행되어 프로그램 창이 띄어진 것을 확인 할 수 있습니다.

지금까지의 CreateProcessW() API 호출 흐름을 정리해보도록 하겠습니다.

kernel32.CreateProcessW
     kernel32.CreateProcessInternalW
           ntdll.ZwCreateUserProcess    //프로세스 생성됨(메인 스레드는 Suspend 상태
           ntdll.ZwResumeThread        //메인 스레드 Resume 시킴(프로세스가 실행됨)

자식 프로세스 생성에 있어서 가장 마지막에 호출되는 API가 바로 ntdll.ZwResumeThread() 입니다. 따라서 우리는 이 API를 후킹하여 자식 프로세스의 EP코드가 실행되기 바로직전에 제어를 가로챈 후 원하는 API를 후킹시킬 수 있습니다.

이 4개의 API (CreateProcessW, CreateProcessInternalW, ZwCreateUserprocess, ZwResumeThread) 중에서 어떤 걸 후킹해도 우리 목적에 맞는 글로벌 후킹이 가능합니다.

"리버싱 핵심원리" 에서는 ntdll.ZwResumeThread() API 후킹을 실습했기 때문에 그걸 토대로 저도 실습을 하겠습니다.


출처, 참고: 리버싱핵심원리-이승원 지음






You Might Also Like

0 개의 댓글