Category : Files from Magazines
Archive   : DDJ9403A.ZIP
Filename : UC394.ASC

 
Output of file : UC394.ASC contained in archive : DDJ9403A.ZIP
_UNDOCUMENTED CORNER COLUMN_
edited by Andrew Schulman
"RINGO: VXDS ON THE FLY"
by Alex Shmidt


Listing 1

/* CALLGATE.H */
typedef DWORD (FAR PASCAL *GATEPROC)(WORD svc, WORD cnt, DWORD extra);

/* SeeYouAtRing0 services */
#define Get386_Svc 0 //get system info
#define PhysToLin_Svc Get386_Svc + 1 //map phys to linear
#define Register_Hwnd_Svc PhysToLin_Svc + 1 //register HWND
#define Unregister_Hwnd_Svc Register_Hwnd_Svc + 1 //unregister HWND
#define StopVM_Svc Unregister_Hwnd_Svc + 1 //toggle DOS box exec
#define RemapGate_Svc StopVM_Svc + 1 //remap call gate

typedef struct { /* call gate procedure parameters */
DWORD G_Dword; // Dword parameter
WORD G_Word; // Word parameter
WORD G_Svc; // service number
}GPARAM;

/* RingoInit functions */
#define EXITRINGO 0xFFFF
#define INITRINGO 0



Listing 2

/* RINGO.C -- excerpts */
//#define CALLGATE_386 //define CALLGATE_386 to get gates from CALLGATE.386

#include
#include "386.h"
#include "callgate.h"

#ifdef CALLGATE_386
GATEPROC GetFirstCallGateVxD (FARPROC entrypoint,BYTE paramcount);
void DestroyInitGateVxD (WORD callgateselector);
#endif

VOID WINAPI RingoInit(void);
VOID WINAPI SeeYouAtRing0(void);
VOID WINAPI MakeSureOurSegIsInMemory(void);
GATEPROC GetLdtRing0CallGate (FARPROC entrypoint,
BYTE paramcount,WORD callgate);
GATEPROC GDT_Gate,LDT_Gate;

int FAR PASCAL LibMain ( HANDLE hInstance, WORD wDataSeg,
WORD cbHeapSize, LPSTR lpszCmdLine )
{
FARPROC ri = (FARPROC) RingoInit;

if (!(GetWinFlags () & WF_ENHANCED)) /*VxDs exist in enhanced mode only*/
return 0;

#ifdef CALLGATE_386 // get the GDT call gate from CALLGATE.386
if (!(LDT_Gate = GetFirstCallGateVxD (ri, sizeof(GPARAM)/4)))
#else // get the LDT call gate with INT 2F, AX=168A
if (!(LDT_Gate = GetLdtRing0CallGate (ri, sizeof(GPARAM)/4, 0)))
#endif
return 0;

/*** get the main call gate in GDT ***/
GDT_Gate = (GATEPROC)LDT_Gate (INITRINGO, sizeof(GPARAM)/4,
(DWORD)SeeYouAtRing0);
if (cbHeapSize)
UnlockData (0);
return (1);
}

char vendor[] = "MS-DOS"; // Microsoft's signature

GATEPROC GetLdtRing0CallGate (FARPROC gproc, BYTE params,WORD gatesel)
{
#define VENDOR_SPECIFIC_API 0x168a
WORD ldt_map; // LDT selector, which maps LDT itself
WORD (far * entryp)(void); // entry point to get the above
LPCALLGATEDESCRPT CGateDescriptor; // build call gate descriptor with this
WORD RW_ldt_map; /* ldt map selector fixes segment read-only problem */
WORD CGateSelector; // to be a call gate selector
DWORD initgate_flat; // callgate procedure's linear address

_asm {
mov si, offset vendor
mov ax, VENDOR_SPECIFIC_API
int 2fh
or al, al
jnz no_vendor
mov word ptr [entryp], di /* private entry point */
mov word ptr [entryp+2], es
mov ax, 100h /* magic number */
}

ldt_map = entryp(); /* returns LDT map selector */

_asm jnc vendor_ok
no_vendor:
return 0;

vendor_ok:
// When run under SoftICE/W LDT alias returns read_only, give us a good one
if (!(RW_ldt_map = AllocSelector(SELECTOROF((void FAR *)&GDT_Gate))))
return 0;
SetSelectorBase(RW_ldt_map, GetSelectorBase(ldt_map));
SetSelectorLimit(RW_ldt_map, GetSelectorLimit(ldt_map));
if ((CGateSelector = gatesel) == 0) // we might already have one
if (!(CGateSelector = AllocSelector(0))) // Get a selector for the gate
{
FreeSelector (RW_ldt_map);
return 0;
}

// create a pointer to write into the LDT
CGateDescriptor = MAKELP(RW_ldt_map,CGateSelector & SELECTOR_MASK);

// build 32-bit ring 3-to-0 call gate
#define MK_LIN(x) (GetSelectorBase(SELECTOROF(x)) + (DWORD)OFFSETOF(x))
initgate_flat = MK_LIN(gproc);
CGateDescriptor->Offset_O_15 = LOWORD (initgate_flat);
CGateDescriptor->Offset_16_31 = HIWORD (initgate_flat);
CGateDescriptor->Selector = 0x28; // ring0 flat code seg
CGateDescriptor->DWord_Count = params & CALLGATE_DDCOUNT_MASK;
CGateDescriptor->Access_Rights = GATE32_RING3; //pres,sys,dpl3,32CallGate
FreeSelector (RW_ldt_map); // don't need you any more
return ((GATEPROC)MAKELP(CGateSelector,0));
}

DWORD WINAPI _export MapPhysToLinear (DWORD physaddr, WORD mapsize)
{
return (GDT_Gate)(PhysToLin_Svc,mapsize,physaddr); /* DPMI alternative */
}



Listing 3

;;; RINGO.INC -- excerpts

GPARAM struc ; parameters
G_Dword dd ?
G_Word dw ?
G_Svc dw ?
GPARAM ends
CALLGATE_FRAME struc ; stack frame at the time of ring transition
CG_pushbp dd ?
CG_Old_EIP dd ? ; this is where we came from
CG_Old_CS dd ? ; and will get back
CG_Params db (type GPARAM) dup (?) ; call gate parameters
CG_Old_ESP dd ? ; caller's
CG_Old_SS dd ? ; stack
CALLGATE_FRAME ends

BuildGateStackFrame macro dataseg
push ebp
mov ebp,esp
push gs
push ds
push es
push fs
push esi
push edi
ifidni ,<_DATA>
mov ax,ds
mov gs,ax ; we'll access our data seg via gs
endif
mov ax,ss
mov ds,ax ; ring 0 flat data delector
mov es,ax
mov fs,ax
ifdifi ,<_DATA>
call GetRingoGdtDataSel
endif
endm

ClearGateStackFrame macro cleanup
pop edi
pop esi
pop fs
pop es
pop ds
pop gs
pop ebp
ret cleanup
endm

movoffs macro reg,off32 ; run-time fixup
mov reg, offset &off32
add reg,gs:[ringo_flat]
endm



Listing Four

;;; CALLGATE.ASM -- excerpts

.386p
include vmm.inc
include ringo.inc
include 386.inc
public RingoInit,SeeYouAtRing0,MakeSureOurSegIsInMemory
_GATESEG segment dword use32 public 'CODE'
assume cs:_GATESEG,gs:_DATA
RingoInit proc far
BuildGateStackFrame _DATA
cmp [ebp].CG_Params.G_Svc,EXITRINGOCALL
jnz short @f
call RingoExit ; deallocate everything we've got
jmp short retini
@@: call RelocateRingo ; run-time relocation and fixups
jc short init_ret
call DynalinkTrick ; get the VxD chain root
call InsertRingoDDB ; welcome to the VxD club
call CreateRingoGDTGate ; GDT call gate to SeeYouAtRing0
retini: mov edx, eax ; prepare return values for the ring 3
shr edx, 16
ClearGateStackFrame ; clear both ring stack frames
RingoInit endp

SeeYouAtRing0 proc far ; The callgate service proc
BuildGateStackFrame
VMMCall Get_Cur_VM_Handle ; always helpful
movzx eax, [ebp].CG_Params.G_Svc ; service dispatcher
cmp eax,LASTSVC
ja @f
call gs:Gate_Service_Table[eax*4]
@@: mov edx, eax
shr edx, 16
ClearGateStackFrame
SeeYouAtRing0 endp

CreateRingoGDTGate proc
movzx edx, word ptr [ebp].CG_Params.G_Dword ; offset16
add edx,gs:[ringo_flat] ; fixup
mov ax, cs ; VMM code selector
mov cx, [ebp].CG_Params.G_Word ; parameter count
and cx, CALLGATE_DDCOUNT_MASK ; make sure it's a reasonable number
or cx, GATE32_RING3 ; call gate type
call BuildCallGateDWords
VMMCall _Allocate_GDT_Selector, ; undocumented flag
ror eax,16
ret
CreateRingoGDTGate endp

BeginProc DestroyGDTCallGate,public
movzx eax,[ebp].CG_Params.G_Word
VMMCall _Free_GDT_Selector,
ret
EndProc DestroyGDTCallGate

BuildCallGateDWords proc
movzx eax, ax
shl eax, 16 ; selector
mov ax, dx ; offset 0-15
mov dx, cx ; offset 16-31 + type + count
ret
BuildCallGateDWords endp

;****************************************************************************
; To get the VxD Base (VMM DDB ptr) we're using the undocumented fact that
; VMM's dynalink handler (considered a 'fault' 20h in DDK spec parlance)
; returns it in ecx. The idea is to hook VMM fault 20h, call any VMM service
; to get our fault handler receive control, call VMM's dynalink directly,
; store ecx in a static variable, and hook fault 20h again, this time
; with fault handlers reversed.
;****************************************************************************

BeginProc DynalinkTrick
mov esi, gs:[OurDynalinkHandler]
twice: mov eax, 20h
VMMCall Hook_VMM_Fault ; install our handler
mov gs:[OLD_DYNALINK_HANDLER], esi
VMMCall Get_VMM_Version ; need one call get it executed
cmp esi, gs:[OurDynalinkHandler]
jnz twice
mov eax, gs:[VXD_FIRST]
ret
EndProc DynalinkTrick

Ringo_Dynalink_Handler proc
call gs:[OLD_DYNALINK_HANDLER]
mov gs:[VXD_FIRST], ecx ; DDB pointer
ret
Ringo_Dynalink_Handler endp

PhysToLin proc ; physical to linear address mapping
movzx ecx, [ebp].CG_Params.G_Word
VMMcall _MapPhysToLinear,<[ebp].CG_Params.G_Dword,ecx,0>
ret
PhysToLin endp

ringo_flat dd 0 ; run-time space base
OLD_DYNALINK_HANDLER dd 0
VXD_FIRST dd 0 ; VxD chain root
OurDynalinkHandler dd offset Ringo_Dynalink_Handler
Ringo_DDB VxD_Desc_Block <,,,1,0,,'Ringo ',,offset RingoControlProc,,,,,,,>
Gate_Service_Table label dword
dd offset Get386
dd offset PhysToLin
dd offset RegisterHWND
dd offset UnregisterHWND
dd offset StopVM
dd offset RemapCallGate
_GATESEG ends
end



  3 Responses to “Category : Files from Magazines
Archive   : DDJ9403A.ZIP
Filename : UC394.ASC

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/