#include "usb2lpt.h" /*********************** ** Globale Variablen ** ***********************/ static LARGE_INTEGER OldInt1; /* bleibt Null ohne Pentium */ static LARGE_INTEGER IDT; static WORD SaveDS,SaveFS; // Für ISR zum Restaurieren /*static*/ ULONG CurThreadPtr; // Get_Cur_Thread_Handle-Ersatz // Strukturzeiger für 2. Kernel-Stack (Win9x) C0013E78 // Unter W2K/WXP ist der aktuelle Thread durch FS: adressiert // ...dann ist diese Variable = Null. void NewInt1(void); #define Usage_Len 32 // >=4, die ersten vier (auch) via DR0..DR3 static WORD Usage[Usage_Len]; // Überwachte Portadressen (von DR0..DR3) // Der Wert 0 bedeutet: freies Debugregister // Der Wert 1 weist beim Treiber-Start besetzte Debugregister aus static ULONG UsageBits; static PDEVICE_EXTENSION X4DR[Usage_Len]; // zugehörige USB2LPT-Geräte //static PDEVICE_EXTENSION TimerX; // Für 1-s-Timer genutztes Gerät static MYTIMER debset; // Debugregister-Setz-Zeitgeber (periodisch) // Der Timer dient zur Feststellung "geklauter" Debugregister. /***************************** ** Debug-Register und Int1 ** *****************************/ /* Zu tun: Auf Mehrprozessormaschinen müssen in _allen_ Prozessoren * die Debugregister gesetzt/gelesen/geprüft werden. * Ein NTDDK-Treiber kann dazu KeSetTargetProcessorDpc benutzen? */ static void __declspec(naked) SetHook1(void) { /* PE: CX:EAX=neue Adresse für INT1 */ /* PA: CX:EAX=alte Adresse von INT1 */ _asm{ sidt [IDT] mov edx,cr0 push edx btr edx,16 /* Supervisor Mode Write Protect */ mov cr0,edx mov edx,[dword ptr IDT+2] xchg ax,[edx+0x08] /* Low-Teil Offset */ rol eax,16 xchg ax,[edx+0x0E] /* High-Teil Offset */ rol eax,16 xchg cx,[edx+0x0A] /* Segment */ pop edx mov cr0,edx ret } } static void __declspec(naked) SwapID(void) { /* Pentium-Test */ _asm{ pushfd pop eax btc eax,21 push eax popfd ret } } static void __declspec(naked) HookInt1(void) { /* Faule Annahme: bei INT1 befindet sich bereits ein gültiger Gate-Deskriptor /* VR: EAX,CX,EDX; EFlags unverändert */ // NICHT MULTIPROZESSOR-SICHER, weil anderer Prozessor gerade Int1 ausführen // könnte (und ich weiß nicht, wie man ihn daran hindert) _asm{ pushfd cli mov eax,offset NewInt1 mov cx,cs cmp [dword ptr OldInt1],0 jz no_586 call SetHook1 no_586: popfd ret } } static void __declspec(naked) UnhookInt1(void) { /* VR: EAX,CX,ESI; EFlags unverändert */ // NICHT MULTIPROZESSOR-SICHER, weil anderer Prozessor gerade Int1 ausführen // könnte (und ich weiß nicht, wie man ihn daran hindert) _asm{ pushfd cli mov eax,[dword ptr OldInt1] mov cx,[word ptr OldInt1+4] or eax,eax jz no_586 call SetHook1 no_586: popfd ret } } static BOOLEAN __declspec(naked) LoadDR(void) { /* Debugregister laden/wiederherstellen, VR: EAX */ // Liefert TRUE sowie CY=1 wenn sich die Debugregister dabei verändern // NICHT MULTIPROZESSOR-SICHER, weil Debugregister des anderen Prozessors // unerreichbar (und ich weiß nicht, wie) _asm{ pushad xor ecx,ecx // Bit-Sammler mov esi,offset Usage// im Ring 0 immer CLD (?) _emit 0x0F // mov eax,cr4 _emit 0x20 _emit 0xE0 BTS eax,3 /* PENTIUM Debug Extension (DE) aktivieren */ _emit 0x0F // mov cr4,eax _emit 0x22 _emit 0xE0 setnc cl // CL=1 wenn Debug Extension ausgeschaltet war mov ebx,DR7 xor eax,eax lodsw or ah,ah // mit (gültiger) Adresse gefüllt? jz no0 mov edx,DR0 mov DR0,eax sub edx,eax or edx,ecx setnz cl // CL=1 wenn DR0 verändert wurde oder CL=1 war or ebx,0x000E0202 btr ebx,16 /* DR7=xxxxxxxx xxxx1110 xxxxxx1x xxxxxx1x */ no0: lodsw or ah,ah jz no1 mov edx,DR1 mov DR1,eax sub edx,eax or edx,ecx setnz cl // CL=1 wenn DR1 verändert wurde oder CL=1 war or ebx,0x00E00208 btr ebx,20 /* DR7=xxxxxxxx 1110xxxx xxxxxx1x xxxx1xxx */ no1: lodsw or ah,ah jz no2 mov edx,DR2 mov DR2,eax sub edx,eax or edx,ecx setnz cl // CL=1 wenn DR2 verändert wurde oder CL=1 war or ebx,0x0E000220 btr ebx,24 /* DR7=xxxx1110 xxxxxxxx xxxxxx1x xx1xxxxx */ no2: lodsw or ah,ah jz no3 mov edx,DR3 mov DR3,eax sub edx,eax or edx,ecx setnz cl // CL=1 wenn DR3 verändert wurde oder CL=1 war or ebx,0xE0000280 btr ebx,28 /* DR7=1110xxxx xxxxxxxx xxxxxx1x 1xxxxxxx */ no3: mov edx,DR7 mov DR7,ebx sub edx,ebx or edx,ecx setnz cl // CL=1 wenn DR7 verändert wurde oder CL=1 war shr ecx,1 // Returnwert nach CY popad setc al // für sog. Hochsprachen... ret } } static VOID SetDebDpc(IN PKDPC dpc,PVOID x,PVOID a,PVOID b) { if (LoadDR()) { int i; // In allen Zählern inkrementieren for (i=0;iac.steal++; Vlpt_KdPrint2(("Debugregister gemaust!\n")); } } void PrepareDR(void) { /* PA: [OldInt1]=Adresse von INT1, aber nur beim Pentium */ // Weiterhin SaveDS, SaveFS, CurThreadPtr _asm{ sidt [IDT] mov esi,[dword ptr IDT+2] /* BASE */ // Sucht ab OldInt0 den Befehl "mov edi,[xxxxxxxx]"; der Wert ist der // globale Zeiger für den aktuellen Thread (Stack-Tausch) (Win98) mov di,[esi+6] // High-Teil Int0 (bei Int1 stört SoftICE) rol edi,16 mov di,[esi] // Low-Teil mov eax,0xC766006A // So geht's bei W2K los scasd je l2 // keine Bytefolge suchen, alles FS-adressierbar mov ecx,100h mov al,0x8B // Bytefolge 8B 3D suchen l1: repne scasb jne l2 cmp byte ptr [edi],0x3D jne l1 mov eax,[edi+1] jmp l3 l2: xor eax,eax // Null für WinNT l3: mov [CurThreadPtr],eax // gleichzeitig Win9x-Kennung // holt den OldInt1-Zeiger, aber nur, wenn's ein Pentium ist call SwapID mov edi,eax call SwapID cmp edi,eax jz no_586 // kein Pentium mov edi,offset OldInt1 cld mov ax,[esi+0x08] /* Low-Teil Offset */ stosw mov ax,[esi+0x0E] /* High-Teil Offset */ stosw movzx eax,word ptr [esi+0x0A] /* Segment */ stosd mov [SaveDS],ds // Win9x: 30h WinNT: mov [SaveFS],fs // Win9x: 78h WinNT: // markiert die bereits vor dem Treiber-Start verwendeten Debugregister // als "nicht verwendungsfähig für uns". Aufzurufen beim Treiber-Start // NICHT MULTIPROZESSOR-SICHER mov esi,offset Usage mov eax,DR7 push 4 pop ecx l: test al,3 // Lx oder Gx gesetzt? (Also in Benutzung?) setnz [esi] // wenn ja, auf 1 setzen, sonst 0 lassen shr eax,2 // nächstes Debugregister add esi,2 // nächstes Usage-Word loop l } // Debugregister-Diebstahl zyklisch rückgängig machen (WinXP) // Besser wäre es, die Ursache auszumachen... KeInitializeTimer(&debset.tmr); KeInitializeDpc(&debset.dpc,SetDebDpc,NULL); no_586:; } static void _fastcall SetTimerX() { if (!KeSetTimerEx(&debset.tmr,RtlConvertLongToLargeInteger(100*-10000), 100,&debset.dpc)) TRAP(); } int _stdcall AllocDR(WORD adr,PDEVICE_EXTENSION X) { // Belegung eines E/A-Debugregisters und andere Arbeiten int i; if (adr&0x3) return -1; // Fehlerkode: falsche Adresse if (!(adr&0xFF00)) return -1; // Board-Register sind ebenfalls unzulässig if (!OldInt1.QuadPart) return -6; // Kein Pentium // if (!CurThreadPtr) return -7; // Keine Anzapfung möglich for (i=0; iuc.flags&UC_Debugreg) i=0; for (; i=Usage_Len) return -4;// Ungültiges "Handle" if (!(Usage[dr]&0xFF00)) return -5; // Debugregister nicht in Benutzung X4DR[dr]=NULL; UsageBits&=~(1<