📄 vxdmon.asm
字号:
;****************************************************************************
; *
; VXDMHLP *
; *
; Copyright (c) 1996 Bryce Cogswell and Mark Russinovich *
; All rights reserved *
; *
;****************************************************************************
; *
; VXDMHLP: Monitors entry and exit of VxDs. *
; *
;****************************************************************************
;===========================================================================
page ,132
title VXDMHLP - VXDMHLP VxD
name VXDMHLP.vxd
;===========================================================================
;
; Module:
; Contains everything
;
;===========================================================================
;
; Functional Description: -
;
;
;
;============================================================================
;============================================================================
; I N C L U D E S
;============================================================================
.386p
.xlist
include vmm.inc
include vwin32.inc
include debug.inc
; for message box
include shell.inc
; for testing
include vcache.inc
.list
include VXDMON.inc
;============================================================================
; MACROS
;============================================================================
;============================================================================
; P U B L I C D A T A
;============================================================================
VXD_LOCKED_DATA_SEG
; flags for stats operations
UPDATESTATS EQU 1
ZEROSTATS EQU 2
UPDATEZEROSTATS EQU 3
myRDTSC MACRO
db 0Fh, 31h ; rdtsc
nop ; pad to 4 bytes long
nop ; pad to 4 bytes long
ENDM
; -------------------------------------------------------------------------
; Jump table for commands initiated by Devmon Windows program
; -------------------------------------------------------------------------
Service_Table label dword
dd offset32 ioctl_closehandle
dd offset32 ioctl_getversion
dd offset32 ioctl_getstats
dd offset32 ioctl_getzerostats
dd offset32 ioctl_zerostats
dd offset32 ioctl_hookservice
dd offset32 ioctl_unhookservice
dd offset32 ioctl_getoverhead
Service_Table_Size EQU ($ - Service_Table) / 4
; -------------------------------------------------------------------------
; This points to the most recently called service.
; -------------------------------------------------------------------------
; max call stack depth
MRUMaxStack EQU 32
; max amount by which we expect stack to grow during VxD calls
MRUMaxLocalStack EQU 512
; size of this structure must be power of 2
MRUService STRUC
MRU_Ordinal DD ?
MRU_SP DD ?
MRUService ENDS
; call stack
MRUStack MRUService MRUMaxStack dup (<?>)
; current call stack pointer
MRUStackPtr DD 0
; indicates if error on exit
FixRetErr DD 0
; -------------------------------------------------------------------------
; Use this to track error conditions
; -------------------------------------------------------------------------
IoctlError DD 0
; -------------------------------------------------------------------------
; This template defines the structure we allocate for each hooked service.
; It is customized for a particular service upon creation.
;
; We provide labels for all relocatable addresses so that we can adjust
; them when the template is instantiated.
; -------------------------------------------------------------------------
HookTemplate:
ServiceStats <0,0,0,0,0,0,0>
HookTemplatePrevHooker dd ?
HookTemplatePrevPtr EQU offset32 $ + 4 - offset32 HookTemplate
BeginProc HookTemplateProc, Hook_Proc HookTemplatePrevHooker
call MonEnter
HookTemplateMonEnter EQU offset32 $ - offset32 HookTemplate - 4
jmp [HookTemplatePrevHooker]
HookTemplatePrevHookerJmp EQU offset32 $ - offset32 HookTemplate - 4
EndProc HookTemplateProc
align 4
HookTemplateEnd:
HookTemplateLen EQU (offset32 HookTemplateEnd - offset32 HookTemplate)
MaxHooks EQU 2000
MaxPages EQU ((HookTemplateLen * MaxHooks + 4095) / 4096)
HookTable dd 0
HookFree dd 0
HookUsed dd 0
; -------------------------------------------------------------------------
; This template defines the structure we allocate to capture when a service
; returns. It is customized for a particular service at the time the
; service is invoked.
; -------------------------------------------------------------------------
RetTemplate:
call MonExit
RetTemplateHooker EQU (offset32 $ - offset32 RetTemplate)
dd 0 ; pointer to hooker structure
RetTemplateOrigAddr EQU (offset32 $ - offset32 RetTemplate)
dd 0 ; original return address
RetTemplateSP EQU (offset32 $ - offset32 RetTemplate)
dd 0 ; pointer to return address on stack
RetTemplateTime EQU (offset32 $ - offset32 RetTemplate)
dd 0
dd 0
RetTemplateEnd:
MaxReturn EQU 400
RetTemplateLen EQU (offset32 RetTemplateEnd - offset32 RetTemplate)
RetTableSize EQU (MaxReturn * RetTemplateLen)
ReturnTable db (MaxReturn * RetTemplateLen) dup (?)
ReturnFree dd offset32 ReturnTable
VXD_LOCKED_DATA_ENDS
;============================================================================
; D E V I C E D E C L A R A T I O N
;============================================================================
VXD_LOCKED_CODE_SEG
DECLARE_VIRTUAL_DEVICE VXDMHLP, \
VXDMHLP_MAJOR_VERSION, \
VXDMHLP_MINOR_VERSION, \
VXDMHLP_Control, , \
UNDEFINED_INIT_ORDER
;============================================================================
; M A I N C O D E
;============================================================================
; -------------------------------------------------------------------------
; Called each time a service is invoked.
; -------------------------------------------------------------------------
BeginProc MonEnter
pushfd
; disable interrupts so our timing computations aren't corrupted
cli
push esi
push edi
push eax
push edx
; get pointer to hook structure
mov esi, [esp+20] ; get return address
sub esi, HookTemplateMonEnter + 4
; increment entry count
inc [esi].SS_Enter
; allocate a return structure to replace original return with
mov eax, [ReturnFree] ; get location of return function
mov edi, [eax].RetTemplateHooker ; get location of next on list
mov [ReturnFree], edi ; update pointer to first on list
; change return address to point to us, fetch original return address
mov edi, eax ; copy pointer to return structure
xchg [esp+24], eax ; store new return address, fetch old
; save original return address
mov [edi].RetTemplateOrigAddr, eax
; store service hooker address
mov [edi].RetTemplateHooker, esi
; save address of return address on stack
lea eax, [esp+24]
mov [edi].RetTemplateSP, eax
; do stuff for recording callers/callees
call MRUEnter
; update time spent in function (do as late as possible)
rdts1: myRDTSC ; edx:eax = rdtsc
mov [edi].RetTemplateTime, eax ; store time low
mov [edi].RetTemplateTime+4, edx ; store time high
pop edx
pop eax
pop edi
pop esi
popfd
ret
EndProc MonEnter
; -------------------------------------------------------------------------
; Called each time a service returns from invocation.
; -------------------------------------------------------------------------
BeginProc MonExit
pushfd
push esi
push edi
push eax
push edx
; disable interrupts so our timing computations aren't corrupted
cli
; get pointer to original structure
mov edi, [esp+20] ; return address
sub edi, RetTemplateHooker ; point to front of return template
mov esi, [edi].RetTemplateHooker ; get hooker structure pointer
; update time spent in function (do as early as possible)
rdts2: myRDTSC ; edx:eax = rdtsc
sub eax, [edi].RetTemplateTime
sbb edx, [edi].RetTemplateTime+4
add [esi].SS_TimeLo, eax ; add time low
adc [esi].SS_TimeHi, edx ; add time high
; replace our return address with original
mov edx, [edi].RetTemplateOrigAddr
mov [esp+20], edx ; replace return address
; increment exit count
inc [esi].SS_Exit
; make return address structure available to someone else
xor edx, edx
mov [edi].RetTemplateSP, edx ; mark as unused
mov edx, [ReturnFree] ; get base list pointer
mov [edi].RetTemplateHooker, edx ; set link pointer to base
; now finalize freeing the structure
mov [ReturnFree], edi ; set base list pointer to ours
; do stuff for recording callers/callees
call MRUExit
pop edx
pop eax
pop edi
pop esi
popfd
ret
EndProc MonExit
BeginProc MRUEnter
; if stack is currently empty, only put us on it
mov eax, MRUStackPtr
or eax, eax
jz mru_enter_reset
; ensure we're using same stack as MRU
; check if esp is larger than last
add eax, offset32 MRUStack - size MRUService
mov edx, [eax].MRU_SP
sub edx, esp
je mru_enter_reset
; check if esp is much smaller than last
cmp edx, MRUMaxLocalStack
jg mru_enter_reset
; indicate that we were called by MRU service
mov edx, [esi].SS_CallerPtr ; get position to save caller
push [eax].MRU_Ordinal ; get last called service
pop [esi+edx*4].SS_Caller ; save caller
inc edx
and edx, CALLER_CNT-1
mov [esi].SS_CallerPtr, edx ; update caller pointer
; update MRU call stack
mov edx, [esi].SS_Ordinal
mov [eax+size MRUService].MRU_Ordinal, edx
mov [eax+size MRUService].MRU_SP, esp
; update stack pointer location
sub eax, offset32 MRUStack - 2 * size MRUService
and eax, (MRUMaxStack-1) * size MRUService
mov MRUStackPtr, eax
; all done
ret
mru_enter_reset:
; reset mru stack to be empty
mov eax, size MRUService
mov MRUStackPtr, eax
; make us the only thing on the stack
mov edx, [esi].SS_Ordinal
mov MRUStack.MRU_Ordinal, edx
mov MRUStack.MRU_SP, esp
; all done
ret
EndProc MRUEnter
BeginProc MRUExit
; get pointer to top item on call stack
mov eax, MRUStackPtr ; eax = last stack entry
or eax, eax
jz mru_exit_empty ; stack is empty
; ensure that it is us
sub eax, size MRUService ; back down to previous item
mov edx, [MRUStack+eax].MRU_Ordinal
cmp [esi].SS_Ordinal, edx
jne mru_exit_reset ; who knows how we got here?
; update stack pointer location
mov MRUStackPtr, eax
; all done
ret
mru_exit_reset:
xor eax, eax
mov MRUStackPtr, eax
mru_exit_empty:
; all done
ret
EndProc MRUExit
; -------------------------------------------------------------------------
; Initialize the linked list of hooks for hooked services.
; These are created using the HookTemplate.
; -------------------------------------------------------------------------
BeginProc InitHookTable
; Allocate space for hook functions and statistics.
; We initialize enough memory to hook tons of services, but
; lock only the portion we need, allowing most to be paged out.
VMMcall _PageAllocate, <MaxPages, PG_SYS, 0, 0, 0, 0, 0, PAGEZEROINIT>
mov [HookTable], eax ; save table pointer
mov edi, eax
mov [HookFree], edi ; set pointer to first
lea esi, HookTemplate
mov ecx, MaxHooks
sub eax, esi
cld
init_hook_loop:
mov edx, ecx
; Copy template
mov ecx, HookTemplateLen
rep movsb
sub esi, HookTemplateLen
; Fix up relocatable items
mov [edi-HookTemplateLen].SS_Next, edi ; set pointer to next
sub [edi-HookTemplateLen].HookTemplateMonEnter, eax
add [edi-HookTemplateLen].HookTemplatePrevHookerJmp, eax
add [edi-HookTemplateLen].HookTemplatePrevPtr, eax
add eax, HookTemplateLen
mov ecx, edx
loop init_hook_loop
xor ecx, ecx
mov [edi-HookTemplateLen].SS_Next, ecx ; set pointer to next
ret
EndProc InitHookTable
; -------------------------------------------------------------------------
; Initialize the linked list of return points for invoked functions.
; These are created using the RetTemplate.
; -------------------------------------------------------------------------
BeginProc InitReturnTable
lea edi, ReturnTable
mov [ReturnFree], edi ; set pointer to first
lea esi, RetTemplate
mov ecx, MaxReturn
mov eax, offset32 ReturnTable - offset32 RetTemplate
cld
init_return_loop:
mov edx, ecx
mov ecx, RetTemplateLen
rep movsb
sub esi, RetTemplateLen
mov [edi-RetTemplateLen+RetTemplateHooker], edi ; set pointer to next
sub [edi-RetTemplateLen+RetTemplateHooker-4], eax ; adjust call address
add eax, RetTemplateLen
mov ecx, edx
loop init_return_loop
xor ecx, ecx
mov [edi-RetTemplateLen+RetTemplateHooker], ecx ; set pointer to next
ret
EndProc InitReturnTable
;============================================================================
;
; VXDMHLP_Control - Device control procedure for the VxD. Dispatches all
; Windows VxD messages.
;
; Exit: If carry clear then
; Successful
; else
; Control call failed
;
; Destroys: EAX, EBX, ECX, EDX, ESI, EDI, Flags
;
;============================================================================
public VXDMHLP_Control
VXDMHLP_Control PROC NEAR
Control_Dispatch SYS_DYNAMIC_DEVICE_INIT, VXDMHLP_Device_Init
Control_Dispatch SYS_DYNAMIC_DEVICE_EXIT, VXDMHLP_Device_Exit
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -