ReadProcessMemory... :( Please Help!
ReadProcessMemory... :( Please Help!
I am having some problems with ReadProcessMemory returning the value at the address specified. Yes the code below is a compilation of many examples that i have tried to get working and for the most part works except getting a correct return value. The example below displays the same buffer content (supposedly return value) for every address given to it even if i manually change the address. Also maybe someone could provide a better in-depth representation of what exactly each parameter of this Api is for? Any help is appreciated since this Api thing is giving me a headache...
-Abystus
OpenWindow(0,300,300,800,500,"Memster",#PB_Window_SystemMenu)
ButtonGadget(0,10,10,200,20, "Read Memory")
EditorGadget(1, 10, 35, 300, 400)
SetForegroundWindow_(WindowID(0))
Procedure ReadMemory()
HWND = FindWindow_(NULL, "Calculator")
si.SYSTEM_INFO
*mbi.MEMORY_BASIC_INFORMATION
ret = 0
pid = 0
GetWindowThreadProcessId_(HWND, @pid)
;Opens Process With full access
hProcess = OpenProcess_(#PROCESS_ALL_ACCESS, #False, pid);
;Grab System Information
GetSystemInfo_(si)
;Find Memory Bounds
lpMin = si\lpMinimumApplicationAddress
lpMax = si\lpMaximumApplicationAddress
lLenMBI = SizeOf(MEMORY_BASIC_INFORMATION )
adr=AllocateMemory(28)
*mbi=adr
;Do the Scan
For x = lpMin To lpMax
WaitWindowEvent()
ret = VirtualQueryEx_(hProcess, lpMin, adr,lLenMBI )
If ret = lLenMBI
If *mbi\RegionSize > 0
sBuffer = AllocateMemory(*mbi\RegionSize)
res = ReadProcessMemory_(hProcess, *mbi\BaseAddress, sBuffer, *mbi\RegionSize, @lWritten)
If lWritten>0 And res>0
SetGadgetText(1, GetGadgetText(1) + Str(sBuffer) + #CRLF$ )
EndIf
FreeMemory(sBuffer)
EndIf
lpMem = *mbi\BaseAddress + *mbi\RegionSize
Else
Break
EndIf
;Delay(1)
Next
EndProcedure
Repeat
;Get Event
EventID = WaitWindowEvent()
If EventID = #PB_Event_Gadget
;If event is a gadget event then do case
Select EventGadget()
Case 0
ReadMemory()
EndSelect
Else
;Else Choose from available window events
Select EventID
Case #PB_Event_CloseWindow
Break
Default
EndSelect
EndIf
Delay(1)
ForEver
-Abystus
OpenWindow(0,300,300,800,500,"Memster",#PB_Window_SystemMenu)
ButtonGadget(0,10,10,200,20, "Read Memory")
EditorGadget(1, 10, 35, 300, 400)
SetForegroundWindow_(WindowID(0))
Procedure ReadMemory()
HWND = FindWindow_(NULL, "Calculator")
si.SYSTEM_INFO
*mbi.MEMORY_BASIC_INFORMATION
ret = 0
pid = 0
GetWindowThreadProcessId_(HWND, @pid)
;Opens Process With full access
hProcess = OpenProcess_(#PROCESS_ALL_ACCESS, #False, pid);
;Grab System Information
GetSystemInfo_(si)
;Find Memory Bounds
lpMin = si\lpMinimumApplicationAddress
lpMax = si\lpMaximumApplicationAddress
lLenMBI = SizeOf(MEMORY_BASIC_INFORMATION )
adr=AllocateMemory(28)
*mbi=adr
;Do the Scan
For x = lpMin To lpMax
WaitWindowEvent()
ret = VirtualQueryEx_(hProcess, lpMin, adr,lLenMBI )
If ret = lLenMBI
If *mbi\RegionSize > 0
sBuffer = AllocateMemory(*mbi\RegionSize)
res = ReadProcessMemory_(hProcess, *mbi\BaseAddress, sBuffer, *mbi\RegionSize, @lWritten)
If lWritten>0 And res>0
SetGadgetText(1, GetGadgetText(1) + Str(sBuffer) + #CRLF$ )
EndIf
FreeMemory(sBuffer)
EndIf
lpMem = *mbi\BaseAddress + *mbi\RegionSize
Else
Break
EndIf
;Delay(1)
Next
EndProcedure
Repeat
;Get Event
EventID = WaitWindowEvent()
If EventID = #PB_Event_Gadget
;If event is a gadget event then do case
Select EventGadget()
Case 0
ReadMemory()
EndSelect
Else
;Else Choose from available window events
Select EventID
Case #PB_Event_CloseWindow
Break
Default
EndSelect
EndIf
Delay(1)
ForEver
- Fluid Byte
- Addict
- Posts: 2336
- Joined: Fri Jul 21, 2006 4:41 am
- Location: Berlin, Germany
Sorry about the tag, I was in a rush to post it. The below should be in the correct format :).
Code: Select all
;Generate Window/Controls
OpenWindow(0,300,300,800,500,"Memster",#PB_Window_SystemMenu)
ButtonGadget(0,10,10,200,20, "Read Memory")
EditorGadget(1, 10, 35, 300, 400)
SetForegroundWindow_(WindowID(0))
Procedure ReadMemory()
;Find Window
HWND = FindWindow_(NULL, "Calculator")
;Declaration
si.SYSTEM_INFO
*mbi.MEMORY_BASIC_INFORMATION
ret = 0
pid = 0
;Get ProcessID
GetWindowThreadProcessId_(HWND, @pid)
;Opens Process With full access
hProcess = OpenProcess_(#PROCESS_ALL_ACCESS, #False, pid);
;Grab System Information
GetSystemInfo_(si)
;Find Memory Bounds
lpMin = si\lpMinimumApplicationAddress
lpMax = si\lpMaximumApplicationAddress
lLenMBI = SizeOf(MEMORY_BASIC_INFORMATION )
adr=AllocateMemory(28)
*mbi=adr
;Do the Scan
For x = lpMin To lpMax
WaitWindowEvent()
ret = VirtualQueryEx_(hProcess, lpMin, adr,lLenMBI )
If ret = lLenMBI
If *mbi\RegionSize > 0
sBuffer = AllocateMemory(*mbi\RegionSize)
res = ReadProcessMemory_(hProcess, *mbi\BaseAddress, sBuffer, *mbi\RegionSize, @lWritten)
If lWritten>0 And res>0
SetGadgetText(1, GetGadgetText(1) + Str(sBuffer) + #CRLF$ )
EndIf
FreeMemory(sBuffer)
EndIf
lpMem = *mbi\BaseAddress + *mbi\RegionSize
Else
Break
EndIf
Next
EndProcedure
Repeat
;Get Event
EventID = WaitWindowEvent()
If EventID = #PB_Event_Gadget
;If event is a gadget event then do case
Select EventGadget()
Case 0
ReadMemory()
Default
;Do Nothing
EndSelect
Else
;Else Choose from available window events
Select EventID
Case #PB_Event_CloseWindow
;Break if Window was closed
Break
Default
;Do Nothing
EndSelect
EndIf
;Delay to avoid Memory Usage
Delay(1)
ForEver
Yea I've seen that page quite a few times and the way I understand it from examples and even from that page is that the buffer is suppose to return the value at said address. However it appears that whatever the buffer is set to is not changed when the API returns, if it is even returning correctly for me that is. I do not get any errors on execution or anything else that I would expect to get. If anyone has a better example to go by to read a range of memory within a process and return values said addresses within that range please do.
Re: ReadProcessMemory... :( Please Help!
abystus wrote:I am having some problems with ReadProcessMemory returning the value at the address specified. Yes the code below is a compilation of many examples that i have tried to get working and for the most part works except getting a correct return value. The example below displays the same buffer content (supposedly return value) for every address given to it even if i manually change the address. Also maybe someone could provide a better in-depth representation of what exactly each parameter of this Api is for? Any help is appreciated since this Api thing is giving me a headache...
I've commented the Scanning routine to highlight some problems:
Code: Select all
;Do the Scan
For x = lpMin To lpMax
WaitWindowEvent()
ret = VirtualQueryEx_(hProcess, lpMin, adr,lLenMBI )
If ret = lLenMBI
If *mbi\RegionSize > 0
sBuffer = AllocateMemory(*mbi\RegionSize)
res = ReadProcessMemory_(hProcess, *mbi\BaseAddress, sBuffer, *mbi\RegionSize, @lWritten) ;<== *mbi\BaseAddress is a constant
If lWritten>0 And res>0
SetGadgetText(1, GetGadgetText(1) + Str(sBuffer) + #CRLF$ ) ;<== sBuffer contains an address so Str(sBuffer) displays the address
EndIf
FreeMemory(sBuffer)
EndIf
lpMem = *mbi\BaseAddress + *mbi\RegionSize ;<== this is a constant and is never used
Else
Break
EndIf
Next
Here is the same routine with a few changes to solve those same problems (note you will want to shut down the Calendar program to abort scanning with the default region because it is 900+ megabytes long):
Code: Select all
;Do the Scan
For x = lpMin To lpMax
WaitWindowEvent()
ret = VirtualQueryEx_(hProcess, lpMin, adr,lLenMBI )
If ret = lLenMBI
If *mbi\RegionSize > 0
If lpMem <> 0
lpMem + *mbi\RegionSize ;<=== progressively update memory pointer
Else
lpMem = *mbi\BaseAddress + *mbi\RegionSize
EndIf
sBuffer = AllocateMemory(*mbi\RegionSize)
res = ReadProcessMemory_(hProcess, lpMem, sBuffer, *mbi\RegionSize, @lWritten) ;<==Change memory address so that all memory regions will be returned as we loop
If lWritten>0 And res>0
For i = 0 To lWritten - 1 ; <=== hack, replace Null bytes with a different character so that contents of memory can be read as a string
If PeekB(sBuffer) = 0
PokeB(sBuffer + i,1)
EndIf
Next
SetGadgetText(1, GetGadgetText(1) + PeekS(sBuffer) + #CRLF$ ) ;<== convert memory contents to a string with PeekS(sBuffer)
EndIf
FreeMemory(sBuffer)
EndIf
Else
Break
EndIf
Next

Very interesting, I tested it out and I'm getting some weird return data shown below:
Code: Select all
È
{
I found some old VB6 Code to read from a specific address. I have used this before in the making of a trainer type application. I may work on trying to convert this logic into purebasic since its a little more already predefined as what and where things need to happen. Im sure if i can reproduce this in PB giving it addresses should be the easy part
.
- Abystus

- Abystus
Code: Select all
Public Function ReadAByte(gamewindowtext As String, address As Long, valbuffer As Byte)
Dim hwnd As Long
Dim pid As Long
Dim phandle As Long
hwnd = FindWindow(vbNullString, gamewindowtext)
If (hwnd = 0) Then
MsgBox "The Game Is Not Working", vbCritical, "Error"
End
Exit Function
End If
GetWindowThreadProcessId hwnd, pid
phandle = OpenProcess(PROCESS_ALL_ACCESS, False, pid)
If (phandle = 0) Then
MsgBox "Can't get ProcessId", vbCritical, "Error"
Exit Function
End If
ReadProcessMemory phandle, address, valbuffer, 1, 0&
CloseHandle hProcess
End Function
[quote="abystus"]Very interesting, I tested it out and I'm getting some weird return data shown below:
Code: Select all
È
{
Maybe I'm just not understanding what exactly we are returning from the previous source. The vb6 alternative produces a numeric value from what is stored at that address. I am wanting to produce a similar execution in PB.The question is "what format did you need it in?" Your previous code obtained the contents of memory and then just displayed the starting address of the buffer. It was a little hard to guess what you were trying to "see". I guessed and displayed the memory contents in the buffer as characters. If you want to operate/search the contents of the buffer instead of "seeing" it then that is the part you would need to add to the previous code.
Basically if you look at pretty much any memory editor you will see memory values are stored with a numeric/hexadecimal value as shown below:

In the image each 2 digit hex value is a representation of the value at each memory address on that line, 6 memory addresses at a time in this instance. However when a program returns a reference to value it should most likely be in the numerical format 0-255 instead of 0-FF. Maybe our example is returning the very right column shown in the memory editor? I'm not really that great at interacting with memory from a programmers stand point, I normally deal with business applications. However I am trying to understand just exactly what we are returning in our example.
I understand you converted it to string using SPeek which in turn might have caused it to possibly convert from ascii to character format. I could possibly be getting to wrapped up in this conversion from vb to pb, I figured it would be much simpler and even comparable to the vb alternative. Am I just missing something here? Thanks again for all your help on this matter, maybe I should go back to hacking memory instead of trying to program for it

-Abystus[/code]
Hey just letting you know I got a chance to sit down and see exactly what you were doing, I changed PeekS to PeekB and seem to be getting some acceptable results, however I see the addresses skip around a good bit. Im taking a guess that the below code is working correctly:
I didn't quite understand that the buffer was a value holder (almost like a storage address) that you had to peek into to get a value from in a desired format (I thought it just returned). The example now lists the address along with its value in the box. Let me know what you think, and so very sorry for all the confusion
.
-Abystus
Code: Select all
;Generate Window/Controls
OpenWindow(0,300,300,800,500,"Memster",#PB_Window_SystemMenu)
ButtonGadget(0,10,10,200,20, "Read Memory")
EditorGadget(1, 10, 35, 300, 400)
EditorGadget(3, 220, 10, 50, 20)
SetForegroundWindow_(WindowID(0))
Procedure ReadMemory()
;Find Window
HWND = FindWindow_(NULL, "Calculator")
;Declaration
si.SYSTEM_INFO
*mbi.MEMORY_BASIC_INFORMATION
ret = 0
pid = 0
;Get ProcessID
GetWindowThreadProcessId_(HWND, @pid)
;Opens Process With full access
hProcess = OpenProcess_(#PROCESS_ALL_ACCESS, #False, pid);
;Grab System Information
GetSystemInfo_(si)
;Find Memory Bounds
lpMin = si\lpMinimumApplicationAddress
lpMax = si\lpMaximumApplicationAddress
lLenMBI = SizeOf(MEMORY_BASIC_INFORMATION )
adr=AllocateMemory(28)
*mbi=adr
;;Do the Scan
For x = lpMin To lpMax
WaitWindowEvent()
ret = VirtualQueryEx_(hProcess, lpMin, adr,lLenMBI )
If ret = lLenMBI
If *mbi\RegionSize > 0
If lpMem <> 0
lpMem + *mbi\RegionSize ;<=== progressively update memory pointer
Else
lpMem = *mbi\BaseAddress + *mbi\RegionSize
EndIf
sBuffer = AllocateMemory(*mbi\RegionSize)
res = ReadProcessMemory_(hProcess, lpMem, sBuffer, *mbi\RegionSize, @lWritten) ;<==Change memory address so that all memory regions will be returned as we loop
If lWritten>0 And res>0
For i = 0 To lWritten - 1 ; <=== hack, replace Null bytes with a different character so that contents of memory can be read as a string
;WaitWindowEvent()
;if PeekB(sBuffer) = 0
; PokeB(sBuffer + i,1)
;EndIf
Next
If Str(PeekB(sBuffer)) = GetGadgetText(3)
SetGadgetText(1, GetGadgetText(1) + Str(lpmem) + " " + Str(PeekB(sBuffer)) + #CRLF$ ) ;<== convert memory contents to a string with PeekS(sBuffer)
EndIf
EndIf
FreeMemory(sBuffer)
EndIf
Else
Break
EndIf
Next
EndProcedure
Repeat
;Get Event
EventID = WaitWindowEvent()
If EventID = #PB_Event_Gadget
;If event is a gadget event then do case
Select EventGadget()
Case 0
ReadMemory()
Default
;Do Nothing
EndSelect
Else
;Else Choose from available window events
Select EventID
Case #PB_Event_CloseWindow
;Break if Window was closed
Break
Default
;Do Nothing
EndSelect
EndIf
;Delay to avoid Memory Usage
Delay(1)
ForEver

-Abystus
OK just tested it out with a live address and a value I already know and it is returning correctly, however I'm thinking my address range is off because I'm not finding correct addresses within the desired process. Is there anything that could be causing it not to be pulling the memory specific to the calculator application? Like somehow the base address is off? Getting really close
to having this thing working.
-Abystus

-Abystus
@abystus
I know its an old thread, but i was searching around for something else and came across this thread. Maybe this would be useful for getting a module base address:
works it seems in Vista and Windows 7, don't know about XP as i haven't used it in XP.
He's probably not around any longer.
I know its an old thread, but i was searching around for something else and came across this thread. Maybe this would be useful for getting a module base address:
Code: Select all
; get the module base
#MAX_MODULE_NAME32=255
#MAX_MODULE_NAME32plus=#MAX_MODULE_NAME32+1
#TH32CS_SNAPPROCESS=$2
#TH32CS_SNAPMODULE=$8
OpenLibrary(0, "kernel32.dll")
Procedure.s RetrieveModuleBase(ProcName.s, ModuleName.s)
lReturnID.l
hSnapProcess.l
hSnapModule.l
proc.PROCESSENTRY32
Module.MODULEENTRY32
hSnapProcess=CallFunction(0, "CreateToolhelp32Snapshot", #TH32CS_SNAPPROCESS, 0)
If hSnapProcess <> 0
proc\dwSize = SizeOf(proc)
lReturnID = CallFunction(0, "Process32First", hSnapProcess, @proc)
While lReturnID<>0
If FindString(Left(PeekS(@proc\szExeFile), Len(ProcName)), ProcName, 1)=1
hSnapModule = CallFunction(0, "CreateToolhelp32Snapshot", #TH32CS_SNAPMODULE, proc\th32ProcessID)
If hSnapModule
Module\dwSize = SizeOf(Module)
lReturnID = CallFunction(0, "Module32First", hSnapModule, @Module)
While lReturnID<>0
If FindString(Left(PeekS(@Module\szModule), Len(ModuleName)), ModuleName, 1)=1
CloseLibrary(0)
ProcedureReturn "$"+Hex(Module\modBaseAddr)
EndIf
lReturnID = CallFunction(0, "Module32Next", hSnapModule, @Module)
Wend
EndIf
EndIf
lReturnID = CallFunction(0, "Process32Next", hSnapProcess, @proc)
Wend
EndIf
CloseLibrary(0)
ProcedureReturn "0"
EndProcedure
Debug RetrieveModuleBase("notepad.exe", "kernel32.dll")
He's probably not around any longer.
Re: ReadProcessMemory... :( Please Help!
About "kernel32.dll" module's base, we can use "Debug "$"+Hex(GetModuleHandle_("kernel32.dll"))".
-
- Enthusiast
- Posts: 118
- Joined: Thu May 17, 2007 8:35 pm
- Location: USA
Re: ReadProcessMemory... :( Please Help!
Yes but imagine if you wanted the base of a non-system .dll in another program (i.e. notepad.exe). I don't think your method would work.Poplar wrote:About "kernel32.dll" module's base, we can use "Debug "$"+Hex(GetModuleHandle_("kernel32.dll"))".
best,
Mike