Pointer collection

03/28/2009 10:44 jogurtman#256
Can someone make a trainer from that exp pointer...
Please?????
03/28/2009 21:19 0o0#257
thanks Shareen, I've sent you a msg.
03/29/2009 03:07 xindobnix#258
Quote:
Originally Posted by asgborges View Post
its is working with what PW version/language??
PW v1.3.9 Build 2265 (PW Indo)
I have never been tried in the PW inter
:p
03/29/2009 15:40 Shareen#259
This post is a continuation of post on strings and char name as well as a response to a PM from OoO.

It contains detailed step by step explanation on how to find base pointer and offsets for Name in Perfect World (PW), with high amount of graphical content and in depth explanations.

As before, Cheat Engine (CE) was used as a memory scanning tool and for this particular example, hacked exe for PW International (the one in US). Exe was supplied to me by OoO and as far as I can tell, only unlimited zoom was changed from original version, but as I have never played on International version, other changes may have been done to exe as well.
I should also point out, that CE is used with all settings on default, so if you changed any, you might be getting different results.

Character name that was used is "Accessor", without " obviously.

Let us begin.
Start PW, start CE, hook CE to process elementclient.exe (OoO: I renamed hacked .exe to match original name).
Setup search parameters, click First Scan and you get something like this:
[Only registered and activated users can see links. Click Here To Register...]

Right, 19 results. Plenty to work with, but not too much thankfully. We're going to skip whole elimination process and start working on all of them. Not that it doesn't work, but it'll take some time and probably only eliminate 1-2 matches. So, select them all and click red arrow to copy them in window below.

Now we are going to remove false positives by right clicking on first entry and selecting "Find out what accesses this address". Little window will pop up (referred to op codes window from here) and as it does, we alt tab to PW for a moment than back to CE. If the op codes window remains empty, close it and remove the entry. Else leave entry and move on to the next one. Continue doing that untill you have removed all entries that yielded no results. Series of images below depict this process:
[Only registered and activated users can see links. Click Here To Register...]

[Only registered and activated users can see links. Click Here To Register...]
This is the little window (op codes window) in question. Note that first time you click "Find out what accesses this address" you are presented with a question to which you answer Yes. Besides the op codes window, a smaller one will also open, which you can ignore and close if you desire. We won't be needing it.
I will not go into any detail as to what this windows do and how, as that information can be obtained from CE forums as well as many other place.

Window above remains empty after alt tabbing to PW and back, so we will remove this entry after closing window.
Below is an example of how it looks like when it doesn't remain empty:
[Only registered and activated users can see links. Click Here To Register...]


Now we have eliminated all those that yielded no results and we are left with...
[Only registered and activated users can see links. Click Here To Register...]

...3 entries in my case. Luck is on our side today :)

We know now that one of these 3 is the value we are after, but we have no other means of filtering it further, so we might as well begin searching for base address. Hints posted before, tell us that we are looking for level 3 pointer, that first offset must be 0 and third one must be 0x20. But careful now! Numeric ordering is assumed from our perspective, from how we add them. First one we add is numbered first and so on. But actual ordering should be done other way around with first one being the one "closest" to base pointer. Reason we are assuming "wrong" ordering is because our first pointer is the one we encounter first. I'm not trying to confuse you here, just warn you to be careful when reading documentation from other sources.

I'll start with first entry, despite the fact I know it's wrong. I'll do this to show how you can tell it's wrong, using information above.
Right click first entry, select what accessed this address and alt tab to PW then back to CE. Op codes window gets filled with some stuff as it did before and now we are going to take a look at it a bit closer.
First click Stop, this is to stop debugger from running. You will notice button caption changed to Close. Double click on first entry in op codes window (or select it and click button "More Information").
[Only registered and activated users can see links. Click Here To Register...]

I picked first entry and used probable address in search. For that you want to set Value type to 4 bytes, Scan type to exact value and checking Hex check box. Enter probable address and click First Scan.
[Only registered and activated users can see links. Click Here To Register...]

I only got 1 match, but you may get more. Either way, following process must be done for all matches, since you do not know which one is right.
Add every match as pointer by clicking on button "Add address manually" and fill window that opens like depicted here:
[Only registered and activated users can see links. Click Here To Register...]

You can optionally change description as well, so you can track it easier later. I made my description into "name, level 1". Click OK once done and you will notice it gets added in lower window. Note P-> before address, it means it's a pointer to that address and it's what we will be working with now.

It's a level 1 pointer, now we use it to find next offset, for level 2. Right click on it and again select "Find what accesses this address" from dropdown. Since this is a pointer, you are presented with an option:
[Only registered and activated users can see links. Click Here To Register...]

Click on first button from the top captioned "Find out what accesses this pointer" and you are once again presented with op codes window. And again, as before, you will want to alt tab PW and then back to CE.
I got this:
[Only registered and activated users can see links. Click Here To Register...]

Look at the image carefully. None of them has expected offset (in the range of 0x5F0 as mentioned few times already). Thus, none of them is correct and as a result pointer we made is incorrect as well as the original entry we started from. Good, at least we are down one false positive.
Close op codes window and remove pointer that you added as well as first value entry we started from.

Now we move to the next entry, which just happens to be correct one. Same procedure as above is used, right click, Find out what accesses.
[Only registered and activated users can see links. Click Here To Register...]

Both entried have 0 offset, thus both are candidates and as luck will have it, both also have same probable address. Run a search for it and add result (results) as pointer as described above.
[Only registered and activated users can see links. Click Here To Register...]

Again, right click on pointer you just added and select Find what accesses this address. DO NOT forget to alt tab to PW and back.
[Only registered and activated users can see links. Click Here To Register...]

Well I'll be damned! Not only is the offset in the range of 0x5F0 but it actually IS 0x5F0 on this version. We must be on the right track for sure.

With a smile on your face search for probable address.
[Only registered and activated users can see links. Click Here To Register...]

Ouch, 21 results. Oh well, most often first one is correct so let's go with it.
We want to add it as another (2nd) offset to pointer entry. To do this, double click address column of pointer entry (it's the one we added remember, P->address ) and same window opens as before when we were adding it. Now click button Add pointer and you get another row to fill.
[Only registered and activated users can see links. Click Here To Register...]

Click OK and optionally modify description. I made my "level 2, name", since this is now a level 2 pointer to name. You will notice that Type column became UText[0] and Value column is empty. It appears to be CE bug, but we can fix that without serious delay by double clicking on UText[0] and setting length to what it needs to be.

Only one offset left now and at the risk of repeating my self, right click on pointer entry and select Find what accesses this address. You will quickly realize that op codes window is filling fast without even alt tabing to PW. Yes sir, we are now deep in PW memory bowels and code here runs regardless of whether PW UI is active or not. Skip the alt tabbing and just click Stop.
[Only registered and activated users can see links. Click Here To Register...]

Offsets are all 0x20, as expected. Note probable address of first entry in op codes window. It's 0x034A89A0, just a bit lower that the address for second entry in our pointer which was 0x034A89C0. This is always a good sign, base pointer should be very low in address list and if we are moving towards that direction we must be doing something right.
Run a search for probable address now and ...
[Only registered and activated users can see links. Click Here To Register...]

.. oh yeah, I'm home honey !!! We got base address.

Add this one as the one before, double click on P->address, click Add Pointer, fill and click OK once done.
[Only registered and activated users can see links. Click Here To Register...]

You can now modify description to "Name, base pointer", congratulate your self on a job well done, have a beer or a cup of tea and save CE table before your computer crashes :).

In order to test it fully, close CE and PW (even restart your computer if you really want to be sure, or use different computer), then run PW and CE, hook elementclient.exe process again and load saved CE table.
If your pointer still points to Name you can rest assured that it works.

Last image shows what you got in the end and it's what was written many of times on forums:
base address + offsets
0x009652E4 + 0x20 + 0x5F0 + 0 <- Name

That is also what you were looking for OoO, base address and offsets to Name on cracked exe.

For those that want to test it out on their own, I've done the same for original exe for PW International (US version) and it's:
0x0096B6E4 + 0x20 + 0x5F0 + 0


Turns out that base address + 0x20 points to a player struct that contains all info for logged in character. Knowing that, one can easily play with second offset and see what you get. Of course, first offset (0) is not needed for numeric values like hp, mp, etc,.. so you are down to 2 level pointer then.
Current HP on cracked exe for example:
[Only registered and activated users can see links. Click Here To Register...]

Type is no longer text of course, you'll need to change that to 4 bytes for hp for example. But the rest is practically identical.

This is by far not the only way this can be done, if you know any assembler op codes widow alone offers possibilities beyond and then some.
Try, experiment, learn and don't forget to have fun.

If you lack knowledge of CE do the tutorial provided by CE and/or visit CE forums.
It may be that I missed something on some steps or commented it badly. I will answer questions and explain in more detailed if that is the case.

I will not however answer questions from people, where it's plainly visible that they didn't even read it all. I know it's a lot but seeing that someone went trough the trouble of putting it together, you might at least read it all before posting questions.
03/29/2009 20:52 0o0#260
Shareen,

Thanks a bunch for the guide. Only step where i kept going wrong was i changed chars to see which offset stayed the same and tried working on that one instead of adding all and checking for the offset.

Guide was very helpful however, the pic are missing? or i can't see em?
And ya I did all the steps and exactly as you stated.
Great!! i see the pics now!
Thanks once again.
03/29/2009 21:10 Shareen#261
I'm glad it helped you OoO.
About the missing pictures, anyone else having this problem?
04/12/2009 00:18 Shareen#262
Quote:
Originally Posted by vuduy View Post
Resource offset is as followed (similar to NPC list offsets).

[Base address], 0x8, 0x28, 0x18, index*4, 0x4

index is from 0-768.

...
This one has been bothering me for a while.
Index may indeed be from 0-768, but it doesn't mean it really is that high at any one time. Since for all arrays you also get value of acctuall number of elements in array, would it not be prudent to use that and loop from 0-nb_of_elements instead of always looping full 768?
768 is just a maximum limit of items around you that game supports at the moment while average number of items around you is what.. 10-15, maybe a bit more.
Surely that would save some CPU cycles, especially if you consider you need to do the same for players and npcs as well.
04/12/2009 19:40 xindobnix#263
Quote:
Originally Posted by Shareen View Post
This one has been bothering me for a while.
Index may indeed be from 0-768, but it doesn't mean it really is that high at any one time. Since for all arrays you also get value of acctuall number of elements in array, would it not be prudent to use that and loop from 0-nb_of_elements instead of always looping full 768?
768 is just a maximum limit of items around you that game supports at the moment while average number of items around you is what.. 10-15, maybe a bit more.
Surely that would save some CPU cycles, especially if you consider you need to do the same for players and npcs as well.
[base] + 0x8 + 0x28 + 0x14 = Item Count
[base] + 0x8 + 0x28 + 0x24 = Item Max Count
04/14/2009 13:26 Smurfin#264
Quote:
Originally Posted by vuduy View Post
Why don't you start by dumping the list of resources at current location by using what I told you?

If you can't do that, there's no hope of doing something more.

EDIT:

I'll help you start with:
Code:
Func ListResource() 
  Local $temp[8], $i
  $temp[1] = 0x8
  $temp[2] = 0x28
  $temp[3] = 0x18
  For $i = 0 to 769
    $temp[4] = $i * 4
    $temp[5] = 0x4
    $temp[6] = 0x164 ; Name offset
    $temp[7] = 0 ; Name offset index 0
    $r = _MemoryPointerRead($baseAddress, $ProcessHandle, $temp, "wchar[25]")
    If $r[1] <> "" Then
      ConsoleWrite($i & ". " & $r[1] & @CRLF)
    EndIf
  Next
EndFunc
thanks for the info, i missed this post.
04/14/2009 16:00 vuduy#265
Quote:
Originally Posted by Shareen View Post
This one has been bothering me for a while.
Index may indeed be from 0-768, but it doesn't mean it really is that high at any one time. Since for all arrays you also get value of acctuall number of elements in array, would it not be prudent to use that and loop from 0-nb_of_elements instead of always looping full 768?
768 is just a maximum limit of items around you that game supports at the moment while average number of items around you is what.. 10-15, maybe a bit more.
Surely that would save some CPU cycles, especially if you consider you need to do the same for players and npcs as well.
Players list is sequential and has array size at a given time; whereas NPC list, resource list, loot list are randomly allocated; they are not sequential, and therefore must be traversed the whole fixed array.

To save CPU cycles, you should read in the whole list array (4*768 size structure), remove all the values that are 0, and you will have the exact size list of pointers to the individual objects.
04/14/2009 21:29 xindobnix#266
ada yg punya offset chat g?
04/15/2009 15:23 asgborges#267
Quote:
Originally Posted by vuduy View Post
Players list is sequential and has array size at a given time; whereas NPC list, resource list, loot list are randomly allocated; they are not sequential, and therefore must be traversed the whole fixed array.

To save CPU cycles, you should read in the whole list array (4*768 size structure), remove all the values that are 0, and you will have the exact size list of pointers to the individual objects.
no... you are wrong...
like xindobnix said: we have "Item Count" that count exactly number of "things" are displayed and its updated in real-time!
each list have your own offset for "Item Count".

we have 3 lists:
->Resource/Loot list
->NPC/Mob list
->Players list

last info: this numbers can be affected by 'd_viewradius' and 'd_playerradius' in console debug.
04/15/2009 15:58 Shareen#268
Quote:
Originally Posted by vuduy View Post
Players list is sequential and has array size at a given time; whereas NPC list, resource list, loot list are randomly allocated; they are not sequential, and therefore must be traversed the whole fixed array.

To save CPU cycles, you should read in the whole list array (4*768 size structure), remove all the values that are 0, and you will have the exact size list of pointers to the individual objects.


Quote:
Originally Posted by asgborges View Post
no... you are wrong...
like xindobnix said: we have "Item Count" that count exactly number of "things" are displayed and its updated in real-time!
each list have your own offset for "Item Count".

we have 3 lists:
->Resource/Loot list
->NPC/Mob list
->Players list

last info: this numbers can be affected by 'd_viewradius' and 'd_playerradius' in console debug.

I'm doing some test regarding this, since I'd really like to get to the bottom of it.

We all agree that Player list is sequential arrray. My tests confirm it.

I must disagree with vuduy about NPC list, my tests shows it is also a sequential list, vuduy if you have additional comments about this one, please share.
However, vuduy is rigth about resource list, tests show it is NOT sequential. As I've seen so far, certain offset always maps to certain resource on map, but I need to conduct some more test to confirm that 100%.

On a side note, I've noticed when you are standing around 2 or more same resources, ie Withered root, address to a name is same for both and address value is rather low. Pointer to a name in database that game has loaded?
Also, names of resources in this case are null terminated, which is rather interesting considering player and npcs names in the list have a fixed size.

asgborges, we do indeed have size of array for all, but it's only usefull when array is sequential (ie. indexes follow in sequential order, 0x4, 0x8, 0xc, 0x10,.etc...), which resource list isn't as we've discovered.

Well, there is one possible use for size of array even on nonsequential arrays:
Break loop when loop count reaches number of resources, since there is no point in going further if you've mapped out all there is already.

I understand that looping trough all will provide me with all resources, but my goals aren't bot making, but only in understanding of why things are the way they are. For that reason I'm trying to find out why resource list in nonsequential among other things.
04/15/2009 18:40 asgborges#269
Quote:
Originally Posted by Shareen View Post
NOT sequential.
let me explain some things...

the array list is a SEQUENCIAL list of offsets and its dont change ever since maybe game-updates.

the array list VALUES changes ALL the times... because your "seeing-radius" and because its ONLINE game wich all things moves all the times!!

for example, in INDEX-1 you can have value: 000012 thats represents "mob-12"...
if you walk a bit.. this value change to 000031 thats represents "mob-31"... and on so on...

the offsets for INDEX-1 still the same all the times... but yor value no!!
ITS REAL-TIME UPDATED!!!

the Item-Count represents the ALL things in your RADIUS view...
example: Item-Count = 28 (you are seeing 28 "things" in radar/radius, wich depends of kind)

DONT NEED GET ALL COMPLETE LIST... JUST FIRST 28(0-27) ITEMS (like my example)

THE ARRAY LIST STILL THE SAME... BUT YOUR VALUES CHANGES ALL THE TIMES... THATS ALL!!!
[Only registered and activated users can see links. Click Here To Register...]
04/15/2009 19:15 Shareen#270
asgborges, calm down :)

I get the same as you for Players and NPC, but not for Resources.

You have application to prove your point (assuming from the images posted), as have I.
Since both work, I can only assume we are using 2 different lists.
One is sequential, other is not.

Would also explain why vuduy said with him NPC and Resource list is not sequential, while with me NPC are (and resources are not since I'm using his list).

Next step is to compare offsets I guess, to get to the bottom of it.

Mine are:
- Players list (sequential):
base_ptr + 0x8 + 0x20 + x090 + index + player_struct <-- list
base_ptr + 0x8 + 0x20 + x094 <-- player count


- NPCs list (sequential):
base_ptr + 0x8 + 0x24 + 0x50 + index + npc_struct <-- list
base_ptr + 0x8 + 0x24 + 0x54 <-- npcs count


- Resources list (using the one vuduy posted, which works but isn't sequential):
base_ptr + 0x8 + 0x28 + 0x18 + index + 4 + 164 + 0 <-- resource name
base_ptr + 0x8 + 0x28 + 0x14 <-- resource count

* My attempt at finding resource list, which didn't yield results but follows logic above (and should in theory work on sequential list):
base_ptr + 0x8 + 0x28 + 0x10 + index + resource_struct <-- list

Obviously there will be some differences between versions, but it shouldn't be a problem to adjust for that.