%include "ntice.inc"
%include "ntddk.inc"

	BITS    32

PatchData istruc NTIcedumpHdr
	at NTIcedumpHdr.ID,		db NTICEDUMP_ID		; speaks for itself
	at NTIcedumpHdr.Len,		dw PATCH_HEADER_SIZE	; header size
	at NTIcedumpHdr.PatchVer,	dw 0100h		; nticedump patcher version
	at NTIcedumpHdr.Ver,		dd NTICEDUMP_BUILD	; nticedump version
	at NTIcedumpHdr.SiVer,		dd NTICE_VERSION	; target SoftICE version
	at NTIcedumpHdr.VA,		dd Init      		; RVA of Call to Init
iend
; insert any extra data here
; i.e. Credits string
; but keep below 64k =)
	db 'IceDump ',VERSION_TO_ASCII(NTICEDUMP_BUILD),' for NTICE ',VERSION_TO_ASCII(NTICE_VERSION),0
.End:

PATCH_HEADER_SIZE EQU (PatchData.End - PatchData)
%assign PATCH_ORIGIN_ADJUSTED (PAGEIN_PATCH_ORIGIN - PATCH_HEADER_SIZE)


	ORG PATCH_ORIGIN_ADJUSTED

;-------------------------------------------------------------------------------
; Init will be called by NT. Takes 2 DWORDS as params. This call is
; responsible with the debug extension vector init, as well as "normal"
; NTICE initialization. It will replace original DriverEntry. The PE entry
; point will be set to point to this routine.
;-------------------------------------------------------------------------------
Init:
%if      NTICE_VERSION = 0x322 || NTICE_VERSION = 0x323

	call	.delta322
.delta322:
	pop	eax
	sub	eax, .delta322
	lea	ecx, [eax+Init]
	push	ecx
	pop	dword [eax+SELF_REF]
%endif					; END 322 & 323 specific initialization patches

	push	dword [esp+8]		; push pRegistryPath
	push	dword [esp+8]		; push pDriverObject
	call	pNticeInit		; call NticeDeviceInit
	test	eax, eax		; EAX = STATUS_SUCCESS ?
	jl	near .return		; nope, branch error

	pushad				; save'em all

	call	.delta
.delta:
	pop	ebp			; EBP: Current Address
	sub	ebp, .delta		; 

.fixups:
	mov	ecx, MaxSrv		; initialize loop count
	lea	edi, [ebp+tInternalApiTable]	; EDI: pointer to internal API table

.next_service:
	add	dword [edi], ebp	; perform fixup
	add	edi, byte 4		; advance to next slot
	loop	.next_service		; more API's ?

.get_ntoskrnl_ptrs:
	lea	edi, [ebp+CallTable]	; EBX: pointer to Call Table
	lea	esi, [ebp+tImportNameTable]	; ESI: pointer to API Names
	mov	ecx, MaxImportId	; intialize loop count

.next_api:
	call	pExpression2Integer	; return EAX: API virtual address
	jb	.exit			; Fail extension commands initialization on error

	stosd				; store API pointer in Call table
	inc	esi			; step to next string
	loop	.next_api

.apply_patches:
	mov	ebx, cr0		; EBX: CR0
	push	ebx			; save it for later use
	btr	ebx, 16			; Clear Write Protect bit
	mov	cr0, ebx

	mov	byte  [ebp+CRS_END], 0xC3	; patch retn
	mov	byte  [ebp+PAGEIN_CMDLINE], 0xBE	; patch mov esi, imm32
	mov	dword [ebp+PAGEIN_PARSER+1], Parser - PAGEIN_PARSER - 5
	mov	dword [ebp+PCI_VENDORS], -1
	lea	eax,  [ebp+Init]
	mov	dword [ebp+dIGNOREFAULTS1], eax	; let ntoskrnl
	lea	eax,  [ebp+End]			; handle faults
	mov	dword [ebp+dIGNOREFAULTS2], eax	; in this range

; hook pINT3_CleanupForPAGEIN
	lea	eax,[ebp+pINT3_CleanupForPAGEIN+0x18]	; call pMemcopy
	lea	ebx,[ebp+HookCleanupForPAGEIN-4]
	sub	ebx,eax
	mov	[eax],ebx

	pop	ebx
	mov	cr0, ebx			;revert CR0 to normal state

.hook_idt:
	mov	dl, 0x60			; Interrupt Gate DPL = 3
	lea	edi, [ebp+Icall_handler]	; handler EIP = Icall_handler
	mov	eax, 0xFF			; target vector 0xFF
	call	pHookInt_IDT			; Hook IDT

.exit:
	popad					; restore all registers

.return:
	retn	8 ; return to OS (__stdcall always assumed for DriverEntry )


;-------------------------------------------------------------------------------
;
;-------------------------------------------------------------------------------

Parser:
	pushad
	call	.delta
.delta:
	pop	ebp
	sub	ebp, .delta

	call	pSaveRegs		; save client State
	call	pSkipWord		; skip over PAGEIN
	jb	Parse_Help

	lodsb
	and	al, 0x5F		; toupper
	cmp	al, 'D'
	jz	near Parse_Dump

	cmp	al, 'S'
	jz	Parse_Suspend

	cmp	al, 'R'
	jz	Parse_Resume

	cmp	al, 'B'
	jz	Parse_Bhrama

	cmp	al, 'L'
	jz	near Parse_Load

	cmp	al, 'N'
	jz	near Parse_ScreenDump

	jmp	short Parse_Help

.error:
	push	ebx
	call	pPrintErrorToCommandWindow

.exit:
	call	pRestoreRegs		; restore client state
	popad
	retn

Parse_Help:
	lea	ebx, [ebp+help_d]
	push	ebx
	call	pPrintErrorToCommandWindow

	lea	ebx, [ebp+help_s]
	push	ebx
	call	pPrintErrorToCommandWindow

	lea	ebx, [ebp+help_r]
	push	ebx
	call	pPrintErrorToCommandWindow

	lea	ebx, [ebp+help_b]
	push	ebx
	call	pPrintErrorToCommandWindow

	lea	ebx, [ebp+help_l]
	push	ebx
	call	pPrintErrorToCommandWindow

	lea	ebx, [ebp+help_v]
	push	ebx
	call	pPrintErrorToCommandWindow

	jmp	short Parser.exit

Parse_Suspend:
;	mov	dword [ebp+dClient_EAX], Srv_Suspend
	lea	ebx, [ebp+nim_err]
	jmp	Parser.error

Parse_Resume:
;	mov	dword [ebp+dClient_EAX], Srv_Resume
	lea	ebx , [ebp+nim_err]
	jmp	Parser.error

Parse_Bhrama:
	lea	ebx,[ebp+Error_V86]
	test	byte [ebp+dClient_EFLAGS+2],2	; is client in V86 mode?
	jnz	near Parser.error

	lea	ebx,[ebp+Error_PM16]
	lar	eax,[ebp+dClient_CS]		; is client 32 bit?
	bt	eax,22
	jnc	near Parser.error

	lea	ebx,[ebp+Error_PMR0]
	test	byte [ebp+dClient_CS],3		; is client in ring-0?
	jz	near Parser.error

	lea	ebx,[ebp+Error_NoWnd]
	call	pSkipWhiteSpace
	jz	near Parser.error

	call	GetAPIs
	lea	ebx,[ebp+Error_API]
	jc	near Parser.error

	mov	ebx,cr0
	push	ebx
	btr	ebx,16
	mov	cr0,ebx

	mov	eax,[ebp+dClient_EIP]		; use current EIP
	mov	[ebp+Bhrama_Struc+BhramaComStruc.EIP],eax

	mov	edi,esi
	mov	ecx,-1
	xor	eax,eax
	repnz	scasb
	sub	edi,esi
	mov	ecx,edi	
	lea	edi,[ebp+Procdump.WindowName]
	rep	movsb
	stosb

	lea	esi,[ebp+Procdump]
	mov	ecx,Bhrama_Struc.end-Procdump
	call	CopyToUserLand
	or	eax,eax
	jnz	.1

	pop	ebx
	mov	cr0,ebx
	lea	ebx,[ebp+Error_NoUser]
	jmp	Parser.error

.1:
	mov	[ebp+dClient_EBP],eax
	mov	[ebp+dClient_EIP],eax	; set client (E)IP
	mov	[ebp+dClient_ESP],eax	; set client (E)SP
	sub	dword [ebp+dClient_ESP],byte 4
	mov	[ebp+oPAGEIN_INT3],eax	; set address of final INT3
	add	dword [ebp+oPAGEIN_INT3],byte Procdump.return-Procdump

	mov	ebx,[ebp+API.oGetCurrentProcessID]
	mov	[eax+Procdump.oGetCurrentProcessID-Procdump-4],ebx
	sub	[eax+Procdump.oGetCurrentProcessID-Procdump-4],eax
	sub	dword [eax+Procdump.oGetCurrentProcessID-Procdump-4],byte Procdump.oGetCurrentProcessID-Procdump

	mov	ebx,[ebp+API.oFindWindowA]
	mov	[eax+Procdump.oFindWindowA-Procdump-4],ebx
	sub	[eax+Procdump.oFindWindowA-Procdump-4],eax
	sub	dword [eax+Procdump.oFindWindowA-Procdump-4],byte Procdump.oFindWindowA-Procdump

	mov	ebx,[ebp+API.oSendMessageA]
	mov	[eax+Procdump.oSendMessageA-Procdump-4],ebx
	sub	[eax+Procdump.oSendMessageA-Procdump-4],eax
	sub	dword [eax+Procdump.oSendMessageA-Procdump-4],byte Procdump.oSendMessageA-Procdump

	mov	[eax+Procdump.DataPointer-Procdump],eax
	add	dword [eax+Procdump.DataPointer-Procdump],byte Bhrama_Struc-Procdump

	lea	eax,[eax+Procdump.WindowName-Procdump]
	mov	[ebp+dClient_ESI],eax		; bhrama server's window name

	pop	ebx
	mov	cr0,ebx

	xor	eax,eax
	inc	eax

	mov	[ebp+fPAGEIN_InProgress],eax	; set internal Winice flag to 1
	mov	[ebp+fExecuteMoreCommands],ah	; set internal Winice flag to 0

	popad
	retn


; ------------------------------------------------------------------------------
; this is where we call Procdump based on Stone's example
;
; ebp: linear address of Procdump on client stack
; esi: Bhrama window name
; ------------------------------------------------------------------------------
	align 4
Procdump:
	call	.oGetCurrentProcessID
.oGetCurrentProcessID:

	mov	[ebp+Bhrama_Struc+BhramaComStruc.PID-Procdump],eax
;	mov	[Bhrama_Struc+BhramaComStruc.EIP],0x0
;	mov	[Bhrama_Struc+BhramaComStruc.OptL1],0x00000000
;	mov	[Bhrama_Struc+BhramaComStruc.OptL2],0x01000001
;	mov	[Bhrama_Struc+BhramaComStruc.OptL3],0x01010001
;	mov	[Bhrama_Struc+BhramaComStruc.OptL4],0x00010000
;	mov	[Bhrama_Struc+BhramaComStruc.OptL5],0x00000000

; LookUp for ProcDump Server.
	push	esi
	push	byte 0
	call	.oFindWindowA
.oFindWindowA:

	test	eax,eax
	jz	.return

; Send Dump Message to ProcDump Server.
.sendmsg:
	add	ebp,byte .Service-Procdump
	push	ebp
	push	byte 0
	push	byte WM_COPYDATA
	push	eax			; ProcDump's hwnd
	call	.oSendMessageA
.oSendMessageA:

.return:
	int3


	align 4
.WindowName:	times 64 db 0

	align 4
.Service:	dd 1
.DataLength:	dd BhramaComStruc_size
.DataPointer:	dd Bhrama_Struc

Bhrama_Struc:
istruc BhramaComStruc
  at BhramaComStruc.version,	dd 3
  at BhramaComStruc.PID,	dd 0
  at BhramaComStruc.EIP,	dd 0
  at BhramaComStruc.OptL1,	dd 0x00000000
  at BhramaComStruc.OptL2,	dd 0x01000101
  at BhramaComStruc.OptL3,	dd 0x01010001
  at BhramaComStruc.OptL4,	dd 0x00030000
  at BhramaComStruc.OptL5,	dd 0x00000000
iend
.end:


Parse_ScreenDump:
	call	pSkipWhiteSpace
	jz	Parser.exit


Parse_Dump:
	call	pSkipWhiteSpace
	jz	.set_pth_mode

	lea	ebx, [ebp+evl_err]
	call	pExpression2Integer	; Parse address
	jb	near Parser.error

	mov	[ebp+dClient_EDI], eax	; store address in Client_EDI
	mov	dword [ebp+dClient_EAX], Srv_Dump	; srv code goes in EAX
	call	pSkipWhiteSpace
	jz	.emulate		; emulate old PAGEIN behaviour

	call	pExpression2Integer	; Parse Length
	jb	near Parser.error

	call	pSkipWhiteSpace		; advance to filename
	jnz	.cont			; ESI: pointer to file name

	jmp	Parser.exit

.set_pth_mode:
	xor	byte [ebp+PathMode], 1
	lea	ebx, [ebp+msg_p0]
	jnz	.on

	lea	ebx, [ebp+msg_p1]
.on:
	jmp	Parser.error

.emulate:
	xor	eax, eax		; Zero length
	xor	esi, esi		; No file name
	jmp	.exprt_mode

.cont:
	cmp	byte [ebp+PathMode], 1
	jz	.exprt_mode
	sub	esi, 4
	mov	dword [esi], '\??\'

.exprt_mode:
	mov	[ebp+dClient_ESI], esi	; pointer to filename
	mov	[ebp+dClient_ECX], eax	; store length
	call	CanResume		; are we allowed to play the game ?

	test	byte [ebp+dClient_CS], 3	; ring-0 Client ?
	jz	near .ring0

	mov	ecx, EntryPoint.end - EntryPoint; number of bytes to copy
	push	ecx

	lea	eax, [ebp+EntryPoint]		; EAX: source
	push	eax

	test	byte [ebp+dClient_EFLAGS+2], 2	; V86 mode client?
	jz	.PM

	mov	eax,cr4
	test	eax,1				; CR4.VME
	jz	.set_iopl

	str	ax
	call	pMapSelectorToLinAddr
	jnc	.set_redirection

	lea	ebx, [ebp+tss_err]
	push	ebx
	call	pPrintErrorToCommandWindow
	jmp	Parser.exit

.set_redirection:
	movzx	edi, word [eax+0x66]		; start of i/o perm map
	lea	edi, [edi+eax-0x20]		; start of int redir map
	mov	eax, 0xFF			; our interrupt
	bts	[edi], eax			; no redirection to V86 handler

.set_iopl:
	mov	eax, [ebp+dClient_EFLAGS]		; save IOPL
	mov	[ebp+dClient_EBX], eax
	or	byte [ebp+dClient_EFLAGS+1], 0x30	; IOPL=3

	movzx	eax, word [ebp+dClient_SS]
	mov	[ebp+dClient_CS], eax		; set new client CS
	shl	eax, 4
	movzx	edi, word [ebp+dClient_ESP]
	sub	edi, ecx			; bug, should handle underflow
	add	eax, edi
	push	eax
	jmp	short .copy

.PM:
	movzx	eax, word [ebp+dClient_SS]
	call	pMapSelectorToLinAddr
	jnc	.got_linaddr

	add	esp, byte 8
	lea	ebx, [ebp+sel_err]
	jmp	Parser.error

.got_linaddr:
	mov	edi, eax
	add	edi, [ebp+dClient_ESP]		; EDI: linear Client ESP
	sub	edi, ecx			; EDI destination ( on client Stack )
	push	edi
	mov	word [ebp+dClient_CS], 0x1B	; set new client CS
	mov	word [ebp+dClient_SS], 0x23	; set new client SS

.copy:
	call	pMemcopy			; memcpy with protection from faults
	lea	ebx, [ebp+stk_err]
	test	eax, eax
	jz	near Parser.error

	mov	ebx, edi			; EBX: new EIP
	lea	eax, [edi+EntryPoint.i3-EntryPoint]; EAX: INT3 location
	mov	[ebp+dClient_ESP], edi		; adjust client stack  
	jmp	short .setup

.ring0:
	lea	eax, [ebp+EntryPoint.i3]	; INT3 location for ring-0 code
	lea	ebx, [ebp+EntryPoint]		; Get EIP

.setup:
	mov	[ebp+oPAGEIN_INT3], eax		; register INT3 location
	mov	[ebp+dClient_EIP], ebx		; set new client EIP
	xor	eax, eax
	inc	eax
	mov	[ebp+fPAGEIN_InProgress], eax	; set PAGEIN internal var
	mov	[ebp+fExecuteMoreCommands], ah	; leave ntice	
	popad
	retn

PathMode:	db 1


Parse_Load:
	call	pSkipWhiteSpace
	jz	.set_pth_mode

	lea	ebx, [ebp+evl_err]
	call	pExpression2Integer	; Parse address
	jb	near Parser.error

	mov	[ebp+dClient_EDI], eax	; store address in Client_EDI
	mov	dword [ebp+dClient_EAX], Srv_Load	; srv code goes in EAX
	call	pSkipWhiteSpace
	jz	near Parser.error

	call	pExpression2Integer	; Parse Length
	jb	near Parser.error

	call	pSkipWhiteSpace		; advance to filename
	jnz	.cont			; ESI: pointer to file name

	jmp	Parser.exit

.set_pth_mode:
	xor	byte [ebp+PathMode], 1
	lea	ebx, [ebp+msg_p0]
	jnz	.on

	lea	ebx, [ebp+msg_p1]
.on:
	jmp	Parser.error

.cont:
	cmp	byte [ebp+PathMode], 1
	jz	.exprt_mode

	sub	esi, 4
	mov	dword [esi], '\??\'

.exprt_mode:
	mov	[ebp+dClient_ESI], esi	; pointer to filename
	mov	[ebp+dClient_ECX], eax	; store length
	call	CanResume		; are we allowed to play the game ?

	test	byte [ebp+dClient_CS], 3	; ring-0 Client ?
	jz	near .ring0

	mov	ecx, EntryPoint.end - EntryPoint; number of bytes to copy
	push	ecx

	lea	eax, [ebp+EntryPoint]		; EAX: source
	push	eax

	test	byte [ebp+dClient_EFLAGS+2], 2	; V86 mode client?
	jz	.PM

	mov	eax,cr4
	test	eax,1				; CR4.VME
	jz	.set_iopl

	str	ax
	call	pMapSelectorToLinAddr
	jnc	.set_redirection

	lea	ebx, [ebp+tss_err]
	push	ebx
	call	pPrintErrorToCommandWindow
	jmp	Parser.exit

.set_redirection:
	movzx	edi, word [eax+0x66]		; start of i/o perm map
	lea	edi, [edi+eax-0x20]		; start of int redir map
	mov	eax, 0xFF			; our interrupt
	bts	[edi], eax			; no redirection to V86 handler

.set_iopl:
	mov	eax, [ebp+dClient_EFLAGS]		; save IOPL
	mov	[ebp+dClient_EBX], eax
	or	byte [ebp+dClient_EFLAGS+1], 0x30	; IOPL=3

	movzx	eax, word [ebp+dClient_SS]
	mov	[ebp+dClient_CS], eax		; set new client CS
	shl	eax, 4
	movzx	edi, word [ebp+dClient_ESP]
	sub	edi, ecx			; bug, should handle underflow
	add	eax, edi
	push	eax
	jmp	short .copy

.PM:
	movzx	eax, word [ebp+dClient_SS]
	call	pMapSelectorToLinAddr
	jnc	.got_linaddr

	add	esp, byte 8
	lea	ebx, [ebp+sel_err]
	jmp	Parser.error

.got_linaddr:
	mov	edi, eax
	add	edi, [ebp+dClient_ESP]		; EDI: linear Client ESP
	sub	edi, ecx			; EDI destination ( on client Stack )
	push	edi
	mov	word [ebp+dClient_CS], 0x1B	; set new client CS
	mov	word [ebp+dClient_SS], 0x23	; set new client SS

.copy:
	call	pMemcopy			; memcpy with protection from faults
	lea	ebx, [ebp+stk_err]
	test	eax, eax
	jz	near Parser.error

	mov	ebx, edi			; EBX: new EIP
	lea	eax, [edi+EntryPoint.i3-EntryPoint]; EAX: INT3 location
	mov	[ebp+dClient_ESP], edi		; adjust client stack  
	jmp	short .setup

.ring0:
	lea	eax, [ebp+EntryPoint.i3]	; INT3 location for ring-0 code
	lea	ebx, [ebp+EntryPoint]		; Get EIP

.setup:
	mov	[ebp+oPAGEIN_INT3], eax		; register INT3 location
	mov	[ebp+dClient_EIP], ebx		; set new client EIP
	xor	eax, eax
	inc	eax
	mov	[ebp+fPAGEIN_InProgress], eax	; set PAGEIN internal var
	mov	[ebp+fExecuteMoreCommands], ah	; leave ntice	
	popad
	retn


;-------------------------------------------------------------------------------
; Check if we are allowed to tweak client execution. In case of error, it
; will NOT return to the caller.
;-------------------------------------------------------------------------------
CanResume:
	call	pGetIRQLLevel			; Get current IRQL level
	lea	ebx, [ebp+irq_err]
	cmp	eax, byte 2			; IRQL > Dispatch_Level ?
	jnb	.error

	lea	ebx, [ebp+int_err]
	test	byte [ebp+dClient_EFLAGS+1], 2	; interrupts enabled
	jz	.error				; nope, bye

	lea	ebx, [ebp+ctx_err]
	mov	eax, [ebp+dCurrentContext]
	cmp	eax, [ebp+dPopupContext]
	jnz	.error

	retn

.error:
	pop	eax		; Remove return address from stack
	jmp	Parser.error	; and branch command parser exit
				; That's it, return to NTICE, 
				; nothing to be done


;------------------------------------------------------------------------------------ 
; client EAX: service ID
; client EBX: EFLAGS having original IOPL, only for V86 mode
;
; rest is service dependent
;------------------------------------------------------------------------------------ 
EntryPoint:
	int	0xFF		; Initiate an extension call
.i3:
	int3			; Break back in NTICE
.end:

Icall_handler:
	ExceptionFrame2KeTrapFrame HW_ERROR_CODE_OFF, PRIMARY
	call	.delta
.delta:
	pop	esi
	sub	esi, .delta

	test	byte [ebp+KeTrapFrame.EFLAGS+2], 2	; EFLAGS.VM
	jz	.PM

	mov	eax, [ebp+KeTrapFrame.EBX]	; grab EFLAGS
	mov	[ebp+KeTrapFrame.EFLAGS], eax	; restore IOPL

.PM:
	mov	eax, [ebp+KeTrapFrame.EAX]	; grab service ID
	mov	[ebp+KeTrapFrame.EAX], esi	; Save ntice base in the trap frame
	add	esi, tInternalApiTable		; ESI: ptr to extension routines table
	sti
	call	[esi+eax*4]			; call requested service
	cli
	KeTrapFrame2ExceptionFrame HW_ERROR_CODE_ON, PRIMARY
	iretd


;-------------------------------------------------------------------------------
SrvVer:
	retn

;-------------------------------------------------------------------------------
SrvDump:
	mov	eax, ebp			; EAX : trape frame ptr
	push	ebp				; save trape frame ptr		
	sub	esp, 8+8+24+8+4
	mov	ebp, esp
	mov	esi, [eax+KeTrapFrame.EAX]	; 
	lea	edi, [esi+CallTable]		; EDI: ntoskrnl import table	
	cmp	dword [eax+KeTrapFrame.ESI], byte 0	; Do we have a filename ptr ?
	jz	near .emulate			; If no , emulate old PAGEIN 
						; [ebp+52] == Trap frame ptr
						; [ebp+48] == FileHandle			      
						; EBP+40 == IoStatusBlock	                               
						; EBP+16 == Object Attributes
						; EBP+8  == AnsiString
						; EBP == UnicodeString		

	lea	eax, [ebp+16]			; get ptr to Object Attributes
	InitializeObjectAttributes  ebp , dword 0x40 , dword 0 , dword 0
	mov	eax, [ebp+52]			; EAX: ptr Trap frame
	push	dword [eax+KeTrapFrame.ESI]
	lea	eax, [ebp+8]			; OUT PANSI_STRING	
	push	eax
	call	[edi+RtlInitAnsiString]

	push	byte 1				; Allocate Destination String Buffer
	lea	eax, [ebp+8]			; IN PANSI_STRING
	push	eax
	push	ebp				; OUT PUNICODE_STRING
	call	[edi+RtlAnsiStringToUnicodeString]

	push	byte 0
	push	byte 0
	push	dword 0x850			       
	push	byte 5				; FILE_SUPERSEED
	push	byte 0				; no sharing
	push	dword 0x80			; FILE_ATTRIBUTE_NORMAL
	push	byte 0				; allocation size 0
	lea	eax, [ebp+40]			; EAX: PIO_STATUS_BLOCK
	push	eax
	lea	eax, [ebp+16]			; EAX: POBJECT_ATTRIBUTES
	push	eax
	push	dword 0x120116			; Desired Access
	lea	eax, [ebp+48]			; ptr File Handle
	push	eax
	lea	ebx, [esi+opn_err]
	call	[edi+ZwCreateFile]
	test	eax, eax
	jl	.free_string

	push	byte 0				; No KEY
	push	byte 0				; Null File Offset
	mov	eax, [ebp+52]
	push	dword [eax+KeTrapFrame.ECX]	; Length
	push	dword [eax+KeTrapFrame.EDI]	; buffer address
	lea	eax, [ebp+40]			; PIO_STATUS_BLOCK
	push	eax
	push	byte 0				; null APC context 
	push	byte 0				; no APC
	push	byte 0				; no completion Event
	push	dword [ebp+48]			; File handle
	lea	ebx, [esi+wrt_err]
	call	[edi+ZwWriteFile]
	test	eax, eax
	jl	.free_close

	push	ebp
	call	[edi+RtlFreeUnicodeString]	; Free temp unicode storage space

	push	dword [ebp+48]
	call	[edi+ZwClose]			; Close the file
	jmp	short .return

.emulate:
	lea	ebx, [esi+npr_err]
	mov	esi, [ebp+52]			; ESI = ptr trap frame
	mov	esi, [esi+KeTrapFrame.EDI]	; ESI: pagein address    
	push	esi
	call	[edi+MmIsAddressValid]		; check if it is a valid address
	test	al, al
	jz	.error

	mov	eax, [esi]			; touch the page and bring it in

.return:
	add	esp, 8+8+24+8+4
	pop	ebp
	retn					; return to Icall_Handler

.free_close:
	push	dword [ebp+48]
	call	[edi+ZwClose]

.free_string:
	push	ebp
	call	[edi+RtlFreeUnicodeString]

.error:
	push	ebx				; EBX: ptr to error msg
	call	[edi+DbgPrint]			; print error msg 	
	pop	eax				; DbgPrint follows C calling convention
	jmp	short .return


;-------------------------------------------------------------------------------
SrvDumpX:
	retn


;-------------------------------------------------------------------------------
SrvSr:
	retn


;-------------------------------------------------------------------------------
SrvBhr:
	retn


;-------------------------------------------------------------------------------
SrvLoad:
	mov	eax, ebp			; EAX : trape frame ptr
	push	ebp				; save trape frame ptr		
	sub	esp, 8+8+24+8+4
	mov	ebp, esp
	mov	esi, [eax+KeTrapFrame.EAX]
	lea	edi, [esi+CallTable]		; EDI: ntoskrnl import table	

						; [ebp+52] == Trap frame ptr
						; [ebp+48] == FileHandle			      
						; EBP+40 == IoStatusBlock	                               
						; EBP+16 == Object Attributes
						; EBP+8  == AnsiString
						; EBP == UnicodeString		

	lea	eax, [ebp+16]			; get ptr to Object Attributes
	InitializeObjectAttributes  ebp , dword 0x40 , dword 0 , dword 0
	mov	eax, [ebp+52]			; EAX: ptr Trap frame
	push	dword [eax+KeTrapFrame.ESI]
	lea	eax, [ebp+8]			; OUT PANSI_STRING	
	push	eax
	call	[edi+RtlInitAnsiString]

	push	byte 1				; Allocate Destination String Buffer
	lea	eax, [ebp+8]			; IN PANSI_STRING
	push	eax
	push	ebp				; OUT PUNICODE_STRING
	call	[edi+RtlAnsiStringToUnicodeString]

	push	byte 0
	push	byte 0
	push	dword 0x850
	push	byte 1				; FILE_OPEN
	push	byte 1				; share: read
	push	byte 0				; attribs don't apply
	push	byte 0				; allocation size 0
	lea	eax, [ebp+40]			; EAX: PIO_STATUS_BLOCK
	push	eax
	lea	eax, [ebp+16]			; EAX: POBJECT_ATTRIBUTES
	push	eax
	push	dword 0x120109			; Desired Access
	lea	eax, [ebp+48]			; ptr File Handle
	push	eax
	lea	ebx, [esi+opn_err]
	call	[edi+ZwCreateFile]	
	test	eax, eax
	jl	.free_string

	push	byte 0				; No KEY
	push	byte 0				; Null File Offset
	mov	eax, [ebp+52]
	push	dword [eax+KeTrapFrame.ECX]	; Length
	push	dword [eax+KeTrapFrame.EDI]	; buffer address
	lea	eax, [ebp+40]			; PIO_STATUS_BLOCK
	push	eax
	push	byte 0				; null APC context 
	push	byte 0				; no APC
	push	byte 0				; no completion Event
	push	dword [ebp+48]			; File handle
	lea	ebx, [esi+wrt_err]
	call	[edi+ZwReadFile]
	test	eax, eax
	jl	.free_close

	push	ebp
	call	[edi+RtlFreeUnicodeString]	; Free temp unicode storage space

	push	dword [ebp+48]
	call	[edi+ZwClose]			; Close the file

.return:
	add	esp, 8+8+24+8+4
	pop	ebp
	retn					; return to Icall_Handler

.free_close:
	push	dword [ebp+48]
	call	[edi+ZwClose]

.free_string:
	push	ebp
	call	[edi+RtlFreeUnicodeString]

.error:
	push	ebx				; EBX: ptr to error msg
	call	[edi+DbgPrint]			; print error msg 	
	pop	eax				; DbgPrint follows C calling convention
	jmp	short .return


;------------------------------------------------------------------------------
; The following call will be assembled only if target NTICE version is 322,
; which does not have a pGetIrqlLevel in the form we expect. This call can be
; guaranteed as safe only in NT 4.0, since it relies on the hardcoded value of
; KPCR base

%if 	NTICE_VERSION = 0x322

pGetIRQLLevel:
	push	edi
	mov	edi, KPCRSelfPointer+KPCR.Irql
	call	pMOV_AL_EDI_safe
	pop	edi
	jc	.error

	movzx	eax, al
	retn

.error:
	mov	eax, 3
	retn
%endif


;-------------------------------------------------------------------------------
; ecx: amount, esi: dataptr, ebp: ntice base
;
; eax: destination or 0 on error
;-------------------------------------------------------------------------------
CopyToUserLand:
	xor	eax,eax

	cmp	dword [ebp+UserLandBuffer.size],byte 0
	jz	.1

	retn

.1:
	cmp	ecx,SAVEBUFFERSIZE
	jb	.2

	retn

.2:
	push	edi
	mov	edi,[ebp+dClient_ESP]
	and	edi,0xFFFFF000

	call	pMOV_AL_EDI_safe	; is page present?
	jnc	.3

	xor	eax,eax
	pop	edi
	retn

.3:
	mov	[ebp+UserLandBuffer.size],ecx
	mov	[ebp+UserLandBuffer.userptr],edi
	mov	eax,edi			; save 'cos we will return it

	push	ecx
	push	esi

	mov	esi,edi			; save user stack to temporary buffer
	lea	edi,[ebp+UserLandBuffer.data]
	rep	movsb

	pop	esi			; copy data to the user stack
	pop	ecx
	mov	edi,eax
	rep	movsb

	pop	edi
	retn


;-------------------------------------------------------------------------------
; ebp: ntice base
;-------------------------------------------------------------------------------
RestoreUserLand:
	cmp	dword [ebp+UserLandBuffer.size],byte 0
	jnz	.1

	retn

.1:
	push	ecx
	push	esi
	push	edi
	pushfd
	cld

	mov	edi,[ebp+UserLandBuffer.userptr]
	lea	esi,[ebp+UserLandBuffer.data]	; copy data to the user stack
	mov	ecx,[ebp+UserLandBuffer.size]
	rep	movsb

	mov	dword [ebp+UserLandBuffer.size],0
	mov	dword [ebp+UserLandBuffer.userptr],0

	popfd
	pop	edi
	pop	esi
	pop	ecx
	retn


; save buffer, should be smaller than 4k (x86 page size)
SAVEBUFFERSIZE	equ 512
	align 4
UserLandBuffer:
.data:	times SAVEBUFFERSIZE db 0
.size:		dd 0
.userptr:	dd 0


;-------------------------------------------------------------------------------
; call RestoreUserLand while cleanup after a PAGEIN like int3
;-------------------------------------------------------------------------------
HookCleanupForPAGEIN:
	push	ebp
	call	.delta
.delta:
	pop	ebp
	sub	ebp,.delta
	call	RestoreUserLand
	pop	ebp
	jmp	pMemcopy


;-------------------------------------------------------------------------------
; resolve win32 api symbols
;-------------------------------------------------------------------------------
GetAPIs:
	push	esi
	push	ecx
	push	ebx
	push	eax

	or	ecx,byte -1

	mov	ebx,cr0
	push	ebx
	btr	ebx,16
	mov	cr0,ebx

.loop:
	inc	ecx
	cmp	dword [8*ecx+ebp+API+4],byte 0
	jnz	.1

	pop	ebx
	mov	cr0,ebx

	pop	eax
	pop	ebx
	pop	ecx
	pop	esi

	clc
	retn

.1:
	cmp	dword [8*ecx+ebp+API],byte 0
	jnz	.loop

	mov	esi,[8*ecx+ebp+API+4]
	add	esi,ebp
	
	call	pExpression2Integer
	jnb	.2

	pop	ebx
	mov	cr0,ebx

	pop	eax
	pop	ebx
	pop	ecx
	pop	esi

	stc
	retn

.2:
	mov	[8*ecx+ebp+API],eax
	jmp	short .loop


	align 4

API:
.oGetCurrentProcessID:	dd 0, .GetCurrentProcessID
.oFindWindowA:		dd 0, .FindWindowA
.oSendMessageA:		dd 0, .SendMessageA
;.oOpenProcess:		dd 0, .OpenProcess
;.oResumeThread:		dd 0, .ResumeThread
;.oSuspendThread:	dd 0, .SuspendThread
;.oExitThread:		dd 0, .ExitThread
;.oExitProcess:		dd 0, .ExitProcess
;.oTerminateThread:	dd 0, .TerminateThread
;.oTerminateProcess:	dd 0, .TerminateProcess

; null record, do not remove
			dd 0, 0

.GetCurrentProcessID:	db 'GetCurrentProcessID',0
.FindWindowA:		db 'FindWindowA',0
.SendMessageA:		db 'SendMessageA',0
;.OpenProcess:		db 'OpenProcess',0
;.ResumeThread:		db 'ResumeThread',0
;.SuspendThread:		db 'SuspendThread',0
;.ExitThread:		db 'ExitThread',0
;.ExitProcess:		db 'ExitProcess',0
;.TerminateThread:	db 'TerminateThread',0
;.TerminateProcess:	db 'TerminateProcess',0


tImportNameTable: 
	db 'ZwCreateFile',0
	db 'ZwReadFile',0
	db 'ZwWriteFile',0
	db 'ZwClose',0
	db 'RtlAnsiStringToUnicodeString',0
	db 'RtlInitAnsiString',0
	db 'DbgPrint',0
	db 'RtlFreeUnicodeString',0
	db 'MmIsAddressValid',0
	db 'ZwSetInformationFile',0
	db 'KeAttachProcess',0
	db 'KeDetachProcess',0
	db 'KeInitializeDpc',0
	db 'KeInsertQueueDpc',0

tKernel32NameTable:

	align 4
CallTable:	TIMES MaxImportId db 'SRVC'

tInternalApiTable:
	dd	SrvVer			;0 - version
	dd	SrvDump			;1 - dump
	dd	SrvSr			;2 - suspend
	dd	SrvSr			;3 - resume
	dd	SrvBhr			;4 - bhrama
	dd	SrvDumpX		;5 - extended dump
	dd	SrvLoad			;6 - load


;-------------------------------------------------------------------------------
; flag variables
;-------------------------------------------------------------------------------


;-------------------------------------------------------------------------------
; Error strings
;-------------------------------------------------------------------------------
int_err	db 'Interrupts must be enabled to use this extension.',0
irq_err	db 'IRQL must be below DISPATCH_LEVEL to use this extension.',0
stk_err	db 'Cannot use this extension because current thread`s stack is not present.',0
tss_err	db 'Unable to determine TSS base',0
sel_err	db 'Client SS is invalid???',0
ctx_err	db 'Cannot dump from this context. Revert to pop-up context.',0
arg_err	db 'Arguments required.',0
evl_err	db 'Cannot evaluate expression.',0
prc_err	db 'Cannot attach an invalid process. Check KPEB parameter.',0
opn_err	db 'Failed to create output file. Possible reason: wrong path name.',CRLF_0
wrt_err	db 'Failed to dump requested data. Possible reason: invalid memory range.',CRLF_0
npr_err	db 'Page at specified address is either Reserved or Not Committed.',CRLF_0
msg_p0	db 'Path Expert mode is now on',0
msg_p1	db 'Path Expert mode is now off',0
nim_err	db 'Command currently not implemented.',0

Error_V86:	db 'EFLAGS.VM=1, only win32 clients are supported.',0
Error_PM16:	db 'CS.D=0, only win32 clients are supported.',0
Error_PMR0:	db 'CS.DPL=0, only win32 clients are supported.',0
Error_API:	db 'unable to resolve some win32 APIs, check winice.dat.',0
Error_NoID:	db 'specify PID/TID.',0
Error_NoWnd:	db 'specify Bhrama server window name',0
Error_NoUser:	db 'could not copy to user land',0

;-------------------------------------------------------------------------------
; Help strings
;-------------------------------------------------------------------------------
help_d	db 'PAGEIN D <address> [ <length> <filename> ]',0
help_d1	db 'PAGEIN D',0
help_s	db 'PAGEIN S <KTEB>',0
help_r	db 'PAGEIN R <KTEB>',0
help_b	db 'PAGEIN B <Bhrama window name>',0
help_l	db 'PAGEIN L <address> <length> <filename>',0
help_v	db 'nticedump Beta 1 build 0014  http://icedump.tsx.org or http://icedump.cjb.net.',0

End:
