본문 바로가기
개발 및 운영/프로그래밍

KiUserApcDispatcher Hooking

by Joseph.Lee 2017. 10. 21.

ntdll.dll의 KiUserApcDispatcher API을 후킹하려고 시도했는데 일반적인 후킹방법으로는 프로그램이 잘못된 메모리를 참조해서 오류가 나게 되었습니다.


인터넷을 찾아보면 이런 소스도 찾아볼 수 있는데...

https://github.com/blaquee/APCHook/blob/master/AntiDebugAPC/Source.cpp


일단 __forceinline(함수의 prologue을 없애기 위해) 때문에 Debug모드에서는 당연히 작동하지 않고

Release모드에서도 APC Queue을 실행시키는 SleepEx함수를 실행하면 오류가 뜹니다.


후킹된 KiUserApcDispacher에서 다른 작업을 하고 원래 KiUserApcDispatcher을 실행하면 원래함수를 call 할 때 rsp가 바뀌어서 문제가 생기는거 같습니다.


일단... 원인을 알기 위해 KiUserApcDispacher가 어케 작동하는지부터 알아야 합니다.

원래 x64에서는 처음 4개의 Argument을 rcx, rdx, r8, r9 으로 넘깁니다.

하지만 위 소스를 보면 rcx같은건 rsp+18h 같은걸로 덮어씌워 버립니다.

다른것도 마찬가지구요.

그리고 원래 x64에서 rsp+18h 은

mov [rsp+18h], r8

이런식으로나 레지스터로 받은 인수를 저장해서 사용하지 인수를 직접 받지는 않습니다.

하지만.. 요 놈은 좀 특이한 놈인걸 알 수 있습니다.

그래서 백날 이 함수를 후킹해서 C소스로 인수를 똑같이 넘겨봐짜 오류밖에 못봅니다.

그래서! 어셈으로 후킹코드를 만들었습니다.


뭐.. 결론부터 말하면..

rsp : 호출된 쓰레드의 CONTEXT 구조체 주소

(Context switch하는것처럼 호출된 쓰레드의 모든 레지스터를 push하나봅니다.)

qword ptr [rsp + 00h] : APCFunc의 NormalContext

qword ptr [rsp + 08h] : APCFunc의 SystemArgument1

qword ptr [rsp + 10h] : APCFunc의 SystemArgument2

qword ptr [rsp + 18h] : APCFunc의 주소




후킹 함수를 호출하기 위해 x64 function call 스타일대로 rcx, rdx, r8, r9에 필요한 인수들을 넣고

rsp을 복사하고

함수를 호출하기 위해 rsp을 바꾼 뒤

복사했던 초기 rsp도 인수로 넣어주고

후킹 함수를 호출하고

다시 복구합니다.


C에서의 후킹함수는 아래와 같이 사용할 수 있습니다.


반응형

댓글