How to know the complete memory of another program ?

Just starting out? Need help? Post your questions and find answers here.
White_Leaf
New User
New User
Posts: 5
Joined: Sat May 05, 2007 12:35 pm

How to know the complete memory of another program ?

Post by White_Leaf »

Hello

I've read a lot about trainers, and already made own ones. But everytime, you use specific memory adresses to patch (which you have to know of course). But I wonder how can I know the complete range of the memory a program uses ? Some mini-games only ose a few MB memory. How can I get the start and end offset of these memorymaps ?
White_Leaf
New User
New User
Posts: 5
Joined: Sat May 05, 2007 12:35 pm

Post by White_Leaf »

Ok, now I've read an interesting article about memory scanning, and the author has written that the
programs (can) always use range 0x00000000 - 0x7FFFFFFF (which is the 2GB memory limit).
But wouldn't the end offset be the total memory usage of another program ? For example:
I start notepad. After the program launches, it uses 1304 kb = 1335296 bytes.
So, I think the range of the program would be 0x00000000 - 0x00146000 correct ?
Or maybe I have to add the imagebase of the launches application to the value, too ?
Is there a way in PB to read the total memory usage by another program as well ?
So many questions ^^
milan1612
Addict
Addict
Posts: 894
Joined: Thu Apr 05, 2007 12:15 am
Location: Nuremberg, Germany
Contact:

Post by milan1612 »

Search for 'trainer' or 'memory' and you'll find answers :wink:
Windows 7 & PureBasic 4.4
White_Leaf
New User
New User
Posts: 5
Joined: Sat May 05, 2007 12:35 pm

Post by White_Leaf »

I already did that. I'm not asking about reading or writing into a specific memory address (which is quite simple). I need to know the complete memory range of an open process (start - end), so I'm able to scan the whole process memory by myself.
milan1612
Addict
Addict
Posts: 894
Joined: Thu Apr 05, 2007 12:15 am
Location: Nuremberg, Germany
Contact:

Post by milan1612 »

Maybe that's what you're looking for?:
http://msdn2.microsoft.com/en-us/library/ms682050.aspx
Windows 7 & PureBasic 4.4
White_Leaf
New User
New User
Posts: 5
Joined: Sat May 05, 2007 12:35 pm

Post by White_Leaf »

Hey thanks a lot. That does indeed seem to be exactly what I'm looking for. I'm trying to translate it, to see the results :)
Thanks again.
User avatar
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

Post by ts-soft »

win32.hlp wrote:In the Microsoft® Win32® application programming interface (API), each process has its own 32-bit virtual address space that enables addressing up to 4 gigabytes (GB) of memory.
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
Image
White_Leaf
New User
New User
Posts: 5
Joined: Sat May 05, 2007 12:35 pm

Post by White_Leaf »

Hmm...maybe the article I read is a little out of date ^^ But I highly doubt that there are games or other applications which use the maximum of possible memory :)
However, the function milan1612 posted works like a charm, and now I'm able to get the current memory usage of the process.
The only question left is now, if I need to add some imagebase to the memoryrange. For example in my test I read the usage of RAM notepad needs. I ended up with that result:

Process memory range: 0x00000000 - 0x298000

Can I now just access those offsets to read from the memory or do I miss something ?

Update: My memory scanner works now. But, I still have a small problem with it: I used a public memory scanner to compare the results, and where the public one finds 8x the searchstring, mine finds it only 7x. The reason is that my scanner search 0x00000000 - memory usage, while the public one finds the last hit outside of that range (dunno why).
But even more problematic is the fact, that my scanner needs 20719ms for the scan of 3324kb while the public one only needs ~100ms!
Also, it does only scans 556kb of that process. So there seems to be some rules to follow (not all memory is available for the process itself etc.)
Maybe someone has some background info about that ?
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re:

Post by PB »

I'm doing a trainer app that needs to know the start/end memory addresses of an app, too, so I can scan the range for specific byte values. The link that milan1612 mentions hasn't helped me much, as I don't know how to convert C to PureBasic. Looking at it though, it doesn't seem to show the start/end addresses anyway?

So, is anyone here able to give a working example of getting the start/end memory locations of a running process, say Calc.exe? Thanks.
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8453
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: How to know the complete memory of another program ?

Post by netmaestro »

What the heck, I'll convert it since it's good useful code. But I don't really know where you'd get start/end addresses either.
I did find this interesting comment from David Davison: http://c.ittoolbox.com/groups/technical ... nt-2603507

Code: Select all

;================================================================
; Collecting Memory Usage Information For a Process
; netmaestro September 2009
; Converted from the original c published by MSDN at:
; http://msdn.microsoft.com/en-us/library/ms682050(VS.85).aspx
;================================================================

Prototype GetProcessMemoryInfo( hProcess, address, size )
Prototype EnumProcesses( *array, size, *cbneeded )

psapi = OpenLibrary(#PB_Any, "psapi.dll")

Global GetProcessMemoryInfo_.GetProcessMemoryInfo = GetFunction(psapi, "GetProcessMemoryInfo")
Global EnumProcesses_.EnumProcesses = GetFunction(psapi, "EnumProcesses")


Structure PROCESS_MEMORY_COUNTERS 
  cb.l
  PageFaultCount.l
  PeakWorkingSetSize.i
  WorkingSetSize.i
  QuotaPeakPagedPoolUsage.i
  QuotaPagedPoolUsage.i
  QuotaPeakNonPagedPoolUsage.i
  QuotaNonPagedPoolUsage.i
  PagefileUsage.i
  PeakPagefileUsage.i
EndStructure

Procedure PrintMemoryInfo( processID )

  Protected hProcess.i
  Protected pmc.PROCESS_MEMORY_COUNTERS

  hProcess = OpenProcess_(  #PROCESS_QUERY_INFORMATION | #PROCESS_VM_READ, #False, processID )
  If (hProcess=0)
      ProcedureReturn
  EndIf
  
  ; Print the process identifier.

  Debug "\nProcess ID: " + Str(processID)
  
  ; Print information about the memory usage of the process.
  
  If GetProcessMemoryInfo_( hProcess, @pmc, SizeOf(pmc)) 

    Debug "\tPageFaultCount: " + Str( pmc\PageFaultCount )
    Debug "\tPeakWorkingSetSize: "+ Str(pmc\PeakWorkingSetSize )
    Debug "\tWorkingSetSize: " + Str( pmc\WorkingSetSize )
    Debug "\tQuotaPeakPagedPoolUsage: " + Str(pmc\QuotaPeakPagedPoolUsage )
    Debug "\tQuotaPagedPoolUsage: " + Str( pmc\QuotaPagedPoolUsage )
    Debug "\tQuotaPeakNonPagedPoolUsage: " + Str( pmc\QuotaPeakNonPagedPoolUsage )
    Debug "\tQuotaNonPagedPoolUsage: " + Str( pmc\QuotaNonPagedPoolUsage )
    Debug "\tPagefileUsage: " + Str( pmc\PagefileUsage )
    Debug "\tPeakPagefileUsage: " + Str( pmc\PeakPagefileUsage )
    Debug ""
  
  EndIf
  CloseHandle_( hProcess )
    
EndProcedure


;Get the List of process identifiers.

Dim aProcesses(1024)
cbNeeded.i
cProcesses.i
i.l

EnumProcesses_( @aProcesses(), ArraySize(aProcesses()), @cbNeeded ) 
 
; Calculate how many process identifiers were returned.

cProcesses = cbNeeded / SizeOf(LONG)

; Print the memory usage For each process

For i = 0 To cProcesses-1
  PrintMemoryInfo( aProcesses(i))
Next

CloseLibrary(psapi)
BERESHEIT
Thorium
Addict
Addict
Posts: 1314
Joined: Sat Aug 15, 2009 6:59 pm

Re: How to know the complete memory of another program ?

Post by Thorium »

You can only access allocated memory. And yes you can enumerate the allocated memory regions.

This is a procedure i wrote to enumerate the memory regions of a process that contain executable code:

Code: Select all

Procedure.l GetExecutableMemRegions(RegionList.Region(1))

  Define.l Addr,RetVal,RegionCnt
  Define.MEMORY_BASIC_INFORMATION MemoryInfo

  RegionCnt = -1

  Repeat
  
    Addr = Addr + MemoryInfo\RegionSize
    RetVal = VirtualQuery_(Addr,MemoryInfo,SizeOf(MEMORY_BASIC_INFORMATION))
    
    If RetVal > 0 
      If MemoryInfo\State = #MEM_COMMIT
      
        If MemoryInfo\Protect = #PAGE_EXECUTE Or MemoryInfo\Protect = #PAGE_EXECUTE_READ Or MemoryInfo\Protect = #PAGE_EXECUTE_READWRITE Or MemoryInfo\Protect = #PAGE_EXECUTE_WRITECOPY
        
          RegionCnt = RegionCnt + 1
          ReDim RegionList.Region(RegionCnt)
          RegionList(RegionCnt)\BaseAddr = MemoryInfo\BaseAddress
          RegionList(RegionCnt)\Size = MemoryInfo\RegionSize
          
        EndIf
      
      EndIf  
    EndIf
  
  Until RetVal < 1

  ProcedureReturn RegionCnt

EndProcedure
Use VirtualQueryEx if you want to enumerate the memory regions of another process.

If you want a realy fast memory scanner you have to write your scanning code in a DLL and inject it into the process you want to scan. So you can directly access the memory without copieing it.
akj
Enthusiast
Enthusiast
Posts: 668
Joined: Mon Jun 09, 2003 10:08 pm
Location: Nottingham

Re: How to know the complete memory of another program ?

Post by akj »

@netmaestro:

I found it useful to extend your code by also retrieving the .EXE pathname:

Code: Select all

Prototype GetModuleFileNameEx(hProcess, module, *name, size)
Global GetModuleFileNameEx_.GetModuleFileNameEx = GetFunction(psapi, "GetModuleFileNameExA")

; ... Within PrintMemoryInfo(), after getting hProcess: ...

size = 512
name$ = Space(size+2)
If GetModuleFileNameEx_(hProcess, #Null, @name$, size)
  name$ = Trim(name$)
  Debug "Process pathname: "+name$
EndIf
Anthony Jordan
akj
Enthusiast
Enthusiast
Posts: 668
Joined: Mon Jun 09, 2003 10:08 pm
Location: Nottingham

Re: How to know the complete memory of another program ?

Post by akj »

@Thorium:

Please give an example of how to call your procedure GetExecutableMemRegions()
Anthony Jordan
Thorium
Addict
Addict
Posts: 1314
Joined: Sat Aug 15, 2009 6:59 pm

Re: How to know the complete memory of another program ?

Post by Thorium »

akj wrote:@Thorium:

Please give an example of how to call your procedure GetExecutableMemRegions()
Ok. :)

I just copied the procedure out of one of my old projects. Now i have reworked it. Works now on x86 and x64, can enumerate the memory regions of another process and enumerates all commited regions, not only executable regions.

Keep in mind that every process runs in it's own address space that starts from 0. You don't need to calculate any position. You just need to use the Win-API to access the address space of another process.
I saw that nobody cared about what ts-soft wrote. This is very basic stuff and if you want to work with other processes than your own you have to know it. Just read about the memory managment on MSDN: http://msdn.microsoft.com/en-us/library/aa366525.aspx

Code: Select all

EnableExplicit

Structure Region
  BaseAddr.i
  Size.i
EndStructure

Procedure.i GetMemRegions(hProcess.i, Array RegionList.Region(1))

  Define.i Addr, RetVal, RegionCnt
  Define.MEMORY_BASIC_INFORMATION MemoryInfo

  RegionCnt = -1

  Repeat
  
    Addr = Addr + MemoryInfo\RegionSize
    RetVal = VirtualQueryEx_(hProcess, Addr, MemoryInfo, SizeOf(MEMORY_BASIC_INFORMATION))
    
    If RetVal <> 0 And MemoryInfo\State = #MEM_COMMIT
      RegionCnt = RegionCnt + 1
      ReDim RegionList.Region(RegionCnt)
      RegionList(RegionCnt)\BaseAddr = MemoryInfo\BaseAddress
      RegionList(RegionCnt)\Size = MemoryInfo\RegionSize  
    EndIf
  
  Until RetVal < 1

  ProcedureReturn RegionCnt

EndProcedure

Define.i i, RegionCnt, hProcess
Dim RegionList.Region(0)

hProcess = GetCurrentProcess_()
RegionCnt = GetMemRegions(hProcess, RegionList())

Debug "count of memory regions in process address space: " + Str(RegionCnt + 1)
For i = 0 To RegionCnt
  Debug "region: " + Str(i + 1)
  Debug "base address: " + Hex(RegionList(i)\BaseAddr)
  Debug "size: " + Hex(RegionList(i)\Size)
  Debug "--------------------------------"
Next
Post Reply