diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/mvdm/vdmdbg/vdmdbg.c | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/mvdm/vdmdbg/vdmdbg.c')
-rw-r--r-- | private/mvdm/vdmdbg/vdmdbg.c | 2299 |
1 files changed, 2299 insertions, 0 deletions
diff --git a/private/mvdm/vdmdbg/vdmdbg.c b/private/mvdm/vdmdbg/vdmdbg.c new file mode 100644 index 000000000..c4a9def1d --- /dev/null +++ b/private/mvdm/vdmdbg/vdmdbg.c @@ -0,0 +1,2299 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + vdmdbg.c + +Abstract: + + This module contains the debugging support needed to debug + 16-bit VDM applications + +Author: + + Bob Day (bobday) 16-Sep-1992 Wrote it + +Revision History: + +--*/ + +#include <nt.h> +#include <ntdbg.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> +#include <vdmdbg.h> +#include <dbginfo.h> +#include <stdio.h> +#include <string.h> + +typedef WORD HAND16; + +#define SHAREWOW_MAIN +#include <sharewow.h> + +#if DBG +#define DEBUG 1 +#endif + +#define TOOL_HMASTER 0 // Offset to hGlobalHeap (in kdata.asm) +#define TOOL_HMODFIRST 4 // Offset to hExeHead (in kdata.asm) +#define TOOL_HEADTDB 14 // Offset to headTDB (in kdata.asm) +#define TOOL_HMASTLEN 22 // Offset to SelTableLen (in kdata.asm) +#define TOOL_HMASTSTART 24 // Offset to SelTableStart (in kdata.asm) + +#define HI_FIRST 6 // Offset to hi_first in heap header +#define HI_SIZE 24 // Size of HeapInfo structure + +#define GI_LRUCHAIN 2 // Offset to gi_lruchain in heap header +#define GI_LRUCOUNT 4 // Offset to gi_lrucount in heap header +#define GI_FREECOUNT 16 // Offset to gi_free_count in heap header + +#define GA_COUNT 0 // Offset to ga_count in arena header +#define GA_OWNER386 18 // Offset to "pga_owner member in globalarena + +#define GA_OWNER 1 // Offset to "owner" member within Arena + +#define GA_FLAGS 5 // Offset to ga_flags in arena header +#define GA_NEXT 9 // Offset to ga_next in arena header +#define GA_HANDLE 10 // Offset to ga_handle in arena header +#define GA_LRUNEXT 14 // Offset to ga_lrunext in arena header +#define GA_FREENEXT GA_LRUNEXT // Offset to ga_freenext in arena header + +#define GA_SIZE 16 // Size of the GlobalArena structure + +#define LI_SIG HI_SIZE+10 // Offset to signature +#define LI_SIZE HI_SIZE+12 // Size of LocalInfo structure +#define LOCALSIG 0x4C48 // 'HL' Signature + +#define TDB_next 0 // Offset to next TDB in TDB +#define TDB_PDB 72 // Offset to PDB in TDB + +#define GF_PDB_OWNER 0x100 // Low byte is kernel flags + +#define NEMAGIC 0x454E // 'NE' Signature + +#define NE_MAGIC 0 // Offset to NE in module header +#define NE_USAGE 2 // Offset to usage +#define NE_CBENTTAB 6 // Offset to cbenttab (really next module ptr) +#define NE_PATHOFFSET 10 // Offset to file path stuff +#define NE_CSEG 28 // Offset to cseg, number of segs in module +#define NE_SEGTAB 34 // Offset to segment table ptr in modhdr +#define NE_RESTAB 38 // Offset to resident names table ptr in modhdr + +#define NS_HANDLE 8 // Offset to handle in seg table +#define NEW_SEG1_SIZE 10 // Size of the NS_ stuff + + +#define MAX_MODULE_NAME_LENGTH 128 +#define MAX_MODULE_PATH_LENGTH 128 + +WORD wKernelSeg = 0; +DWORD dwOffsetTHHOOK = 0L; +LPVOID lpRemoteAddress = NULL; +DWORD lpRemoteBlock = 0; +BOOL fKernel386 = FALSE; + +#define HANDLE_NULL ((HANDLE)NULL) + +//---------------------------------------------------------------------------- +// InternalGetThreadSelectorEntry() +// +// Routine to return a LDT_ENTRY structure for the passed in selector number. +// Its is assumed that we are talking about protect mode selectors. +// For x86 systems, take the easy way and just call the system. For non-x86 +// systems, we get some information from softpc and index into them as the +// LDT and GDT tables. +// +//---------------------------------------------------------------------------- +BOOL InternalGetThreadSelectorEntry( + HANDLE hProcess, + HANDLE hThread, + WORD wSelector, + LPVDMLDT_ENTRY lpSelectorEntry +) { +#ifdef i386 + + // Do the nice simple thing for x86 systems. + + return( GetThreadSelectorEntry(hThread,wSelector,lpSelectorEntry) ); +#else + + // For non-intel systems, query the information from the LDT and + // GDT that we have pointers to from the VDMINTERNALINFO that we + // got passed. + + + RtlFillMemory( lpSelectorEntry, sizeof(VDMLDT_ENTRY), (UCHAR)0 ); + + // BUGBUG - Implement a method of determining the LDT on MIPS/ALPHA + // BUGBUG - Also adjust the base value of the selector to account for + // Intel M Memory not based at 0. + + return( FALSE ); +#endif +} + +//---------------------------------------------------------------------------- +// VDMGetThreadSelectorEntry() +// +// Public interface to the InternalGetThreadSelectorEntry, needed because +// that routine requires the process handle. +// +//---------------------------------------------------------------------------- +BOOL +WINAPI +VDMGetThreadSelectorEntry( + HANDLE hProcess, + HANDLE hThread, + WORD wSelector, + LPVDMLDT_ENTRY lpSelectorEntry +) { + BOOL fResult; + + fResult = InternalGetThreadSelectorEntry( + hProcess, + hThread, + wSelector, + lpSelectorEntry ); + + return( fResult ); +} + +//---------------------------------------------------------------------------- +// InternalGetPointer() +// +// Routine to convert a 16-bit address into a 32-bit address. If fProtMode +// is TRUE, then the selector table lookup is performed. Otherwise, simple +// real mode address calculations are performed. On non-x86 systems, the +// base of real memory is added into the +// +//---------------------------------------------------------------------------- +ULONG +WINAPI +InternalGetPointer( + HANDLE hProcess, + HANDLE hThread, + WORD wSelector, + DWORD dwOffset, + BOOL fProtMode +) { + VDMLDT_ENTRY le; + ULONG ulResult; + ULONG base; + ULONG limit; + BOOL b; + + if ( fProtMode ) { + b = InternalGetThreadSelectorEntry( hProcess, + hThread, + wSelector, + &le ); + if ( !b ) { + return( 0 ); + } + + base = ((ULONG)le.HighWord.Bytes.BaseHi << 24) + + ((ULONG)le.HighWord.Bytes.BaseMid << 16) + + ((ULONG)le.BaseLow); + limit = (ULONG)le.LimitLow + + ((ULONG)le.HighWord.Bits.LimitHi << 16); + if ( le.HighWord.Bits.Granularity ) { + limit <<= 12; + limit += 0xFFF; + } + } else { + base = wSelector << 4; + limit = 0xFFFF; + } + if ( dwOffset > limit ) { + ulResult = 0; + } else { + ulResult = base + dwOffset; +#ifndef i386 + // BUGBUG this should be the start of intel memory + ulResult += 0; +#endif + } + + return( ulResult ); +} + +//---------------------------------------------------------------------------- +// VDMGetPointer() +// +// Public interface to the InternalGetPointer, needed because that +// routine requires the process handle. +// +//---------------------------------------------------------------------------- +ULONG +WINAPI +VDMGetPointer( + HANDLE hProcess, + HANDLE hThread, + WORD wSelector, + DWORD dwOffset, + BOOL fProtMode +) { + ULONG ulResult; + + ulResult = InternalGetPointer( + hProcess, + hThread, + wSelector, + dwOffset, + fProtMode ); + + return( ulResult ); +} + +//---------------------------------------------------------------------------- +// VDMGetThreadContext() +// +// Interface to get the simulated context. The same functionality as +// GetThreadContext except that it happens on the simulated 16-bit context, +// rather than the 32-bit context. +// +//---------------------------------------------------------------------------- +BOOL +WINAPI +VDMGetThreadContext( + LPDEBUG_EVENT lpDebugEvent, + LPVDMCONTEXT lpVDMContext +) { + VDMINTERNALINFO viInfo; + VDMCONTEXT vcContext; + LPDWORD lpdw; + DWORD address; + BOOL b; + DWORD lpNumberOfBytesRead; + HANDLE hProcess; + INT i; + + hProcess = OpenProcess( PROCESS_VM_READ, FALSE, lpDebugEvent->dwProcessId ); + + lpdw = &(lpDebugEvent->u.Exception.ExceptionRecord.ExceptionInformation[0]); + + address = lpdw[3]; + + b = ReadProcessMemory( + hProcess, + (LPVOID)address, + &viInfo, + sizeof(viInfo), + &lpNumberOfBytesRead + ); + if ( !b || lpNumberOfBytesRead != sizeof(viInfo) ) { + return( FALSE ); + } + + address = (DWORD)viInfo.vdmContext; + + b = ReadProcessMemory( + hProcess, + (LPVOID)address, + &vcContext, + sizeof(vcContext), + &lpNumberOfBytesRead + ); + if ( !b || lpNumberOfBytesRead != sizeof(vcContext) ) { + return( FALSE ); + } + + CloseHandle( hProcess ); + + if ((lpVDMContext->ContextFlags & VDMCONTEXT_CONTROL) == VDMCONTEXT_CONTROL) { + + // + // Set registers ebp, eip, cs, eflag, esp and ss. + // + + lpVDMContext->Ebp = vcContext.Ebp; + lpVDMContext->Eip = vcContext.Eip; + lpVDMContext->SegCs = vcContext.SegCs; + lpVDMContext->EFlags = vcContext.EFlags; + lpVDMContext->SegSs = vcContext.SegSs; + lpVDMContext->Esp = vcContext.Esp; + } + + // + // Set segment register contents if specified. + // + + if ((lpVDMContext->ContextFlags & VDMCONTEXT_SEGMENTS) == VDMCONTEXT_SEGMENTS) { + + // + // Set segment registers gs, fs, es, ds. + // + // These values are junk most of the time, but useful + // for debugging under certain conditions. Therefore, + // we report whatever was in the frame. + // + + lpVDMContext->SegGs = vcContext.SegGs; + lpVDMContext->SegFs = vcContext.SegFs; + lpVDMContext->SegEs = vcContext.SegEs; + lpVDMContext->SegDs = vcContext.SegDs; + } + + // + // Set integer register contents if specified. + // + + if ((lpVDMContext->ContextFlags & VDMCONTEXT_INTEGER) == VDMCONTEXT_INTEGER) { + + // + // Set integer registers edi, esi, ebx, edx, ecx, eax + // + + lpVDMContext->Edi = vcContext.Edi; + lpVDMContext->Esi = vcContext.Esi; + lpVDMContext->Ebx = vcContext.Ebx; + lpVDMContext->Ecx = vcContext.Ecx; + lpVDMContext->Edx = vcContext.Edx; + lpVDMContext->Eax = vcContext.Eax; + } + + // + // Fetch floating register contents if requested, and type of target + // is user. (system frames have no fp state, so ignore request) + // + + if ( (lpVDMContext->ContextFlags & VDMCONTEXT_FLOATING_POINT) == + VDMCONTEXT_FLOATING_POINT ) { + + lpVDMContext->FloatSave.ControlWord = vcContext.FloatSave.ControlWord; + lpVDMContext->FloatSave.StatusWord = vcContext.FloatSave.StatusWord; + lpVDMContext->FloatSave.TagWord = vcContext.FloatSave.TagWord; + lpVDMContext->FloatSave.ErrorOffset = vcContext.FloatSave.ErrorOffset; + lpVDMContext->FloatSave.ErrorSelector = vcContext.FloatSave.ErrorSelector; + lpVDMContext->FloatSave.DataOffset = vcContext.FloatSave.DataOffset; + lpVDMContext->FloatSave.DataSelector = vcContext.FloatSave.DataSelector; + lpVDMContext->FloatSave.Cr0NpxState = vcContext.FloatSave.Cr0NpxState; + for (i = 0; i < SIZE_OF_80387_REGISTERS; i++) { + lpVDMContext->FloatSave.RegisterArea[i] = vcContext.FloatSave.RegisterArea[i]; + } + } + + // + // Fetch Dr register contents if requested. Values may be trash. + // + + if ((lpVDMContext->ContextFlags & VDMCONTEXT_DEBUG_REGISTERS) == + VDMCONTEXT_DEBUG_REGISTERS) { + + lpVDMContext->Dr0 = vcContext.Dr0; + lpVDMContext->Dr1 = vcContext.Dr1; + lpVDMContext->Dr2 = vcContext.Dr2; + lpVDMContext->Dr3 = vcContext.Dr3; + lpVDMContext->Dr6 = vcContext.Dr6; + lpVDMContext->Dr7 = vcContext.Dr7; + } + + return( TRUE ); +} + +//---------------------------------------------------------------------------- +// VDMSetThreadContext() +// +// Interface to set the simulated context. Similar in most respects to +// the SetThreadContext API supported by Win NT. Only differences are +// in the bits which must be "sanitized". +// +//---------------------------------------------------------------------------- +BOOL +WINAPI +VDMSetThreadContext( + LPDEBUG_EVENT lpDebugEvent, + LPVDMCONTEXT lpVDMContext +) { + VDMINTERNALINFO viInfo; + VDMCONTEXT vcContext; + LPDWORD lpdw; + DWORD address; + BOOL b; + DWORD lpNumberOfBytes; + HANDLE hProcess; + INT i; + + + hProcess = OpenProcess( PROCESS_VM_OPERATION | + PROCESS_VM_READ | + PROCESS_VM_WRITE, + FALSE, + lpDebugEvent->dwProcessId ); + + lpdw = &(lpDebugEvent->u.Exception.ExceptionRecord.ExceptionInformation[0]); + + address = lpdw[3]; + + b = ReadProcessMemory( + hProcess, + (LPVOID)address, + &viInfo, + sizeof(viInfo), + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != sizeof(viInfo) ) { + return( FALSE ); + } + + address = (DWORD)viInfo.vdmContext; + + b = ReadProcessMemory( + hProcess, + (LPVOID)address, + &vcContext, + sizeof(vcContext), + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != sizeof(vcContext) ) { + return( FALSE ); + } + + if ((lpVDMContext->ContextFlags & VDMCONTEXT_CONTROL) == VDMCONTEXT_CONTROL) { + + // + // Set registers ebp, eip, cs, eflag, esp and ss. + // + + vcContext.Ebp = lpVDMContext->Ebp; + vcContext.Eip = lpVDMContext->Eip; + + // + // Don't allow them to modify the mode bit. + // + // Only allow these bits to get set: 01100000110111110111 + // V86FLAGS_CARRY 0x00001 + // V86FLAGS_? 0x00002 + // V86FLAGS_PARITY 0x00004 + // V86FLAGS_AUXCARRY 0x00010 + // V86FLAGS_ZERO 0x00040 + // V86FLAGS_SIGN 0x00080 + // V86FLAGS_TRACE 0x00100 + // V86FLAGS_INTERRUPT 0x00200 + // V86FLAGS_DIRECTION 0x00400 + // V86FLAGS_OVERFLOW 0x00800 + // V86FLAGS_RESUME 0x10000 + // V86FLAGS_VM86 0x20000 + // V86FLAGS_ALIGNMENT 0x40000 + // + // Commonly flags will be 0x10246 + // + if ( vcContext.EFlags & V86FLAGS_V86 ) { + vcContext.EFlags = V86FLAGS_V86 | (lpVDMContext->EFlags & + ( V86FLAGS_CARRY + | 0x0002 + | V86FLAGS_PARITY + | V86FLAGS_AUXCARRY + | V86FLAGS_ZERO + | V86FLAGS_SIGN + | V86FLAGS_TRACE + | V86FLAGS_INTERRUPT + | V86FLAGS_DIRECTION + | V86FLAGS_OVERFLOW + | V86FLAGS_RESUME + | V86FLAGS_ALIGNMENT + | V86FLAGS_IOPL + )); + } else { + vcContext.EFlags = ~V86FLAGS_V86 & (lpVDMContext->EFlags & + ( V86FLAGS_CARRY + | 0x0002 + | V86FLAGS_PARITY + | V86FLAGS_AUXCARRY + | V86FLAGS_ZERO + | V86FLAGS_SIGN + | V86FLAGS_TRACE + | V86FLAGS_INTERRUPT + | V86FLAGS_DIRECTION + | V86FLAGS_OVERFLOW + | V86FLAGS_RESUME + | V86FLAGS_ALIGNMENT + | V86FLAGS_IOPL + )); + } + + // + // CS might only be allowable as a ring 3 selector. + // + if ( vcContext.EFlags & V86FLAGS_V86 ) { + vcContext.SegCs = lpVDMContext->SegCs; + } else { +#ifdef i386 + vcContext.SegCs = lpVDMContext->SegCs | 0x0003; +#else + vcContext.SegCs = lpVDMContext->SegCs; +#endif + } + + vcContext.SegSs = lpVDMContext->SegSs; + vcContext.Esp = lpVDMContext->Esp; + } + + // + // Set segment register contents if specified. + // + + if ((lpVDMContext->ContextFlags & VDMCONTEXT_SEGMENTS) == VDMCONTEXT_SEGMENTS) { + + // + // Set segment registers gs, fs, es, ds. + // + vcContext.SegGs = lpVDMContext->SegGs; + vcContext.SegFs = lpVDMContext->SegFs; + vcContext.SegEs = lpVDMContext->SegEs; + vcContext.SegDs = lpVDMContext->SegDs; + } + + // + // Set integer register contents if specified. + // + + if ((lpVDMContext->ContextFlags & VDMCONTEXT_INTEGER) == VDMCONTEXT_INTEGER) { + + // + // Set integer registers edi, esi, ebx, edx, ecx, eax + // + + vcContext.Edi = lpVDMContext->Edi; + vcContext.Esi = lpVDMContext->Esi; + vcContext.Ebx = lpVDMContext->Ebx; + vcContext.Ecx = lpVDMContext->Ecx; + vcContext.Edx = lpVDMContext->Edx; + vcContext.Eax = lpVDMContext->Eax; + } + + // + // Fetch floating register contents if requested, and type of target + // is user. + // + + if ( (lpVDMContext->ContextFlags & VDMCONTEXT_FLOATING_POINT) == + VDMCONTEXT_FLOATING_POINT ) { + + vcContext.FloatSave.ControlWord = lpVDMContext->FloatSave.ControlWord; + vcContext.FloatSave.StatusWord = lpVDMContext->FloatSave.StatusWord; + vcContext.FloatSave.TagWord = lpVDMContext->FloatSave.TagWord; + vcContext.FloatSave.ErrorOffset = lpVDMContext->FloatSave.ErrorOffset; + vcContext.FloatSave.ErrorSelector = lpVDMContext->FloatSave.ErrorSelector; + vcContext.FloatSave.DataOffset = lpVDMContext->FloatSave.DataOffset; + vcContext.FloatSave.DataSelector = lpVDMContext->FloatSave.DataSelector; + vcContext.FloatSave.Cr0NpxState = lpVDMContext->FloatSave.Cr0NpxState; + for (i = 0; i < SIZE_OF_80387_REGISTERS; i++) { + vcContext.FloatSave.RegisterArea[i] = lpVDMContext->FloatSave.RegisterArea[i]; + } + } + + // + // Fetch Dr register contents if requested. Values may be trash. + // + + if ((lpVDMContext->ContextFlags & VDMCONTEXT_DEBUG_REGISTERS) == + VDMCONTEXT_DEBUG_REGISTERS) { + + vcContext.Dr0 = lpVDMContext->Dr0; + vcContext.Dr1 = lpVDMContext->Dr1; + vcContext.Dr2 = lpVDMContext->Dr2; + vcContext.Dr3 = lpVDMContext->Dr3; + vcContext.Dr6 = lpVDMContext->Dr6; + vcContext.Dr7 = lpVDMContext->Dr7; + } + b = WriteProcessMemory( + hProcess, + (LPVOID)address, + &vcContext, + sizeof(vcContext), + &lpNumberOfBytes + ); + + if ( !b || lpNumberOfBytes != sizeof(vcContext) ) { + return( FALSE ); + } + + CloseHandle( hProcess ); + + return( TRUE ); +} + +//---------------------------------------------------------------------------- +// VDMKillWOW() +// +// Interface to kill the wow sub-system. This may not be needed and is +// certainly not needed now. We are going to look into fixing the +// debugging interface so this is not necessary. +// +//---------------------------------------------------------------------------- +BOOL +WINAPI +VDMKillWOW( + VOID +) { + return( FALSE ); +} + +//---------------------------------------------------------------------------- +// VDMDetectWOW() +// +// Interface to detect whether the wow sub-system has already been started. +// This may not be needed and is certainly not needed now. We are going +// to look into fixing the debugging interface so this is not necessary. +// +//---------------------------------------------------------------------------- +BOOL +WINAPI +VDMDetectWOW( + VOID +) { + return( FALSE ); +} + +//---------------------------------------------------------------------------- +// VDMBreakThread() +// +// Interface to interrupt a thread while it is running without any break- +// points. An ideal debugger would have this feature. Since it is hard +// to implement, we will be doing it later. +// +//---------------------------------------------------------------------------- +BOOL +WINAPI +VDMBreakThread( + HANDLE hProcess, + HANDLE hThread +) { + return( FALSE ); +} + +//---------------------------------------------------------------------------- +// VDMProcessException() +// +// This function acts as a filter of debug events. Most debug events +// should be ignored by the debugger (because they don't have the context +// record pointer or the internal info structure setup. Those events +// cause this function to return FALSE, which tells the debugger to just +// blindly continue the exception. When the function does return TRUE, +// the debugger should look at the exception code to determine what to +// do (and all the the structures have been set up properly to deal with +// calls to the other APIs). +// +//---------------------------------------------------------------------------- +BOOL +WINAPI +VDMProcessException( + LPDEBUG_EVENT lpDebugEvent +) { + LPDWORD lpdw; + int mode; + BOOL fResult; + + lpdw = &(lpDebugEvent->u.Exception.ExceptionRecord.ExceptionInformation[0]); + + + mode = LOWORD(lpdw[0]); + + fResult = TRUE; + + switch( mode ) { + case DBG_SEGLOAD: + case DBG_SEGMOVE: + case DBG_SEGFREE: + case DBG_MODLOAD: + case DBG_MODFREE: + fResult = FALSE; + case DBG_SINGLESTEP: + case DBG_BREAK: + case DBG_GPFAULT: + case DBG_DIVOVERFLOW: + case DBG_INSTRFAULT: + case DBG_TASKSTART: + case DBG_TASKSTOP: + case DBG_DLLSTART: + case DBG_DLLSTOP: + default: + if ( wKernelSeg == 0 || lpRemoteAddress == 0 ) { + VDMINTERNALINFO viInfo; + DWORD address; + DWORD lpNumberOfBytesRead; + HANDLE hProcess; + BOOL b; + + hProcess = OpenProcess( PROCESS_VM_READ, FALSE, lpDebugEvent->dwProcessId ); + + if ( hProcess == HANDLE_NULL ) { + fResult = FALSE; + break; + } + address = lpdw[3]; + + b = ReadProcessMemory( + hProcess, + (LPVOID)address, + &viInfo, + sizeof(viInfo), + &lpNumberOfBytesRead + ); + if ( !b || lpNumberOfBytesRead != sizeof(viInfo) ) { + fResult = FALSE; + break; + + } + + if ( wKernelSeg == 0 ) { + wKernelSeg = viInfo.wKernelSeg; + dwOffsetTHHOOK = viInfo.dwOffsetTHHOOK; + } + if ( lpRemoteAddress == NULL ) { + lpRemoteAddress = viInfo.lpRemoteAddress; + } + if ( lpRemoteBlock == 0 ) { + lpRemoteBlock = viInfo.lpRemoteBlock; + } + fKernel386 = viInfo.f386; + + CloseHandle( hProcess ); + } + break; + } + + return( fResult ); +} + + +//---------------------------------------------------------------------------- +// ReadItem +// +// Internal routine used to read items out of the debugee's address space. +// The routine returns TRUE for failure. This allows easy failure testing. +// +//---------------------------------------------------------------------------- +BOOL +ReadItem( + HANDLE hProcess, + HANDLE hThread, + WORD wSeg, + DWORD dwOffset, + LPVOID lpitem, + UINT nSize +) { + LPVOID lp; + BOOL b; + DWORD dwBytes; + + if ( nSize == 0 ) { + return( FALSE ); + } + + lp = (LPVOID)InternalGetPointer( + hProcess, + hThread, + (WORD)(wSeg | 1), + dwOffset, + TRUE ); + if ( lp == NULL ) return( TRUE ); + + b = ReadProcessMemory( + hProcess, + lp, + lpitem, + nSize, + &dwBytes ); + if ( !b || dwBytes != nSize ) return( TRUE ); + + return( FALSE ); +} + +//---------------------------------------------------------------------------- +// WriteItem +// +// Internal routine used to write items into the debugee's address space. +// The routine returns TRUE for failure. This allows easy failure testing. +// +//---------------------------------------------------------------------------- +BOOL +WriteItem( + HANDLE hProcess, + HANDLE hThread, + WORD wSeg, + DWORD dwOffset, + LPVOID lpitem, + UINT nSize +) { + LPVOID lp; + BOOL b; + DWORD dwBytes; + + if ( nSize == 0 ) { + return( FALSE ); + } + + lp = (LPVOID)InternalGetPointer( + hProcess, + hThread, + (WORD)(wSeg | 1), + dwOffset, + TRUE ); + if ( lp == NULL ) return( TRUE ); + + b = WriteProcessMemory( + hProcess, + lp, + lpitem, + nSize, + &dwBytes ); + if ( !b || dwBytes != nSize ) return( TRUE ); + + return( FALSE ); +} + +#define READ_FIXED_ITEM(seg,offset,item) \ + if ( ReadItem(hProcess,hThread,seg,offset,&item,sizeof(item)) ) goto punt; + +#define WRITE_FIXED_ITEM(seg,offset,item) \ + if ( WriteItem(hProcess,hThread,seg,offset,&item,sizeof(item)) ) goto punt; + +#define LOAD_FIXED_ITEM(seg,offset,item) \ + ReadItem(hProcess,hThread,seg,offset,&item,sizeof(item)) + +#define READ_SIZED_ITEM(seg,offset,item,size) \ + if ( ReadItem(hProcess,hThread,seg,offset,item,size) ) goto punt; + +#define WRITE_SIZED_ITEM(seg,offset,item,size) \ + if ( WriteItem(hProcess,hThread,seg,offset,item,size) ) goto punt; + +//---------------------------------------------------------------------------- +// VDMGetSelectorModule() +// +// Interface to determine the module and segment associated with a given +// selector. This is useful during debugging to associate symbols with +// code and data segments. The symbol lookup should be done by the +// debugger, given the module and segment number. +// +// This code was adapted from the Win 3.1 ToolHelp DLL +// +//---------------------------------------------------------------------------- +BOOL +WINAPI +VDMGetSelectorModule( + HANDLE hProcess, + HANDLE hThread, + WORD wSelector, + PUINT lpSegmentNumber, + LPSTR lpModuleName, + UINT nNameSize, + LPSTR lpModulePath, + UINT nPathSize +) { + BOOL b; + DWORD lpNumberOfBytes; + BOOL fResult; + DWORD lphMaster; + DWORD lphMasterLen; + DWORD lphMasterStart; + DWORD lpOwner; + DWORD lpThisModuleResTab; + DWORD lpThisModuleName; + DWORD lpPath; + DWORD lpThisModulecSeg; + DWORD lpThisModuleSegTab; + DWORD lpThisSegHandle; + WORD wMaster; + WORD wMasterLen; + DWORD dwMasterStart; + DWORD dwArenaOffset; + WORD wArenaSlot; + DWORD lpArena; + WORD wModHandle; + WORD wResTab; + UCHAR cLength; + WORD wPathOffset; + UCHAR cPath; + WORD cSeg; + WORD iSeg; + WORD wSegTab; + WORD wHandle; + CHAR chName[MAX_MODULE_NAME_LENGTH]; + CHAR chPath[MAX_MODULE_PATH_LENGTH]; + + if ( lpModuleName != NULL ) *lpModuleName = '\0'; + if ( lpModulePath != NULL ) *lpModulePath = '\0'; + if ( lpSegmentNumber != NULL ) *lpSegmentNumber = 0; + + fResult = FALSE; + + if ( wKernelSeg == 0 ) { + return( FALSE ); + } + + // Read out the master heap selector + + lphMaster = InternalGetPointer( + hProcess, + hThread, + wKernelSeg, + dwOffsetTHHOOK + TOOL_HMASTER, // To hGlobalHeap + TRUE ); + if ( lphMaster == (DWORD)NULL ) goto punt; + + b = ReadProcessMemory( + hProcess, + (LPVOID)lphMaster, + &wMaster, + sizeof(wMaster), + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != sizeof(wMaster) ) goto punt; + + wMaster |= 1; // Convert to selector + + // Read out the master heap selector length + + lphMasterLen = InternalGetPointer( + hProcess, + hThread, + wKernelSeg, + dwOffsetTHHOOK + TOOL_HMASTLEN, // To SelTableLen + TRUE ); + if ( lphMasterLen == (DWORD)NULL ) goto punt; + + b = ReadProcessMemory( + hProcess, + (LPVOID)lphMasterLen, + &wMasterLen, + sizeof(wMasterLen), + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != sizeof(wMasterLen) ) goto punt; + + // Read out the master heap selector start + + lphMasterStart = InternalGetPointer( + hProcess, + hThread, + wKernelSeg, + dwOffsetTHHOOK + TOOL_HMASTSTART, // To SelTableStart + TRUE ); + if ( lphMasterStart == (DWORD)NULL ) goto punt; + + b = ReadProcessMemory( + hProcess, + (LPVOID)lphMasterStart, + &dwMasterStart, + sizeof(dwMasterStart), + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != sizeof(dwMasterStart) ) goto punt; + + // Now make sure the selector provided is in the right range + + if ( fKernel386 ) { + + // 386 kernel? + wArenaSlot = (WORD)(wSelector & 0xFFF8); // Mask low 3 bits + + wArenaSlot = wArenaSlot >> 1; // Sel/8*4 + + if ( (WORD)wArenaSlot > wMasterLen ) goto punt; // Out of range + + wArenaSlot += (WORD)dwMasterStart; + + // Ok, Now read out the area header offset + + dwArenaOffset = (DWORD)0; // Default to 0 + + lpArena = InternalGetPointer( + hProcess, + hThread, + wMaster, + wArenaSlot, + TRUE ); + if ( lpArena == (DWORD)NULL ) goto punt; + + // 386 Kernel? + b = ReadProcessMemory( + hProcess, + (LPVOID)lpArena, + &dwArenaOffset, + sizeof(dwArenaOffset), + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != sizeof(dwArenaOffset) ) goto punt; + + // Read out the owner member + + lpOwner = InternalGetPointer( + hProcess, + hThread, + wMaster, + dwArenaOffset+GA_OWNER386, + TRUE ); + if ( lpOwner == (DWORD)NULL ) goto punt; + + } else { + lpOwner = InternalGetPointer( + hProcess, + hThread, + wSelector, + 0, + TRUE ); + if ( lpOwner == (DWORD)NULL ) goto punt; + + lpOwner -= GA_SIZE; + lpOwner += GA_OWNER; + } + + b = ReadProcessMemory( + hProcess, + (LPVOID)lpOwner, + &wModHandle, + sizeof(wModHandle), + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != sizeof(wModHandle) ) goto punt; + + // Now read out the owners module name + + // Name is the first name in the resident names table + + lpThisModuleResTab = InternalGetPointer( + hProcess, + hThread, + wModHandle, + NE_RESTAB, + TRUE ); + if ( lpThisModuleResTab == (DWORD)NULL ) goto punt; + + b = ReadProcessMemory( + hProcess, + (LPVOID)lpThisModuleResTab, + &wResTab, + sizeof(wResTab), + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != sizeof(wResTab) ) goto punt; + + // Get the 1st byte of the resident names table (1st byte of module name) + + lpThisModuleName = InternalGetPointer( + hProcess, + hThread, + wModHandle, + wResTab, + TRUE ); + if ( lpThisModuleName == (DWORD)NULL ) goto punt; + + // PASCAL string (1st byte is length), read the byte. + + b = ReadProcessMemory( + hProcess, + (LPVOID)lpThisModuleName, + &cLength, + sizeof(cLength), + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != sizeof(cLength) ) goto punt; + + if ( cLength > MAX_MODULE_NAME_LENGTH ) goto punt; + + // Now go read the text of the name + + lpThisModuleName += 1; + + b = ReadProcessMemory( + hProcess, + (LPVOID)lpThisModuleName, + &chName, + cLength, + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != (DWORD)cLength ) goto punt; + + chName[cLength] = '\0'; // Nul terminate it + + // Grab out the path name too! + + lpPath = InternalGetPointer( + hProcess, + hThread, + wModHandle, + NE_PATHOFFSET, + TRUE ); + if ( lpPath == (DWORD)NULL ) goto punt; + + b = ReadProcessMemory( + hProcess, + (LPVOID)lpPath, + &wPathOffset, + sizeof(wPathOffset), + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != sizeof(wPathOffset) ) goto punt; + + // Get the 1st byte of the path name + + lpThisModuleName = InternalGetPointer( + hProcess, + hThread, + wModHandle, + wPathOffset, + TRUE ); + if ( lpThisModuleName == (DWORD)NULL ) goto punt; + + // PASCAL string (1st byte is length), read the byte. + + b = ReadProcessMemory( + hProcess, + (LPVOID)lpThisModuleName, + &cPath, + sizeof(cPath), + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != sizeof(cPath) ) goto punt; + + if ( cPath > MAX_MODULE_NAME_LENGTH ) goto punt; + + lpThisModuleName += 8; // 1st 8 characters are ignored + cPath -= 8; + + // Now go read the text of the name + + b = ReadProcessMemory( + hProcess, + (LPVOID)lpThisModuleName, + &chPath, + cPath, + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != (DWORD)cPath ) goto punt; + + chPath[cPath] = '\0'; // Nul terminate it + + // Ok, we found the module we need, now grab the right selector for the + // segment number passed in. + + lpThisModulecSeg = InternalGetPointer( + hProcess, + hThread, + wModHandle, + NE_CSEG, + TRUE ); + if ( lpThisModulecSeg == (DWORD)NULL ) goto punt; + + b = ReadProcessMemory( + hProcess, + (LPVOID)lpThisModulecSeg, + &cSeg, + sizeof(cSeg), + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != sizeof(cSeg) ) goto punt; + + // Read the segment table pointer for this module + + lpThisModuleSegTab = InternalGetPointer( + hProcess, + hThread, + wModHandle, + NE_SEGTAB, + TRUE ); + if ( lpThisModuleSegTab == (DWORD)NULL ) goto punt; + + b = ReadProcessMemory( + hProcess, + (LPVOID)lpThisModuleSegTab, + &wSegTab, + sizeof(wSegTab), + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != sizeof(wSegTab) ) goto punt; + + // Loop through all of the segments for this module trying to find + // one with the right handle. + + iSeg = 0; + wSelector &= 0xFFF8; + + while ( iSeg < cSeg ) { + + lpThisSegHandle = InternalGetPointer( + hProcess, + hThread, + wModHandle, + wSegTab+iSeg*NEW_SEG1_SIZE+NS_HANDLE, + TRUE ); + if ( lpThisSegHandle == (DWORD)NULL ) goto punt; + + b = ReadProcessMemory( + hProcess, + (LPVOID)lpThisSegHandle, + &wHandle, + sizeof(wHandle), + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != sizeof(wHandle) ) goto punt; + + wHandle &= 0xFFF8; + + if ( wHandle == (WORD)wSelector ) { + break; + } + iSeg++; + } + + if ( iSeg >= cSeg ) goto punt; // Wasn't found at all! + + if ( lpModuleName && strlen(chName)+1 > nNameSize ) goto punt; + if ( lpModulePath && strlen(chPath)+1 > nPathSize ) goto punt; + + if ( lpModuleName != NULL ) strcpy( lpModuleName, chName ); + if ( lpModulePath != NULL ) strcpy( lpModulePath, chPath ); + if ( lpSegmentNumber != NULL ) *lpSegmentNumber = iSeg; + + fResult = TRUE; + +punt: + return( fResult ); +} + +//---------------------------------------------------------------------------- +// VDMGetModuleSelector() +// +// Interface to determine the selector for a given module's segment. +// This is useful during debugging to associate code and data segments +// with symbols. The symbol lookup should be done by the debugger, to +// determine the module and segment number, which are then passed to us +// and we determine the current selector for that module's segment. +// +// Again, this code was adapted from the Win 3.1 ToolHelp DLL +// +//---------------------------------------------------------------------------- +BOOL +WINAPI +VDMGetModuleSelector( + HANDLE hProcess, + HANDLE hThread, + UINT uSegmentNumber, + LPSTR lpModuleName, + LPWORD lpSelector +) { + BOOL b; + DWORD lpNumberOfBytes; + BOOL fResult; + WORD wModHandle; + DWORD lpModuleHead; + DWORD lpThisModuleName; + DWORD lpThisModuleNext; + DWORD lpThisModuleResTab; + DWORD lpThisModulecSeg; + DWORD lpThisModuleSegTab; + DWORD lpThisSegHandle; + WORD wResTab; + UCHAR cLength; + WORD cSeg; + WORD wSegTab; + WORD wHandle; + CHAR chName[MAX_MODULE_NAME_LENGTH]; + + *lpSelector = 0; + + fResult = FALSE; + + if ( wKernelSeg == 0 ) { + return( FALSE ); + } + + lpModuleHead = InternalGetPointer( + hProcess, + hThread, + wKernelSeg, + dwOffsetTHHOOK + TOOL_HMODFIRST, + TRUE ); + if ( lpModuleHead == (DWORD)NULL ) goto punt; + + // lpModuleHead is a pointer into kernels data segment. It points to the + // head of the module list (a chain of near pointers). + + b = ReadProcessMemory( + hProcess, + (LPVOID)lpModuleHead, + &wModHandle, + sizeof(wModHandle), + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != sizeof(wModHandle) ) goto punt; + + while( wModHandle != (WORD)0 ) { + + wModHandle |= 1; + + // Name is the first name in the resident names table + + lpThisModuleResTab = InternalGetPointer( + hProcess, + hThread, + wModHandle, + NE_RESTAB, + TRUE ); + if ( lpThisModuleResTab == (DWORD)NULL ) goto punt; + + b = ReadProcessMemory( + hProcess, + (LPVOID)lpThisModuleResTab, + &wResTab, + sizeof(wResTab), + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != sizeof(wResTab) ) goto punt; + + // Get the 1st byte of the resident names table (1st byte of module name) + + lpThisModuleName = InternalGetPointer( + hProcess, + hThread, + wModHandle, + wResTab, + TRUE ); + if ( lpThisModuleName == (DWORD)NULL ) goto punt; + + // PASCAL string (1st byte is length), read the byte. + + b = ReadProcessMemory( + hProcess, + (LPVOID)lpThisModuleName, + &cLength, + sizeof(cLength), + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != sizeof(cLength) ) goto punt; + + if ( cLength > MAX_MODULE_NAME_LENGTH ) goto punt; + + lpThisModuleName += 1; + + // Now go read the text of the name + + b = ReadProcessMemory( + hProcess, + (LPVOID)lpThisModuleName, + &chName, + cLength, + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != (DWORD)cLength ) goto punt; + + chName[cLength] = '\0'; // Nul terminate it + + if ( _stricmp(chName, lpModuleName) == 0 ) { + // Found the name which matches! + break; + } + + // Move to the next module in the list. + + lpThisModuleNext = InternalGetPointer( + hProcess, + hThread, + wModHandle, + NE_CBENTTAB, + TRUE ); + if ( lpThisModuleNext == (DWORD)NULL ) goto punt; + + b = ReadProcessMemory( + hProcess, + (LPVOID)lpThisModuleNext, + &wModHandle, + sizeof(wModHandle), + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != sizeof(wModHandle) ) goto punt; + } + + if ( wModHandle == (WORD)0 ) { + goto punt; + } + + // Ok, we found the module we need, now grab the right selector for the + // segment number passed in. + + lpThisModulecSeg = InternalGetPointer( + hProcess, + hThread, + wModHandle, + NE_CSEG, + TRUE ); + if ( lpThisModulecSeg == (DWORD)NULL ) goto punt; + + b = ReadProcessMemory( + hProcess, + (LPVOID)lpThisModulecSeg, + &cSeg, + sizeof(cSeg), + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != sizeof(cSeg) ) goto punt; + + if ( uSegmentNumber > (DWORD)cSeg ) goto punt; + + // Read the segment table pointer for this module + + lpThisModuleSegTab = InternalGetPointer( + hProcess, + hThread, + wModHandle, + NE_SEGTAB, + TRUE ); + if ( lpThisModuleSegTab == (DWORD)NULL ) goto punt; + + b = ReadProcessMemory( + hProcess, + (LPVOID)lpThisModuleSegTab, + &wSegTab, + sizeof(wSegTab), + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != sizeof(wSegTab) ) goto punt; + + lpThisSegHandle = InternalGetPointer( + hProcess, + hThread, + wModHandle, + wSegTab+(WORD)uSegmentNumber*NEW_SEG1_SIZE+NS_HANDLE, + TRUE ); + if ( lpThisSegHandle == (DWORD)NULL ) goto punt; + + b = ReadProcessMemory( + hProcess, + (LPVOID)lpThisSegHandle, + &wHandle, + sizeof(wHandle), + &lpNumberOfBytes + ); + if ( !b || lpNumberOfBytes != sizeof(wHandle) ) goto punt; + + *lpSelector = (WORD)(wHandle | 1); + + fResult = TRUE; + +punt: + return( fResult ); +} + +#define LONG_TIMEOUT INFINITE + +BOOL VDMCallRemote16( + HANDLE hProcess, + HANDLE hThread, + LPSTR lpModuleName, + LPSTR lpEntryName, + LPBYTE lpArgs, + WORD wArgsPassed, + WORD wArgsSize, + LPDWORD lpdwReturnValue, + DEBUGEVENTPROC lpEventProc, + LPVOID lpData +) { + HANDLE hRemoteThread; + DWORD dwThreadId; + DWORD dwContinueCode; + DEBUG_EVENT de; + BOOL b; + BOOL fContinue; + COM_HEADER comhead; + WORD wRemoteSeg; + WORD wRemoteOff; + WORD wOff; + UINT uModuleLength; + UINT uEntryLength; + + if ( lpRemoteAddress == NULL || lpRemoteBlock == 0 ) { +#ifdef DEBUG + OutputDebugString("Remote address or remote block not initialized\n"); +#endif + return( FALSE ); + } + + wRemoteSeg = HIWORD(lpRemoteBlock); + wRemoteOff = LOWORD(lpRemoteBlock); + wOff = wRemoteOff; + + // Fill in the communications buffer header + + READ_FIXED_ITEM( wRemoteSeg, wOff, comhead ); + + comhead.wArgsPassed = wArgsPassed; + comhead.wArgsSize = wArgsSize; + + uModuleLength = strlen(lpModuleName) + 1; + uEntryLength = strlen(lpEntryName) + 1; + + // + // If this call won't fit into the buffer, then fail. + // + if ( (UINT)comhead.wBlockLength < sizeof(comhead) + wArgsSize + uModuleLength + uEntryLength ) { +#ifdef DEBUG + OutputDebugString("Block won't fit\n"); +#endif + return( FALSE ); + } + + + WRITE_FIXED_ITEM( wRemoteSeg, wOff, comhead ); + wOff += sizeof(comhead); + + // Fill in the communications buffer arguments + WRITE_SIZED_ITEM( wRemoteSeg, wOff, lpArgs, wArgsSize ); + wOff += wArgsSize; + + // Fill in the communications buffer module name and entry name + WRITE_SIZED_ITEM( wRemoteSeg, wOff, lpModuleName, uModuleLength ); + wOff += uModuleLength; + + WRITE_SIZED_ITEM( wRemoteSeg, wOff, lpEntryName, uEntryLength ); + wOff += uEntryLength; + + hRemoteThread = CreateRemoteThread( + hProcess, + NULL, + (DWORD)0, + lpRemoteAddress, + NULL, + 0, + &dwThreadId ); + + if ( hRemoteThread == (HANDLE)0 ) { // Fail if we couldn't creaet thrd +#ifdef DEBUG + OutputDebugString("CreateRemoteThread failed\n"); +#endif + return( FALSE ); + } + + // + // Wait for the EXIT_THREAD_DEBUG_EVENT. + // + + fContinue = TRUE; + + while ( fContinue ) { + + b = WaitForDebugEvent( &de, LONG_TIMEOUT ); + + if (!b) { + TerminateThread( hRemoteThread, 0 ); + CloseHandle( hRemoteThread ); + return( FALSE ); + } + + if ( de.dwThreadId == dwThreadId && + de.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT ) { + fContinue = FALSE; + } + + if ( lpEventProc ) { + dwContinueCode = (* lpEventProc)( &de, lpData ); + } else { + dwContinueCode = DBG_CONTINUE; + } + + ContinueDebugEvent( de.dwProcessId, de.dwThreadId, dwContinueCode ); + + } + + b = WaitForSingleObject( hRemoteThread, LONG_TIMEOUT ); + CloseHandle( hRemoteThread ); + + if (b) { +#ifdef DEBUG + OutputDebugString("Wait for remote thread failed\n"); +#endif + return( FALSE ); + } + + // + // Get the return value and returned arguments + // + wOff = wRemoteOff; + + READ_FIXED_ITEM( wRemoteSeg, wOff, comhead ); + wOff += sizeof(comhead); + + *lpdwReturnValue = comhead.dwReturnValue; + + // Read back the communications buffer arguments + READ_SIZED_ITEM( wRemoteSeg, wOff, lpArgs, wArgsSize ); + + return( comhead.wSuccess ); + +punt: + return( FALSE ); +} + +DWORD +WINAPI +VDMGetRemoteBlock16( + HANDLE hProcess, + HANDLE hThread +) { + if ( lpRemoteBlock == 0 ) { + return( 0 ); + } + return( ((DWORD)lpRemoteBlock) + sizeof(COM_HEADER) ); +} + + +typedef struct { + DWORD dwSize; + DWORD dwAddress; + DWORD dwBlockSize; + WORD hBlock; + WORD wcLock; + WORD wcPageLock; + WORD wFlags; + WORD wHeapPresent; + WORD hOwner; + WORD wType; + WORD wData; + DWORD dwNext; + DWORD dwNextAlt; +} GLOBALENTRY16, *LPGLOBALENTRY16; + +VOID CopyToGlobalEntry16( + LPGLOBALENTRY lpGlobalEntry, + LPGLOBALENTRY16 lpGlobalEntry16 +) { + if ( lpGlobalEntry == NULL || lpGlobalEntry16 == NULL ) { + return; + } + lpGlobalEntry16->dwSize = sizeof(GLOBALENTRY16); + lpGlobalEntry16->dwAddress = lpGlobalEntry->dwAddress; + lpGlobalEntry16->dwBlockSize = lpGlobalEntry->dwBlockSize; + lpGlobalEntry16->hBlock = (WORD)lpGlobalEntry->hBlock; + lpGlobalEntry16->wcLock = lpGlobalEntry->wcLock; + lpGlobalEntry16->wcPageLock = lpGlobalEntry->wcPageLock; + lpGlobalEntry16->wFlags = lpGlobalEntry->wFlags; + lpGlobalEntry16->wHeapPresent = lpGlobalEntry->wHeapPresent; + lpGlobalEntry16->hOwner = (WORD)lpGlobalEntry->hOwner; + lpGlobalEntry16->wType = lpGlobalEntry->wType; + lpGlobalEntry16->wData = lpGlobalEntry->wData; + lpGlobalEntry16->dwNext = lpGlobalEntry->dwNext; + lpGlobalEntry16->dwNextAlt = lpGlobalEntry->dwNextAlt; +} + +VOID CopyFromGlobalEntry16( + LPGLOBALENTRY lpGlobalEntry, + LPGLOBALENTRY16 lpGlobalEntry16 +) { + if ( lpGlobalEntry == NULL || lpGlobalEntry16 == NULL ) { + return; + } + lpGlobalEntry->dwSize = sizeof(GLOBALENTRY); + lpGlobalEntry->dwAddress = lpGlobalEntry16->dwAddress; + lpGlobalEntry->dwBlockSize = lpGlobalEntry16->dwBlockSize; + lpGlobalEntry->hBlock = (HANDLE)lpGlobalEntry16->hBlock; + lpGlobalEntry->wcLock = lpGlobalEntry16->wcLock; + lpGlobalEntry->wcPageLock = lpGlobalEntry16->wcPageLock; + lpGlobalEntry->wFlags = lpGlobalEntry16->wFlags; + lpGlobalEntry->wHeapPresent = lpGlobalEntry16->wHeapPresent; + lpGlobalEntry->hOwner = (HANDLE)lpGlobalEntry16->hOwner; + lpGlobalEntry->wType = lpGlobalEntry16->wType; + lpGlobalEntry->wData = lpGlobalEntry16->wData; + lpGlobalEntry->dwNext = lpGlobalEntry16->dwNext; + lpGlobalEntry->dwNextAlt = lpGlobalEntry16->dwNextAlt; +} + + +BOOL +WINAPI +VDMGlobalFirst( + HANDLE hProcess, + HANDLE hThread, + LPGLOBALENTRY lpGlobalEntry, + WORD wFlags, + DEBUGEVENTPROC lpEventProc, + LPVOID lpData +) { +#define GF_SIZE 6 // 6 bytes are passed to GlobalFirst + BYTE Args[GF_SIZE+sizeof(GLOBALENTRY16)]; + LPBYTE lpbyte; + DWORD vpBuff; + DWORD dwResult; + BOOL b; + + if ( lpGlobalEntry->dwSize != sizeof(GLOBALENTRY) ) { + return( FALSE ); + } + + vpBuff = VDMGetRemoteBlock16( hProcess, hThread ); + vpBuff += GF_SIZE; + + lpbyte = Args; + + // Push the flags + (*(LPWORD)lpbyte) = wFlags; + lpbyte += sizeof(WORD); + + // Push the pointer to the pointer to the GLOBALENTRY16 structure + (*(LPWORD)lpbyte) = LOWORD(vpBuff); + lpbyte += sizeof(WORD); + + (*(LPWORD)lpbyte) = HIWORD(vpBuff); + lpbyte += sizeof(WORD); + + CopyToGlobalEntry16( lpGlobalEntry, (LPGLOBALENTRY16)lpbyte ); + + b = VDMCallRemote16( + hProcess, + hThread, + "TOOLHELP.DLL", + "GlobalFirst", + Args, + GF_SIZE, + sizeof(Args), + &dwResult, + lpEventProc, + lpData ); + + if ( !b ) { + return( FALSE ); + } + CopyFromGlobalEntry16( lpGlobalEntry, (LPGLOBALENTRY16)lpbyte ); + + + return( (BOOL)((WORD)dwResult) ); + +punt: + return( FALSE ); +} + + +BOOL +WINAPI +VDMGlobalNext( + HANDLE hProcess, + HANDLE hThread, + LPGLOBALENTRY lpGlobalEntry, + WORD wFlags, + DEBUGEVENTPROC lpEventProc, + LPVOID lpData +) { +#define GN_SIZE 6 // 6 bytes are passed to GlobalNext + BYTE Args[GN_SIZE+sizeof(GLOBALENTRY16)]; + LPBYTE lpbyte; + DWORD vpBuff; + DWORD dwResult; + BOOL b; + + if ( lpGlobalEntry->dwSize != sizeof(GLOBALENTRY) ) { + return( FALSE ); + } + + vpBuff = VDMGetRemoteBlock16( hProcess, hThread ); + vpBuff += GN_SIZE; + + lpbyte = Args; + + // Push the flags + (*(LPWORD)lpbyte) = wFlags; + lpbyte += sizeof(WORD); + + // Push the pointer to the pointer to the GLOBALENTRY16 structure + (*(LPWORD)lpbyte) = LOWORD(vpBuff); + lpbyte += sizeof(WORD); + + (*(LPWORD)lpbyte) = HIWORD(vpBuff); + lpbyte += sizeof(WORD); + + CopyToGlobalEntry16( lpGlobalEntry, (LPGLOBALENTRY16)lpbyte ); + + b = VDMCallRemote16( + hProcess, + hThread, + "TOOLHELP.DLL", + "GlobalNext", + Args, + GN_SIZE, + sizeof(Args), + &dwResult, + lpEventProc, + lpData ); + + if ( !b ) { + return( FALSE ); + } + CopyFromGlobalEntry16( lpGlobalEntry, (LPGLOBALENTRY16)lpbyte ); + + return( (BOOL)((WORD)dwResult) ); + +punt: + return( FALSE ); +} + +#pragma pack(2) +typedef struct { + DWORD dwSize; + char szModule[MAX_MODULE_NAME+1]; + WORD hModule; + WORD wcUsage; + char szExePath[MAX_PATH16+1]; + WORD wNext; +} MODULEENTRY16, *LPMODULEENTRY16; +#pragma pack() + +VOID CopyToModuleEntry16( + LPMODULEENTRY lpModuleEntry, + LPMODULEENTRY16 lpModuleEntry16 +) { + if ( lpModuleEntry == NULL || lpModuleEntry16 == NULL ) { + return; + } + lpModuleEntry16->dwSize = sizeof(MODULEENTRY16); + lpModuleEntry16->hModule = (WORD)lpModuleEntry->hModule; + lpModuleEntry16->wcUsage = lpModuleEntry->wcUsage; + lpModuleEntry16->wNext = lpModuleEntry->wNext; + strncpy( lpModuleEntry16->szModule, lpModuleEntry->szModule, MAX_MODULE_NAME ); + strncpy( lpModuleEntry16->szExePath, lpModuleEntry->szExePath, MAX_PATH16 ); +} + +VOID CopyFromModuleEntry16( + LPMODULEENTRY lpModuleEntry, + LPMODULEENTRY16 lpModuleEntry16 +) { + if ( lpModuleEntry == NULL || lpModuleEntry16 == NULL ) { + return; + } + lpModuleEntry->dwSize = sizeof(MODULEENTRY); + lpModuleEntry->hModule = (HANDLE)lpModuleEntry16->hModule; + lpModuleEntry->wcUsage = lpModuleEntry16->wcUsage; + lpModuleEntry->wNext = lpModuleEntry16->wNext; + strncpy( lpModuleEntry->szModule, lpModuleEntry16->szModule, MAX_MODULE_NAME ); + strncpy( lpModuleEntry->szExePath, lpModuleEntry16->szExePath, MAX_PATH16 ); +} + +BOOL +WINAPI +VDMModuleFirst( + HANDLE hProcess, + HANDLE hThread, + LPMODULEENTRY lpModuleEntry, + DEBUGEVENTPROC lpEventProc, + LPVOID lpData +) { +#define MF_SIZE 4 // 4 bytes are passed to ModuleFirst + BYTE Args[GF_SIZE+sizeof(MODULEENTRY16)]; + LPBYTE lpbyte; + DWORD vpBuff; + DWORD dwResult; + BOOL b; + + if ( lpModuleEntry->dwSize != sizeof(MODULEENTRY) ) { + return( FALSE ); + } + + vpBuff = VDMGetRemoteBlock16( hProcess, hThread ); + vpBuff += MF_SIZE; + + lpbyte = Args; + + // Push the pointer to the pointer to the MODULEENTRY16 structure + (*(LPWORD)lpbyte) = LOWORD(vpBuff); + lpbyte += sizeof(WORD); + + (*(LPWORD)lpbyte) = HIWORD(vpBuff); + lpbyte += sizeof(WORD); + + CopyToModuleEntry16( lpModuleEntry, (LPMODULEENTRY16)lpbyte ); + + b = VDMCallRemote16( + hProcess, + hThread, + "TOOLHELP.DLL", + "ModuleFirst", + Args, + MF_SIZE, + sizeof(Args), + &dwResult, + lpEventProc, + lpData ); + + if ( !b ) { + return( FALSE ); + } + CopyFromModuleEntry16( lpModuleEntry, (LPMODULEENTRY16)lpbyte ); + + return( (BOOL)((WORD)dwResult) ); + +punt: + return( FALSE ); +} + +BOOL +WINAPI +VDMModuleNext( + HANDLE hProcess, + HANDLE hThread, + LPMODULEENTRY lpModuleEntry, + DEBUGEVENTPROC lpEventProc, + LPVOID lpData +) { +#define MN_SIZE 4 // 4 bytes are passed to ModuleNext + BYTE Args[GF_SIZE+sizeof(MODULEENTRY16)]; + LPBYTE lpbyte; + DWORD vpBuff; + DWORD dwResult; + BOOL b; + + if ( lpModuleEntry->dwSize != sizeof(MODULEENTRY) ) { + return( FALSE ); + } + + vpBuff = VDMGetRemoteBlock16( hProcess, hThread ); + vpBuff += MN_SIZE; + + lpbyte = Args; + + // Push the pointer to the pointer to the MODULEENTRY16 structure + (*(LPWORD)lpbyte) = LOWORD(vpBuff); + lpbyte += sizeof(WORD); + + (*(LPWORD)lpbyte) = HIWORD(vpBuff); + lpbyte += sizeof(WORD); + + CopyToModuleEntry16( lpModuleEntry, (LPMODULEENTRY16)lpbyte ); + + b = VDMCallRemote16( + hProcess, + hThread, + "TOOLHELP.DLL", + "ModuleNext", + Args, + MN_SIZE, + sizeof(Args), + &dwResult, + lpEventProc, + lpData ); + + if ( !b ) { + return( FALSE ); + } + CopyFromModuleEntry16( lpModuleEntry, (LPMODULEENTRY16)lpbyte ); + + return( (BOOL)((WORD)dwResult) ); + +punt: + return( FALSE ); +} + +INT +WINAPI +VDMEnumProcessWOW( + PROCESSENUMPROC fp, + LPARAM lparam +) { + LPSHAREDTASKMEM lpstm; + LPSHAREDPROCESS lpsp; + DWORD dwOffset; + INT count; + BOOL f; + HANDLE hProcess; + + /* + ** Open the shared memory window + */ + lpstm = LOCKSHAREWOW(); + if ( lpstm == NULL ) { + // Wow must not be running + return( 0 ); + } + + // + // Now traverse through all of the processes in the + // list, calling the callback function for each. + // + count = 0; + dwOffset = lpstm->dwFirstProcess; + + while ( dwOffset != 0 ) { + lpsp = (LPSHAREDPROCESS)((CHAR *)lpstm + dwOffset); + + if ( lpsp->dwType != SMO_PROCESS ) { + // Some memory corruption problem + OutputDebugString("VDMDBG: Shared memory object is not a process? (memory corruption)\n"); + return( 0 ); + } + + // + // Make sure the process hasn't gone away because of a + // crash or other rude shutdown that prevents cleanup. + // + + hProcess = OpenProcess( + SYNCHRONIZE, + FALSE, + lpsp->dwProcessId + ); + + if (hProcess) { + + CloseHandle(hProcess); + + count++; + if ( fp ) { + f = (*fp)( lpsp->dwProcessId, lpsp->dwAttributes, lparam ); + if ( f ) { + UNLOCKSHAREWOW(); + return( count ); + } + } + + } else { + + // + // This is a ghost entry, change the process ID to zero + // so that the next WOW started will be sure to remove + // this entry even if the process ID is recycled. + // + + lpsp->dwProcessId = 0; + } + + dwOffset = lpsp->dwNextProcess; + } + + UNLOCKSHAREWOW(); + return( count ); +} + + +INT +WINAPI +VDMEnumTaskWOWWorker( + DWORD dwProcessId, + void * fp, + LPARAM lparam, + BOOL fEx +) { + LPSHAREDTASKMEM lpstm; + LPSHAREDPROCESS lpsp; + LPSHAREDTASK lpst; + DWORD dwOffset; + INT count = 0; + BOOL f; + + // + // Open the shared memory window + // + lpstm = LOCKSHAREWOW(); + if ( lpstm == NULL ) { + // Wow must not be running + return( 0 ); + } + + // + // Now traverse through all of the processes in the + // list, looking for the one with the proper id. + // + + dwOffset = lpstm->dwFirstProcess; + while ( dwOffset != 0 ) { + lpsp = (LPSHAREDPROCESS)((CHAR *)lpstm + dwOffset); + + if ( lpsp->dwType != SMO_PROCESS ) { + // Some memory corruption problem + OutputDebugString("VDMDBG: shared memory object is not a process? (memory corruption)\n"); + UNLOCKSHAREWOW(); + return( 0 ); + } + if ( lpsp->dwProcessId == dwProcessId ) { + break; + } + dwOffset = lpsp->dwNextProcess; + } + + if ( dwOffset == 0 ) { // We must not have found this Id. + UNLOCKSHAREWOW(); + return( 0 ); + } + + // + // Now enumerate all of the tasks for this process + // + dwOffset = lpsp->dwFirstTask; + while( dwOffset != 0 ) { + lpst = (LPSHAREDTASK)((CHAR *)lpstm + dwOffset ); + + if ( lpst->dwType != SMO_TASK ) { + // Some memory corruption problem + OutputDebugString("VDMDBG: shared memory object is not a task? (memory corruption)\n"); + UNLOCKSHAREWOW(); + return( 0 ); + } + count++; + if ( fp && lpst->hMod16 ) { + if (fEx) { + f = ((TASKENUMPROCEX)fp)( lpst->dwThreadId, lpst->hMod16, lpst->hTask16, + lpst->szModName, lpst->szFilePath, lparam ); + } else { + f = ((TASKENUMPROC)fp)( lpst->dwThreadId, lpst->hMod16, lpst->hTask16, lparam ); + } + if ( f ) { + UNLOCKSHAREWOW(); + return( count ); + } + } + dwOffset = lpst->dwNextTask; + } + + UNLOCKSHAREWOW(); + return( count ); +} + + +INT +WINAPI +VDMEnumTaskWOW( + DWORD dwProcessId, + TASKENUMPROC fp, + LPARAM lparam +) { + return VDMEnumTaskWOWWorker(dwProcessId, (void *)fp, lparam, 0); +} + + +INT +WINAPI +VDMEnumTaskWOWEx( + DWORD dwProcessId, + TASKENUMPROCEX fp, + LPARAM lparam +) { + return VDMEnumTaskWOWWorker(dwProcessId, (void *)fp, lparam, 1); +} + + +BOOL +WINAPI +VDMTerminateTaskWOW( + DWORD dwProcessId, + WORD htask +) +{ + BOOL fRet = FALSE; + LPSHAREDTASKMEM lpstm; + LPSHAREDPROCESS lpsp; + LPSHAREDTASK lpst; + DWORD dwOffset; + INT count; + HANDLE hProcess; + HANDLE hRemoteThread; + DWORD dwThreadId; + + // + // Open the shared memory window + // + lpstm = LOCKSHAREWOW(); + if ( lpstm == NULL ) { + // Wow must not be running + return( 0 ); + } + + // + // Now traverse through all of the processes in the + // list, looking for the one with the proper id. + // + + dwOffset = lpstm->dwFirstProcess; + while ( dwOffset != 0 ) { + lpsp = (LPSHAREDPROCESS)((CHAR *)lpstm + dwOffset); + + if ( lpsp->dwType != SMO_PROCESS ) { + // Some memory corruption problem + OutputDebugString("VDMDBG: shared memory object is not a process? (memory corruption)\n"); + goto UnlockReturn; + } + if ( lpsp->dwProcessId == dwProcessId ) { + break; + } + dwOffset = lpsp->dwNextProcess; + } + + if ( dwOffset == 0 ) { // We must not have found this Id. + goto UnlockReturn; + } + + // + // Get a handle to the process and start W32HungAppNotifyThread + // running with htask as the parameter. + // + + hProcess = OpenProcess( + PROCESS_ALL_ACCESS, + FALSE, + lpsp->dwProcessId + ); + + if (hProcess) { + + hRemoteThread = CreateRemoteThread( + hProcess, + NULL, + 0, + lpsp->pfnW32HungAppNotifyThread, + (LPVOID) htask, + 0, + &dwThreadId + ); + + if (hRemoteThread) { + fRet = TRUE; + CloseHandle(hRemoteThread); + } + + CloseHandle(hProcess); + } + + +UnlockReturn: + UNLOCKSHAREWOW(); + + return fRet; +} + + +BOOL +VDMStartTaskInWOW( + DWORD pidTarget, + LPSTR lpCommandLine, + WORD wShow +) +{ + HWND hwnd = NULL; + DWORD pid; + BOOL fRet; + + do { + + hwnd = FindWindowEx(NULL, hwnd, TEXT("WowExecClass"), NULL); + + if (hwnd) { + + pid = 0; + GetWindowThreadProcessId(hwnd, &pid); + } + + } while (hwnd && pid != pidTarget); + + + if (hwnd && pid == pidTarget) { + +#define WM_WOWEXEC_START_TASK (WM_USER+2) + PostMessage(hwnd, WM_WOWEXEC_START_TASK, GlobalAddAtom(lpCommandLine), wShow); + fRet = TRUE; + + } else { + + fRet = FALSE; + } + + return fRet; +} |