.386p
.XLIST
include tvmm2.inc
include debug2.inc
.LIST
locals
VDONGLE_Major_Ver equ 1
VDONGLE_Minor_Ver equ 06
VDONGLE_Ver equ VDONGLE_Major_Ver*256+VDONGLE_Minor_Ver
VDONGLE_Device_ID equ 3B48h ;ab Version 1.02
;>You have been assigned a device ID of 3B48h for your VELGNOD.386 virtual
;>device. This number is uniquely assigned to this device.
Declare_Virtual_Device VDONGLE, VDONGLE_Major_Ver, VDONGLE_Minor_Ver,\
VDONGLE_Control_Proc, VDONGLE_Device_ID,\
3B000000h, , VDONGLE_API
;3C000000 ist die VPD_Init_Order des konkurrierenden VPD.VXD unter Windows95
;Int2F-API-Funktionen (Nur für System-VM):
;AH=0 Versionsnummer besorgen (AH=Hauptversion, AL=Nebenversion)
;AH=1 Callback-Adresse festlegen (ES:BX=Adresse)
; Callback wird mit AL=Datenbyte und AH=Port-Festlegung gerufen
; AH Bits 0..1 geben Portadresse an, AH Bit 2 ist beim Lesen gesetzt
;AH=2 Callback und Puffer ausschalten (beim Beenden der .EXE bzw. in der
; WEP der .DLL aufrufen)
;AH=3 Emulationsmodus einschalten (AL=1) oder ausschalten (AL=0)
; Bei inaktivem Callback bezieht sich die "Emulation" auf das
; Vorgaukeln eines fehlenden Dongles - Vermeidung von Portzugriffen
; z.B. bei schlecht gecrackten Programmen in Verbindung mit LPTDAC
; AL=FF (altes API: AL=2) fragt aktuelle Stellung ab; Ergebnis in AL
; Standard ist AUSgeschaltet.
;AH=4 Zugriff-Knack einschalten (AL=1) oder ausschalten (AL=0)
; AL=FF (altes API: AL=2) fragt aktuelle Stellung ab; Ergebnis in AL
; Standard ist EINgeschaltet, beeinflußbar über SYSTEM.INI-Eintrag
;AH=5 V.1.01: Puffer aktivieren (ES:BX=Adresse, CX=Länge in WORDs)
; Der Puffer ist in Words organisiert, ähnlich einem Pascal-String
; mit Unicode-Zeichen, und mit vorangestelltem Längen-Word.
; Abschluß der Kette bildet ein IN-Befehl, der ebenfalls mit ab-
; gespeichert wird (jedoch nicht in die Längen-Zählung eingeht).
; Ist der Puffer zu kurz, enthält das Längen-Word CX-1 und nur
; OUT-Befehle (kein IN am Ende). Deshalb: Puffer ausreichend
; dimensionieren, z.B. 2048 Words groß.
; V.1.03: Ist ES=0, dann reserviert VDONGLE.386 einen Puffer und
; einen GDT-Eintrag; der Selektor darauf wird in AX zurückgeliefert
;AH=6 V.1.04: Int21/AH=2C (Uhrzeit abholen, hh:mm:ss:hh = CH:CL:DH:DL)
; abfangen und an Callback mit AX=2C01 und EDX=Uhrzeit weiterreichen.
; AL=1: einschalten, AL=0: ausschalten, AL=FF: Stellung abfragen
; Zweck ist das Anhalten bzw. definierte Starten von
; Zufallsgeneratoren. Der Callback kann mit AL=0 verhindern, daß die
; originale Routine gerufen wird. Mit AX=2C23h kann der Callback die
; wirkliche Uhrzeit abholen, ohne daß reentrant der Callback gerufen
; wird (Hintertür) [V.1.06: Nur System_VM trappen]
;AH=7 V.1.05: Trapping aktivieren (AL=1) oder deaktivieren (AL=0)
;AH=8 V.1.06: OUT-Zusammenfassung aktivieren (AL=1), deaktivieren (AL=0)
; bzw. abfragen (AL=FFh)
;*******************************************
;*** Residente Daten und Code (pageable) ***
;*******************************************
VxD_DATA_SEG
PortBase dd 378h ;Portadresse der Emulation
;Die Portadresse wird durch "VDonglePort=LPTx" oder "...=xxx" unter [386enh]
;festgelegt. (Gilt nicht für Sys_Dynamic_Init)
; Standard ist LPT1, falls vorhanden, sonst 378h
; (bei Sys_Dynamic_Init =37C, wegen VPD.VXD bzw. VLPT.SYS)
PhysBase dd 378h ;Physikalische Portadresse
;Die Portadresse wird durch "VDonglePhys=LPTx" oder "...=xxx" unter [386enh]
;festgelegt. (Gilt nicht für Sys_Dynamic_Init)
; Standard ist LPT1, falls vorhanden, sonst 378h
; (auch bei Sys_Dynamic_Init)
CallbackAdr dd 0 ;16:16-Rückruf-Funktion in System-VM
BufferAdr dd 0 ;FLAT-Pufferadresse
BufferLen dd 0 ;Puffer-Länge in WORDs
EmuMode db 0 ;Emulation ein/aus
TickSound db 1 ;Knackgeräusch über Speaker ein/aus
;Das Knackgeräusch kann mit "VDongleTick=off" unter [386enh] per defaut
;ausgeschaltet werden. (Gilt nicht für Sys_Dynamic_Init)
;Hier folgen die Daten für die Emulation (EmuMode<>0)
DataMirror db 0
CtlIMirror db 11000111b ;"Read-Only"!
CtlOMirror db 11101100b
RetVal db 0
HeapSel dw 0 ;Heap-Selektor
Semaphore dd 0 ;Handle zum Einschläfern von DOS-Boxen...
ChangedPort dw 0 ;zur Rücknahme des Patches beim Beenden
WasAddr dw 0
DosTime dd ? ;Übergabezelle für Longints
HookSwitch db 0
ConcatEquals db 0 ;Identische Zugriffe im Puffer zusammenfassen
align 4
uptab dd OFFSET32 GetVer
dd OFFSET32 SetCallback
dd OFFSET32 RemoveCallback
dd OFFSET32 SetEmu
dd OFFSET32 SetTick
dd OFFSET32 SetBuffer
dd OFFSET32 Hook212C
dd OFFSET32 TrapControl
dd OFFSET32 SetConcat
VxD_DATA_ENDS
VxD_CODE_SEG
;VxD-obligatorische Steuer-Prozedur
BeginProc VDONGLE_Control_Proc
Debug_Out "VDONGLE: ControlProc"
Control_Dispatch Device_Init, VDONGLE_Init
Control_Dispatch System_Exit, VDONGLE_Exit
Control_Dispatch Init_Complete, VDONGLE_Init2
Control_Dispatch 1bh, VDONGLE_Dynamic_Init
Control_Dispatch 1ch, VDONGLE_Dynamic_Exit
clc
ret
EndProc VDONGLE_Control_Proc
BeginProc VDONGLE_Exit
mov eax,[Semaphore]
VMMCall Destroy_Semaphore
call UnEditLpt ;Edition zurücknehmen
stc
ret
EndProc VDONGLE_Exit
BeginProc VDONGLE_Dynamic_Exit
call ClearHeap
call VDONGLE_Exit ;Semaphore verwerfen
mov edx,[PortBase]
LD ecx,3
@@l: VMMCall 00010116h ;Remove_IO_Handler
inc edx
loopd @@l
LD eax,21h
lea esi,NewInt21
VMMjmp 00010118h ;Unhook_V86_Int_Chain
EndProc VDONGLE_Dynamic_Exit
EnableTrappings proc
mov edx,[PortBase]
LD ecx,3
@@l: VMMCall Enable_Global_Trapping
inc edx
loop @@l
ret
EnableTrappings endp
;Ein Tick aus dem Lautsprecher ausgeben...
MakeTick proc
cmp [TickSound],0 ;eingeschaltet?
jz @@e ;nein, schweigen!
push eax
pushf
BTST [TickSound],bit 1 ;LAUT eingeschaltet?
cli
jz @@1 ;nein, schweigen!
mov al,10100000b ;Zähler 2 (Speaker) auf Modus 0 (Intr am Ende)
out 43h,al
mov al,2 ;512, rund 1/2 Millisekunde
out 42h,al ;Puls definierter Länge ausgeben
@@1: in al,61h
or al,3
out 61h,al ;und hörbar machen!
popf
pop eax
@@e: ret
MakeTick endp
EndTick proc
cmp [TickSound],1 ;eingeschaltet (nicht LAUT?)
jne @@e ;nein, nichts tun!
push eax
pushf
cli
in al,61h
and al,not 3
out 61h,al ;und AUS!
popf
pop eax
@@e: ret
EndTick endp
;Callback rufen; die richtige VM ist bereits aktiv
;AX wird ins Callback hinein gegeben; AL wird als Ergebnis durchgereicht
CallCallback proc
cmp [CallbackAdr],0
jz @@e ;hier: Notbremse!
Push_Client_State Uses_EDI
VMMCall Begin_Nest_Exec
mov [ebp.Client_AX],ax ;AX zum Aufruf setzen!
mov eax,[DosTime]
mov [ebp.Client_EDX],eax
movzx edx,word ptr [CallbackAdr]
mov cx,word ptr [CallbackAdr+2]
VMMCall Simulate_Far_Call
VMMCall Resume_Exec
mov eax,[ebp.Client_EDX]
mov [DosTime],eax
mov al,[ebp.Client_AL] ;AL als Ergebnis liefern
VMMCall End_Nest_Exec
Pop_Client_State Uses_ESI
@@e: ret
CallCallback endp
;Callback rufen und wartenden Prozeß aufwecken
Call3back proc
mov eax,edx
call CallCallback
mov [RetVal],al ;Ergebnis sichern
mov eax,[Semaphore]
VMMCall Signal_Semaphore
ret
Call3back endp
;Direktaufruf oder via Priority_VM_Event...
CallWindows proc
cmp [CallbackAdr],0
jz @@e ;Ohne Callback kein Windows-Ruf
VMMCall Test_Sys_VM_Handle ;Aktuelle VM ist System-VM?
jz CallCallback ;Ja - Direkt-Aufruf!
;Callback vermitteln und einschlafen
mov edx,eax
mov eax,Time_Critical_Boost
VMMCall Get_Sys_VM_Handle
xor ecx,ecx
lea esi,Call3back
VMMCall Call_Priority_VM_Event
mov eax,[Semaphore]
LD ecx,Block_Svc_Ints or Block_Enable_Ints
VMMCall Wait_Semaphore
mov al,[RetVal]
@@e: ret
CallWindows endp
PutInList proc
mov esi,[BufferAdr]
cmp esi,1
jc @@e ;Kein Puffer - raus!
movzx edx,word ptr [esi] ;Aktuelle String-Länge
cmp [ConcatEquals],0
jz @@1 ;Immer eintragen!
or edx,edx ;Puffer leer?
jz @@1 ;Dann auch immer eintragen!
cmp [esi+edx*2],ax ;Schon vorhanden?
jz @@e ;ja, ignorieren - und CY=0
@@1: inc edx
mov [esi+edx*2],ax ;Befehl eintragen
bt eax,10 ;IN-Befehl?
jc @@e ;Windows rufen
mov [esi],dx ;String ist länger geworden...
cmp edx,[BufferLen] ;Puffer voll - CY=0 ?
cmc ;CY umdrehen
@@e: ret
PutInList endp
;------------------------------------------------------------------------------
; ENTRY:
; EBX = VM Handle.
; ECX = Type of I/O
; EDX = Port number
; EBP = Pointer to client register structure
; EXIT:
; EAX = data input or output depending on type of I/O
;------------------------------------------------------------------------------
BeginProc IOCallback High_Freq
push esi edi
call MakeTick
Dispatch_Byte_IO Fall_Through, @@O
sub edx,[PortBase]
mov al,[DataMirror+edx]
cmp [EmuMode],0
jnz @@1 ;Emulation EIN, vom Spiegel lesen!
push edx
add edx,[PhysBase]
in al,dx ;Emu AUS, vom Dongle lesen!
pop edx
@@1: mov ah,dl
or ah,4 ;Bit 2 als IN-Kennung setzen
jmp @@5
@@O:
sub edx,[PortBase]
cmp dl,1 ;Ausnahme: Eingabeport?
je @@4 ;Nicht beschreiben
mov [DataMirror+edx],al ;Mirror beschreiben
@@4: cmp [EmuMode],0
jnz @@3 ;Emulation EIN, zum Spiegel schreiben!
push edx
add edx,[PhysBase]
out dx,al ;Emu AUS, zum Dongle schreiben!
pop edx
@@3: mov ah,dl
@@5: call PutInList ;liefert CY, wenn CallWindows erforderlich
jnc @@e
call CallWindows ;Callback rufen (falls vorhanden)
call ClearBuffer
@@e: call EndTick
clc
pop edi esi
ret
EndProc IOCallback
BeginProc NewInt21, High_Freq
VMMCall Test_Sys_VM_Handle
jnz @@cont ;Weiter, wenn Ruf aus DOS-Box
mov eax,[ebp.Client_EAX]
cmp ah,2Ch
jnz @@cont
cmp al,'#' ;Spezielle Kennung
jz @@cont
cmp [HookSwitch],1
jnz @@cont ;Ausgeschaltet!
call MakeTick
push [ebp.Client_CX] ;hh:mm
push [ebp.Client_DX] ;ss:hs
pop [DosTime] ;im LongInt zusammenfassen
mov al,1
BSET [HookSwitch],bit 7 ;Reenter-Flag
call CallWindows
BRES [HookSwitch],bit 7 ;Reenter-Flag
call EndTick
or al,al
jnz @@cont
push [DosTime]
pop [ebp.Client_DX] ;ss:hs
pop [ebp.Client_CX] ;hh:mm
ret ;CY=0
@@cont:
stc
ret
EndProc NewInt21
GetVer proc
mov [ebp.Client_AX],VDONGLE_Ver
ret
GetVer endp
SetCallback proc
push [ebp.Client_ES]
push [ebp.Client_BX]
rcb1: pop [CallbackAdr]
ret
SetCallback endp
RemoveCallback proc
call ClearHeap
xor eax,eax ;Ausnullen
mov [BufferAdr],eax
mov [BufferLen],eax
push 0
jmp rcb1
RemoveCallback endp
SetEmu:
lea esi,EmuMode
jmp GetSetSwitch
SetTick:
lea esi,TickSound
jmp GetSetSwitch
Hook212C:
lea esi,HookSwitch
jmp GetSetSwitch
SetConcat:
lea esi,ConcatEquals
GetSetSwitch proc
mov al,[ebp.Client_AL]
cmp al,0FFh
je @@1
xchg [esi],al ;Alte Schalterstellung liefern!
jmp @@2
@@1: mov al,[esi]
@@2: mov [ebp.Client_AL],al
ret
GetSetSwitch endp
TrapControl proc
mov al,[ebp.Client_AL]
or al,al
jnz EnableTrappings
DisableTrappings:
mov edx,[PortBase]
LD ecx,3
@@l: VMMCall Disable_Global_Trapping
inc edx
loop @@l
ret
TrapControl endp
BeginProc SetBuffer
movzx ecx,[ebp.Client_CX]
cmp ecx,2 ;Mindestens 2 WORDs?
jc @@z
cmp [ebp.Client_ES],0 ;Selektor Null?
jnz @@2
push ecx
add ecx,ecx ;in Bytes!
call ReAllocHeap
mov [ebp.Client_AX],ax ;Selektor in AX zurückliefern
pop ecx
jmp @@3
@@2: push ecx
call ClearHeap
pop ecx
Client_Ptr_Flat eax,ES,BX
cmp eax,-1
jnz @@1
@@z: xor eax,eax
xor ecx,ecx
@@1: mov [BufferAdr],eax
@@3: dec ecx ;maximale Pascal-String-Länge
mov [BufferLen],ecx ;Adresse und Länge eintragen
EndProc SetBuffer
BeginProc ClearBuffer
mov esi,[BufferAdr]
or esi,esi
jz @@e
mov word ptr [esi],0
@@e: ret
EndProc ClearBuffer
ClearHeap:
xor ecx,ecx
ReAllocHeap proc
;PE: ECX=neue Heap-Größe (0=Heap aufräumen, falls vorhanden)
; [BufferAdr]=Heap-Adresse (nur wenn HeapSel<>0, sonst Annahme: kein Heap)
; [HeapSel]=alter Heap-Selektor
;PA: [BufferAdr]=neue Heap-Adresse
; [HeapSel]=AX=neuer Heap-Selektor
cmp [HeapSel],0
jnz @@realloc
jecxz @@e2 ;Nichts tun! (Dreifachsprung wegen Codegröße)
push ecx ;_HeapAllocate zerstört ECX!!
VMMCall _HeapAllocate, <ecx,0>
pop ecx
or eax,eax
@@e2: jz @@e1 ;Fehler!
mov [BufferAdr],eax
dec ecx ;Größe-->Limit
VMMCall _BuildDescriptorDWORDS, <eax,ecx,RW_Data_Type,0,0>
;Selektor besorgen
VMMCall _Allocate_GDT_Selector, <edx,eax,0>
mov [HeapSel],ax
or eax,eax
jnz @@e1 ;Okay!
jmp @@freemem
@@realloc:
jecxz @@free
push ecx ;_HeapReAllocate vermutlich auch!
VMMCall _HeapReAllocate, <[BufferAdr],ecx,HeapNoCopy>
pop ecx
mov [BufferAdr],eax ;Neue lineare Adresse!
or eax,eax
jz @@free
dec ecx
VMMCall _BuildDescriptorDWORDS, <eax,ecx,RW_Data_Type,0,0>
movzx ecx,[HeapSel]
VMMCall _SetDescriptor, <ecx,ebx,edx,eax,0>
@@e1: jmp @@e ;Okay!
@@free:
xor eax,eax
xchg [HeapSel],ax
VMMCall _Free_GDT_Selector, <eax,0>
@@freemem:
xor eax,eax
xchg [BufferAdr],eax
or eax,eax
jz @@e
VMMCall _HeapFree, <eax,0>
@@e: mov ax,[HeapSel]
ret
ReAllocHeap endp
BeginProc VDONGLE_API
Debug_Out "VDONGLE: API Call"
VMMCall Test_Sys_VM_Handle
jnz @@e ;Anforderungen aus DPMI-Programmen verweigern
movzx eax,[ebp.Client_AH]
cmp eax,8
ja @@err
call [uptab+eax*4]
@@ok: BRES [ebp.Client_Flags],CF_Mask
jmp @@e
@@err: BSET [ebp.Client_Flags],CF_Mask
@@e: ret
EndProc VDONGLE_API
UnEditLpt proc ;Änderungen in der BIOS-Tabelle zurücknehmen
movzx esi,[ChangedPort]
or esi,esi
jz @@e
mov dx,[WasAddr]
mov [esi],dx
@@e: ret
UnEditLpt endp
VxD_CODE_ENDS
;****************************************
;*** Initialisierungs-Daten und -Code ***
;****************************************
VxD_IDATA_SEG
Port$ db "VDonglePort",0
Phys$ db "VDonglePhys",0
Tick$ db "VDongleTick",0
Trap$ db "VDongleTrap",0
VxD_IDATA_ENDS
VxD_ICODE_SEG
GetEntry proc
;PE: EDI=String, ESI=0 (!!)
;PA: EAX=Portadresse
; CY=1: kein oder ungültiger Eintrag
VMMCall Get_Profile_String
jc @@e ;Nicht gefunden? - Nicht auswerten!
mov eax,[edx]
and eax,00DFDFDFh ;Großbuchstaben!
cmp eax,'TPL' ;"LPT"?
je @@2 ;ja
VMMCall Convert_Hex_String
cmp byte ptr [edx],1 ;korrekt null-terminiert?
cmc
jmp @@e
@@2:
mov al,[edx+3] ;Nummer...
sub al,'1'
cmp al,4
cmc
jc @@e
movzx eax,al
movzx eax,word ptr [408h+eax*2] ;LPT-Adresse...
cmp eax,1 ;Null? (Wäre ein Fehler!)
@@e: ret
GetEntry endp
EditLpt proc
;PE: [PortBase]=Portadresse
;PA: diese Portadresse wird global (??) in 408h eingetragen.
; Falls keine Adresse frei ist (OS/2-Szenario), wird LPT3 überbügelt.
; Falls die angegebene Adresse bereits vorhanden ist, wird nichts getan.
; Die Änderungen werden für die Rücknahme beim Beenden von Windows gemerkt.
mov esi,408h
xor eax,eax
mov edx,[PortBase]
LD ecx,3
@@l: lodsw ;1. freie LPT suchen oder letzte überbügeln
cmp eax,edx
je @@e ;kein Patch erforderlich!
cmp eax,[PhysBase]
je @@1 ;Portadresse ersetzen!
or eax,eax
loopnz @@l
@@1: dec esi
dec esi
xchg [esi],dx ;eintragen
mov [ChangedPort],si ;merken
mov [WasAddr],dx
@@e: ret
EditLpt endp
InitPhysBase proc
movzx eax,word ptr ds:[408h] ;LPT1-Portadresse
or eax,eax
jz @@e
mov [PhysBase],eax
mov [PortBase],eax
@@e: ret
InitPhysBase endp
;I/O-Handler installieren (3fache Ausführung)
Try_Install_EDX_IO:
mov [PortBase],edx
Try_Install_IO_Handlers proc
lea esi,IOCallback
mov edx,[PortBase]
LD ecx,3 ;mit 3 Bytes eine 3 in ECX!
@@l: VMMcall Install_IO_Handler
jc @@e ;Schwerer Fehler
inc edx ;Nächste Portadresse
loopd @@l
@@e: ret
Try_Install_IO_Handlers endp
BeginProc VDONGLE_Init
Trace_Out "VDONGLE: Device_Init"
call InitPhysBase
;Knackgeräusch ein/aus?
xor esi,esi
lea edi,Tick$
VMMCall Get_Profile_Boolean
jbe @@i4 ;erschlägt CY und Z gleichermaßen
MAX al,2
mov [TickSound],al ;Bool-Wert ablegen
@@i4: ;Portadresse(n) besorgen
lea edi,Port$
call GetEntry
jc @@i1 ;Nicht gefunden? - Nicht auswerten!
mov [PortBase],eax
mov [PhysBase],eax
@@i1: lea edi,Phys$
call GetEntry
jc @@i2 ;Nicht gefunden? - Nicht auswerten!
mov [PhysBase],eax
@@i2: jmp @@i3
VDONGLE_Dynamic_Init: ;Einsprung Dynamische Initialisierung
VMMCall Get_VMM_Version
cmp ah,4 ;Windows95 erforderlich!!
jc @@e
call InitPhysBase
@@i3: call Try_install_IO_Handlers
jnc @@i5 ;Okay!
mov dx,37Ch ;Versuch auf üblicherweise freier Adresse
call Try_Install_EDX_IO
jnc @@i6 ;Okay!
mov dx,27Ch ;Noch ein letzter Versuch...
call Try_Install_EDX_IO
jnc @@e ;Fehler (Achselzucken)
@@i6: call EditLpt
@@i5: call DisableTrappings
;Semaphor installieren
xor ecx,ecx
VMMCall Create_Semaphore;ECX ist bereits 0!
jc @@e ;Fehler - raus!
mov [Semaphore],eax ;Handle speichern
LD eax,21h
lea esi,NewInt21
VMMCall Hook_V86_Int_Chain
jc VDONGLE_Exit
@@e: ret
EndProc VDONGLE_Init
VDongle_Init2 proc
pushad
xor esi,esi
lea edi,Trap$
VMMCall Get_Profile_Boolean
jbe @@e
or al,al
jz @@e
call EnableTrappings
@@e: popad
clc
ret
VDongle_Init2 endp
VxD_ICODE_ENDS
END
Detected encoding: OEM (CP437) | 1
|
|