Programming/Kernel / Driver2008. 12. 3. 11:02

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 에서만 테스트 되었으므로, 다른 운영체제에서는 동작하지 않을 수 있다는 단점이 있습니다.

Posted by skensita