Jump to content

Improved _Mem() UDF's


Nomad
 Share

Recommended Posts

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?

In AutoIt, you can call a function just like this:
Health()oÝ÷ ٩ݶ­ßÛ"´pYaj÷­ëç}ç-jÇV®¶­sbb33c·f&&ÆRÒVÇF
sets the named variable equal to the value returned by the function. Edited by Nomad
Link to comment
Share on other sites

  • Replies 90
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Well, I got to this sooner than I'd expected. Please read through the whole message before you reply to anything. I did some more testing after I initially started this reply and put those results under the _______ below, rather than trying to completely rewrite this and lose my train of thought.

I put all three error checks in place. Right away it told me that the process ID is wrong. In TSearch it reports it as KnightOnline.exe and in task manager it's KnightOnLine.exe (capital "L"). I didn't know if that would make a difference, so I tried it both ways, but still got the ID error.

Then I noticed that one of the views you can use in TSearch lists the PID, which is 1074 for Knight Online. So, instead of $pid = WinGetProcess ("KnightOnLine.exe"), I changed it to $pid = 1074. Is 1074 going to always be the PID for this game, or is that just an arbitrary number that may change from time to time? I haven't found a way to identify what the text PID really is if it's neither of the ones listed by TSearch and task manager.

That got me past the first error check, but then the error for MemoryOpen was 1, which is Invalid $iv_Pid. And the error for MemoryRead was 1, Invalid $ah_Handle. If the PID of 1074 is correct (as it seems to be), shouldn't that also be good for the Open and Read functions?

Looking at your functions, I wasn't sure if using the 1074 would have any adverse affects instead of using the "KnightOnline.exe".

Before this discussion goes on too long, there is one thing I need to point out, in case it would have any bearing on my problem.

In order to bypass HackShield to be able to use things like ACTool or AutoIt, I need to run another program (which has some features I use as well) before starting Knight Online. Would that in any way affect the memory reading? I wouldn't think so, since you are looking at certain areas of memory, and both programs wouldn't be using the same addresses (would they?).

______________________________

OK, after looking more closely at the PID's in TSearch, I noticed that they're in hex, not decimal like I had thought when I first saw the 1074. So I tried "1074" (with quotes) for some reason, and then 0x1074.

But the strange thing is that using "1074", 0x1074, or 1074 all make the PID check think that the process is active, even when I've closed Knight Online and checked to see that that PID isn't listed in TSearch's list of active processes. If I switch back to $pid=WinGetProcess("KnightOnline.exe"), the check fails like it should.

*** Edit ***

I did try running the script (with the "KnightOnline.exe" back in place) without using the bypass program I mentioned above and still get the same fail result on the PID check.

Edited by Styler001
Link to comment
Share on other sites

Then I noticed that one of the views you can use in TSearch lists the PID, which is 1074 for Knight Online. So, instead of $pid = WinGetProcess ("KnightOnLine.exe"), I changed it to $pid = 1074. Is 1074 going to always be the PID for this game, or is that just an arbitrary number that may change from time to time? I haven't found a way to identify what the text PID really is if it's neither of the ones listed by TSearch and task manager.

That got me past the first error check, but then the error for MemoryOpen was 1, which is Invalid $iv_Pid. And the error for MemoryRead was 1, Invalid $ah_Handle. If the PID of 1074 is correct (as it seems to be), shouldn't that also be good for the Open and Read functions?

The only reason that got you by the first error check was because $pid wasn't equal to -1 because you set it to 1074. :wacko: I could be wrong, but 1074 seems a little small to be a process ID. My process ID's are usually at least 6-8 digits in length. Don't trust another program to get your process ID, you need to make absolutely sure you have the correct process ID or you're not going anywhere.

Also, WinGetProcess() requires the title of the window, not the name of the process. Use WinGetTitle("") with the game window active to get the full and exact title if you are not 100% sure you can type it in correctly (case-sensitive too, I believe). Or you can also use $pid = ProcessExists("KnightOnLine.exe") if that name is correct. That is where you use the process name.

You need to make absolutely sure you have the correct process ID. Once you have it, _MemoryOpen will no longer give you an @Error = 1, and from that point, the script I modified for you should work flawlessly.

In order to bypass HackShield to be able to use things like ACTool or AutoIt, I need to run another program (which has some features I use as well) before starting Knight Online. Would that in any way affect the memory reading? I wouldn't think so, since you are looking at certain areas of memory, and both programs wouldn't be using the same addresses (would they?).

That would probably have no effect. I've used Ollydbg, Cheat Engine, and my _Memory functions all at the same time reading at the same addresses before. But even if it did, it wouldn't make _MemoryOpen give @Error =1. The first thing _MemoryOpen does is check to see if the process ID currently exists. That is also the only part of the function that will give that @Error number and it also has absolutely nothing to do with reading memory, it is a commonly used AutoIt function.

Also, just on a side note, 0x1074 in Decimal is 4212. :D But as I said, don't trust another program to get your process ID. Let your script do it, and yes, the process ID will change each time the program is run. You really need to figure this out because there are a lot of AutoIt functions which have nothing to do with my functions that require a valid process ID. Get back to me to let me know how it goes. If you get a valid process ID, and get past the @Error = 1 for _MemoryOpen and are still having problems, then we can move on. But until then, it means that you don't have a valid process ID.

Nomad :D

Edited by Nomad
Link to comment
Share on other sites

thanks alot i havent got a chance to mess around with it but i no it will help me. i ve been searching to do this with autoit. I have expirence with Ollydbg and Tsearch... and if you wanted to learn Olly you should check these tuts (dont no if u need to login and 10% isnt ollydbg tutorials)

or for Tsearch I made a vid tut my self. here.

Just trying to help :D

Thanks Nomad

Edited by lopolop
Link to comment
Share on other sites

thanks alot i havent got a chance to mess around with it but i no it will help me. i ve been searching to do this with autoit. I have expirence with Ollydbg and Tsearch... and if you wanted to learn Olly you should check these tuts (dont no if u need to login and 10% isnt ollydbg tutorials)

or for Tsearch I made a vid tut my self. here.

Just trying to help :wacko:

Thanks Nomad

Anytime. :D If you have any questions feel free to ask.

I tried the link you provided. I was going to add it to the first post if there were some good tutorials there that might help out some of the others, but I think you have to register to view the board. I got this error:

"Sorry, the link that brought you to this page seems to be out of date or broken."

Then there was a login prompt. So I'm guessing that's the reason. Maybe I'll register and try to take a look.

Nomad :D

Edit: Ok, registered and had a look. That's a very good link :) I'm going to add it and suggest that people interested in Olly tutorials should register and have a look at them. There's definately a lot of info to absorb there. Thanks lopolop :D

Edited by Nomad
Link to comment
Share on other sites

Also, WinGetProcess() requires the title of the window, not the name of the process. Use WinGetTitle("") with the game window active to get the full and exact title if you are not 100% sure you can type it in correctly (case-sensitive too, I believe). Or you can also use $pid = ProcessExists("KnightOnLine.exe") if that name is correct. That is where you use the process name.

Oh, I feel like such a retard! All this time I was thinking WinGetProcess needed the process name (KnightOnline.exe), not the title. And I don't know how many times I've looked in the help file about the different PID options and totally missed that "title" aspect. The actual title as displayed by Windows is Knight OnLine Client. I'd even contemplated using the title, but for some reason I thought that probably wouldn't work.

And now that you've pointed me in that direction, the game's servers are down for maintenance. Doh!

I'll try that change when they come back up.

Link to comment
Share on other sites

Oh, I feel like such a retard! All this time I was thinking WinGetProcess needed the process name (KnightOnline.exe), not the title. And I don't know how many times I've looked in the help file about the different PID options and totally missed that "title" aspect. The actual title as displayed by Windows is Knight OnLine Client. I'd even contemplated using the title, but for some reason I thought that probably wouldn't work.

And now that you've pointed me in that direction, the game's servers are down for maintenance. Doh!

I'll try that change when they come back up.

LOL, figures...

Don't feel bad, it didn't dawn on me at first that you were using the process name in place of the window title either. As long as you learn from your mistakes, it's time well spent. :wacko:

Hopefully everything will go smooth for you once the servers are back up, and it probably will and that's why they are down (things like that happen to me).

Good luck,

Nomad :D

Link to comment
Share on other sites

OH MY GOD!!!!!

It's amazing what you get when you put the right info into these functions.

$MaxHealth = 1211

$CurrentHealth = 1097

CurrentHealth wasn't 1109 because I'd taken some extra damage. And just to make sure it was getting the MaxHealth correct, I removed some armor and got:

$MaxHealth = 1109

$CurrentHealth = 1097

Just the results I was expecting to see. :D

Nomad, I want to really thank you for all the time you put into helping me with this. Now be warned, since the addresses can change, I need to figure out your pointer functions. Hopefully, now that I seem to understand a little better what's going on, I won't need to pester you so much with those. :">

Link to comment
Share on other sites

OH MY GOD!!!!!

It's amazing what you get when you put the right info into these functions.

CurrentHealth wasn't 1109 because I'd taken some extra damage. And just to make sure it was getting the MaxHealth correct, I removed some armor and got:

Just the results I was expecting to see. :(

Nomad, I want to really thank you for all the time you put into helping me with this. Now be warned, since the addresses can change, I need to figure out your pointer functions. Hopefully, now that I seem to understand a little better what's going on, I won't need to pester you so much with those. ': '>

I'm glad it all worked out for you, the time spent doesn't bother me. Besides, others who are having the same problem can look over this and find their answer, I hope. ;)

I figured those were just dynamic addresses. Most games use Dynamic Memory Allocation, which means you'll need to use the pointer functions I wrote. If you're capable of finding all of the pointers, then you will also find the offsets. Using the functions is easy, I doubt you will need help once you reach that point. But if you do, just ask.

Unfortunately, there is no one single method for locating pointers. All games use pointers in different ways, and to different levels. Some only go 1 level deep (Static Address >> Pointer >> Data), and some go as deep as 7 or more (Static Address >> Pointer >> Pointer >> Pointer >> Pointer >> Pointer >> Pointer >> Pointer >> Data). :wacko: But if you read over the information for the functions carefully, using them will be easy no matter how many pointers you have (finding those pointers is a different story).

Cheat Engine or T-Search "might" be able to find them for you. I tried to use them to find pointers for Diablo II (which is 3 levels deep), and had no luck. I had to use Ollydbg. The probable pointers specified were not the pointers in my case. I tried the pointer scanner thing, but it didn't work either, and usually ended up jamming after a little while and I'd have to ctrl-alt-del and shut-down Cheat Engine.

I still use Cheat Engine sometimes, mainly just for quick memory things like double checking values returned by my functions. But I may make a script something like erifash did to do this for me, unless someone else makes one first (which doesn't bother me any). :) It's been a pleasure. :D

Have fun and cya around,

Nomad :D

Who's next? :D

Link to comment
Share on other sites

After the recent issue someone had with getting their process ID, I decided to write a function to aid in retrieving the process ID for anyone having trouble with that. The function creates a small GUI with a combo box that will show all processes currently active on the computer. Then just select the process. A MsgBox will pop up and ask you if that is the correct process. If "yes" is clicked, the function closes everything it opened and returns the process ID of the process selected. If "no" is clicked, the MsgBox closes and the GUI will wait for another process to be selected. The GUI will stay open until "yes" is clicked in the MsgBox, or the "Cancel" button on the GUI is pressed.

This function is only intended for aiding those who are having trouble. If someone wishes to modify it for use in their finished script, be my guest.

See the first post if you are in need of this function.

Nomad :D

Link to comment
Share on other sites

I take it that "someone" you referred to in your last post was me. :">

Anyway, I'm back again. This time asking for help with the _MemoryPointerRead function.

I tried your example you included in the zip file, replacing the addresses and pointers with those appropriate for my needs. As you said, that was relatively easy. In a roundabout way, using your example for the pointer read function I have determined that it is in fact getting all of the right results for me.

One problem I had initially was that running your example as is (but, of course, with my info), it returned an error on the MsgBox line, pointing to $Value[0] and saying, "Subscript used with non-Array variable." So, I don't know if I did the right thing, but I made the following changes to the example script:

$ProcessID = WinGetProcess("Knight OnLine Client")

$Address = 0x00816804

Dim $Offset[2]
$Offset[0] = 1180
$Offset[1] = 1184

Dim $Value[2], $CurrentHealthAddress, $CurrentHealthValue

$Handle = _MemoryOpen($ProcessID)

$Value[0] = _MemoryPointerRead($Address, $Handle, $Offset)    ; returns 1097 (current health)
;$Value[1] = _MemoryPointerRead($Address, $Handle, $Offset)

_MemoryClose($Handle)

MsgBox(4096, "Returned", "Address = " & $Value[0] & @CRLF & "Value =" & $Value[1])

I'm sure it's probably a mess and at this point, after trying so many things before coming here for help, I'm really not sure how I came up with what I did in that code. As it is running, the MsgBox returns a value of 1097 (which is actually the current health value) at offset 1184 instead of the address (which, at one point in my playing around it did return correctly). I just commented out that $Value[1] line since it's just returning the same thing.

I've got no problem with it returning the value instead of the address. I just can't figure out how to get it to also return the value of 1109 (my max health) at offset 1180. Since I've seen that the addresses are correct, I don't know (other than for verification at this time) if I need to see them in the results anymore.

Sorry if that code looks very "off". This combining arrays with your new functions really gets me stumped and stupid at times. I see I never did use those variables $CurrentHealthAddress and $CurrentHealthValue after I'd declared them.

Sorry for the headaches I'm probably causing you, especially on the weekend. :D

Link to comment
Share on other sites

Looking at the sample script you posted, it appears that you might be trying to read both values you want with the same set of offsets. Your current health and your max health will be two different addresses, so that means you'll have to call _MemoryPointerRead 2 times (which you did). But that also means you will need 2 different arrays of offsets (which you didn't do).

Also, if you check the header for the _MemoryPointerRead function, you will see that $Array[0] is not used, so your offset of 1180 is not even going to be read (but if it had been you wouldn't have gotten any correct values since you would have ended up at an address you didn't want). So the only offset that was read was 1184, which lead to your current health.

One other thing, if you check the function header again, you will see that the function returns 2 values in an array, the destination address ($Array[0]), and the value there ($Array[1])

Try this, and study the syntax:

$ProcessID = WinGetProcess("Knight OnLine Client")

$Address = 0x00816804

Dim $CurrentHealthOffset[2]
$CurrentHealthOffset[0] = 'NULL' ;not used, doesn't matter, won't read anything here
$CurrentHealthOffset[1] = 1184

Dim $MaxHealthOffset[2]
$MaxHealthOffset[1] = 1180

Dim $CurrentHealth[2], $MaxHealth[2]

$Handle = _MemoryOpen($ProcessID)

$CurrentHealth = _MemoryPointerRead($Address, $Handle, $CurrentHealthOffset)
$MaxHealth = _MemoryPointerRead($Address, $Handle, $MaxHealthOffset)

_MemoryClose($Handle)

MsgBox(4096, "CurrentHealth", "Address = " & $CurrentHealth[0] & @CRLF & "Value = " & $CurrentHealth[1])
MsgBox(4096, "MaxHealth", "Address = " & $MaxHealth[0] & @CRLF & "Value = " & $MaxHealth[1])

Weekend or not, it doesn't matter to me. If I'm online then I'm not busy, if I'm not online, then I can't see your post anyway. I'll probably be gone all night and most of tomorrow, I usually am on the weekend... got some pilsner calling my name. :wacko:

Nomad :D

Edited by Nomad
Link to comment
Share on other sites

Thanks, Nomad.

I had noticed in your function that the $Offset[0] is not used, but then I saw in your example that you had assigned a value to it, so that threw me a little.

And for whatever reason, I was thinking that I would just be able to do a "simple" plug-n-play by putting both offsets in the script. I guess I'm letting this whole memory address thing get me all flustered into thinking, for some reason, that I've got to learn alot of new stuff to work with them. When, in actuality (as I've seen again and again here), all the old rules still apply to everything else you are trying to do. Oh, well. That's pretty much how I felt when I came into the AutoIt world. But, slowly but surely, I'm getting a hang of things.

The funny thing is (to me, anyway), is that I knew I had to incorporate that other offset into the mix, but I just couldn't figure out how to do it on the misguided path I was travelling down.

Arrrrgh! KO servers are down again!

(If I was able to, I'd buy you a couple [or more] pilsners for all your help. Cheers!)

Edited by Styler001
Link to comment
Share on other sites

Well, I tried it, and it gets through most of the script until it gives another of those "Subscript used with non-Array variable" errors when it gets to the message boxes.

I see that you've declared $CurrentHealth and $MaxHealth as arrays, so I don't know why it's saying that. So I also don't know what it takes to fix it. Damn, I feel so helpless when it comes to these things that seem to make sense, but AutoIt has something else in mind. :D:wacko:

Link to comment
Share on other sites

Well, I tried it, and it gets through most of the script until it gives another of those "Subscript used with non-Array variable" errors when it gets to the message boxes.

I see that you've declared $CurrentHealth and $MaxHealth as arrays, so I don't know why it's saying that. So I also don't know what it takes to fix it. Damn, I feel so helpless when it comes to these things that seem to make sense, but AutoIt has something else in mind. :D:wacko:

Narrow down the variable that is causing the error, then check the error codes from the functions and see if they are giving an error. You could also try doing one _MemoryPointerRead function at a time. Do one, then the other and see what happens. I can't run your script since I don't have the game, so I need more information about what's going on with it.

Edit: I did a test run with the exact script I posted but I changed the window name, since I don't have the game, and it worked fine for me. If you made any changes to what I posted, then it would be helpful to know what was changed. Otherwise it should be working fine unless you aren't getting your correct process ID again.

Edit: Ok, I'm off. Probably won't be back for at least 24 hours. Later. :D

Edited by Nomad
Link to comment
Share on other sites

*** Edit ***

I got the thing working finally. But I'll leave the rest of this post intact in case there was something I did wrong that should be addressed. I'll post what I did in the next message.

*** End Edit ***

OK, here's the script. I didn't edit anything from the one you'd posted. But I did put in the error checks (I think I did it right), and they don't produce any errors. I'm attaching a screenshot of the error I get, and the script. Again, your functions are included in the script at this time, so that's why you don't see an "include" of them right now. The line 37 the error screenshot gives is the first MsgBox line. I did also try commenting out all of the portions related to MaxHealth, but I still came up with the same error.

#include <Array.au3>

$ProcessID = WinGetProcess("Knight OnLine Client")

If $ProcessID = -1 Then
 MsgBox(4096, "ERROR", "The process doesn't exist")
EndIf

$Address = 0x00816804

Dim $CurrentHealthOffset[2]
$CurrentHealthOffset[0] = 'NULL' ;not used, doesn't matter, won't read anything here
$CurrentHealthOffset[1] = 1184

Dim $MaxHealthOffset[2]
$MaxHealthOffset[1] = 1180

Dim $CurrentHealth[2], $MaxHealth[2]

$Handle = _MemoryOpen($ProcessID)
If @Error Then
    MsgBox(4096, "_MemoryOpen", "_MemoryOpen @Error = " & @Error)
EndIf

$CurrentHealth = _MemoryPointerRead($Address, $Handle, $CurrentHealthOffset)
If @Error Then
    MsgBox(4096, "_MemoryPointerRead", "_MemoryPointerRead @Error = " & @Error)
EndIf

$MaxHealth = _MemoryPointerRead($Address, $Handle, $MaxHealthOffset)
If @Error Then
    MsgBox(4096, "_MemoryPointerRead", "_MemoryPointerRead @Error = " & @Error)
EndIf

_MemoryClose($Handle)

MsgBox(4096, "CurrentHealth", "Address = " & $CurrentHealth[0] & @CRLF & "Value = " & $CurrentHealth[1])
MsgBox(4096, "MaxHealth", "Address = " & $MaxHealth[0] & @CRLF & "Value = " & $MaxHealth[1])
Edited by Styler001
Link to comment
Share on other sites

OK. Since this was saying $CurrentHealth wasn't an array, I decided to force it to be one like I did previously when I was trying to figure out the pointer read function. I don't know if this is the way it should look, but it gives me the results I expect (even when the values in the game change). All I did was tack on a [1] on $CurrentHealth and $MaxHealth when they are defined using the _MemoryPointerRead function.

#include <Array.au3>
#include <Nomad's_Memory.inc.au3>

$ProcessID = WinGetProcess("Knight OnLine Client")

$Address = 0x00816804

Dim $CurrentHealthOffset[2]
$CurrentHealthOffset[0] = 'NULL' ;not used, doesn't matter, won't read anything here
$CurrentHealthOffset[1] = 1184

Dim $MaxHealthOffset[2]
$MaxHealthOffset[1] = 1180

Dim $CurrentHealth[2], $MaxHealth[2]

$Handle = _MemoryOpen($ProcessID)

$CurrentHealth[1] = _MemoryPointerRead($Address, $Handle, $CurrentHealthOffset)

$MaxHealth[1] = _MemoryPointerRead($Address, $Handle, $MaxHealthOffset)

_MemoryClose($Handle)

MsgBox(4096, "Health", "Current Health = " & $CurrentHealth[1] & @CRLF & @CRLF & "Max Health = " & $MaxHealth[1])

Nomad, I think I owe you a case of pilsner now. :D

Link to comment
Share on other sites

ok well i was trying to get this to work and it hasnt i use Tsearch and found the Address 5B70C4C is for health so.. shouldnt this work?

here is the link to the game...

#include <Memory.au3>

HotKeySet("`", "Health")

$DecimalWrite = 1000
$ProcessID = WinGetProcess("Alien Clones - Miniclip.com - Microsoft Internet Explorer")
Func Health()
    $ProcessInformation = _MemoryOpen($ProcessID)
    _MemoryWrite(0x5B70C4C, $ProcessInformation, $DecimalWrite, 'double')
EndFunc
Edited by lopolop
Link to comment
Share on other sites

@Styler001 Do you have the most current functions. The old _MemoryPointerRead function only returned one piece of information, the value, and was therefor not an array. The new function returns an array with $Array[0] = destination address, and $Array[1] = value.

@Lololop I'm looking into it. The syntax looks ok, but maybe since the game is in a java applet the ability to write to memory is restricted or something. Also, are you 100% sure you have the correct address? If you had more than 1 Internet Explorer window open, it's possible you might have attached to the wrong one. I'm going to mess around with it and see what I can find out, I've never messed with memory uder these circumstances.

Edit:

I found about 13 addresses that were health related, they weren't as big of a number as the address in your example. Also, they are dynamic, 0x3C077A0 was one of the health addresses the first time (0-99) and 0x3A277A0 was one of the health addresses after a refresh of the page, and all 13 addresses were extremely close to each other. When I browse the memory region of the address you have, it shows nothing but "??". I was able to read and write the addresses using your example for the addresses I found, but not to the one you have. I was also not able to find a 'double' type value related to health, all of these were 'dword'.

Try reading the address you think it is and see what it says in a MsgBox before trying to write to the address. Then read it again after writing.

Edited by Nomad
Link to comment
Share on other sites

That sounds like that might be what the problem is. I thought I was keeping up on your updates. I must've fallen behind. I'll get them again and get rid of the ones I've got.

*** Edit ***

Yep, that was the problem. I had them saved in two different places and must've been referencing the old version. Thanks again for all your help.

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...