본문 바로가기

My Study/Reversing

User Callback Address

 OS에서 메시지가 발생했을 때 해당 메시지는 OS에서 적절한 응용 프로그램의 메시지 큐에 넣게 됩니다.
그리고 응용 프로그램에서는 메시지 큐에 메시지가 들어오게 되면 적절한 Callback함수를 호출하게 되면서 해당 메시지를 처리하게 됩니다. 보통 API같은 경우 switch문을 사용해 메시지를 처리합니다.

메시지가 발생했을 때 보통 어떤 루틴으로 가게될까요??
해당 값은 커널 영역에 나와있습니다.

nt! KeUserCallbackDispatcher에 그 값이 있습니다.


KeUserCallbackdispatcher의 값은 0x80554f14로 커널 주소이고 그 안에는 0x7c93e440으로 유저 주소 입니다.
그리고 그 값은 ntdll! KiUserCallbackDispatcher입니다.

이제 유저 영역에서 저 주소에 BreakPoint를 걸고 메시지를 발생시켜보겠습니다.
메시지 발생은 해당 응용 프로그램을 클릭 또는 마우스만 대도 바로 발생하기 때문에 BreakPoint에서 멈춰있을 것입니다.

테스트는 올디에서 했지만 WinDbg에서 더 보기 편하므로 WinDbg에서 봐보겠습니다.

일단 어떤 주소를 Call하고 있는 부분이 있습니다.

Call하기 전의 EAX에는 KernelCallbackTable 값이 있고 해당 테이블에 있는 값들 중 index EDX를 가지고 Call하고 있습니다.
그리고 그 아래로는 제어가 돌아오지 않더군요.

위에서 보여주었던 KiUserCallbackDispatcher함수는 함수명만 존재하지 문서화되지 않은 함수입니다.
해당 함수안에서는 index EDX를 가지고 유저모드에 존재하는 콜백 함수들을 호출합니다.
API를 할 때 디폴트 콜백함수로 많이 쓰는 WndProc을 예로 들어보겠습니다.

WinMain에서 메시지 처리를 하기위해 콜백 함수를 등록해 놓고 
GetMessage, TranslateMessage, DispatchMessage를 사용해 메시지가 발생하면 WndProc 콜백함수를 호출하게 됩니다.
이 때 메시지를 콜백함수로 보내는 함수인 DispatchMessage함수 또한 KiUserCallbackDispatcher를 호출하게 됩니다.

직접 테스트 해본 결과 WM_PAINT 메시지가 발생했을 때 
DispatchMessage -> KiUserCallbackDispatcher -> Callback Routine
이렇게 호출이 됬습니다.

그리고 KiUserCallbackDispatcher 함수를 리버싱 해보았습니다.

KiUserCallbackDispatcher에서 index EDX를 가지고 PEB의 KernelCallbackTable에서 적당한 값을 호출합니다.
호출 결과 WinDbg에서 USER32!__FnDWORD 라고만 나오는군요.


두개의 함수를 호출하고 있습니다. 그 중 하나는 XyCallbackReturn 함수라는군요. 하지만 해당 함수 또한 문서화되지 않은 함수라 특별한 설명이 안나와있습니다. 

그리고 다른 하나 함수를 실행하니 제가 만든 WM_PAINT 메시지 루틴으로 넘어갔습니다. 그 아래로 제어가 넘어오지 않은채 말이죠. 고로 XyCallbackReturn 함수는 무시하고 일단 첫번째 함수 내부로 들어가보겠습니다.

들어가보니 이번엔 제대로 된 함수가 나오는군요. ( DispatchClientMessage


먼저 DispatchClientMessage 함수는 Windows Message를 받는 WndProc을 Call하기 위해서 호출되는 함수입니다.
내부적으로 호출되는 함수는 하나 뿐이군요. UserCallWinProcCheckWow 함수입니다.

이거고 저거고 죄다 undocumented 함수들 뿐이군요. 하지만 들어가는 인자를 보니 세 개 정도는 알 수 있었습니다.

Arg1 = 00000000    
Arg2 = 00401100    //WndProc 주소
Arg3 = 000300B8   //DispatchMessage가 받은 인자
Arg4 = 0000000F   //WinUser.h에 정의된 WM_PAINT 값
Arg5 = 00000000
Arg6 = 00000000
Arg7 = 005F53D4
Arg8 = 00000001

UserCallWinProcCheckWow 함수 내부로 들어가보겠습니다. ( 상당히 양이 많군요. )
호출되는 함수 위주로 보겠습니다.

1. RtlActivateActivationContextUnsafeFast  : Undocumented  -> 대충 함수 명만 봐서 인자로 들어가는 컨텍스트를 빠르게 활성화 시키는 함수인듯..

2. _BeginIfHookedUserApiHook
인터넷에 나와있는 리버싱된 코드
BOOL FASTCALL BeginIfHookedUserApiHook( VOID )
{
   InterlockedIncrement(&gcCallUserApiHook);
   if (IsInsideUserApiHook()) 
       return TRUE;
 
   InterlockedDecrement(&gcCallUserApiHook);
   return FALSE;
}
코드를 대충 봤을 때
gcCallUserApiHook은 후킹이 됬는지 안됬는지 판단하기 위한 값 인거 같습니다.

IsInsideUserApiHook 함수는 간단하게 C로 표현해 보면 ..
BOOL IsInsideUserApiHook ( void )
{
     if( 변수1 == 0 )
          return FALSE;

     if( 변수2 == 0 )
          return FALSE;

     return TRUE;
}
이렇게 되는데 변수1, 변수2가 뭔지는 잘 모르겠습니다. 뭔가 체크하는 함수인데 함수명으로봐서
UserApiHook이 안에 있는지 없는지 체크하는 함수 같습니다.

3. InternalCallWinProc   !!!!!!!!!!!!!!!!! WinProc 호출하는 함수 함수 함수??~!!!
뭔가 기쁘군요. 해당 함수의 인자를 봐보겠습니다.

Arg1 = 00401100
Arg2 = 000300B8
Arg3 = 0000000F
Arg4 = 00000000
Arg5 = 00000000

아까 제가 본 3개의 인자가 다 있습니다. ㅠ_ㅠ
이제 InternalCallWinProc 함수 내부로 들어가보겠습니다. 뭔가 나올 것 같군요. ( 처음 시도하면서 바로 글 작성 중이라..;; )

딱 하나의 함수만 Call하고 있습니다. 
Call을 보니 InternalCallWinProc 함수의 첫번째 인자를 호출하고 있군요. 바로 WndProc 주소입니다.!!!! 랄라~

인자입니다.

0012FD54   000300B8     // hWnd
0012FD58   0000000F     // iMessage
0012FD5C   00000000    // wParam
0012FD60   00000000     // lParam

이렇게 되겠군요.

일단 다시 전체적인 정리를 해보겠습니다.
1. 응용 프로그램은 메시지를 기다린다.
2. 메시지가 왔으면 DispatchMessage 함수를 사용해 WndProc 콜백 함수를 호출한다.
3. 이때 바로 호출되는 것이 아닌 ntdll! KiUserCallbackDispatcher 함수를 호출 
   ( nt! KeUserCallbackDispatcher 에 값 존재 )
4. KiUserCallbackDispatcher 함수 에서는 특정 index 값을 가지고 PEB->KernelCallbackTable에서 적당한 값 호출
5. 그 안에선 DispatchClientMessage 호출
6. DispatchClientMessage 안에선 UserCallWinProcCheckWow 호출
7. UserCallWinProcCheckWow 안에선 InternalCallWinProc 호출
8. InternalCallWinProc 안에선 WndProc 호출!

KiUserCallbackDispatcher 빼고는 전부 User32.dll에서 이루어지는군요.

음.... 이걸로 뭐할까요..ㅠ_ㅠ 무조건 커널로 들어가는 줄 알았는데 그건 아닌가 봅니다..
하지만 DispatchMessage -> KiUserCallbackDispatcher 로 올 때는 Kernel을 거치겠죠??
시간나면 직접 봐봐야겠습니다.

'My Study > Reversing' 카테고리의 다른 글

Code Virtualized  (9) 2011.06.27
ZwSetSystemInformation  (2) 2011.01.11
Cheat Engine의 축하 메시지??  (3) 2010.12.27
Visual C++ SEH Filter,Handler 루틴  (0) 2010.11.11
실행 시 함수 얻어오는 바이너리 분석  (2) 2010.10.11