PspTerminateThreadByPointer() 주소 구하기.
일단, PspTerminateThreadByPointer()를 구하기 위해서는
어느 함수에서 PspTerminateThreadByPointer()를 호출하는지 알 필요가 있습니다.
필자는 WinDbg의 힘을 빌렸고, 아래와 같은 함수들이 대개 PspTerminateThreadByPointer()를 호출한다는 것을 알아 내었습니다.
NtTerminateProcess()
NtTerminateThread()
PsTerminateSystemThread()
PspTerminateProcess()
......
(이 외에도 여럿 있을 수 있음)
이 중, NtXxx()의 함수는 실제 구현코드를 가지고, 코드가 그만큼 길기 때문에 나중에 생각하기로 했습니다.
또한, PspTerminateProcess()는 Unexported 된 함수이므로 생각하지 않기로 했습니다.
위의 목록 중, 가장 간단한 코드를 가지고 있는 함수는 바로 PsTerminateSystemThread() 입니다.
한번 코드를 보도록 하죠.
nt!PsTerminateSystemThread:
805c9754 8bff mov edi,edi
805c9756 55 push ebp
805c9757 8bec mov ebp,esp
805c9759 64a124010000 mov eax,dword ptr fs:[00000124h]
805c975f f6804802000010 test byte ptr [eax+248h],10h
805c9766 7507 jne nt!PsTerminateSystemThread+0x1b (805c976f)
805c9768 b80d0000c0 mov eax,0C000000Dh
805c976d eb09 jmp nt!PsTerminateSystemThread+0x24 (805c9778)
805c976f ff7508 push dword ptr [ebp+8]
805c9772 50 push eax
805c9773 e828fcffff call nt!PspTerminateThreadByPointer (805c93a0)
805c9778 5d pop ebp
805c9779 c20400 ret 4
805c977c cc int 3
805c977d cc int 3
805c977e cc int 3
805c977f cc int 3
805c9780 cc int 3
805c9781 cc int 3
nt!PsTerminateProcess:
805c9782 8bff mov edi,edi
805c9784 55 push ebp
805c9785 8bec mov ebp,esp
805c9787 5d pop ebp
......
(아래 생략)
역시....간결하군요,
일단 함수를 호출할 때 쓰이는 call 명령이 있는 부분을 찾아봅시다.
탁 보이는군요.
805c9773 e828fcffff call nt!PspTerminateThreadByPointer (805c93a0)
그리고 Code Bytes는 e8 28 fc ff ff 가 됩니다.
e8은 call 명령을 뜻합니다.
"잠깐! 그렇다면 뒤의 이 알수없는 28 fc ff ff 는 데체 뭐야?! a0 93 c5 80이 와야 하는 게 아니었어?!"
.....라고 저는 생각했었습니다(그때는 어셈을 지금보다 더 몰랐으므로).
공식(....이랄것까지야 없지만, 알아둡시다.)에 의하면,
"call 명령의 다음 4바이트+명령어 주소+5=호출하는 함수의 실제 주소" 라고 합니다.
call 명령의 다음 4바이트는 위에서 보면 28 fc ff ff, 즉 4바이트 정수로 변환하면 0xfffffc28이 됩니다.
여기에서 simple한 방정식을 풀어야 원래의 호출 주소를 구할 수 있습니다.
이동할 대상 = d 라고 하고
call 명령의 다음 4바이트 = i + 1
명령어 주소 = i(상수)
f(i + 1) = d - (i + 5) 에서
구할 주소 d = f(i + 1) + (i + 5)
(단, f(x)=*x 로 정의한다.)
한번 맞나 볼까요 ㅇ_ㅇ?
call 명령의 다음 4바이트+명령어 주소+5=PspTerminateThreadByPointer()
0xfffffc28+0x805c9773+5=0x805c93a0=PspTerminateThreadByPointer()
정확히 맞아 떨어졌습니다.
이제, 그에 따라 함수를 구현해 보면 이렇습니다.
PVOID PspDumpPspTerminateThreadByPointer()
{
PVOID PspTerminateThreadByPointer;
PVOID InstructionPointer=MmFindAddressIncludeInstructionCodeBytes(
(PVOID)PsTerminateSystemThread,
"\xe8\x28\xfc\xff\xff", //call PspTerminateThreadByPointer
5,
0x100); //Proc Length = 0x2D!
DbgPrint("InstructionPointer 0x%p", InstructionPointer);
//이동할 대상 = dest
//call 명령의 다음 4바이트 = inst + 1
//명령어 주소 = inst(상수)
//f(inst + 1) = dest - (inst + 5)
//dest = f(inst + 1) + (inst + 5)
//x = dest
//단, f(x)=*x이다.
if(MmIsAddressValid(InstructionPointer))
{
//call 명령의 다음 4바이트+명령어 주소+5=PspTerminateThreadByPointer()
//0xfffffc28+0x805c9773+5=((0x805c9773+5)-0x000003d7)-1=0x805c93a0
//PspTerminateThreadByPointer=0x805c93a0
DbgPrint("Call(=0xE8) Next 4 Bytes : 0x%p", *(PULONG)((PUCHAR)InstructionPointer+1));
DbgPrint("Address Of InstructionPointer+5 0x%p", (ULONG)InstructionPointer+5);
PspTerminateThreadByPointer=
(PVOID)(*(PULONG)((PUCHAR)InstructionPointer+1)+(ULONG)InstructionPointer+5);
if(MmIsAddressValid(PspTerminateThreadByPointer))
{
DbgPrint("Found PspTerminateThreadByPointer at Address 0x%p", PspTerminateThreadByPointer);
return PspTerminateThreadByPointer;
}
}
return NULL;
}
※ 위의 함수는 Windows XP SP2 에서만 테스트 되었으므로, 다른 운영체제에서는 동작하지 않을 수 있다는 단점이 있습니다.