Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Memory Functions - Reading and Writing.


  • Please log in to reply
15 replies to this topic
gamax92
  • Members
  • 411 posts
  • Last active: Aug 06 2013 05:00 AM
  • Joined: 05 Dec 2010
memory read write cheat engine
Ever wanted to look at the memory of other processes? - Generic Intro

This is my collection of various memory scripts I've seen in the forums.
Its been a while and the german forums went down, so I'm not sure who to credit.
If you see your work, please contact me.

Documentation:
Don't ask what 0x1F0FFF is for, I don't know
You have to open the process first, don't try to supply an HWND not from the MemoryOpen functions.'

MemoryOpenFromPID(PID, Privilege=0x1F0FFF) - Open the Process via PID with access 0x1F0FFF
MemoryOpenFromName(Name, Privilege=0x1F0FFF) - Open the Process via Name (program.exe) with access 0x1F0FFF
MemoryOpenFromTitle(title, privilege=0x1F0FFF) - Open the Process via its Title with access 0x1F0FFF
Functions above Return HWND of program. Use this in below functions.

MemoryClose(hwnd) - Close one of the opened processes. Do this to save memory.
MemoryWrite(hwnd, address, writevalue, datatype="int", length=4, offset=0) - Write WriteValue to Address+Offset as DataType of size Length.
MemoryRead(hwnd, address, datatype="int", length=4, offset=0) - Read a value of DataType of size Length at Address+Offset. Returns retrieved value.

MemoryWritePointer(hwnd, base, writevalue, datatype="int", length=4, offsets=0, offset_1=0, offset_2=0, ...) -_
Same as MemoryWrite except offsets are used for pointers. Offsets = Number of offsets.
MemoryReadPointer(hwnd, base, datatype="int", length=4, offsets=0, offset_1=0, offset_2=0, ...) -_
Same as MemoryRead except offsets are used for pointers. Offsets = Number of offsets.
Functions above support a maximum of 9 offsets.

MemoryGetAddrPID(PID, DllName) - Get the base address for a module called DllName in process of PID
MemoryGetAddrName(Name, DllName) - Get the base address for a module called DllName in process of Name
MemoryGetAddrTitle(Title, DllName) - Get the base address for a module called DllName in process of Title
SetPrivilege(privilege = "SeDebugPrivilege") - Not sure, this function came with the MemoryRead/Write functions.
SuspendProcess(hwnd) - Freezes the process via HWND
ResumeProcess(hwnd) - Thaws the process via HWND
Download
MemoryOpenFromPID(PID, Privilege=0x1F0FFF)
{
	HWND := DllCall("OpenProcess", "Uint", Privilege, "int", 0, "int", PID)
	return HWND
}

MemoryOpenFromName(Name, Privilege=0x1F0FFF)
{
	Process, Exist, %Name%
	PID := ErrorLevel
	Return MemoryOpenFromPID(PID, Privilege)
}

MemoryOpenFromTitle(title, privilege=0x1F0FFF)
{
	WinGet, PID, PID, %title%
	Return MemoryOpenFromPID(PID, Privilege)
}

MemoryClose(hwnd)
{
	return DllCall("CloseHandle", "int", hwnd)
}

MemoryWrite(hwnd, address, writevalue, datatype="int", length=4, offset=0)
{
	VarSetCapacity(finalvalue, length, 0)
	NumPut(writevalue, finalvalue, 0, datatype)
	return DllCall("WriteProcessMemory", "Uint", hwnd, "Uint", address+offset, "Uint", &finalvalue, "Uint", length, "Uint", 0)
}

MemoryRead(hwnd, address, datatype="int", length=4, offset=0)
{
	VarSetCapacity(readvalue,length, 0)
	DllCall("ReadProcessMemory","Uint",hwnd,"Uint",address+offset,"Str",readvalue,"Uint",length,"Uint *",0)
	finalvalue := NumGet(readvalue,0,datatype)
	return finalvalue
}

MemoryWritePointer(hwnd, base, writevalue, datatype="int", length=4, offsets=0, offset_1=0, offset_2=0, offset_3=0, offset_4=0, offset_5=0, offset_6=0, offset_7=0, offset_8=0, offset_9=0)
{
	B_FormatInteger := A_FormatInteger 
	Loop, %offsets%
	{
		baseresult := MemoryRead(hwnd,base)
		Offset := Offset_%A_Index%
		SetFormat, integer, h
		base := baseresult + Offset
		SetFormat, integer, d
	}
	SetFormat, Integer, %B_FormatInteger%
	return MemoryWrite(hwnd,address,writevalue,datatype,length)
}

MemoryReadPointer(hwnd, base, datatype="int", length=4, offsets=0, offset_1=0, offset_2=0, offset_3=0, offset_4=0, offset_5=0, offset_6=0, offset_7=0, offset_8=0, offset_9=0)
{
	B_FormatInteger := A_FormatInteger 
	Loop, %offsets%
	{
		baseresult := MemoryRead(hwnd,base)
		Offset := Offset_%A_Index%
		SetFormat, integer, h
		base := baseresult + Offset
		SetFormat, integer, d
	}
	SetFormat, Integer, %B_FormatInteger%
	return MemoryRead(hwnd,base,datatyp,length)
}

MemoryGetAddrPID(PID, DllName)
{
    VarSetCapacity(me32, 548, 0)
    NumPut(548, me32)
    snapMod := DllCall("CreateToolhelp32Snapshot", "Uint", 0x00000008, "Uint", PID)
    If (snapMod = -1)
        Return 0
    If (DllCall("Module32First", "Uint", snapMod, "Uint", &me32))
	{
		Loop
       	{
            If (!DllCall("lstrcmpi", "Str", DllName, "UInt", &me32 + 32)) {
                DllCall("CloseHandle", "UInt", snapMod)
                Return NumGet(&me32 + 20)
            }
        }
		Until !DllCall("Module32Next", "Uint", snapMod, "UInt", &me32)
    }
    DllCall("CloseHandle", "Uint", snapMod)
    Return 0
}

MemoryGetAddrName(Name, DllName)
{
	Process, Exist, %Name%
	PID := ErrorLevel
	Return MemoryGetAddrPID(PID, DllName)
}

MemoryGetAddrTitle(Title, DllName)
{
	WinGet, PID, PID, %Title%
	Return MemoryGetAddrPID(PID, DllName)
}

SetPrivilege(privilege = "SeDebugPrivilege")
{
	success := DllCall("advapi32.dll\LookupPrivilegeValueA","uint",0,"str",privilege,"int64*",luid_SeDebugPrivilege)
	if (success = 1) && (ErrorLevel = 0)
	{
		returnval = 0
	}
	else
	{
		returnval = %ErrorLevel%
	}
	return %returnval%
}

SuspendProcess(hwnd)
{
	return DllCall("ntdll\NtSuspendProcess","uint",hwnd)
}

ResumeProcess(hwnd)
{
	return DllCall("ntdll\NtResumeProcess","uint",hwnd)
}


side
  • Members
  • 168 posts
  • Last active: Nov 30 2014 03:41 PM
  • Joined: 01 Nov 2012

time to dll injection!~!~!~!



Verdlin
  • Members
  • 256 posts
  • Last active: Apr 29 2016 06:46 PM
  • Joined: 21 Dec 2012

Awesome! Thanks.

 

FYI:

PROCESS_ALL_ACCESS:=0x1F0FFF
; or, decimal
PROCESS_ALL_ACCESS:=2035711

wink.png


Scripts are written and tested using AHK_H 64w (unless otherwise specified).

CFlyout. EasyIni. Dynamic Label Execution (No Reload). Word Lookup.


Verdlin
  • Members
  • 256 posts
  • Last active: Apr 29 2016 06:46 PM
  • Joined: 21 Dec 2012

time to dll injection!~!~!~!

 

Then check out InjectAHKDll()!


Scripts are written and tested using AHK_H 64w (unless otherwise specified).

CFlyout. EasyIni. Dynamic Label Execution (No Reload). Word Lookup.


Bruttosozialprodukt
  • Members
  • 457 posts
  • Last active: Oct 18 2015 08:47 AM
  • Joined: 20 Oct 2012

In the "function MemoryReadPointer"
return MemoryRead(hwnd,base,datatyp,length)

should be
return MemoryRead(hwnd,base,datatype,length)

 

otherwise the result will always be returned as integer value.



newbieme
  • Members
  • 100 posts
  • Last active: Aug 07 2015 11:22 AM
  • Joined: 26 Mar 2014

Hi,

I am trying to work with these functions, but:

var:=MemoryOpenFromName(calc.exe, Privilege=0x1F0FFF)

MsgBox %var%

returns me 0.

 

please help, thank you



RHCP
  • Members
  • 1228 posts
  • Last active: Apr 08 2017 06:17 PM
  • Joined: 29 May 2006

It should be :

 msgbox % hProcess:=MemoryOpenFromName("calc.exe", 0x1F0FFF)
 ; or
 msgbox % hProcess:=MemoryOpenFromName("calc.exe")

Those lines at the top of the posted scripts are the function definitions. They're not exactly examples of how to call them.

 

Here is another class for reading, writing, and scanning memory.

https://github.com/K...classMemory.ahk

The documentation quite verbose and it requires AHK_L.



newbieme
  • Members
  • 100 posts
  • Last active: Aug 07 2015 11:22 AM
  • Joined: 26 Mar 2014

thank you, it is working!

 

have another problem:

hProcess:=MemoryOpenFromName("calc.exe", 0x1F0FFF)
msgbox % mem:=MemoryRead(%hProcess%,BC292599FB,"string")

again it returns 0. 



RHCP
  • Members
  • 1228 posts
  • Last active: Apr 08 2017 06:17 PM
  • Joined: 29 May 2006

You should spend some time reading the manual, particularly sections pertaining to expression and non-expression syntax.

http://www.autohotke...s/Variables.htm

http://www.autohotke...s/Functions.htm

hProcess := MemoryOpenFromName("calc.exe", 0x1F0FFF)
msgbox % mem:=MemoryRead(hProcess, 0xBC292599FB, "string")

Note the lack of percentages and the addition of '0x'. "BC292599FB" would be a variable name, whereas 0xBC292599FB is a hexadecimal number.

This will still fail however, as that function can not read strings. Even if it could, you would still need to be running AHK64 to read such a high memory address.



Cren
  • Members
  • 7 posts
  • Last active: Nov 04 2015 02:09 PM
  • Joined: 10 Oct 2015

Hi all, this is my first post on this forum.

 

I am looking for using functions written by gamax92 in the opening message, but I cannot figure out why they're not working as expected.

 

Here is my script:

UniqueID := MemoryOpenFromName("calc.exe", 0x1F0FFF)
MsgBox % mem := MemoryRead(hProcess, 0x7132F438, "int")
return

MemoryOpenFromPID(PID, Privilege=0x1F0FFF)
{
	HWND := DllCall("OpenProcess", "Uint", Privilege, "int", 0, "int", PID)
	return HWND
}

MemoryOpenFromName(Name, Privilege=0x1F0FFF)
{
	Process, Exist, %Name%
	PID := ErrorLevel
	Return MemoryOpenFromPID(PID, Privilege)
}

MemoryRead(hwnd, address, datatype="int", length=4, offset=0)
{
	VarSetCapacity(readvalue,length, 0)
	DllCall("ReadProcessMemory","Uint",hwnd,"Uint",address+offset,"Str",readvalue,"Uint",length,"Uint *",0)
	finalvalue := NumGet(readvalue,0,datatype)
	return finalvalue
}

As you can see, it is just made by three gamax92's functions and my purpose is to retrieve the value in a memory address from Windows' calculator.

 

I know the address of that variable by using Cheat Engine 6.4: it seems to be a static address containing 15:

 

x3v7tt.png

 

Therefore I would expect my script to return a message box with 15, not 0.

 

Anyone can help me to understand where I am wrong?

 



RHCP
  • Members
  • 1228 posts
  • Last active: Apr 08 2017 06:17 PM
  • Joined: 29 May 2006

You are assigning the return value of MemoryOpenFromName() to the variable 'UniqueID', but then passing the variable 'hProcess' to MemoryRead(). You need to pass 'UniqueID' to memoryRead().

 

Some of the functions in the original post are quite outdated.  The memory read/write pointer functions will significantly impact the performance of the script, even if they are never executed!

 

It returns 0 because the function has no error checking. The variable which stores the result is initialised to the value 0, but the ReadProcessMemory() call fails and so the unaltered result value is returned.

 

I would write the function something like this, but the original will work fine too - at least for 32 bit apps.

hProcess := MemoryOpenFromName("calc.exe", 0x1F0FFF)
mem := MemoryRead(hProcess, 0x774CACB0)
msgbox % "hProcess: " hProcess "`nValue: " mem
return

MemoryOpenFromPID(PID, Privilege=0x1F0FFF)
{
  return DllCall("OpenProcess", "UInt", Privilege, "int", 0, "UInt", PID, "Ptr")
}

MemoryOpenFromName(Name, Privilege=0x1F0FFF)
{
  Process, Exist, %Name%
  PID := ErrorLevel
  Return MemoryOpenFromPID(PID, Privilege)
}

MemoryRead(hProcess, address, dataType := "UInt")
{
  static aTypeSize := {    "UChar":    1,  "Char":     1
                      ,   "UShort":   2,  "Short":    2
                      ,   "UInt":     4,  "Int":      4
                      ,   "UFloat":   4,  "Float":    4 ; No such thing as a UFloat, but AHK treats it as a float so it 'works'
                      ,   "Int64":    8,  "Double":   8}
  if !aTypeSize.HasKey(dataType)
    throw, "MemoryRead()`n" dataType "`nIs an invalid data type!"
  if DllCall("ReadProcessMemory", "Ptr", hProcess, "Ptr", address, dataType "*", result, "Ptr", aTypeSize[dataType], "Ptr", 0)
    return result
  return ; return null/blank on error
}


Cren
  • Members
  • 7 posts
  • Last active: Nov 04 2015 02:09 PM
  • Joined: 10 Oct 2015

 

You are assigning the return value of MemoryOpenFromName() to the variable 'UniqueID', but then passing the variable 'hProcess' to MemoryRead(). You need to pass 'UniqueID' to memoryRead().

 

What a shame, definitely my bad :/

 

Now that works, nevertheless I am having new issues: as I have succeeded in retrieving the right value from the address in calc.exe, I've tried something more difficult, that is, doing the same with a more complex program.

 

I've chosen a game, StarCraft II, because it's what I currently have on this hard disk, and tried to perform the same trick: even though PID is properly retrieved, this...

DllCall("OpenProcess", "Uint", Privilege, "int", 0, "int", PID)

...returns 0... how is that possibile?

 

On the contrary...

WinExist("StarCraft II")

...seems to return the proper value (0x80C24 in my case), but when I call...

MsgBox % mem := MemoryRead(0x80C24, 0x3C8EA34)

...the message box is just empty (of course 0x3C8EA34 is a static value discovered by Cheat Engine 6.4).

 

What am I missing here?



RHCP
  • Members
  • 1228 posts
  • Last active: Apr 08 2017 06:17 PM
  • Joined: 29 May 2006

If the game is running as admin, then the script will require elevated/admin permissions, too.

 

 

 After running this line, check the value of A_LastError for clues on why the OpenProcess() failed.

DllCall("OpenProcess", "Uint", Privilege, "int", 0, "int", PID)

Post the entire script too. As a result of the latest SC patch (3.0), you may be running the 64-bit HotS client, in which case the process name is "SC2_x64.exe" rather than "SC2.exe".



Cren
  • Members
  • 7 posts
  • Last active: Nov 04 2015 02:09 PM
  • Joined: 10 Oct 2015

If the game is running as admin, then the script will require elevated/admin permissions, too.

 

 

 After running this line, check the value of A_LastError for clues on why the OpenProcess() failed.

DllCall("OpenProcess", "Uint", Privilege, "int", 0, "int", PID)

Post the entire script too. As a result of the latest SC patch (3.0), you may be running the 64-bit HotS client, in which case the process name is "SC2_x64.exe" rather than "SC2.exe".

 

This is the entire script:

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

UniqueID := MemoryOpenFromName("SC2.exe")
MsgBox % mem := MemoryRead(UniqueID, 0x3C8EA34)
MsgBox % WinExist("StarCraft II")
return

MemoryOpenFromPID(PID, Privilege=0x1F0FFF)
{
	HWND := DllCall("OpenProcess", "Uint", Privilege, "int", 0, "int", PID)
	MsgBox % A_LastError
	return HWND
}

MemoryOpenFromName(Name, Privilege=0x1F0FFF)
{
	Process, Exist, %Name%
	PID := ErrorLevel
	Return MemoryOpenFromPID(PID, Privilege)
}

MemoryRead(hProcess, address, dataType := "UInt")
{
	static aTypeSize := {   "UChar":    1,  "Char":     1
						,   "UShort":   2,  "Short":    2
						,   "UInt":     4,  "Int":      4
						,   "UFloat":   4,  "Float":    4 ; No such thing as a UFloat, but AHK treats it as a float so it 'works'
						,   "Int64":    8,  "Double":   8}
	if !aTypeSize.HasKey(dataType)
		throw, "MemoryRead()`n" dataType "`nIs an invalid data type!"
	if DllCall("ReadProcessMemory", "Ptr", hProcess, "Ptr", address, dataType "*", result, "Ptr", aTypeSize[dataType], "Ptr", 0)
		return result
	return ; return null/blank on error
}

As for the process name, I am using an older version of the game (2.0.9.26147), hence both task manager and Cheat Engine 6.4 shows SC2.exe *32.

 

A_LastError is equal to 5; from Microsoft System Error Codes (0-499) this seems to be

ERROR_ACCESS_DENIED Access is denied. 5 (0x5)        

RHCP
  • Members
  • 1228 posts
  • Last active: Apr 08 2017 06:17 PM
  • Joined: 29 May 2006

Did you try running the script as admin?