1.FOR NT
From: "Slava M. Usov" <[email protected]>
Subject: Re: Trapping Software Interrupts in NT... Possible?
Date: Thursday, March 30, 2000 10:42 PM
Sal <[email protected]> wrote in message news:#VpgJGWm$GA.302@cppssbbsa05...
> Hi,
>
> I'm developing a WinNT5 / Win2k application
that needs to trap
software
> interrupts. I am relatively new to kernel/driver development,
so any info
> would be _greatly_ appreciated.
>
> For example, the software executes something
along the lines of:
> __asm {
>
int 0xNN ; NN == number of interrupt not
available
>
; currently in windows NT ring 3
> applications
> }
>
> And (logically) windows generates an error
because the interrupt isn't
> available. Is there *any* way to enable the interrupt, so that
a custom
> routine gets executed when software makes the request?
>
> I realize that the 16bit MS-DOS VM environment
does somethign similair
> to this to enable MS-DOS applications to call int 20h. Could
anyone point
> me to info on how this is done?
Well, with some creative use of SEH, this can be done in user mode.
Specifically, you may have the function you want to be executed each
time an
int instruction is executed. The sample code follows.
There are some comments in the code that may give you a hint how it
works.
Note that the technique exemplified is very slow, because it requires
two
kernel mode transitions for each INT, resulting in ca 3270 CPU clocks
for
each INT. You should not really be using it!
#include <windows.h>
#include <iostream>
using namespace std;
typedef unsigned char uchar;
typedef unsigned long ulong;
// both PushFrame() and PopFrame()
// invalidate edx
#define PushFrame(_handler) __asm \
{
\
__asm lea edx, _handler
\
__asm push edx
\
__asm push fs:[0]
\
__asm mov fs:[0], esp
\
}
// IMPORTANT: PopFrame assumes that the stack
// is in the state as if PushFrame just executed.
//
// it is deadly incorrect to return from a
// function without executing PopFrame()
//
// well, in some cases it may work;
// but if you have to ask, don't do it!
#define PopFrame() __asm
\
{
\
__asm mov edx,[esp]
\
__asm mov fs:[0], edx
\
__asm add esp, 8
\
}
EXCEPTION_DISPOSITION __cdecl _nested_eh(
struct _EXCEPTION_RECORD *er,
void * ef,
struct _CONTEXT *ctx,
void * DispatcherContext
)
{
static unsigned long zero = 0;
ctx->Ecx = (unsigned long)&zero;
return ExceptionContinueExecution;
}
__declspec(naked) ulong __fastcall _get_two(void *addr)
{
// due to the __fastcall convention,
// the first parameter is in ecx
PushFrame(_nested_eh);
__asm mov ax, word ptr [ecx]
PopFrame();
__asm ret
}
// __stcall convention is IMPORTANT
typedef void (__stdcall *int_r)(uchar int_num);
struct int_context
{
ulong eax; // eax is saved here
int_r ir; // int routine
ulong ret; // return address
ulong num; // int number
};
__declspec(naked) void _int_dispatch()
{
__asm push [eax]int_context.num
__asm push [eax]int_context.ret
__asm push [eax]int_context.ir
__asm mov eax, [eax]int_context.eax
__asm ret
}
EXCEPTION_DISPOSITION __cdecl _int_except_handler(
struct _EXCEPTION_RECORD *er,
void * ef,
struct _CONTEXT *ctx,
void * DispatcherContext
)
{
// see if it is a real exception or just unwinding
if( er->ExceptionFlags & (2 | 4) )
{
// unwinding in progress...
// we don't have to do anything
return ExceptionContinueSearch;
}
// will parse only two byte INT instructions
// thus INT 3 and INTO will not be processed
// INT 3 is a breakpoint and may be handled
// in a more straight forward manner
// note that INT 2C won't be handled, either
// the exception handler won't even see it
// because it's used as a syscall
ulong _int = _get_two(er->ExceptionAddress);
if( (_int & 0xff) != 0xcd )
return ExceptionContinueSearch;
// get to int_context structure pushed on stack
// just before the SEH frame
int_context *ic = (int_context*)((ulong*)ef + 2);
ic->eax = ctx->Eax;
ic->ret = (ulong)er->ExceptionAddress + 2;
ic->num = (_int >> 8) & 0xff;
// load the address of the int_context into eax
// note eax has already been saved in int_context
ctx->Eax = (ulong)ic;
ctx->Eip = (ulong)_int_dispatch;
return ExceptionContinueExecution;
}
// InvokeIntInterceptor()/RemoveIntInterceptor()
// invalidate edx, too
#define InvokeIntInterceptor(r) \
{
\
__asm sub esp, 16
\
__asm lea edx, r
\
__asm mov [esp].ir, edx \
PushFrame(_int_except_handler); \
}
#define RemoveIntInterceptor() \
{
\
PopFrame();
\
__asm add esp, 16
\
}
// END of implementation
// user code goes below
// must conform to int_r definition
// __stcall convention is IMPORTANT
void __stdcall int_routine(uchar int_num)
{
// generally, we should be careful here to save
// and restore the registers for we have the *exactly*
// same state as it was when INT XX was executed,
// and after the function returns, the next instruction
// after INT XX will see the *exactly* same registers
// this function leaves behind
// in this specific sample it is irrelevant
// so we don't care
cout << "INT " << hex << (ulong)int_num <<
endl;
}
int main()
{
InvokeIntInterceptor(int_routine);
// the following int instruction
// will get executed unnoticed
// in general you should not execute
// int 0x21 because chances are you may
// have a valid register cominataion
// for a syscall to execute successfully
__asm int 0x2c
// the rest should work as expected
__asm int 0x21
__asm int 0x22
__asm int 0x23
__asm int 0x24
__asm int 0x25
__asm int 0x26
__asm int 0x26
RemoveIntInterceptor();
return 0;
}
--
Slava
Please send any replies to this newsgroup.
microsoft.public.win32.programmer.kernel
2. FOR 9X
.386p
;;
;;Int82 supporter
;;Written by Lu Lin,2000.4.13
;;Abstract:
;; Dynamic loadable vxd used to install
;; interrupt 82 handler
;;
;; We need a dll for handle
the interrupt 82. Its name
;;exist under regestery key "HKLM\SOFTWARE\",value
"Int82"
;;contents a ASCIIZ string shows the interrupt
handler dll
;;name, e.g. "c:\windows\system\abc.dll"
;;Please be noted that we will use a default
handler
;;"c:\windows\systemInthdl.dll" if the value
"Int82" doesn't
;;present.
;;Future release will support deviceio to install the handler.
BLD_COFF EQU 1
IS_32 EQU 1
MASM6 EQU 1
DEV_IO EQU 60
include vmm.inc
include vxdldr.inc
Declare_Virtual_Device INT82,6,0,ctrlproc,Undefined_Device_ID,1000000h,,,
Vxd_DATA_SEG
PreviousGPHandler dd 0
Int82Handler dd 0
hModule dd 0
pModuleName dd 0
cbname dd 260
hkey dd 0
key db "Software",0
value db "Int82",0
ModuleName db "c:\windows\system\Inthdl.dll",0
FunctionName db "InterruptHandle",0
Vxd_DATA_ENDS
VxD_CODE_SEG
;;
;;interrupt 82h handler
;;
BeginProc v82
pushad
push ds
mov bx,[ebp.Client_CS]
mov ds,bx
mov ebx,[ebp.Client_EIP]
cmp word ptr ds:[ebx],82cdh
jz CatchInt82
pop ds
popad
jmp dword ptr PreviousGPHandler
CatchInt82:
add [ebp.Client_EIP],2
pop ds
popad
cmp Int82Handler,0
jz back_home
mov
eax,[ebp.client_EAX]
mov
ebx,[ebp.client_EBX]
mov
ecx,[ebp.client_ECX]
mov
edx,[ebp.client_EDX]
mov
esi,[ebp.client_ESI]
mov
edi,[ebp.client_EDI]
call
dword ptr Int82Handler
mov
[ebp.client_EAX],eax
mov
[ebp.client_EBX],ebx
mov
[ebp.client_ECX],ecx
mov
[ebp.client_EDX],edx
mov
[ebp.client_ESI],esi
mov
[ebp.client_EDI],edi
back_home:
ret
EndProc v82
;==============================================================================
; Device IO interface:
; ecx = Service No
; ebx = DDB
; edx = hDevice ,it is opened by a ring3 application
; esi = lpDIOCParms,passed from DeviceIoControl
;==============================================================================
BeginProc DEVICE_IO
xor eax,eax
cmp ecx,DIOC_OPEN ;;Must return 0
to tell WIN32 that this VxD supports DEVIOCTL
jz Normal_Exit
cmp ecx,DIOC_CLOSEHANDLE ;;sent when VxD
is unloaded just before SYS_DYNAMIC_EXIT
jz Normal_Exit
cmp
ecx,DEV_IO
jz Run_io
mov eax,32h ;;error:not supported
ret
Normal_Exit:
ret
Run_io:
;;
;;Add codes here
;;
ret
EndProc DEVICE_IO
VxD_CODE_ENDS
VxD_LOCKED_CODE_SEG
;;
;;Called when dynamic init
;;
BeginProc Dynamic_Init
;;step1:
mov eax,13
mov esi,offset32 v82
VMMCall Hook_PM_Fault
mov PreviousGPHandler,esi
jnc step2
stc
ret
step2:
VMMCall
_HeapAllocate,<260,HEAPZEROINIT>
mov pModuleName,eax
VMMCall _RegOpenKey,<HKEY_LOCAL_MACHINE,<OFFSET32
key>,<offset32 hkey>>
cmp eax,0
jnz step3
VMMCall _RegQueryValueEx,<hkey,<OFFSET32
value>,0,0,pModuleName,<OFFSET32 cbName>>
cmp eax, 0
jz step3
VMMCall _HeapFree,<pModuleName,0>
mov pModuleName,offset32 ModuleName
step3:
VxDCall _PELDR_LoadModule,<<offset32
hModule>,pModuleName,0>
cmp eax,0
jz step4
jmp step_n
step4:
VxDCall _PELDR_GetProcAddress,<hModule,<offset32
FunctionName>,0>
mov Int82Handler,eax
step_n:
VMMCall _RegCloseKey,<hkey>
clc
ret
EndProc Dynamic_Init
;;
;;Called when dynamic exit
;;
BeginProc Dynamic_EXIT
stc ;;We don't allow this VXD unload
ret
EndProc Dynamic_EXIT
;;
;;Dispatch routine
;;
BeginProc ctrlproc
Control_Dispatch KERNEL32_INITIALIZED,
Dynamic_Init
Control_Dispatch SYS_DYNAMIC_DEVICE_INIT,
Dynamic_Init
Control_Dispatch SYS_DYNAMIC_DEVICE_EXIT,
Dynamic_EXIT
Control_Dispatch W32_DEVICEIOCONTROL, DEVICE_IO
clc
ret
EndProc ctrlproc
VxD_LOCKED_CODE_ENDS
END