Umfragen | | | | - Seite 1 - |
| | Hat einer von euch schon mal selbst einen kleinen Treiber geproggt? Wenn ja, in welcher Programmiersprache? Hat jemand Infos über Treiberprogrammierung? Hat jemand Möglichkeiten, Treiber zu programmieren? |
| | | | |
| | | | | - Seite 2 - |
| Michael Wodrich | | | | Programmieren, das spannendste Detektivspiel der Welt. | 29.10.2006 ▲ |
| |
| | Thomas Zielinski | Das ist ja sehr interessant. Aber da meine Fremdsprachenkenntnisse ein wenig eingerostet ist wäre es doch nett wenn einer lange weile hat und das übersetzt. |
| | | XProfan X4; Win10 x64 Der Kuchen ist eine lüge! | 01.11.2006 ▲ |
| |
| | | [quote:2e699b275a=Alexej Jakowitsch]Das ist ja sehr interessant. Aber da meine Fremdsprachenkenntnisse ein wenig eingerostet ist wäre es doch nett wenn einer lange weile hat und das übersetzt.[/quote:2e699b275a] Ohne Englischkenntnisse wirst du da trotzdem nicht weiterkommen.
@Michael: Besten Dank, die Seite fehlte noch!. |
| | | | |
| | | So: Wie weit bin ich?
Bin grad mitten beim Treiberproggen. Im Prinzip läuft das Ding schon - es macht aber (so wie ich es zur Zeit starte) noch nicht das, was es soll. D.h.: Lade ich den Treiber nicht durch einen Registryeintrag (CreateService, StartService), sondern auf eine spezielle Art, die ich hier nicht posten möcht, lädt sich der Treiber wirklich unter System und schreibt und liest wie geplant aus der Registry. Zur Zeit kämpfe ich noch ein wenig mit der DriverEntry Proc => mein Problem liegt aber wohl eher daran, das ich in MASM nur Einsteiger bin und dort manches noch nicht durchblicke.
Hier mal die BATCH zur Treibererzeugung für MASM mit angehängter Resourcendatei rsrc:
Treibername muß durch den Namen (ohne Dateiendung) der jeweiligen ASM oder OBJ Datei ersetzt werden. Wer keine Resource anhängen möchte, läßt das rsrc.obj einfach weg.
Gruß
Andreas |
| | | | |
| | | Moin. Treiber läuft nun auch, wenn man ihn über StartService startet. Mein Fehler: Das Register ebx darf scheinbar in einem Treiber unter bestimmten Umständen nicht verwendet werden.
Gruß
Andreas |
| | | | |
| | Michael Wodrich | ebx wird oft als Indexregister benutzt (also wie ein Zeigerwert).
Du mußt auch auf ASSIGN aufpassen: Damit nagelt man auch Register fest - diese Zuweisung muß später auch wieder aufgehoben werden (ein Assign mit none als Wert). Ist nur wichtig, wenn sowas bereits im existierenden Beispielcode existiert (und dann kann Frank wohl besser den Sachverhalt erklären).
Schöne Grüße Michael Wodrich |
| | | Programmieren, das spannendste Detektivspiel der Welt. | 05.11.2006 ▲ |
| |
| | | Einige wichtige Infos zum Einstieg ins Treiberprogging stehen bereits unter [...] , den Rest werde ich versuchen hier zu platzieren. Vorneweg: Wer im Kernel herumhantiert, muß damit rechnen, daß es bei einem Fehler gewaltig crasht. Und wenn ich sage gewaltig, dann meine ich wirklich gewaltig. Ein Reboot mit Festplattenfehler ist da das kleinste Übel - auch das Abrauchen von Hardware ist nicht ganz ausgeschlossen. Es empfiehlt sich deshalb das was irgendwie im Usermode löuft, auch im Usermode zu testen. Die DLLs, auf die es beim Treiberprogging ankommt und aus denen man APIs aufrufen kann sind vor allen Dingen die HAL.DLL, die NTOSKRNL.EXE und die NTDLL.DLL. Da vielle Funktionen (Nt... und Zw... vor allen Dingen) sowohl in der NTOSKRNL.EXE als auch in der NTDLL.DLL vorhanden sind und es die NTDLL ja auch in normalen Anwendungen im Usermode gibt,, kann man da schon eine ganze Menge im Usermode abtesten. Zum Vergleichen mit der NTDLL habe ich hier im Anhang auch mal die Funktionen der NTOSKRNL.EXE (mit [...] ausgelesen) aufgelistet.. Zum Testen einfach die Zeilen include masm32includew2k toskrnl.inc und includelib masm32libw2k toskrnl.lib bei der Deklarierung der MASM Bibliotheken durch include masm32includew2k tdll.inc und includelib masm32libw2k tdll.lib ersetzen und das was der Treiber später tun soll dann in eine normale EXE compilieren.. => keine Gefahr für die Hardware.
Einen Treiber zu proggen hat sehr viel Ähnlichkeit mit dem Erstellen einer DLL - ist aber wesentlich einfacher. Eine DLL besitzt eine Einsprungsfunktion, die beim Laden ausgeführt wird - und so ist es bei einem Treiber auch. Eine Einstiegsfunktion eines Treibers sieht unter MASM folgendermaßen aus:
Ein so geproggter Treiber führt seine Code aus und wird danach wieder aus dem Kernel entfernt.
Ein so geproggter Treiber bleibt noch dem Ausführen des Codes weiterhin im Kernel geladen.
Einfach, oder? ...Fortsetzung folgt, falls Interesse da ist.... |
| | | | |
| | | Da es sowieso nicht den Effekt hatte, den ich gesucht habe, stelle ich das hier mal als Beispiel hin. MASM32 Code:
.386
.model flat, stdcall
option casemap:none
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; I N C L U D E F I L E S
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
include masm32includew2k
tddk.inc
include masm32includew2k
tstatus.inc
include masm32includew2k
toskrnl.inc
includelib masm32libw2k
toskrnl.lib
include masm32MacrosStrings.mac
includelib masm32libw2k
tdll.lib
.data
Object_Attrib dd 24,0,0,64,0,0
P_Object_Attrib dd 24,0,0,0,0,0
COUNTED_ANSI_STRING dw 0,0,0,0
LSA_Unicode dw 0,518,0,0
ACCESS_RIGHTS dd 65539
KeyHandle dd 0
Needed dd 0
OwnID dd 0
Address dd 0
Var dd 0
Prot dd 0,0,0,0,0,0,0
P_ID dd 0,0
PID dd 0
P_ACCESS_WRITE dd 40
P_ACCESS dd 1024
ZwQuery dd 0
ZwWrite dd 0
ErrorAddress dd 0
ReturnError dd -1073741438
P_Handle dd 0
Keyname db RegistryMachineSoftwareScannyVMQuery,0
ValuenameOwnID db OwnID,0
ValuenamePID db PID,0
ValuenameAddress db Address,0
ValuenameVar db Var,0
ValuenameZwQuery db ZwQueryVirtualMemory,0
ValuenameZwWrite db ZwWriteVirtualMemory,0
ValuenameReturn db Return,0
.data?
Key_Info db 530 dup(?)
Unicode db 518 dup(?)
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; C O D E
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.code
start:
DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING
invoke RtlInitAnsiString,addr COUNTED_ANSI_STRING,addr Keyname
;PrintDec eax, Rückgabe von RtlInitAnsiString
lea edx,COUNTED_ANSI_STRING
mov ax,[edx+0]
;PrintDec ax, Länge des Strings
mov ax,[edx+2]
;PrintDec ax, Länge des Bereichs
mov eax,[edx+4]
;PrintStringByAddr eax
lea edx,LSA_Unicode
mov ax,518
mov [edx+2],ax
lea eax,Unicode
mov [edx+4],eax
invoke RtlAnsiStringToUnicodeString,addr LSA_Unicode,addr COUNTED_ANSI_STRING,0
;PrintDec eax, Rückgabe von RtlAnsiStringToUnicodeString
lea edx,LSA_Unicode
mov ax,[edx+0]
;PrintDec ax, Länge des Strings
mov ax,[edx+2]
;PrintDec ax, Länge des Bereichs
lea edx,Object_Attrib
;PrintDec edx, Adresse der Object_Attributes Struktur
lea eax,LSA_Unicode
;PrintDec eax, Adresse der LSA_Unicode Struktur
;PrintDec edx, Vor Änderung
add edx,8
;PrintDec edx, Nach Änderung
mov [edx],eax
invoke ZwOpenKey,addr KeyHandle,ACCESS_RIGHTS,addr Object_Attrib
;PrintDec eax, Rückgabe von ZwOpenKey
;PrintDec KeyHandle,Handle des Schlüssels
.IF eax == 0
invoke RtlInitAnsiString,addr COUNTED_ANSI_STRING,addr ValuenameOwnID
;PrintDec eax, Rückgabe von RtlInitAnsiString
lea edx,COUNTED_ANSI_STRING
mov ax,[edx+0]
;PrintDec ax, Länge des Strings
mov ax,[edx+2]
;PrintDec ax, Länge des Bereichs
mov eax,[edx+4]
;PrintStringByAddr eax
lea edx,LSA_Unicode
mov ax,518
mov [edx+2],ax
lea eax,Unicode
mov [edx+4],eax
invoke RtlAnsiStringToUnicodeString,addr LSA_Unicode,addr COUNTED_ANSI_STRING,0
;PrintDec eax, Rückgabe von RtlAnsiStringToUnicodeString
lea edx,LSA_Unicode
mov ax,[edx+0]
;PrintDec ax, Länge des Strings
mov ax,[edx+2]
;PrintDec ax, Länge des Bereichs
invoke ZwQueryValueKey,KeyHandle,addr LSA_Unicode,2,addr Key_Info,580,addr Needed
;PrintDec eax, Rückgabe von ZwQueryValueKey
.IF eax == 0
lea edx,Key_Info
add edx,12
mov edx,[edx]
mov OwnID,edx
;PrintDec OwnID, Prozess-ID von Scanny
.endif
invoke RtlInitAnsiString,addr COUNTED_ANSI_STRING,addr ValuenamePID
;PrintDec eax, Rückgabe von RtlInitAnsiString
lea edx,COUNTED_ANSI_STRING
mov ax,[edx+0]
;PrintDec ax, Länge des Strings
mov ax,[edx+2]
;PrintDec ax, Länge des Bereichs
mov eax,[edx+4]
;PrintStringByAddr eax
lea edx,LSA_Unicode
mov ax,518
mov [edx+2],ax
lea eax,Unicode
mov [edx+4],eax
invoke RtlAnsiStringToUnicodeString,addr LSA_Unicode,addr COUNTED_ANSI_STRING,0
;PrintDec eax, Rückgabe von RtlAnsiStringToUnicodeString
lea edx,LSA_Unicode
mov ax,[edx+0]
;PrintDec ax, Länge des Strings
mov ax,[edx+2]
;PrintDec ax, Länge des Bereichs
invoke ZwQueryValueKey,KeyHandle,addr LSA_Unicode,2,addr Key_Info,580,addr Needed
;PrintDec eax, Rückgabe von ZwQueryValueKey
.IF eax == 0
lea edx,Key_Info
add edx,12
mov edx,[edx]
mov PID,edx
;PrintDec PID, ID des auszulesenden Prozesses
.endif
invoke RtlInitAnsiString,addr COUNTED_ANSI_STRING,addr ValuenameAddress
;PrintDec eax, Rückgabe von RtlInitAnsiString
lea edx,COUNTED_ANSI_STRING
mov ax,[edx+0]
;PrintDec ax, Länge des Strings
mov ax,[edx+2]
;PrintDec ax, Länge des Bereichs
mov eax,[edx+4]
;PrintStringByAddr eax
lea edx,LSA_Unicode
mov ax,518
mov [edx+2],ax
lea eax,Unicode
mov [edx+4],eax
invoke RtlAnsiStringToUnicodeString,addr LSA_Unicode,addr COUNTED_ANSI_STRING,0
;PrintDec eax, Rückgabe von RtlAnsiStringToUnicodeString
lea edx,LSA_Unicode
mov ax,[edx+0]
;PrintDec ax, Länge des Strings
mov ax,[edx+2]
;PrintDec ax, Länge des Bereichs
invoke ZwQueryValueKey,KeyHandle,addr LSA_Unicode,2,addr Key_Info,580,addr Needed
;PrintDec eax, Rückgabe von ZwQueryValueKey
.IF eax == 0
lea edx,Key_Info
add edx,12
mov edx,[edx]
mov Address,edx
;PrintDec Address, Zu bearbeitende Adresse
.endif
invoke RtlInitAnsiString,addr COUNTED_ANSI_STRING,addr ValuenameVar
;PrintDec eax, Rückgabe von RtlInitAnsiString
lea edx,COUNTED_ANSI_STRING
mov ax,[edx+0]
;PrintDec ax, Länge des Strings
mov ax,[edx+2]
;PrintDec ax, Länge des Bereichs
mov eax,[edx+4]
;PrintStringByAddr eax
lea edx,LSA_Unicode
mov ax,518
mov [edx+2],ax
lea eax,Unicode
mov [edx+4],eax
invoke RtlAnsiStringToUnicodeString,addr LSA_Unicode,addr COUNTED_ANSI_STRING,0
;PrintDec eax, Rückgabe von RtlAnsiStringToUnicodeString
lea edx,LSA_Unicode
mov ax,[edx+0]
;PrintDec ax, Länge des Strings
mov ax,[edx+2]
;PrintDec ax, Länge des Bereichs
invoke ZwQueryValueKey,KeyHandle,addr LSA_Unicode,2,addr Key_Info,580,addr Needed
;PrintDec eax, Rückgabe von ZwQueryValueKey
.IF eax == 0
lea edx,Key_Info
add edx,12
mov edx,[edx]
mov Var,edx
;PrintDec Var, Adresse der Variablen in Scanny
.endif
invoke RtlInitAnsiString,addr COUNTED_ANSI_STRING,addr ValuenameZwQuery
;PrintDec eax, Rückgabe von RtlInitAnsiString
lea edx,COUNTED_ANSI_STRING
mov ax,[edx+0]
;PrintDec ax, Länge des Strings
mov ax,[edx+2]
;PrintDec ax, Länge des Bereichs
mov eax,[edx+4]
;PrintStringByAddr eax
lea edx,LSA_Unicode
mov ax,518
mov [edx+2],ax
lea eax,Unicode
mov [edx+4],eax
invoke RtlAnsiStringToUnicodeString,addr LSA_Unicode,addr COUNTED_ANSI_STRING,0
;PrintDec eax, Rückgabe von RtlAnsiStringToUnicodeString
lea edx,LSA_Unicode
mov ax,[edx+0]
;PrintDec ax, Länge des Strings
mov ax,[edx+2]
;PrintDec ax, Länge des Bereichs
invoke ZwQueryValueKey,KeyHandle,addr LSA_Unicode,2,addr Key_Info,580,addr Needed
;PrintDec eax, Rückgabe von ZwQueryValueKey
.IF eax == 0
lea edx,Key_Info
add edx,12
mov edx,[edx]
mov ZwQuery,edx
;PrintDec ZwQuery, Adresse der Funktion ZwQueryVirtualMemory
.endif
invoke RtlInitAnsiString,addr COUNTED_ANSI_STRING,addr ValuenameZwWrite
;PrintDec eax, Rückgabe von RtlInitAnsiString
lea edx,COUNTED_ANSI_STRING
mov ax,[edx+0]
;PrintDec ax, Länge des Strings
mov ax,[edx+2]
;PrintDec ax, Länge des Bereichs
mov eax,[edx+4]
;PrintStringByAddr eax
lea edx,LSA_Unicode
mov ax,518
mov [edx+2],ax
lea eax,Unicode
mov [edx+4],eax
invoke RtlAnsiStringToUnicodeString,addr LSA_Unicode,addr COUNTED_ANSI_STRING,0
;PrintDec eax, Rückgabe von RtlAnsiStringToUnicodeString
lea edx,LSA_Unicode
mov ax,[edx+0]
;PrintDec ax, Länge des Strings
mov ax,[edx+2]
;PrintDec ax, Länge des Bereichs
invoke ZwQueryValueKey,KeyHandle,addr LSA_Unicode,2,addr Key_Info,580,addr Needed
;PrintDec eax, Rückgabe von ZwQueryValueKey
.IF eax == 0
lea edx,Key_Info
add edx,12
mov edx,[edx]
mov ZwWrite,edx
;PrintDec ZwWrite, Adresse der Funktion ZwWriteVirtualMemory
.endif
invoke RtlInitAnsiString,addr COUNTED_ANSI_STRING,addr ValuenameReturn
;PrintDec eax, Rückgabe von RtlInitAnsiString
lea edx,COUNTED_ANSI_STRING
mov ax,[edx+0]
;PrintDec ax, Länge des Strings
mov ax,[edx+2]
;PrintDec ax, Länge des Bereichs
mov eax,[edx+4]
;PrintStringByAddr eax
lea edx,LSA_Unicode
mov ax,518
mov [edx+2],ax
lea eax,Unicode
mov [edx+4],eax
invoke RtlAnsiStringToUnicodeString,addr LSA_Unicode,addr COUNTED_ANSI_STRING,0
;PrintDec eax, Rückgabe von RtlAnsiStringToUnicodeString
lea edx,LSA_Unicode
mov ax,[edx+0]
;PrintDec ax, Länge des Strings
mov ax,[edx+2]
;PrintDec ax, Länge des Bereichs
invoke ZwQueryValueKey,KeyHandle,addr LSA_Unicode,2,addr Key_Info,580,addr Needed
;PrintDec eax, Rückgabe von ZwQueryValueKey
.IF eax == 0
lea edx,Key_Info
add edx,12
mov edx,[edx]
mov ErrorAddress,edx
;PrintDec ErrorAddress, Adresse der Rückmeldevariablen
.endif
mov edx,PID
mov P_ID,edx
invoke ZwOpenProcess,addr P_Handle,P_ACCESS,addr P_Object_Attrib,addr P_ID
;PrintDec eax, Rückgabe von ZwOpenProcess
.IF eax == 0
lea edx,Needed
push edx
push 28
lea edx,Prot
push edx
push 0
push Address
push P_Handle
call ZwQuery
mov ReturnError,eax
;invoke ZwQueryVirtualMemory,P_Handle,Address,0,addr Prot,28,addr Needed
;PrintDec eax, Rückgabe von ZwQueryVirtualMemory
invoke ZwClose,P_Handle
.endif
mov edx,OwnID
mov P_ID,edx
invoke ZwOpenProcess,addr P_Handle,P_ACCESS_WRITE,addr P_Object_Attrib,addr P_ID
;PrintDec eax, Rückgabe von ZwOpenProcess
.IF eax == 0
lea edx,Needed
push edx
push 28
lea edx,Prot
push edx
push Var
push P_Handle
call ZwWrite
;invoke ZwWriteVirtualMemory,P_Handle,Var,addr Prot,28,addr Needed
lea edx,Needed
push edx
push 4
lea edx,ReturnError
push edx
push ErrorAddress
push P_Handle
call ZwWrite
;PrintDec eax, Rückgabe von ZwWriteVirtualMemory
invoke ZwClose,P_Handle
.endif
invoke ZwClose,KeyHandle
.endif
mov eax,STATUS_DEVICE_CONFIGURATION_ERROR
ret
DriverEntry endp
end start
Gruß
Andreas |
| | | | |
| | | Ich habe mal zu dem MASm32 Quelltext oben noch ein Profan Steuerungsprogramm zum Testen gepackt und alles unten in compilierter Form zum Download bereitgestellt. Profan Steuerungsproggi:
DEF @GetDlgCtrlID(1) !USER32,GetDlgCtrlID
DEF @ButtonClicked(1) @GetDlgCtrlID(@&(1))=-%MENUITEM
DEF @GetModuleHandle(1) !KERNEL32,GetModuleHandleA
DEF @GetProcAddress(2) !KERNEL32,GetProcAddress
Def @GetCurrentProcessID(0) !KERNEL32,GetCurrentProcessId
Def @CloseServiceHandle(1) !ADVAPI32,CloseServiceHandle
Def @StartService(3) !ADVAPI32,StartServiceA
Def @OpenService(3) !ADVAPI32,OpenServiceA
Def @OpenSCManager(3) !ADVAPI32,OpenSCManagerA
Def @CreateService(13) !ADVAPI32,CreateServiceA
Def @DeleteService(1) !ADVAPI32,DeleteService
Def @CloseServiceHandle(1) !ADVAPI32,CloseServiceHandle
Def @OpenSCManager(3) !ADVAPI32,OpenSCManagerA
DEF @GetACP(0) !kernel32,GetACP
DEF @MultiByteToWideChar(6) !kernel32,MultiByteToWideChar
Def @GetSystemInfo(1) !KERNEL32,GetSystemInfo
DeF @FormatMessage(7) !KERNEL32,FormatMessageA
Def @LsaNtStatusToWinError(1) !ADVAPI32,LsaNtStatusToWinError
Declare NTFEHLER&,AHRückgabe&,AHGETERROR_Buffer#,AHGETERROR_Buffer$
Declare Button&,Prot#,Zwischenmerker$,Zwischenmerker&,PID&
Declare M_NAME$,PROC_NAME$,PROC_ADDRESS&,Fehler&,MHANDLE&,SCManager_Handle&,Service&
Declare Zwischenmerker2&,Zwischenmerker3&,PAGE_SIZE&,SYSTEM_INFO#,PRID&
Dim Prot#,28
Windowstyle 31+512
Windowtitle Speicherinfos auslesen
Window 0,0-640,440
Let Button&=@CreateButton(%HWND,Speicherinfos lesen,20,100,300,30)
@Createtext(%HWND,Prozess-ID:,20,140,80,20)
LET PID&=@CreateEdit(%HWND,@STR$(@GetCurrentProcessID()),110,140,100,20)
Usermessages $10
DIM SYSTEM_INFO#,36
@GetSystemInfo(SYSTEM_INFO#)
LET PAGE_SIZE&=@LONG(SYSTEM_INFO#,4)
Dispose SYSTEM_INFO#
IF @val($WINVER)<5
@messagebox(Geht leider auf dieser Windowsversion nicht!!!,Falsche Windowsversion!,64)
@sendmessage(%HWND,$10,0,0)
endif
While %UMESSAGE<>$10
Waitinput
If @Buttonclicked(Button&)
SetMenuitem 0
LET Zwischenmerker$=@INPUT$(Welche Adresse näher untersuchen?,Adresse eingeben,@STR$(%HINSTANCE))
IF Zwischenmerker$<>
Read_VMInfos
endif
endif
wend
Dispose Prot#
Proc Fehlercode_bestimmen
Parameters NTSTATUS%
IF NTSTATUS%=1
LET NTFEHLER&=AHRückgabe&
LET AHRückgabe&=@LsaNtStatusToWinError(NTFEHLER&)
endif
DIM AHGETERROR_Buffer#,32000
@FormatMessage($1000,0,AHRückgabe&,0,AHGETERROR_Buffer#,32000,0) Wandelt Fehlercode in Landesspezifische Message um.
Let AHGETERROR_Buffer$=@trim$(@STRING$(AHGETERROR_Buffer#,0))
Dispose AHGETERROR_Buffer#
Endproc
Proc Start_Driver
Parameters BinaryPathName$,Service_Name$,SC_DisplayName$
IF BinaryPathName$<>
LET SCManager_Handle&=@OpenSCManager(0,0,$F000F)
LET Service&=@CreateService(SCManager_Handle&,@ADDR(Service_Name$),@ADDR(SC_DisplayName$),$10 | $10000,$1,$3,$0,@ADDR(BinaryPathName$),0,0,0,0,0)
IF Service&=0
LET SERVICE&=@OpenService(SCManager_Handle&,@ADDR(Service_Name$),$10 | $10000)
endif
@StartService(Service&,0,0)
@DeleteService(Service&)
@CloseServiceHandle(Service&)
@CloseServiceHandle(SCManager_Handle&)
endif
endproc
Proc Read_VMInfos
Clear Prot#
LET Zwischenmerker&=@VAL(Zwischenmerker$)
WriteIni HKEY_DW_2,SoftwareScannyVMQuery,OwnID=@GetCurrentProcessID()
LET PRID&=@val(@GetText$(PID&))
WriteIni HKEY_DW_2,SoftwareScannyVMQuery,PID=PRID& Hier kann irgendeine PID hin
WriteIni HKEY_DW_2,SoftwareScannyVMQuery,Address=Zwischenmerker&
WriteIni HKEY_DW_2,SoftwareScannyVMQuery,Var=Prot#
WriteIni HKEY_DW_2,SoftwareScannyVMQuery,Return=@addr(Fehler&)
LET M_NAME$=NTDLL.DLL
LET MHANDLE&=@GetModuleHandle(@ADDR(M_NAME$))
LET PROC_NAME$=ZwQueryVirtualMemory
LET PROC_ADDRESS&=@GetProcAddress(MHANDLE&,@ADDR(PROC_NAME$))
WriteIni HKEY_DW_2,SoftwareScannyVMQuery,ZwQueryVirtualMemory=PROC_ADDRESS&
LET PROC_NAME$=ZwWriteVirtualMemory
LET PROC_ADDRESS&=@GetProcAddress(MHANDLE&,@ADDR(PROC_NAME$))
WriteIni HKEY_DW_2,SoftwareScannyVMQuery,ZwWriteVirtualMemory=PROC_ADDRESS&
Start_Driver $Progdir+vmquery.sys,VMQUERY,Speicherstatus lesen
LET AHRÜCKGABE&=Fehler&
Fehlercode_bestimmen 1
Locate 0,0
CLS
Print AHGETERROR_Buffer$
ADDSTRING __________________________________________
ADDSTRING ID des Prozesses: +@Str$(PRID&)
ADDSTRING Zu testende Adresse: +@Str$(Zwischenmerker&)
If Fehler&=0
LET Zwischenmerker2&=@LONG(Prot#,0)+@LONG(Prot#,12)-1
LET Zwischenmerker$=@STR$(@LONG(Prot#,0))+ bis +@STR$(Zwischenmerker2&)
ADDSTRING Adresse liegt in Adressbereich: +Zwischenmerker$
If @int(@LONG(PROT#,12)/PAGE_SIZE&)=1
ADDSTRING Seitenanzahl des Adressbereiches: +eine Seite
else
ADDSTRING Seitenanzahl des Adressbereiches: +@STR$(@int(@LONG(Prot#,12)/PAGE_SIZE&))+ Seiten
endif
ADDSTRING Offsetadresse der Speicherzuweisung: +@STR$(@LONG(Prot#,4))
Clear Zwischenmerker$
LET Zwischenmerker3&=@long(Prot#,24)
IF @or(Zwischenmerker3&,$20000)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ Privat
Zwischenmerker3&=Zwischenmerker3&-$20000
endif
IF @or(Zwischenmerker3&,$40000)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ Mapping
Zwischenmerker3&=Zwischenmerker3&-$40000
endif
IF @or(Zwischenmerker3&,$1000000)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ Image
Zwischenmerker3&=Zwischenmerker3&-$1000000
endif
IF Zwischenmerker3&>0
LET Zwischenmerker$=Zwischenmerker$+ $+@Hex$(Zwischenmerker3&)
endif
LET Zwischenmerker$=@trim$(Zwischenmerker$)
IF Zwischenmerker$<>
ADDSTRING Speichertyp der Seiten: +Zwischenmerker$
endif
Clear Zwischenmerker$
LET Zwischenmerker3&=@long(Prot#,8)
IF @or(Zwischenmerker3&,$1)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ kein Zugriff
Zwischenmerker3&=Zwischenmerker3&-$1
endif
IF @or(Zwischenmerker3&,$2)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ nur lesen
Zwischenmerker3&=Zwischenmerker3&-$2
endif
IF @or(Zwischenmerker3&,$4)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ lesen, schreiben
Zwischenmerker3&=Zwischenmerker3&-$4
endif
IF @or(Zwischenmerker3&,$8)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ copy-on-write
Zwischenmerker3&=Zwischenmerker3&-$8
endif
IF @or(Zwischenmerker3&,$10)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ ausführen
Zwischenmerker3&=Zwischenmerker3&-$10
endif
IF @or(Zwischenmerker3&,$20)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ ausführen, lesen
Zwischenmerker3&=Zwischenmerker3&-$20
endif
IF @or(Zwischenmerker3&,$40)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ ausführen, lesen, schreiben
Zwischenmerker3&=Zwischenmerker3&-$40
endif
IF @or(Zwischenmerker3&,$80)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ ausführen, lesen, schreiben, copy-on-write, read-on-write
Zwischenmerker3&=Zwischenmerker3&-$80
endif
IF @or(Zwischenmerker3&,$100)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ geschützt
Zwischenmerker3&=Zwischenmerker3&-$100
endif
IF @or(Zwischenmerker3&,$200)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ kein Caching
Zwischenmerker3&=Zwischenmerker3&-$200
endif
IF @or(Zwischenmerker3&,$400)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ WRITECOMBINE
Zwischenmerker3&=Zwischenmerker3&-$400
endif
IF Zwischenmerker3&>0
LET Zwischenmerker$=Zwischenmerker$+ $+@Hex$(Zwischenmerker3&)
endif
LET Zwischenmerker$=@trim$(Zwischenmerker$)
IF Zwischenmerker$<>
ADDSTRING Zugewiesen mit Zugriffsflags: +Zwischenmerker$
endif
Clear Zwischenmerker$
LET Zwischenmerker3&=@long(PROT#,20)
IF @or(Zwischenmerker3&,$1)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ kein Zugriff
Zwischenmerker3&=Zwischenmerker3&-$1
endif
IF @or(Zwischenmerker3&,$2)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ nur lesen
Zwischenmerker3&=Zwischenmerker3&-$2
endif
IF @or(Zwischenmerker3&,$4)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ lesen, schreiben
Zwischenmerker3&=Zwischenmerker3&-$4
endif
IF @or(Zwischenmerker3&,$8)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ copy-on-write
Zwischenmerker3&=Zwischenmerker3&-$8
endif
IF @or(Zwischenmerker3&,$10)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ ausführen
Zwischenmerker3&=Zwischenmerker3&-$10
endif
IF @or(Zwischenmerker3&,$20)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ ausführen, lesen
Zwischenmerker3&=Zwischenmerker3&-$20
endif
IF @or(Zwischenmerker3&,$40)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ ausführen, lesen, schreiben
Zwischenmerker3&=Zwischenmerker3&-$40
endif
IF @or(Zwischenmerker3&,$80)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ ausführen, lesen, schreiben, copy-on-write, read-on-write
Zwischenmerker3&=Zwischenmerker3&-$80
endif
IF @or(Zwischenmerker3&,$100)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ geschützt
Zwischenmerker3&=Zwischenmerker3&-$100
endif
IF @or(Zwischenmerker3&,$200)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ kein Caching
Zwischenmerker3&=Zwischenmerker3&-$200
endif
IF @or(Zwischenmerker3&,$400)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ WRITECOMBINE
Zwischenmerker3&=Zwischenmerker3&-$400
endif
IF Zwischenmerker3&>0
LET Zwischenmerker$=Zwischenmerker$+ $+@Hex$(Zwischenmerker3&)
endif
LET Zwischenmerker$=@trim$(Zwischenmerker$)
IF Zwischenmerker$<>
ADDSTRING Augenblicklicher Zugriffsschutz der Seiten: +Zwischenmerker$
endif
Clear Zwischenmerker$
LET Zwischenmerker3&=@long(PROT#,16)
IF @or(Zwischenmerker3&,$1000)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ Physikalischem Speicher zugewiesen.
Zwischenmerker3&=Zwischenmerker3&-$1000
endif
IF @or(Zwischenmerker3&,$10000)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ Frei, kann zugewiesen werden.
Zwischenmerker3&=Zwischenmerker3&-$10000
endif
IF @or(Zwischenmerker3&,$2000)=Zwischenmerker3&
LET Zwischenmerker$=Zwischenmerker$+ Reserviert, kann nicht zugewiesen werden.
Zwischenmerker3&=Zwischenmerker3&-$2000
endif
IF Zwischenmerker3&>0
LET Zwischenmerker$=Zwischenmerker$+ $+@Hex$(Zwischenmerker3&)
endif
LET Zwischenmerker$=@trim$(Zwischenmerker$)
ADDSTRING Status der Seiten: +Zwischenmerker$
LET Zwischenmerker3&=@long(PROT#,16)
IF @or(Zwischenmerker3&,$1000)=Zwischenmerker3&
ADDSTRING Startadresse der Speicherregion: +@str$(@long(Prot#,0))
ADDSTRING Maximal auslesbare Bytes: +@str$(@long(Prot#,12))
endif
Else
ADDSTRING Info: +Für diese Adresse sind keine Daten auslesbar!
endif
@editbox(Ausgelesene Speicherinfos...,1)
endproc
Wenn man unter XP als PID 4 oder unter 2000 als PID 8 eingibt (Prozess System), erkennt man auch gleich die Besonderheiten der Geschichte - obwohl keine Zugriffsrechte geändert wurden und der Prozess in einem normalen Useraccount läuft, kann man den Speicher des Prozesses System ohne weiteres scannen.
Gruß
Andreas |
| | | | |
| | | | - Seite 3 - |
| | | Zur Funktionsweise der Quelltexte von oben:
Das Steuerungsprogramm schreibt nach dem Betätigen des Buttons einige Daten in die Registry, die der zu startende Treiber vmquery.sys später wieder ausliest: OwnID=Prozess-ID des Steuerungsprogrammes PID=ID des Prozesses, dessen Speicher man scannen will Address=Adresse im fremden Prozess, über die man Daten ermitteln will Var=Adresse der Variablen im Steuerungsprozess, die die ausgelesenen Daten aufnehmen soll Return=Adresse der Variablen im Steuerungsprozess, die Fehlerrückmeldungen aufnehmen soll ZwQueryVirtualMemory=Die Funktion, die ich zum Scannen von Prozessspeicher benötige, befindet sich in der NTDLL.DLL und ist über den Funktionsnamen nicht über die NTOSKRNL.EXE auszuführen. Da ich in einem Treiber die Funktion GetProcAddress nicht verwenden kann (kommt ja aus der Userdll kernel32.dll), ermittele ich die Adresse dieser Funktion im Steuerungsprogramm und übergebe sie über die Registry an den Treiber. Ich dafür die Tatsache, das geladene Systemmodule in jedem Prozess an die gleiche virtuelle Adresse geladen werden. ZwWriteVirtualMemory=Auch für diese Funktion ermittele ich die Adresse im Usermode. Ich brauche sie, um die Ausgelesenen Daten direkt in den Steuerungsprozess schreiben zu können.
Über StartService wird dann der Treiber gestartet und die Funktion DriverEntry ausgeführt. StartService wartet dabei solange, bis eine Rückmeldung der Funktion
erfolgt. Erfolgt innerhalb einer bestimmten Zeit keine Rückmeldung, wird der Treiber beendet und aus dem System entfernt.
Ich gebe hier vom Treiber her eine Fehlermeldung zurück - warum? Ist der Returnwert nicht 0 (kein Fehler passiert) wird der Treiber vom Betriebssystem automatisch wieder entladen (da ja ein Fehler passiert ist) und ich brauche mich nicht um irgendwelche Entladevorgänge zu kümmern.
Der gestartete Teiber schreibt dann also die ausgelesenen Daten direkt in den Prozessspeicher des Steuerungsprozesses - da der Steuerungsprozess hübsch wartet bis der Treiber fertig ist, gibt es damit keine Probleme.
Ist der Treiber beendet liest der Steuerungsprozess die übermittelten Daten aus und zeigt diese an - fertig.
Gruß
Andreas |
| | | | |
| | | Sehr nett! Spiele grad damit rum |
| | | | |
| | | Dann Beantworte ich jetzt mal eine bislang noch nicht gestellte Frage: Wozu braucht man diese Infos, die da ausgelesen werden??? Um den virtuellen Speicher fremder Prozesse schnell durchsuchen zu können, muß man vorher genau wissen, an welchen Adressen überhaupt Daten stehen. Bereiche ohne Daten können dann übersprungen werden. Greift man auf virtuelle Speicherbereiche zu, denen noch gar keine reale Speicheradresse zugewiesen worden ist, kann es unter Umständen sogar zu Zugriffsverletzungen kommen (- die altbekannte Windows-Messagebox erscheint und das Programm, dessen Speicher ausgelesen werden soll, wird von Windows beendet).
Was ich zur Zeit gerne hätte, wäre eine Möglichkeit gleiches für Speicherbereiche über 2GB zu tun. Wenn hätte dann die Möglichkeit, den gesammten ´virtuelle Speicher eines Prozesses zu durchforsten und bestimmte Zusammenhänge innerhalb von Windows direkt zu sehen... |
| | | | |
|
AntwortenThemenoptionen | 5.766 Betrachtungen |
ThemeninformationenDieses Thema hat 7 Teilnehmer: |