WQ bot for PWI

09/08/2010 23:28 Interest07#1
I no longer support this bot, adjust the source code / offsets in order to get it to work for your version. Check for the latest version here: [Only registered and activated users can see links. Click Here To Register...]

latest version of bot as of 24/3/13:
[Only registered and activated users can see links. Click Here To Register...]

This bot should work for every (official) version of PW

Latest version for PWI can be found here, thanks to msxgames for continuing the bot :)
[Only registered and activated users can see links. Click Here To Register...]
Next version, thanks again :P
[Only registered and activated users can see links. Click Here To Register...]

Setting up the bot
Download the latest FlyWQ .rar
Unpack it
Update your WQing.ini file
There are two ways of going about this:

1) Copy the elementclient.exe from your Perfect World folder to where you unpacked the FlyWQ. Run the "findWQbotOffsets.exe". This should update the offsets in your WQing.ini

2) Copy or Move the "findWQbotOffsets.exe" to your Perfect World folder containing the elementclient.exe file. Run the offset finder. It should create a WQing.ini file. Move this file to your FlyWQ folder and overwrite the existing WQing.ini with the one you just created.

You will most likely need to update the WQing.ini after every patch.

Run the bot

It should automatically detect the chars you have logged in. You select the ones you want to do WQ on in the left list and press the >> button to have it start working on the WQ. It works without any clicks or keypresses and I believe it even works when minimized to tray icon.

Updates
edit: Now added an offset finder. Place it in the same folder as your elementclient.exe and it should get the offsets you need. Shouldn't need to add NPCids anymore.

edit 2.2: Added support for oddly named characters
edit 2.4: Added support for '|' character in names

(I'm keeping older versions just in case something gets messed up in a later one, but please always download the latest version)
09/09/2010 06:47 kulas2k2#2
hi, how to get questfunctionddress/offsets? im playing at pw-ph. it would be cool if it works on other pw servers.. thank you..
09/09/2010 12:58 Interest07#3
Open up your elementclient.exe in IDA pro

1)
search for text:
Code:
offset aCheckprerequis
2)
You should get only one result. Double click it, this should take you to this function:
[Only registered and activated users can see links. Click Here To Register...]

3)
Go to the top and check the Xrefs, it should be the second Xref shown
[Only registered and activated users can see links. Click Here To Register...]

4)
Go to the top of that function and check the address, this is the address for the questFunction
[Only registered and activated users can see links. Click Here To Register...]

5)
Check the Xrefs again, it should be the third xref shown, follow it. We are now looking for the offset from your character_database to the thisValue. As you can see, it is contained in edi in this example:
[Only registered and activated users can see links. Click Here To Register...]

6)
Now look where edi gets its value from. It'll be one of the parameters of the function we are currently in, in this case the first parameter.
[Only registered and activated users can see links. Click Here To Register...]

7)
Now we'll see where it gets its value. Luckily there is only one Xref here to follow.

[Only registered and activated users can see links. Click Here To Register...]
There we go, it is 0xDDC in this example.



finding the sendPacketFunction is much easier:

1)
search for:
Code:
(void *Src, size_t Size)
2)
You'll get 7 results (most likely), pick the third one:
[Only registered and activated users can see links. Click Here To Register...]

3)
It'll look like this (lots of Xrefs)
[Only registered and activated users can see links. Click Here To Register...]

and there you go, the address of this function.


1)

To find the counter and interval offsets (they're used in sending movement packets) you go up from the send packet function we just found. Follow the second Xref from the large list (this is the function responsible for sending a movement packet), verify by looking for the "push 21h" opcode, as this is the size of a regular move packet. In this example cx will contain the counter value.

[Only registered and activated users can see links. Click Here To Register...]

2)

Go to the top of the function, it will be the last argument when this function is called:

[Only registered and activated users can see links. Click Here To Register...]

3)

Folly the Xref to the preceding function
As we can see, the counter value comes from [esi+0x64]:

[Only registered and activated users can see links. Click Here To Register...]

4)

If we follow the function up to the top, we can see that as usual esi takes on the value of ecx

[Only registered and activated users can see links. Click Here To Register...]

5)

Take the first Xref you see again, and see what the offset to ecx is.

[Only registered and activated users can see links. Click Here To Register...]

6)

There we go, in this example the offset to playercounter is 0x858 + 0x64 = 0x8BC
Usign the 0x858 value we just found, we also know that the offset to interval is 0x858 + 0x18 = 0x870
(So for your version always add 0x64 and 0x18 to whatever value you find in this last step)



FlyspeedOffset:

1) attach CheatEngine to your client window, have a character logged in that can fly and has a standard free airmount. Now search for a float with value 5.5 (your flyspeed).

[Only registered and activated users can see links. Click Here To Register...]

2)

This should result in quite a lot of addresses:

[Only registered and activated users can see links. Click Here To Register...]

3)

Press the increase fly speed button, this should enhance your flyspeed to 7.5, so search next for this value, it should be reduced to one result:

[Only registered and activated users can see links. Click Here To Register...]

4)

Select find out what accesses this address and go ingame and fly a little bit. You should have results like this:

[Only registered and activated users can see links. Click Here To Register...]

5)

Congratulations, your flyspeedoffset is 0x4b0


Transportmode offset:
the values here will be 2 for flying and 0 for on the ground.

1)

Let's start off flying and search for value 2:

[Only registered and activated users can see links. Click Here To Register...]

2)

Pheww, that's a lot of results:

[Only registered and activated users can see links. Click Here To Register...]

3)

now lets drop down and search next for 0:

[Only registered and activated users can see links. Click Here To Register...]

4)

Still quite a few, so we best repeat this step a few times till we only have a couple left. Then it'll be easy to see which address keeps changing to the right value if we fly and stop flying. Take this value and see what accesses this address:

[Only registered and activated users can see links. Click Here To Register...]

5) There we go, offset is 0x608



FlyGearOffset:

Lets take a werefox or werebeast, their standard free flymount Id is 12791.

1)

Search for this value:

[Only registered and activated users can see links. Click Here To Register...]

2)

Now unequip it and search for 0:

[Only registered and activated users can see links. Click Here To Register...]

3)

You'll have one or two values left most likely, just requip the flymount and see which changes. You now have the address value for your flyMount. When looking for what accesses this address, you won't find the offsets as easily, so lets use a different method. We use the transportmode offset we found earlier and display it in CheatEngine:

[Only registered and activated users can see links. Click Here To Register...]

4)

FlyGear: 0x069144B0
TransportMode: 0x06914568

We know the offset for transportmode is 0x608, so to get the offset for FlyGear we simply to the following calculation:

offset = FlyGearAddress - TransportModeAddress + 0x608 =
0x069144B0 - 0x06914568 + 0x608 = 0x550



TargetOffset:

First of all lets select a good friend of all World Questers, Armerigo (the guy you start and end your WQ at). His NPCid is 0x8010449D (This will NOT be his id for all versions of PW), if you do not know his uniqueId for your version, just look at any value, and swap between different NPCs and deselecting and searching for 0.

1)

Search for this value once you have selected him, you'll get a couple of values:

[Only registered and activated users can see links. Click Here To Register...]

2)

Deselect him (don't have anything selected), now search for next value 0:

[Only registered and activated users can see links. Click Here To Register...]

3)

check what accesses this address:

[Only registered and activated users can see links. Click Here To Register...]

tadaa your offset is 0xAD4



Actionstruct offset:

When you are performing an action, [actionstruct + 0x18] will be 1, if you are idle, it will be 0. We will be using this to find out actionstructOffset:

1)

We once again take our trusty flyer and click far away in the distance so we know it will be moving for a while. We then search in cheatEngine for the value 1.

[Only registered and activated users can see links. Click Here To Register...]

2)

These are quite a few... now lets stop moving and search for the value 0:

[Only registered and activated users can see links. Click Here To Register...]

3)

Ah, that's a bit better. Repeat this a few times, once you have whittled it down to a few, usually falling from the sky will show which address is the one you need (it will turn 1, while the last few you have left wont change). Now we will see what accesses this address:

[Only registered and activated users can see links. Click Here To Register...]

4)

double click it and see what the value for the pointer is according to CheatEngine:

[Only registered and activated users can see links. Click Here To Register...]

5)

Search for this value:

[Only registered and activated users can see links. Click Here To Register...]

6)

One by one, try out each of the resulting address:

[Only registered and activated users can see links. Click Here To Register...]

7)

and see what accesses the resulting pointers, if something like this shows up, you've got the actionstruct offset:

[Only registered and activated users can see links. Click Here To Register...]

0xDD4 it is :)



NameOffset:

Well, we know what the name of our character is, it is stored as unicode so:

1)

Search for Text Value, don't forget to check UniCode:

[Only registered and activated users can see links. Click Here To Register...]

2)

now for each of these check what accesses the address until you get something as follows:

[Only registered and activated users can see links. Click Here To Register...]

3)

Double click and take note of the address:

[Only registered and activated users can see links. Click Here To Register...]

4)

Search for this value:

[Only registered and activated users can see links. Click Here To Register...]

5)

Make a pointer to that address with offset 0:

[Only registered and activated users can see links. Click Here To Register...]

6)

find out what accesses this pointer:

[Only registered and activated users can see links. Click Here To Register...]

And there we have our offset.



I believe the other few are so common they'll be around somewhere :P
09/09/2010 17:34 Interest07#4
Added quite some detailed instructions on how to obtain the offsets, I wasn't quite sure which ones can be gotten by using noobs offset retriever, so just threw on most of them.

And the source code... be gentle, I hacked this thing together and it looks like crap, with some redundant bits of code in there too. I only made it cos I wanted to see if I could, but figured might as well have someone benefitting from it:

09/09/2010 20:41 PW-Prophets#5
This looks amazeing!
Thank you!
09/10/2010 08:30 Interest07#6
TWo easy ways to determine where your function was called from (if you can't use the Xrefs, for example with dynamic functions), is setting a breakpoint at the very start of the function. [ESP] will then contain the address of the instruction the function will go to after it has finished, thus leading you to where the function was called from in the first place. Another way is to set the breakpoint and go step by step until you move out of the function, you will then end up in the same place as [ESP] contained.

I prefer the first method as it is a little less work, and if a function is called often from different locations you don't need to perform the step by step stuff a million times. Furthermore, with the first method you can print out [ESP + 4], [ESP + 8], etc for the parameters of the function while you're at it.
09/10/2010 18:00 AEBus#7
What the file "C:\Documents and Settings\Administrator\My Documents\AutoHotkey\Lib\PWlib.ahk"?
And... You source code... this is autohotkey script?
09/10/2010 22:02 AEBus#8
Dear Interest07, I tried to find the offset by IDA, but ....
Quote:
3)
Go to the top and check the Xrefs, it should be the first Xref shown
How check the Xrefs? I could not find a similar code...

Quote:
1)
search for:

Code:
(void *Src, size_t Size)
2)
You'll get 7 results (most likely), pick the third one:
[Only registered and activated users can see links. Click Here To Register...]
still go to the third value?

etc....

i'm noob for a IDA...

Could you find offsets that are using IDA Pro in my client? Offset, which are using CE, I found myself.
[Only registered and activated users can see links. Click Here To Register...] - this is PW Rus client, 1.4.2 build 2305

[Only registered and activated users can see links. Click Here To Register...]
09/11/2010 00:07 Interest07#9
Yeah, my source code is autohotkey script. The PWlib just contains some functions like memory read and possibly converting hex to floats etcetera:

Code:
ReadMemory(MADDRESS=0,PROGRAM="", size=4, retType="UInt*")
{
   Static OLDPROC, ProcessHandle
   VarSetCapacity(MVALUE,size,0)							;Make a variable MVALUE with a capacity of 4 bytes
   If PROGRAM != %OLDPROC%							;If the program is not previously opened
   {
      WinGet, pid, pid, % OLDPROC := PROGRAM					;Get the program's process id
      ProcessHandle := ( ProcessHandle ? 0*(closed:=DllCall("CloseHandle"	;
      ,"UInt",ProcessHandle)) : 0 )+(pid ? DllCall("OpenProcess"		;Make sure the program is open
      ,"Int",16,"Int",0,"UInt",pid) : 0)					;
   }
   If (ProcessHandle) && DllCall("ReadProcessMemory","UInt",ProcessHandle,"UInt",MADDRESS,retType,MVALUE,"UInt",size,"UInt *",0)
   	return MVALUE ;return *(&MVALUE+3)<<24 | *(&MVALUE+2)<<16 | *(&MVALUE+1)<<8 | *(&MVALUE)
   return !ProcessHandle ? "Handle Closed: " closed : "Fail"
}

WriteMemory(WVALUE,MADDRESS,PROGRAM, size=4)
{
	winget, pid, PID, %PROGRAM%

	ProcessHandle := DllCall("OpenProcess", "int", 2035711, "char", 0, "UInt", PID, "UInt")
	DllCall("WriteProcessMemory", "UInt", ProcessHandle, "UInt", MADDRESS, "Uint*", WVALUE, "Uint", size, "Uint *", 0)

	DllCall("CloseHandle", "int", ProcessHandle)
	return
}

HexToFloat(d) {
      Return (1-2*(d>>31)) * (2**((d>>23 & 255)-127)) * (1+(d & 8388607)/8388608) ; 2**23
}

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

In Ida you can name the functions you find (which I did), in your case they'll still all be called their default names, so yes pick the third one :)

For xrefs, go to ida options:

[Only registered and activated users can see links. Click Here To Register...]

change the number of xrefs displayed to 100 or 200 or so. When you're digging around the code a lot, it helps a lot to rename any variables and functions you figure out and add comments. I suppose I shouldve removed them for the screenies. I'll just look into your exe.
09/11/2010 00:37 Interest07#10
sendPacket function:
0x005D7C30

the offset to playercounter is 0x86C + 0x64 = 0x8D0
the offset to interval is 0x86C + 0x18 = 0x884

questFunction:
0x00687CF0

offset:
0xFE8

these are the values for the exe you provided. Also noticed two tiny mistakes in my xplanation on how to find these values :p edited them now, instead of first and second Xref, it should say 2nd and 3rd.
09/11/2010 17:15 AEBus#11
How to find
realBaseAddress
baseOffset
playerOffSet
nameLengthOffset
playerFlyMountOffset
playerXposOffset
playerYposOffset
playerZposOffset
?
09/11/2010 17:37 Interest07#12
nameLengthOffset is always the same
playerFlyMountOffset has been included in the explanation as FlyGearOffset

Assuming you're playing the russian version according to [Only registered and activated users can see links. Click Here To Register...] these are the values you are missing:

realBaseAddress = 0x009C0E6C
baseOffset = 0x1C
playerOffset = 0x20
playerXposOffset = 0x3C
playerYposOffset = 0x40
playerZposOffset = 0x44
playerFlyMountOffset = 0x560

If you think I should add how to find them I will though. Besides the baseAddress (and the flymount offset) they have never changed though
09/12/2010 17:18 AEBus#13
You wq bot don't work in a russian client :( I ordered all offset but the bot does not show any information about the player, nor available quests ... may be the fact that the client's name we do not Element Client a Perfect World?
[Only registered and activated users can see links. Click Here To Register...]
09/12/2010 17:53 Interest07#14
Hmmm, it does not find any character? or did you white out the name?

Where it says stats it will only write the current action (idle, moving[volume 1-30]) not the actual stats of your character. Can you give me a link to where I can download the entire russian pw?

Hmm I can't seem to register an account tehre for some reason

Ah I managed and downloading the client now.

I'll see what I can do to fix it tonight

could you post the offsets you are using here?
09/12/2010 18:37 AEBus#15
[Only registered and activated users can see links. Click Here To Register...]
[Only registered and activated users can see links. Click Here To Register...]
[Only registered and activated users can see links. Click Here To Register...]
[Only registered and activated users can see links. Click Here To Register...]
[Only registered and activated users can see links. Click Here To Register...]

or torrent

[Only registered and activated users can see links. Click Here To Register...]

I registered an account for you, all the data entered in a PM