📄 vxdmon.asm
字号:
Control_Dispatch W32_DEVICEIOCONTROL, VXDMHLP_ioctl
clc
ret
VXDMHLP_Control ENDP
;============================================================================
;
; VXDMHLP_ioctl - Respond to IOcontrol messages sent by Win32 program.
;
; Entry: esi -> DIOC block
;
; Exit:
;
;============================================================================
Public VXDMHLP_ioctl
BeginProc VXDMHLP_ioctl
mov IoctlError, VXDMHLP_ERROR_NOSUCHSERVICE
mov ecx,[esi].dwIoControlCode ; get ioctl code
inc ecx ; base is -1
cmp ecx, Service_Table_Size ; out of bounds ?
jae ioctl_failure ; y: bad code, exit
jmp Service_Table[4*ecx] ; index into table
; -------------------------------------------------------------------------
; -------------------------------------------------------------------------
ioctl_closehandle:
; Nothing to do for this
jmp ioctl_success ; exit successfully
; -------------------------------------------------------------------------
; -------------------------------------------------------------------------
ioctl_getversion:
; Nothing to do for this
jmp ioctl_success ; exit successfully
; -------------------------------------------------------------------------
; Get the statistics we've collected for all hooked services
; -------------------------------------------------------------------------
ioctl_zerostats:
mov ebx, ZEROSTATS ; zero the stats, no update
mov edx, [HookUsed]
cld
ioctl_dozero:
; check for end of list
cmp edx, 0
je ioctl_success
; zero volatile statistics
cli
push esi
lea esi, [edx] ; get stats pointer
xor eax, eax
mov [esi].SS_Enter, eax
mov [esi].SS_Exit, eax
mov [esi].SS_TimeLo, eax
mov [esi].SS_TimeHi, eax
sti
pop esi
; move to next service
mov edx, [edx].SS_Next
jmp ioctl_dozero
; get stats with no zero
ioctl_getstats:
mov ebx, UPDATESTATS ; update with no clear
jmp ioctl_scanstats
; get stats and reset
ioctl_getzerostats:
mov ebx, UPDATEZEROSTATS ; update and zero stats
ioctl_scanstats:
; zero current output size
xor eax, eax
mov ecx, [esi].lpcbBytesReturned
mov [ecx], eax
; get pointer to source and destination buffers
mov edx, [HookUsed]
mov edi, [esi].lpvOutBuffer
; iterate over structures in use, copying
cld
ioctl_docopy:
; check for end of list
cmp edx, 0
je ioctl_success
; update size of output and exit if buffer full
mov ecx, [esi].lpcbBytesReturned ; get output size pointer
mov eax, [ecx] ; get current output size
add eax, size ServiceStats ; update total size
cmp eax, [esi].cbOutBuffer ; less than max output size ?
jg ioctl_success
mov [ecx], eax ; update output size
; copy stats to output buffer
push esi
mov ecx, size ServiceStats / 4
lea esi, [edx] ; get stats pointer
cli
rep movsd
test ebx, ZEROSTATS
je nozero
; zero volatile statistics
xor eax, eax
mov [esi - size ServiceStats].SS_Enter, eax
mov [esi - size ServiceStats].SS_Exit, eax
mov [esi - size ServiceStats].SS_TimeLo, eax
mov [esi - size ServiceStats].SS_TimeHi, eax
nozero:
sti
pop esi
; move to next service
mov edx, [edx].SS_Next
jmp ioctl_docopy
; -------------------------------------------------------------------------
; Hook a new service
; -------------------------------------------------------------------------
ioctl_hookservice:
; get ordinal of interest
mov eax, [esi].lpvInBuffer
mov eax, [eax]
internal_hookservice:
; ensure that the vxd is loaded
mov IoctlError, VXDMHLP_ERROR_NOSUCHVXD
mov edx, eax ; save ordinal
shr eax, 16 ; get device id
jz ioctl_failure ; if zero, we lose
VMMCall Get_DDB ; check for DDB
or ecx, ecx
jz ioctl_failure ; if result zero, we lose
mov eax, edx ; restore ordinal
; get a hook structure
mov IoctlError, VXDMHLP_ERROR_OUTOFMEMORY
mov edi, [HookFree]
cmp edi, 0
je ioctl_failure ; no structures available
; Ensure the page containing the structure is locked in memory.
; We rely on the fact that a page can be locked multiple times.
mov IoctlError, VXDMHLP_ERROR_PAGELOCK
push eax
mov eax, edi
shr eax, 12
VMMcall _LinPageLock, <eax, 1, 0>
or eax, eax ; nonzero if locked, zero if error
pop eax
jz ioctl_failure
; fill in service-specific info in structure
mov [edi].SS_Ordinal, eax
xor edx, edx
mov [edi].SS_Enter, edx
mov [edi].SS_Exit, edx
mov [edi].SS_TimeLo, edx
mov [edi].SS_TimeHi, edx
; hook the service
mov IoctlError, VXDMHLP_ERROR_HOOK
push esi
lea esi, [edi +(offset32 HookTemplateProc - offset32 HookTemplate)]
VMMCall Hook_Device_Service
pop esi
jc ioctl_failure
; update pointer to next available structure
mov edx, [edi].SS_Next
mov [HookFree], edx
; add to list of hooked services
mov eax, [HookUsed]
mov [edi].SS_Next, eax
mov [HookUsed], edi
jmp ioctl_success
; -------------------------------------------------------------------------
; Unhook a service
; -------------------------------------------------------------------------
ioctl_unhookservice:
; get ordinal of interest
mov eax, [esi].lpvInBuffer
mov eax, [eax]
internal_unhookservice:
; locate hook structure
lea edx, [HookUsed]
mov edi, [edx]
mov IoctlError, VXDMHLP_ERROR_NOTFOUND
unhooksearch:
cmp edi, 0
je ioctl_failure
cmp [edi].SS_Ordinal, eax
je unhookfound
lea edx, [edi].SS_Next
mov edi, [edx]
jmp unhooksearch
unhookfound:
; unhook service
mov IoctlError, VXDMHLP_ERROR_UNHOOK
push esi
lea esi, [edi +(offset32 HookTemplateProc - offset32 HookTemplate)]
VMMCall Unhook_Device_Service
pop esi
jc ioctl_failure
; remove from list of used hook structures
mov eax, [edi].SS_Next
mov [edx], eax
; add to list of free hook structures
mov eax, [HookFree]
mov [edi].SS_Next, eax
mov [HookFree], edi
jmp ioctl_success
; -------------------------------------------------------------------------
; Compute monitoring overhead
; -------------------------------------------------------------------------
ioctl_getoverhead:
push esi
; save current time
rdts3: myRDTSC ; edx:eax = rdtsc
push eax
; call Get_VMM_Version 128 times
mov esi, 128
unhooked_time_loop:
VxDCall Get_VMM_Version
dec esi
jnz unhooked_time_loop
; save current time
rdts4: myRDTSC ; edx:eax = rdtsc
push eax
; hook Get_VMM_Version. This should always be possible.
GetVxDServiceOrdinal eax, Get_VMM_Version
call internal_hookservice
jc ioctl_failure
; call it 128 times
mov esi, 128
hooked_time_loop:
VxDCall Get_VMM_Version
dec esi
jnz hooked_time_loop
; get the time we've recorded
lea edx, [HookUsed]
mov edi, [edx]
ovrsearch:
cmp [edi].SS_Ordinal, 10000h
je ovrfound
lea edx, [edi].SS_Next
mov edi, [edx]
jmp ovrsearch
ovrfound:
pushd 0
mov eax, [edi].SS_TimeLo
push eax
; unhook it
GetVxDServiceOrdinal eax, Get_VMM_Version
call internal_unhookservice
; now compute the time difference, overhead = (t4-t3)-(t2-t1)
mov eax, [esp]
sub eax, [esp+4]
sub eax, [esp+8]
add eax, [esp+12]
add esp, 4*4
; eax now contains the overhead for 128 calls
shr eax, 7
; save overhead per call
pop esi
mov edx, [esi].lpvOutBuffer
mov [edx], eax
; set size of output buffer
mov edx, [esi].lpcbBytesReturned ; get output size pointer
mov eax, 4
mov [edx], eax
jmp ioctl_success
ioctl_success:
xor eax, eax ; return zero = success
clc
ret
ioctl_failure:
mov eax, IoctlError
stc
ret
EndProc VXDMHLP_ioctl
;============================================================================
;
; VXDMHLP_Device_Exit - Cleans up any hooks that are still installed before
; exiting.
;
;============================================================================
Public VXDMHLP_Device_Exit
BeginProc VXDMHLP_Device_Exit
; clear error condition
mov FixRetErr, 0
; iterate until no more services are hooked
unhookall_loop:
mov edi, [HookUsed]
; check for end of list
cmp edi, 0
je unhookall_done
; unhook the service
mov eax, [edi].SS_Ordinal
call internal_unhookservice
jnc unhookall_loop
cmp IoctlError, VXDMHLP_ERROR_UNHOOK
jne unhookdel
; major error - can't unload
mov FixRetErr, 1
unhookdel:
; It wasn't found on the list. Just delete it and move on.
mov eax, [HookUsed]
mov eax, [edi].SS_Next
mov [HookUsed], eax
jmp unhookall_loop
unhookall_done:
; Locate all VxD calls that haven't yet returned, and change their
; stack so they return to their original callers instead of MonExit.
lea edi, ReturnTable
mov ecx, MaxReturn
fixret_loop:
; iterate over return structures
mov eax, [edi].RetTemplateSP ; fetch stack pointer
or eax, eax ; check if in use
jz fixret_continue
; ensure stack is still in use (heuristic approach)
shr eax, 12
push ecx
VMMcall _PageCheckLinRange, <eax, 1, 0>
pop ecx
or eax, eax
jz fixret_continue
cli
mov eax, [edi].RetTemplateSP ; fetch stack pointer
; make sure it points at a return template
mov edx, [eax] ; get return address
sub edx, offset32 ReturnTable
cmp edx, RetTableSize ; within return table?
jb fixret_okay
mov FixRetErr, 1
jmp fixret_continue
fixret_okay:
; patch return address
mov edx, [edi].RetTemplateOrigAddr ; fetch original return addr
mov [eax], edx ; restore original return addr
fixret_continue:
sti
add edi, RetTemplateLen
loop fixret_loop
; Free the memory we were using if no errors
stc
cmp FixRetErr, 1 ; clears carry???
je nofree
VMMcall _PageFree, <[HookTable], 0>
clc
nofree:
ret
EndProc VXDMHLP_Device_Exit
VXD_LOCKED_CODE_ENDS
;============================================================================
; D E V I C E I N I T I A L I Z A T I O N C O D E
;============================================================================
VXD_ICODE_SEG
;============================================================================
;
; VXDMHLP_Device_Init - VXDMHLP Initialization
;
;
; Entry: ebx -> System VM handle (not used)
; edx -> Reference data from real mode init portion
;
; Exit: If successful then
; Carry flag is clear
; else
; Carry flag is set to indicate an error -- Device not initialized
;
;============================================================================
VXDMHLPCaption db "VxD Monitor",0
VXDMHLPMessage db " Loading...",0
BeginProc VXDMHLP_Device_Init
if 0
; Put up message box indicating we're loading
VMMcall Get_Cur_VM_Handle
mov eax, MB_OK
mov ecx, OFFSET32 VXDMHLPMessage
mov edi, OFFSET32 VXDMHLPCaption
VxDcall SHELL_SYSMODAL_Message
int 3
endif
; determine if we have cpuid instruction
cli ; disable interrupts
pushfd ; push flags
pop eax ; pop flags
mov edx, eax ; save original flags
xor eax, 200000h ; toggle bit 21
push eax ; push toggled flags
popfd ; load toggled flags
pushfd ; push toggled flags
pop eax ; pop toggled flags
push edx ; push orig flags
popfd ; restore orig flags
sti ; enable interrupts
cmp eax, edx ; did bit 21 change
je nonpentium ; can't change means no cpuid instr
; we have cpuid
mov eax, 1 ; request family id
db 0Fh, 0A2h ; CPUID
cmp eax, 500h ; test for pentium family
jae pentium ; if so, we're OK
; otherwise blot out the rdtsc instructions
; have to zero all rdtsc instructions
nonpentium:
mov eax, 0C033D233h ; xor eax, eax ; xor edx, edx
mov dword ptr rdts1, eax
mov dword ptr rdts2, eax
mov dword ptr rdts3, eax
mov dword ptr rdts4, eax
pentium:
; Initialize
call InitHookTable
call InitReturnTable
; Ready to go
clc
ret
EndProc VXDMHLP_Device_Init
VXD_ICODE_ENDS
end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -