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:
latest version of bot as of 24/3/13:
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
Next version, thanks again :P
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)
2)
You should get only one result. Double click it, this should take you to this function:
3)
Go to the top and check the Xrefs, it should be the second Xref shown
4)
Go to the top of that function and check the address, this is the address for the questFunction
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:
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.
7)
Now we'll see where it gets its value. Luckily there is only one Xref here to follow.
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:
3)
It'll look like this (lots of Xrefs)
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.
2)
Go to the top of the function, it will be the last argument when this function is called:
3)
Folly the Xref to the preceding function
As we can see, the counter value comes from [esi+0x64]:
4)
If we follow the function up to the top, we can see that as usual esi takes on the value of ecx
5)
Take the first Xref you see again, and see what the offset to ecx is.
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).
2)
This should result in quite a lot of addresses:
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:
4)
Select find out what accesses this address and go ingame and fly a little bit. You should have results like this:
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:
2)
Pheww, that's a lot of results:
3)
now lets drop down and search next for 0:
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:
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:
2)
Now unequip it and search for 0:
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:
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:
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:
2)
Deselect him (don't have anything selected), now search for next value 0:
3)
check what accesses this address:
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.
2)
These are quite a few... now lets stop moving and search for the value 0:
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:
4)
double click it and see what the value for the pointer is according to CheatEngine:
5)
Search for this value:
6)
One by one, try out each of the resulting address:
7)
and see what accesses the resulting pointers, if something like this shows up, you've got the actionstruct offset:
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:
2)
now for each of these check what accesses the address until you get something as follows:
3)
Double click and take note of the address:
4)
Search for this value:
5)
Make a pointer to that address with offset 0:
6)
find out what accesses this pointer:
And there we have our offset.
I believe the other few are so common they'll be around somewhere :P
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:
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.
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:
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.
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 edited them now, instead of first and second Xref, it should say 2nd and 3rd.
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?
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