Jump to content

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

ReadMemory fails


  • Please log in to reply
4 replies to this topic
Wyvern010
  • Members
  • 24 posts
  • Last active: Jul 11 2016 11:17 PM
  • Joined: 30 Mar 2015

Hi, When i readmemory From BF4 everything like this 0BBCE9410 works but everything with 151B1D500 (Starting with a NON-ZERO number) Fails? i Also noticed that if Say: 0BBCE9410+0xD3 points to: 151B1D500 it only returns 51B1D500 Wich would make the next MemoryRead Fail. but WHY!?! i cant figure out. I use AHKx64 and read from BF4 x64. These are the functions i Use:

WriteMemory(WVALUE,MADDRESS,PROGRAM) 
{ 
winget, pid, PID, %PROGRAM% 
ProcessHandle := DllCall("OpenProcess", "int", 2035711, "char", 0, "UInt", PID, "UInt") 
DllCall("WriteProcessMemory", "UInt", ProcessHandle, "UInt", MADDRESS, "Uint*", WVALUE, "Uint", 4, "Uint *", 0) 

return 
}

HexToFloat(x) {
   Return (1-2*(x>>31)) * (2**((x>>23 & 255)-150)) * (0x800000 | x & 0x7FFFFF)
}

HexToDouble(x) { ; may be wrong at extreme values
   Return (2*(x>0)-1) * (2**((x>>52 & 0x7FF)-1075)) * (0x10000000000000 | x & 0xFFFFFFFFFFFFF)
}

FloatToHex(f) {
   form := A_FormatInteger
   SetFormat Integer, HEX
   v := DllCall("MulDiv", Float,f, Int,1, Int,1, UInt)
   SetFormat Integer, %form%
   Return v
}

DoubleToHex(d) {
   form := A_FormatInteger
   SetFormat Integer, HEX
   v := DllCall("ntdll.dll\RtlLargeIntegerShiftLeft",Double,d, UChar,0, Int64)
   SetFormat Integer, %form%
   Return v
}

ReadMemory(MADDRESS=0,PROGRAM="",MVALUE=" ",BYTE=4)
{
	Static OLDPROC, ProcessHandle
	if MVALUE := " " 
	VarSetCapacity(MVALUE,4,0)
	If PROGRAM != %OLDPROC%
	{
		WinGet, pid, pid, % OLDPROC := PROGRAM
		ProcessHandle := ( ProcessHandle ? 0*(closed:=DllCall("CloseHandle"
		,"UInt",ProcessHandle)) : 0 )+(pid ? DllCall("OpenProcess"
		,"Int",24,"Int",0,"UInt",pid) : 0)
	}
	If (ProcessHandle) && DllCall("ReadProcessMemory","UInt",ProcessHandle,"UInt",MADDRESS,"str",MVALUE,"UInt",BYTE,"UInt *",0)
	return *(&MVALUE+3)<<24 | *(&MVALUE+2)<<16 | *(&MVALUE+1)<<8 | *(&MVALUE)
	return !ProcessHandle ? "Handle Closed: " closed : "-1"
}

getProcessBaseAddress(WindowTitle, windowMatchMode := "3")    ;WindowTitle can be anything ahk_exe ahk_class etc
{
    if (windowMatchMode && A_TitleMatchMode != windowMatchMode)
    {
        mode := A_TitleMatchMode ; This is a string and will not contain the 0x prefix
        StringReplace, windowMatchMode, windowMatchMode, 0x ; remove hex prefix as SetTitleMatchMode will throw a run time error. This will occur if integer mode is set to hex and matchmode param is passed as an number not a string.
        SetTitleMatchMode, %windowMatchMode%    ;mode 3 is an exact match
    }
    WinGet, hWnd, ID, %WindowTitle%
    if mode
        SetTitleMatchMode, %mode%    ; In case executed in autoexec
    if !hWnd
        return ; return blank failed to find window
    return DllCall(A_PtrSize = 4     ; If DLL call fails, returned value will = 0
        ? "GetWindowLong"
        : "GetWindowLongPtr"
        , "Ptr", hWnd, "Int", -6, A_Is64bitOS ? "Int64" : "UInt")  
        ; For the returned value when the OS is 64 bit use Int64 to prevent negative overflow when AHK is 32 bit and target process is 64bit 
        ; however if the OS is 32 bit, must use UInt, otherwise the number will be huge (however it will still work as the lower 4 bytes are correct)      
        ; Note - it's the OS bitness which matters here, not the scripts/AHKs
}   

ReadMemoryStr(MADDRESS=0, PROGRAM = "", length = 0 , terminator = "")  ; "" = Null
{ 
    Static OLDPROC, ProcessHandle

    If (PROGRAM != OLDPROC || !ProcessHandle)
    {
        WinGet, pid, pid, % OLDPROC := PROGRAM
        ProcessHandle := ( ProcessHandle ? 0*(closed:=DllCall("CloseHandle"
        ,"UInt",ProcessHandle)) : 0 )+(pid ? DllCall("OpenProcess"
        ,"Int",16,"Int",0,"UInt",pid) : 0) ;PID is stored in value pid
    }
    ; length depends on the encoding too
    VarSetCapacity(Output, length ? length : 1, 0)
    If !length ; read until terminator found or something goes wrong/error
	{
        Loop
        { 
            success := DllCall("ReadProcessMemory", "UInt", ProcessHandle, "UInt", MADDRESS++, "str", Output, "Uint", 1, "Uint *", 0) 
            if (ErrorLevel || !success || Output = terminator) 
                break
            teststr .= Output 
		} 
	}		
	Else ; will read X length
	{
        DllCall("ReadProcessMemory", "UInt", ProcessHandle, "UInt", MADDRESS, "str", Output, "Uint", length, "Uint *", 0) 
        ;  Loop % length
        ;     teststr .= chr(NumGet(Output, A_Index-1, "Char"))      
        teststr := StrGet(&Output, length, "UTF-8")
	}
	return teststr  
}

;H for Hex D for Dec
Convert(Number=0, ConvertTo="") {
	TmpNum := Number
	Ok := False
	If TmpNum Is Integer
		Ok := True
	Else If TmpNum Is Xdigit
	{
		Ok := True
		TmpNum := "0x" TmpNum
	} Else If (InStr(TmpNum, "0x"))
		Ok := True
	Else
		Return -1
	If (Ok)
		If (ConvertTo = "D" ) {
			SetFormat Integer, D
			TmpNum += 0
			SetFormat Integer, H
			Return TmpNum
		} Else If (ConvertTo = "H") {
			SetFormat Integer, H
			TmpNum += 0
			SetFormat Integer, D
			Return TmpNum
		} Else
			Return -2
	Else
		Return -3
}


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

Your read/write memory functions only support UINT (32 bit) addresses (up to 0xffffffff).  You should change "Uint" to "Ptr". 

That readMemory function will only return 32 bit values - cant use it to read 8 byte pointers. Also, the writeMemory function opens, but doesnt close the process handle.



Wyvern010
  • Members
  • 24 posts
  • Last active: Jul 11 2016 11:17 PM
  • Joined: 30 Mar 2015
But i fixed the isue with BYTE = 5 and in the return add: *(&MVALUE+4)<<32 as first? How does that work then?

Cus new whel the adress contains an leading 1 it returns correctly.

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

My first statement isn't correct in practice. If memory serves me correctly, with regards to input parameters, DLLCall  takes a pointer sized chunk of the AHK value (which are 64 bit ints) and passes it to the function. Therefore, although you have defined the address as a UInt, an 8 byte ptr value is actually being passed to the function, hence allowing it to work.

*(&MVALUE+4)<<32

That is extracting the next 8 bits from the value. That along with the other code would work for an unsigned 40 bit value, but not all x64 addresses.

 

It would be faster and clearer to use the built in numget() or incorporate the conversion into the DLLCall. But if it satisfies your needs, then that's all the matters :)



Wyvern010
  • Members
  • 24 posts
  • Last active: Jul 11 2016 11:17 PM
  • Joined: 30 Mar 2015
Im really new to reading memory and how it al goes together. I checked numput and numget, but its a bit up my league for now. I will see what i can improve and "mess around" with Uint en ptr to see what happend. Thanks for the directions!