Code: Alles auswählen
;- Einfacher Speicher-Manipulator ("Spiele-Trainer")
;- "Helle" Klaus Helbing, 02.06.2008, PB 4.20
;- Version 4.20 ist erforderlich für Val(Hex), sonst anpassen!
;- Getestet mit WinXP und dem "Test-Klassiker" winmine.exe
;- Für "winmine.exe" interessante Anfangs-Speicher-Adresse: $1005000 (Programm laufen lassen !"
;- Zum Ändern einfach auf die "Zelle" doppel-klicken (linke Maustaste) und schauen
;- Änderungen von Strings sind Zeit-Relevant!
;- Benutzung auf eigene Gefahr!
Global Rot.l
Global WindowID.l
Global Zeile.l
Global Spalte.l
Global GadgetNr.l
Global NeuWert.b
#NbProcessesMax = 10000
Global Dim ProcessesArray(#NbProcessesMax)
Procedure GetProcessList()
If OpenLibrary(0, "psapi.dll")
EnumProcesses = GetFunction(0, "EnumProcesses")
EnumProcessModules = GetFunction(0, "EnumProcessModules")
GetModuleBaseName = GetFunction(0, "GetModuleBaseNameA")
CallFunctionFast(EnumProcesses, ProcessesArray(), #NbProcessesMax, @nProcesses)
For k = 0 To nProcesses >> 2
hProcess = OpenProcess_(#PROCESS_QUERY_INFORMATION | #PROCESS_VM_READ, #False, ProcessesArray(k))
If hProcess
CallFunctionFast(EnumProcessModules, hProcess, @BaseModule, 4, @cbNeeded)
Prozess$ = Space(cbNeeded)
CallFunctionFast(GetModuleBaseName, hProcess, BaseModule, @Prozess$, cbNeeded)
If Len(Prozess$) <> 0 ;z.B. System
AddGadgetItem(0, -1, Prozess$ + Chr(10) + Str(ProcessesArray(k)))
EndIf
CloseHandle_(hProcess)
EndIf
Next
CloseLibrary(0)
EndIf
EndProcedure
Procedure NotifyCallback(WindowID, Message, wParam, lParam) ;für roten Text
If Message = #WM_NOTIFY ;nur WM_NOTIFY-Messages abfangen
*TextColor.NMLVCUSTOMDRAW = lParam
If *TextColor\nmcd\hdr\hWndFrom = GadgetNr
*pnmh.NMHDR = lParam
If *pnmh\code = #NM_DBLCLK ;Double-Click in Liste?
*lpnmitem.NMITEMACTIVATE = lParam
Zeile = *lpnmitem\iItem
Spalte = *lpnmitem\iSubItem
EndIf
Select *TextColor\nmcd\dwDrawStage
Case #CDDS_PREPAINT
ProcedureReturn #CDRF_NOTIFYITEMDRAW
Case #CDDS_ITEMPREPAINT
ProcedureReturn #CDRF_NOTIFYSUBITEMDRAW
Case #CDDS_SUBITEM | #CDDS_ITEMPREPAINT
If Rot
*TextColor\clrText = 255 ;rot
EndIf
EndSelect
EndIf
Else
ProcedureReturn #PB_ProcessPureBasicEvents ;war nichts von Interesse, normal weiter
EndIf
EndProcedure
WindowID = OpenWindow(0, 0, 0, 665, 520, "Auswahl des zu beobachtenden Programmes", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
If WindowID And CreateGadgetList(WindowID(0))
;Structuren definieren
MBI.MEMORY_BASIC_INFORMATION
SysInfo.SYSTEM_INFO
ButtonGadget(1, 0, 0, 0, 0, "Über den Explorer ein Programm auswählen und starten")
ButtonGadget(2, 0, 0, 0, 0, "Ein bereits gestartetes Programm auswählen")
SplitterGadget(0, 10, 10, 645, 150, 1, 2, #PB_Splitter_Vertical | #PB_Splitter_Separator)
Repeat
Event = WaitWindowEvent()
If Event = #PB_Event_CloseWindow
End
EndIf
Until EventGadget() = 1 Or EventGadget() = 2
FreeGadget(0) : FreeGadget(1) : FreeGadget(2)
If EventGadget() = 1 ;Status bleibt auch nach FreeGadget() erhalten (hoffe ich!)
ExplorerTreeGadget(0, 10, 10, 645, 485,"",#PB_Explorer_NoDriveRequester)
Repeat
Event = WaitWindowEvent()
If Event = #PB_Event_CloseWindow
End
EndIf
Until EventType() = #PB_EventType_LeftDoubleClick And GetGadgetState(0) = #PB_Explorer_File
File$ = GetGadgetText(0)
;Programm starten und Programm-Handle ermitteln
hProgram = RunProgram(File$, "", GetCurrentDirectory(), #PB_Program_Open)
;damit die Programm-ID ermitteln; ist die, die auch der Task-Manager anzeigt (variabel!!!)
ProgID = ProgramID(hProgram)
File$ = GetFilePart(File$) ;nur File-Name
Else
ListIconGadget(0, 10, 10, 645, 480, "Name", 345, #PB_ListIcon_GridLines | #PB_ListIcon_FullRowSelect)
AddGadgetColumn(0, 1, "ProgID", 300)
GetProcessList()
Repeat
File$ = GetGadgetItemText(0, GetGadgetState(0))
ProgID = Val(GetGadgetItemText(0, GetGadgetState(0), 1))
Event = WaitWindowEvent()
If Event = #PB_Event_CloseWindow
End
EndIf
Until EventType() = #PB_EventType_LeftDoubleClick Or Event = #PB_Event_CloseWindow
EndIf
FreeGadget(0)
SetWindowTitle(0, "Assoziierte Speicherbereiche für " + File$)
ListIconGadget(0, 10, 10, 645, 485, "Start-Adresse", 125, #PB_ListIcon_GridLines | #PB_ListIcon_FullRowSelect)
AddGadgetColumn(0, 1, "End-Adresse", 125)
AddGadgetColumn(0, 2, "Grösse", 125)
AddGadgetColumn(0, 3, "Status", 215)
GetSystemInfo_(SysInfo) ;Ermittlung des für Programme zur Verfügung stehenden Speichers
MinAdr = SysInfo\lpMinimumApplicationAddress
MaxAdr = SysInfo\lpMaximumApplicationAddress
;jetzt das Ganze für Vollzugriff öffnen
ProcessHandle = OpenProcess_(#PROCESS_ALL_ACCESS, #False, ProgID)
AnfAdresse = MinAdr
Delay(1000) ;Windows etwas Zeit zum Speicher-Organisieren geben
Zeile = 0
While AnfAdresse < MaxAdr ;Speicher abklappern
VirtualQueryEx_(ProcessHandle, AnfAdresse, MBI, SizeOf(MEMORY_BASIC_INFORMATION))
Eigner = MBI\State
Size = MBI\RegionSize
Status = MBI\Protect
If Eigner = #MEM_COMMIT ;Test, ob Speicherbereich mit ausgewähltem Programm assoziiert ist
BaseAdr = MBI\BaseAddress
AddGadgetItem(0, -1, "")
SetGadgetItemText(0, Zeile, "$" + Hex(BaseAdr), 0)
EndAdr = BaseAdr + Size
SetGadgetItemText(0, Zeile, "$" + Hex(EndAdr), 1)
SetGadgetItemText(0, Zeile, "$" + Hex(Size), 2)
If Status = $1
Status$ = "PAGE_NOACCESS"
ElseIf Status = $2
Status$ = "PAGE_READONLY"
ElseIf Status = $4
Status$ = "PAGE_READWRITE"
ElseIf Status = $8
Status$ = "PAGE_WRITECOPY"
ElseIf Status = $10
Status$ = "PAGE_EXECUTE"
ElseIf Status = $20
Status$ = "PAGE_EXECUTE_READ"
ElseIf Status = $40
Status$ = "PAGE_EXECUTE_READWRITE"
ElseIf Status = $80
Status$ = "PAGE_EXECUTE_WRITECOPY"
ElseIf Status = $100
Status$ = "PAGE_GUARD"
ElseIf Status = $200
Status$ = "PAGE_NOCACHE"
ElseIf Status = $400
Status$ = "PAGE_WRITECOMBINE"
Else
Status$ = "Kombination"
EndIf
SetGadgetItemText(0, Zeile, "$" + Hex(Status) + " = " + Status$ , 3)
Status$ = ""
Zeile + 1
EndIf
AnfAdresse + Size
If AnfAdresse < 0 ;negativ!
Break
EndIf
Wend
Repeat
Event = WaitWindowEvent()
If Event = #PB_Event_CloseWindow
End
EndIf
Until EventType() = #PB_EventType_LeftDoubleClick
BaseAdr$ = GetGadgetItemText(0, GetGadgetState(0))
BaseAdr = Val(BaseAdr$)
EndAdr$ = GetGadgetItemText(0, GetGadgetState(0), 1)
EndAdr = Val(EndAdr$)
;Buffer-Speicher anfordern ---
Laenge = (EndAdr - BaseAdr)
Buffer = AllocateMemory(Laenge)
BufferS = AllocateMemory(Laenge)
If Buffer = 0 Or BufferS = 0
MessageRequester("Fehler !", "Der benötigte Speicher konnte nicht bereitgestellt werden !")
End
EndIf
;-----------------------------
FreeGadget(0)
SetWindowTitle(0, "Anzeige Speicherbereich von " + BaseAdr$ +" bis " + EndAdr$ + " für " + File$)
GadgetNr = ListIconGadget(0, 10, 10, 645, 485, "Adresse", 75, #PB_ListIcon_GridLines | #LVS_NOSORTHEADER | #PB_ListIcon_FullRowSelect)
For b = 1 To 16
AddGadgetColumn(0, b, Hex(b-1), 34)
Next
ReadProcessMemory_(ProcessHandle, BaseAdr, Buffer, Laenge, 0)
n = Laenge
n >> 4
n - 1
For k = 0 To n
For i = 0 To 15
Test1$ + Chr(10) + RSet(Hex(PeekB(Buffer + z) & 255), 2, "0")
z + 1
Next
AddGadgetItem(0, -1, Hex(BaseAdr + k << 4) + Test1$)
Test1$ = ""
Next
SetWindowCallback(@NotifyCallback(), 0) ;aktuelle Änderungen im sichtbaren Bereich rot markieren
Repeat : Event = WindowEvent()
CopyMemory(Buffer, BufferS, Laenge)
ReadProcessMemory_(ProcessHandle, BaseAdr, Buffer, Laenge, 0)
z = 0
n = Laenge-4
n >> 4
n - 1
Rot = 0
For k = 0 To n
For i = 0 To 15
If (PeekB(Buffer + z) & 255) <> (PeekB(BufferS + z) & 255)
Wert$=RSet(Hex((PeekB(Buffer + z) & 255)), 2, "0") + "<" ;"<" als Zeichen für verändert
Rot = 255 ;für NotifyCallback (<>0)
SetGadgetItemText(0, k, Wert$, i + 1) ;Wert$ soll rot ausgegeben werden
EndIf
z + 1
Next
Next
;Test auf Ändern
If Zeile <> OldZeile Or Spalte <> OldSpalte
OldZeile = Zeile ;Zeile und Spalte von NotifyCallback
OldSpalte = Spalte
If Spalte > 0 ;Adresse
Adresse = BaseAdr + (Zeile << 4) + (Spalte - 1)
FreeGadget(5)
TextGadget(1, 20, 500, 250, 15, "Ausgewählte Speicher-Adresse : $" + Hex(Adresse))
TextGadget(2, 300, 500, 175, 15, "Aktueller Wert : $" + RSet(Hex(PeekB(Buffer + (Zeile << 4) + (Spalte - 1)) & 255), 2, "0"))
TextGadget(3, 480, 500, 100, 15, "Neuer Wert : ")
TextGadget(4, 545, 500, 50, 15, "")
NeuWert$ = "$"
NoWrite = 0
While Len(NeuWert$) < 3
If GetAsyncKeyState_(#VK_RETURN) = -32767
NoWrite = 1
Break ;Abbruch mit Return
EndIf
For C = 48 To 57 ;Ziffern 0-9
If GetAsyncKeyState_(C) = -32767
NeuWert$ + Chr(C)
SetGadgetText(4, NeuWert$)
EndIf
Next
For C = 65 To 70 ;Buchstaben A-F
If GetAsyncKeyState_(C) = -32767
NeuWert$ + Chr(C)
SetGadgetText(4, NeuWert$) ;pro Forma... und für Tests
EndIf
Next
Wend
If NoWrite = 0
NeuWert = Val(NeuWert$)
VirtualProtectEx_(ProcessHandle, Adresse, 1, #PAGE_EXECUTE_READWRITE , @ProtectStatus)
;ordentlicherweise müsste der alte Protect-Status wiederhergestellt werden, aber liegt ja "nur" im Speicher...
If WriteProcessMemory_(ProcessHandle, Adresse, @NeuWert, 1, #Null) = 0
MessageRequester("Fehler !", "Schreibvorgang war nicht erfolgreich !")
EndIf
OldZeile = 0 : OldSpalte = 0 : Zeile = 0 : Spalte = 0 ;somit sofort wieder anwählbar
EndIf
FreeGadget(1) : FreeGadget(2) : FreeGadget(3) : FreeGadget(4)
TextGadget(5, 200, 500, 400, 15, "Zuletzt geschrieben : Wert " + NeuWert$ + " in Adresse $" + Hex(Adresse))
EndIf
EndIf
;Delay(1)
Until Event = #PB_Event_CloseWindow
CloseWindow(0)
EndIf

Gruß
Helle