Jump to content

Improved _Mem() UDF's


Nomad
 Share

Recommended Posts

Thanks, Ill do just that ^^, And once again, keep up the good work ^^

Here, I was searching the net for some tutorials on stuff and decided to do a little work for you too:

Cheat Engine Pointer Help #1

Cheat Engine Pointer Help #2

There's a lot to read in those topics (especially #2 :wacko: ), and you might have to read it all to understand, but these should help you.

Nomad :D

Link to comment
Share on other sites

  • Replies 90
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

I have adapted these new memory functions in order to create a memory editor in AutoIt. Can anyone test this out with the Diablo II cheats to see if this works?

CODE
#include <GUIConstants.au3>

$gui = GUICreate("AutoIt Memory Editor", 360, 280)

Global $combo = GUICtrlCreateCombo("", 10, 10, 230, 20)

_RefreshList()

$open = GUICtrlCreateButton("Open", 250, 10, 45, 20)

$refresh = GUICtrlCreateButton("Refresh", 305, 10, 45, 20)

GUICtrlCreateGroup("Read", 5, 40, 350, 118)

GUICtrlCreateLabel("Data Type", 10, 58, 60, 15)

$rtype = GUICtrlCreateCombo("byte", 70, 55, 100, 20)

GUICtrlSetData(-1, "ubyte|char|short|ushort|int|uint|dword|udword|ptr|float|double|int64|uint64")

GUICtrlCreateLabel("Address", 10, 88, 60, 15)

$raddress = GUICtrlCreateInput("0x00000000", 70, 85, 100, 20)

$read = GUICtrlCreateButton("Read", 15, 120, 70, 20)

$rclose = GUICtrlCreateButton("Close", 95, 120, 70, 20)

$rdata = GUICtrlCreateEdit("", 180, 55, 170, 95)

GUICtrlCreateGroup("Write", 5, 158, 350, 117)

GUICtrlCreateLabel("Data Type", 10, 176, 60, 15)

$wtype = GUICtrlCreateCombo("byte", 70, 173, 100, 20)

GUICtrlSetData(-1, "ubyte|char|short|ushort|int|uint|dword|udword|ptr|float|double|int64|uint64")

GUICtrlCreateLabel("Address", 10, 206, 60, 15)

$waddress = GUICtrlCreateInput("0x00000000", 70, 203, 100, 20)

$write = GUICtrlCreateButton("Write", 15, 238, 70, 20)

$wclose = GUICtrlCreateButton("Close", 95, 238, 70, 20)

$wdata = GUICtrlCreateEdit("", 180, 173, 170, 95)

GUICtrlSetState($combo, $GUI_FOCUS)

_Disable()

GUISetState()

$proc = 0

$mem = 0

While 1

$msg = GUIGetMsg()

Switch $msg

Case $GUI_EVENT_CLOSE

Exit

Case $combo

$proc = ProcessExists(GUICtrlRead($combo))

Case $refresh

_RefreshList()

Case $open

$mem = _MemOpen($proc)

If @error or $mem = 0 or $proc = 0 Then

mError("Can't open process memory!")

Else

_Enable()

EndIf

Case $read

_SizeOf(GUICtrlRead($rtype))

If @error Then

mError("Wrong data type!")

Else

GUICtrlSetData($rdata, _MemRead($mem, GUICtrlRead($raddress), GUICtrlRead($rtype)))

EndIf

Case $rclose, $wclose

_MemClose($mem)

_Disable()

Case $write

_SizeOf(GUICtrlRead($wtype))

If @error Then

mError("Wrong data type!")

Else

_MemWrite($mem, GUICtrlRead($waddress), GUICtrlRead($wdata), GUICtrlRead($wtype))

EndIf

EndSwitch

Sleep(0)

WEnd

Func mError($sText, $iFatal = 0, $sTitle = "Error", $iOpt = 0)

Local $ret = MsgBox(48 + 4096 + 262144 + $iOpt, $sTitle, $sText)

If $iFatal Then Exit

Return $ret

EndFunc

Func _RefreshList()

Local $ps = ProcessList(), $list = ""

For $i = 1 to $ps[0][0]

$list &= "|" & $ps[$i][0]

Next

GUICtrlSetData($combo, $list)

GUISetState()

EndFunc

Func _Disable()

GUICtrlSetState($rtype, $GUI_DISABLE)

GUICtrlSetState($raddress, $GUI_DISABLE)

GUICtrlSetState($read, $GUI_DISABLE)

GUICtrlSetState($rclose, $GUI_DISABLE)

GUICtrlSetState($rdata, $GUI_DISABLE)

GUICtrlSetState($wtype, $GUI_DISABLE)

GUICtrlSetState($waddress, $GUI_DISABLE)

GUICtrlSetState($write, $GUI_DISABLE)

GUICtrlSetState($wclose, $GUI_DISABLE)

GUICtrlSetState($wdata, $GUI_DISABLE)

GUISetState()

EndFunc

Func _Enable()

GUICtrlSetState($rtype, $GUI_ENABLE)

GUICtrlSetState($raddress, $GUI_ENABLE)

GUICtrlSetState($read, $GUI_ENABLE)

GUICtrlSetState($rclose, $GUI_ENABLE)

GUICtrlSetState($rdata, $GUI_ENABLE)

GUICtrlSetState($wtype, $GUI_ENABLE)

GUICtrlSetState($waddress, $GUI_ENABLE)

GUICtrlSetState($write, $GUI_ENABLE)

GUICtrlSetState($wclose, $GUI_ENABLE)

GUICtrlSetState($wdata, $GUI_ENABLE)

GUISetState()

EndFunc

Func _MemOpen( $i_Pid, $i_Access = 0x1F0FFF, $i_Inherit = 0 )

Local $av_Return[2] = [DllOpen('kernel32.dll')]

Local $ai_Handle = DllCall($av_Return[0], 'int', 'OpenProcess', 'int', $i_Access, 'int', $i_Inherit, 'int', $i_Pid)

If @error Then

DllClose($av_Return[0])

SetError(1)

Return 0

EndIf

$av_Return[1] = $ai_Handle[0]

Return $av_Return

EndFunc

Func _MemRead( $ah_Mem, $i_Address, $s_Type = 'dword' )

If not IsArray($ah_Mem) Then

SetError(1)

Return ''

EndIf

Local $v_Struct = DllStructCreate($s_Type)

DllCall($ah_Mem[0], 'int', 'ReadProcessMemory', 'int', $ah_Mem[1], 'int', $i_Address, 'ptr', DllStructGetPtr($v_Struct), 'int', DllStructGetSize($v_Struct), 'int', '')

If @error Then

SetError(1)

Return ''

EndIf

Return DllStructGetData($v_Struct, 1, 1)

EndFunc

Func _MemWrite( $ah_Mem, $i_Address, $v_Data, $s_Type = 'dword' )

If not IsArray($ah_Mem) Then

SetError(1)

Return 0

EndIf

Local $v_Struct = DllStructCreate($s_Type)

DllStructSetData($v_Struct, 1, $v_Data, 1)

DllCall($ah_Mem[0], 'int', 'WriteProcessMemory', 'int', $ah_Mem[1], 'int', $i_Address, 'ptr', DllStructGetPtr($v_Struct), 'int', DllStructGetSize($v_Struct), 'int', '')

If not @error Then

Return 1

Else

SetError(1)

Return 0

EndIf

EndFunc

Func _MemClose( $ah_Mem )

If not IsArray($ah_Mem) Then

SetError(1)

Return 0

EndIf

DllCall($ah_Mem[0], 'int', 'CloseHandle', 'int', $ah_Mem[1])

If not @error Then

DllClose($ah_Mem[0])

Return 1

Else

DllClose($ah_Mem[0])

SetError(1)

Return 0

EndIf

EndFunc

Func _SizeOf( $s_Type )

Local $v_Struct = DllStructCreate($s_Type), $i_Size = DllStructGetSize($v_Struct)

$v_Struct = 0

Return $i_Size

EndFunc

Very kewl. Works, I tryed it on spider solitaire xD

Now you gotta step it up a notch, and make a search function for it xD, Liek cheatengine. ( first scan you search 4byte and search the value 500, you move the card, your score is 499, you go and search 4byte 499, and it narrows down the addresses, then you can choose the one you want) That would be reall kewl ^^

# MY LOVE FOR YOU... IS LIKE A TRUCK- #
Link to comment
Share on other sites

Thanks ill read them ^^, Or try anyway.

(( Are you saying we are you error-guineapigs ?! xD ))

Of course, nothing better than a wide variety of users on a wide variety of platforms with a wide variety of uses for these functions to test out their functionality in all circumstances. :D:D:D

Nomad :wacko:

Link to comment
Share on other sites

Okay, isn't the codebox working?

No, a copy and paste made the entire script 1 line for me, and I didn't want to spend an hour separating it all. :wacko:

Good work on this. I have a few suggestions though.

1) You should implement some kind of pointer support. For a lot of games you need to read a series of pointers to get to the desired address. I had to read an address, then add the offset to the value at that address, then convert it to hex and read it again, and again... :D

2) When I tried my Diablo II character name, I could only read 1 'char' and it was in decimal, not ASCII. I got 78 instead of 'N'. I tried putting [16] at the end of 'char' in the combo box, but it didn't work.

3) I assume you are using Windows 2000+. I can tell because the combo box drop down size is automatically adjusted for those OS. I'm on Windows 98 though, and it doesn't auto-size. So, with a setting of 20, the combo box will not drop down at all. I had to change it to 100. I prefer to use Windows 98 for AutoIt because if it works on Windows 98, it'll work on any Windows OS (usually).

Once again, nice job on this. I've considered doing something like this, but I'm not sure if I will. Oh, and I didn't mess with the writing aspect of your script, but if I have time later I will.

Nomad :D

Edited by Nomad
Link to comment
Share on other sites

Ok, I just spent the last 4 hours testing out _MemoryPointerRead and _MemoryPointerWrite. After a few small adjustments, I'm confident that they are completely debugged. I have updated the first post with the latest functions. If you have any problems, or are unsure how to use them, post a reply here.

Nomad :D

Link to comment
Share on other sites

In the Diablo II examples you named the funcitons incorrectly. Example:

Local $DllInformation = _MemOpen($ProcessID)oÝ÷ Ù(hºW[y«­¢+Ù1½°ÀÌØí±±%¹½ÉµÑ¥½¸ô}5µ½Éå=Á¸ ÀÌØíAɽÍÍ%

It's a small thing but it could generate a lot of useless questions.

A little reading goes a long way. Post count means nothing.

Link to comment
Share on other sites

In the Diablo II examples you named the funcitons incorrectly. Example:

Local $DllInformation = _MemOpen($ProcessID)oÝ÷ Ù(hºW[y«­¢+Ù1½°ÀÌØí±±%¹½ÉµÑ¥½¸ô}5µ½Éå=Á¸ ÀÌØíAɽÍÍ%

It's a small thing but it could generate a lot of useless questions.

Thanks. I renamed the functions but didn't update the D2 examples, forgot. Edited by Nomad
Link to comment
Share on other sites

Nice, Ill be back when I test out the pointer read & write =P

Hmm, If by the time im completly familiar with your memory udf, and you havnt made one, I should make a help file :D well, *try* :wacko:
# MY LOVE FOR YOU... IS LIKE A TRUCK- #
Link to comment
Share on other sites

Hmm, If by the time im completly familiar with your memory udf, and you havnt made one, I should make a help file :wacko: well, *try* :D

I already have, so I can submit these for inclusion in the beta. I'm just wanting to make sure the functions are completely debugged first. I suppose I could attach them to the first post if necessary.

Nomad :D

Link to comment
Share on other sites

I'm not sure if this is the right place to post this, or if there's a better forum to do it in, but here goes....

I'm trying to use a slightly modified version of JoshDB's example from another thread to read the values in a couple of memory addresses in Knight Online. As of this moment, I know the addresses I'll give are correct since I just checked them again and I get the expected results using TSearch.

The problem I'm having is that I'm expecting to receive values of 1211 for MaxHealth and 1109 for CurrentHealth. But, I get 0 for both. I'm extremely nooby at this part of AutoIt, so I'm pretty sure I'm doing something extremely stupid. I've tried w0uter's and Nomad's functions and get the same results with both, and the last time I tried, I was using Nomad's latest versions.

Anyway, here is JoshDB's original code:

Func Health()
    $h_open = _MemOpen($pid)
    $currentHealth = Int(_MemRead($h_open,IniRead("SLB.ini","memory","currentHealth",0),4))
    $maxHealth = Int(_MemRead($h_open,IniRead("SLB.ini","memory","maxHealth",0),4))
    $Healthpercent = $currentHealth/$maxHealth*100
    _MemClose($h_open)
    
    Return $Healthpercent
EndFuncoÝ÷ Ù(§qæ­¶¬¦§´ýz-­æx®H~)^#ozjøv¬r^¶ayú%"§v·¦¢÷¶´ß¡Þj[a=êÜz{lw#f¢yr¶¼¢h±ç¢|§-¹©eÉø§vØ^½©nzÂ7öih¢H§ú+"¯zÚâyÛاØ^½©nzÊÞqè¯yÛh6^¥§ZÛajÝý²0"IèÀý­¶)àÒ)ìµæ¡ýv×V§w]tô   Ý"¯zfzË«zØZ¶+b²z-­ën®x§FÞq«¬zæyתâazf¬Ðý½ç^rV«yÛazf趭½©nzÊ-êí©ôjwl¶)e­ç÷´ßÛ¢»az·¬º[l#f²êÞÊ·öYZÊ'¢ØzØZ¶Ø^­è¬®¢Ø§r[z«¨µú+6wl~éܶ*'±8Z·lmçºÇ¢ºâg£7ö÷¢Énuçm颭Øb±Êy«­¢+ØÀÌØíÁ¥ô]¥¹ÑAɽÍÌ ÅÕ½Ðí-¹¥¡Ñ=¹±¥¹¹áÅÕ½Ðì¤(ÀÌØí5á!±Ñ ôÀ(ÀÌØí
ÕÉɹÑ!±Ñ ôÀ()
±° ÅÕ½Ðí!±Ñ ÅÕ½Ðì¤)]¥¹Ñ¥ÙÑ ÅÕ½ÐíU¹Ñ¥Ñ±´9½ÑÁÅÕ½Ðì¤)M¹ ÅÕ½ÐìÀÌØí5á!±Ñ ôÅÕ½ÐìµÀìÀÌØí5á!±Ñ µÀì
I1¤$)M¹ ÅÕ½ÐìÀÌØí
ÕÉɹÑ!±Ñ ôÅÕ½ÐìµÀìÀÌØí
ÕÉɹÑ!±Ñ µÀì
I1¤()Õ¹!±Ñ  ¤(ÀÌØí¡}½Á¸ô}5µ½Éå=Á¸ ÀÌØíÁ¥¤(ÀÌØí
ÕÉɹÑ!±Ñ ô%¹Ð¡}5µ½ÉåI ÀÌØí¡}½Á¸°ÁàÁÁÕÀ°Ð¤¤(ÀÌØí5á!±Ñ ô%¹Ð¡}5µ½ÉåI ÀÌØí¡}½Á¸°ÁàÁÁÔå°Ð¤¤(}5µ½Éå
±½Í ÀÌØí¡}½Á¸¤((%IÑÕɸÀÌØí
ÕÉɹÑ!±Ñ (%IÑÕɸÀÌØí5á!±Ñ )¹Õ¹

I've been agonizing over this for a few days and can't seem to see where my problem lies. But, like I said, it's probably a stupid error on my part. I don't know if the problem is because AutoIt has problems reading addresses from Knight Online. Others using ACTool have been able to get this to work, but ACTool is way to primitive when compared to AutoIt to even consider using anymore.

If you guys can help, I'd really appreciate it.

Link to comment
Share on other sites

I'm not sure if this is the right place to post this, or if there's a better forum to do it in, but here goes....

I'm trying to use a slightly modified version of JoshDB's example from another thread to read the values in a couple of memory addresses in Knight Online. As of this moment, I know the addresses I'll give are correct since I just checked them again and I get the expected results using TSearch.

$pid = WinGetProcess ("KnightOnline.exe")
$MaxHealth = 0
$CurrentHealth = 0

Call ("Health")
WinActivate ("Untitled - Notepad")
Send ("$MaxHealth = " & $MaxHealth & @CRLF) 
Send ("$CurrentHealth = " & $CurrentHealth & @CRLF)

Func Health()
    $h_open = _MemoryOpen($pid)
    $CurrentHealth = Int (_MemoryRead ($h_open, 0x0A0EC5A0, 4))
    $MaxHealth = Int (_MemoryRead ($h_open, 0x0A0EC59C, 4))
    _MemoryClose ($h_open)
    
    Return $CurrentHealth
    Return $MaxHealth
EndFunc

Next time don't spend days with a problem like this. If it's a problem caused by your syntax, I can help. If it's a problem caused by improper addresses, I can't help. But if it's a problem caused by me, I want to know about it.

Also, the reason you were getting 0 is because that is what any of my functions return if they have an error, which they did because you were sending the $ah_Handle returned from _MemoryOpen as the address for _MemoryRead, and sending the address as $ah_Handle. The _MemoryRead functions were throwing an error right from the get go. @Error checked at 1 which as stated in the header is: Invalid $ah_Handle. :D

Don't take this the wrong way, I'm just pointing out what you could've done to help solve this. Always check the error messages when things aren't working correctly.

Nomad :wacko:

Edit: hmm, having problems posting...

Edited by Nomad
Link to comment
Share on other sites

Updated the first post with the newest version of the include file, examples, and help files.

The help files are in the format for UDF submission, I think, which is why there is a lot of extra 'stuff' in them. I added the 2 new pointer functions to the include file and also added another return value to them. Now they both return the destination address ($Array[0] for _MemoryPointerRead) and _MemoryPointerRead returns the value stored there, $Array[1]. This was done for obvious reasons.

Also note that the $av_Offset structure has changed. $av_Offset[0] is no longer used, you may need to update any scripts using this function.

Hopefully this will be the last time I need to update. But I'm sure I'll find another reason at some point to make another update. I'm already having thoughts for another improvement... :D

Enjoy,

Nomad :wacko:

Edited by Nomad
Link to comment
Share on other sites

Sorry I didn't post this earlier, but the board was having brainfarts last night and wouldn't let me reply.

Sorry for not saying something about this sooner. It's just that the last time I asked for help here (not from you) I got reemed because the guy assumed I wasn't willing to do any of the work myself. He asked questions and I answered them, and he assumed. So I was a little leary of asking this time because I'm using your memory functions (which, while I don't understand them fully, I do understand the concept of what they are supposed to be doing), and I'm using JoshDB's[\u] snippet that I modified (incorrectly, as I had a feeling). So, neither of these are anything that I've personally put alot of time into like you and Josh have. I guess I'm just a little gunshy now.

Anyway, I tried your corrections, but still got the same results of 0. I'm attaching a screenshot of the TSearch screen showing the process at the top that it's using, as well as the memory addresses and their values. The little graphic below the TSearch screenshot is the health bar (red) with the 1109/1211 showing what I'm looking for.

After the first wrong results, I looked at your modifications and noticed that you hadn't included the Call ("Health"), so I included that, but still got the same results anyway. I also removed the "include" command since I am still just including the _MemoryOpen, _MemoryRead, and _MemoryClose functions directly in the script at this time. Other than those two changes, I haven't made any other modifications to it. But, like I said, I still got the same results with or without the Call ("Health").

I was wondering if the $pid would have anything to do with the problem? I've seen different values for that, but couldn't really tell if there would be a benefit to using ProcessExists instead of WinGetProcess, since they both just seem to return the PID.

One more question...Doesn't declaring $Health as a local variable in the Health function limit its use outside of the function? I had thought that you couldn't pass a local variable outside of its function. I guess I'm a little confused since it was declared globally at the beginning, then locally in the function.

Link to comment
Share on other sites

Don't worry about asking me for help, I don't mind as long as it pertains to something directly related to my scripts. I don't have the time, or patience, to try and help anyone find the addresses to use these functions, but that also doesn't directly apply to my functions. Your questions so far are directly related to the use of my functions and I want to be sure everyone knows how to use them properly. Getting the information needed to use them is your responsibility though. :D

After the first wrong results, I looked at your modifications and noticed that you hadn't included the Call ("Health"), so I included that, but still got the same results anyway. I also removed the "include" command since I am still just including the _MemoryOpen, _MemoryRead, and _MemoryClose functions directly in the script at this time. Other than those two changes, I haven't made any other modifications to it. But, like I said, I still got the same results with or without the Call ("Health").

That shouldn't effect any of your readings anyway. Also, I don't use the Call function to call my functions, in AutoIt you don't need it. But you can use it if you prefer.

I was wondering if the $pid would have anything to do with the problem? I've seen different values for that, but couldn't really tell if there would be a benefit to using ProcessExists instead of WinGetProcess, since they both just seem to return the PID.

Yes, if the process ID is incorrect then you are going to get a return value of 0 since the _MemoryOpen function is not finding the process. Try this to see if you are finding the process correctly, sometimes the name you see in the task manager is not the correct process name to enter:
$pid = WinGetProcess ("windowname")
If $pid = -1 Then
 MsgBox(4096, "ERROR", "The process doesn't exist")
EndIfoÝ÷ Øí«ç$²­¢Kazw!yÉ-á+®ß¢·rîËb¢{-j»b"¶ò:§bjwh¶­)¶¬jëh×6$h_open = _MemoryOpen($pid)
 If @Error Then
  MsgBox(4096, "_MemoryOpen", "_MemoryOpen @Error = " & @Error)
 EndIf
    $CurrentHealth = _MemoryRead (0xA0EC5A0, $h_open)
 If @Error Then
  MsgBox(4096, "_MemoryRead", "_MemoryRead @Error = " & @Error)
 EndIfoÝ÷ Ù8^È^rKaz{¦mêâØ^æz·è®Ø^~éܶ*'Ö©¦X²ÚÛ{Z¶Ø^zºè®Z ±¬¬Ì+¢x*º^©

So $Health = the return value of the function, which was the local value for $Health within the function. I hope that's clear, hehe.

Nomad :wacko:

Link to comment
Share on other sites

Thanks, Nomad. I'll get those checks put in place and give this another shot later this evening (Pacific time zone).

And, yes, your explanations all made sense. I'm just a little confused about not having to use Call. Is the $Health=Health() how the Health function is called?

Edited by Styler001
Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...