-
Contributor
[Guide] Finding not so simple stuff.
Hello, i'm in good mood today and decided to write something useful for this forum. Lots of people here ask for complete solutions/offsets and don't even know how one should get them by himself. So let's show the way.
--Intoduction:--
I will show you a brief example of how should one find anything he needs by himself. Let's take a real one demand (rune cooldown request): someone's request ([C#] Getting GCD or SpellCooldown). As i started to work on it, I realized that it's not really hard one to reveal and not really an easy one. So I've chosen to find rune cooldown offsets (while I didn't ever used it in my bot), still this should be fun.
--Prerequisites:--
Things that you should know/have to complete this guide (or just to get some use of it:
-You should first have a basic knowledge of pointer arithmetic and assembler language.
-IDA installed with Hex-Rays plugin
-any MAC OS .idb file with names to start reversing in IDA (get it here by TOM_RUS)
-OllyDBG or any other debugger you like (debugger will be useful to see for some runtime values. though if we don't need it, we can use offline analys with IDA again, still, I prefer to step over once to form a point)
--Get more info:--
We should gather information. As we know now, we are looking for any type of rune cooldown info. Let's take a look into in-game lua api first (why there? simply because we can easily find any of that function in our debugger and IDA later). Let's open wowwiki and search for word runecooldown: API_GetRuneCooldown.
Ok, now we see that this kind of function returns us the following:
-start time of the rune usage
-it's cooldown
-whether rune is already available.
It takes rune ID as param (later we'll discover that it is not just rune type, but a rune slot total of 6, but let's pretend we know nothing about it
). Actually, we don't care about retrieving what rune ID should we use for what rune, because we can simply check for it calling this script and having nice time in-game.
--IDA reversing session:--
It's now time for reversing. Open IDA and select .idb file (see prerequisites). Look at the functions window, sort functions by name.
Now let's take a look into that script function in the IDA window (you can find it by name using alt+t hotkey when functions window is active and then double click). Don't also forget to decompile it with Hex-Rays plugin (f5 hot key while viewing original disassembly).
Pay attention to the names of functions being called to form a general point (the more you reverse, the easier this will come). Now check out what our function actually returns (as it is lua function, it should push something on lua stack as return values). What you should notice is (i've already renamed return variables with more informative names):
![[Guide] Finding not so simple stuff.-luareturns-jpg](https://www.ownedcore.com/forums/attachments/world-of-warcraft/world-of-warcraft-bots-programs/wow-memory-editing/11020d1443816952t-guide-finding-not-so-simple-stuff-luareturns-jpg)
Return values exactly match our expectations (as we've seen function prototype at wowwiki). Only one note here, the names I gave for variables were chosen not randomly, let's take a look at each of returns (a1 in each statement is param, which is always lua state pointer for lua functions):
-lua_pushboolean(a1, lastTimeUsed == 0)
We see that this function pushes (lastTimeUsed ==0) as runeReady boolean (from prototype), now let's track the usage of lastTimeUsed (simply click on it and it will be highlighted). What we see is that this variable is assigned with function's GetRuneLastTimeUsed return. Ok, as we expected it's just the time rune was used. If it is 0 then rune was not used at all and it is ready for usage (it's easy to make logic conclusions once you already reversed everything till the end, so don't be frustrated if you don't understand the logic at this moment).
-lua_pushnumber(a1, cooldown)
Everything should be clear here. Once we found the actual order of returns we can state that this one is cooldown for sure. Now let's try to guess it's format (like whether those are second or milliseconds and so on, what btw we could easily check calling this function in-game). What we actually see:
![[Guide] Finding not so simple stuff.-cooldown-jpg](https://www.ownedcore.com/forums/attachments/world-of-warcraft/world-of-warcraft-bots-programs/wow-memory-editing/11021d1443816952t-guide-finding-not-so-simple-stuff-cooldown-jpg)
Seems like cooldown (as we'll later find it's not really a cooldown, but frequency) is taken from some array (arrayBase + 4*index). If we track the base array address, it's taken from our player base address (using two offsets). You may not know that it is really playerBase for the moment, you just can assume that all base addresses can be some object base or some static addresses. While some functions were called to acquire that base address, it is not static one for sure. Two functions named ClntObjMgrGetActivePlayer and ClntObjMgrObjectPtr give you player base into variable v7 at screenshot.
Let's take a look at what is done next with playerBase to get arrayBase: [playerBase + 4720]+6840 notice that offsets are not actual since we reverse in some older patch binary and soon we'll need to adjust those in debugger.
Now let's see what is taken as index at our array (named v9 in IDA window). This value is taken from return of the function named GetRuneTypeByIndex which takes param as:
v3 = (signed int)floor(lua_tonumber(a1, 1)) - 1
but wait, it's our first argument to the entire function aka "The rune's id. A number between 1 and 6 denoting which rune to be queried" (from wowwiki), but just with -1 substracted. We will cover GetRuneTypeByIndex function later, we should not go in-depth before we form a whole concept. That is all we need to know for the moment about our cooldown: it's taken from array that is relative to playerbase and index in this array acquired as return of function.
-lua_pushnumber(a1, startTime.m128d_f64[0] * 0.001)
As we already know this is kind of time stamp which is used to track cooldown of the rune. First thing you should notice is *0.001. This one signals that this time stamp is milliseconds based (almost all wow stamps are ms based). Seems like this value is just calculated from our lastTimeUsed variable we already covered:
![[Guide] Finding not so simple stuff.-timestart-png](https://www.ownedcore.com/forums/attachments/world-of-warcraft/world-of-warcraft-bots-programs/wow-memory-editing/11022d1443816952t-guide-finding-not-so-simple-stuff-timestart-png)
--Summary::--
Let's summarize:
1)Our reversed function take one param as lua state pointer, then it retrieves rune type from the lua stack:
(v3 = (signed int)floor(lua_tonumber(a1, 1) - 1)
and as we can see -1 here is to bring index to null based format.
2)It uses this index later to get lastTimeUsed time stamp. If it's null then rune is ready.
3)Then player base is taken and some pointer arithmetic is held to get array with rune cooldown times (frequencies as we'll later know).
Index for this array is not our rebased rune type value (v3 in IDA), but is taken from function's return GetRuneTypeByIndex(v3, 0).
4)After retrieving value of cooldown from array, some operations are done to get actual rune cooldown (1/value or 0 as you can see in IDA).
5)Function returns lastTimeUsed time stamp, actual rune cooldown and bolean value (lastTimeUsed == 0).
--In-depth look:--
Let's now look for functions we don't know. They are GetRuneLastUsedTime and GetRuneTypeByIndex. Let's reverse first one:
![[Guide] Finding not so simple stuff.-runetimestamp-png](https://www.ownedcore.com/forums/attachments/world-of-warcraft/world-of-warcraft-bots-programs/wow-memory-editing/11033d1443816954t-guide-finding-not-so-simple-stuff-runetimestamp-png)
Everything is pretty clear here. If code passes all of error checks, we get return value as array element. While array is at static address. Cool, we are just to get that address in debugger later.
Let's take look at GetRuneTypeByIndex now:
![[Guide] Finding not so simple stuff.-runebytype-png](https://www.ownedcore.com/forums/attachments/world-of-warcraft/world-of-warcraft-bots-programs/wow-memory-editing/11023d1443816952t-guide-finding-not-so-simple-stuff-runebytype-png)
As we see it's very short one. The thing you should notice that second param was given as null for that function (renamed it to const0). So we should pay attention to "else" expression only. We can see that some static address array is indexed here with our v3 (rune type - 1) variable. Same then, we'll meet in debugger.
--Having fun with debugger:--
Launch WoW (32 bit) and attach to it via OllyDBG. Resume the thread once attached (f9 hotkey).
Now let's find our function (GetRuneCooldown). Go to dump thread and do everything you need to find it (wow base address can be found at View->Memory), press ctrl+g in main Olly window and copy paste function address, you are done. What should you see:
![[Guide] Finding not so simple stuff.-dbg1-jpg](https://www.ownedcore.com/forums/attachments/world-of-warcraft/world-of-warcraft-bots-programs/wow-memory-editing/11024d1443816952t-guide-finding-not-so-simple-stuff-dbg1-jpg)
Now we should find some control points to match our function raw view with what we've seen in IDA. Usually you can do it by matching function calls (not always, as our IDA representation was made for MAC with another compiler). We can see our match point here with help of constants being pushed on stack in call
v7 = ClntObjMgrObjectPtr(v4, v5, 16, (unsigned int)"../Object/ObjectClient/Player_C.h", 199).
![[Guide] Finding not so simple stuff.-dbg2-jpg](https://www.ownedcore.com/forums/attachments/world-of-warcraft/world-of-warcraft-bots-programs/wow-memory-editing/11026d1443816954t-guide-finding-not-so-simple-stuff-dbg2-jpg)
Let's follow GetRuneLastUsedTime which is called right after our match point (select the line with call and press enter in Olly):
![[Guide] Finding not so simple stuff.-dbg3-png](https://www.ownedcore.com/forums/attachments/world-of-warcraft/world-of-warcraft-bots-programs/wow-memory-editing/11027d1443816954t-guide-finding-not-so-simple-stuff-dbg3-png)
First offset is found, it's 0x10DD6C4 (mine wowBase is 0x400000, while I've disabled ASLR), so rebased one is 0xCDD6C4. So, the time stamp is actually
[wowBase+ 0xCDD6C4 + (runeType-1) * 4]
Now let's see for GetRuneTypeByIndex which is called right after GetRuneLastUsedTime:
![[Guide] Finding not so simple stuff.-dbg4-png](https://www.ownedcore.com/forums/attachments/world-of-warcraft/world-of-warcraft-bots-programs/wow-memory-editing/11028d1443816954t-guide-finding-not-so-simple-stuff-dbg4-png)
Remember that second param was 0, so we follow JE instruction after CMP with 0. Our second offset is 0x10DD67C (rebased is 0xCDD67C). Index of cooldown array can be found as
[wowBase+ 0xCDD67C + (runeType-1) * 4]
The last but not the least is to clear the pointer arithmetic on the player base address. Lets take a look:
![[Guide] Finding not so simple stuff.-dbg5-png](https://www.ownedcore.com/forums/attachments/world-of-warcraft/world-of-warcraft-bots-programs/wow-memory-editing/11029d1443816954t-guide-finding-not-so-simple-stuff-dbg5-png)
Now we know how to get the address of rune cooldowns array: [playerBase+0x1330]+0x1BC8.
Note about cooldown:
Seems like value of cooldown is taken as 1/(value at our cooldown array) if value >0.01 or taken as 0 in another case.
--In-game test:--
Now we should check the results we've acquired. Simple function that will take cooldown of a rune type (as it was tested, not really a rune type but a rune slote number) is:
PHP Code:
public int RuneCooldown(uint runeType)
{
//to works with time stamps we should get our current time stamp in milliseconds
long frequency;
long perfCount;
Imports.QueryPerformanceFrequency(out frequency);
Imports.QueryPerformanceCounter(out perfCount);
//Current time in ms
long currentTime = (perfCount * 1000) / frequency;
uint dwCodeLoc = (uint)WowReader.MainModule.BaseAddress;
//rebase index as it was done in our reversed function
uint nullBasedType = runeType - 1;
//get millisecond based time stamp at when rune was used
uint timeUsedStart=WowReader.ReadUInt(dwCodeLoc + 0xCDD6C4 + nullBasedType * 4);
//check if it's null
if (timeUsedStart == 0) return 0; //rune ready
//get index for cooldown array (not really a cooldown but some frequency)
uint cooldownArrayIndex = WowReader.ReadUInt(dwCodeLoc + 0xCDD67C + nullBasedType * 4);
//get cd array ptr this.baseAddress=playerBase
uint cooldownArrayPtr = WowReader.ReadUInt(this.baseAddress + 0x1330);
//read our frequency
float temp = WowReader.ReadFloat(cooldownArrayPtr + 0x1BC8 + cooldownArrayIndex * 4);
//now do math with it to get actual cooldown in seconds
float cooldown=0;
if (temp > 0.01)
cooldown = 1 / temp;
//get recovery time. multiply cooldown on 1000 to get it's milliseconds representation
int recoveryTimeLeft = (int)(timeUsedStart + cooldown*1000 - currentTime);
//return in seconds
return recoveryTimeLeft/1000;
}
--How it works:--
And of course all this is meaningless until the function actually works in-game (notice the chat).
![[Guide] Finding not so simple stuff.-wowtest-jpg](https://www.ownedcore.com/forums/attachments/world-of-warcraft/world-of-warcraft-bots-programs/wow-memory-editing/11031d1443816954t-guide-finding-not-so-simple-stuff-wowtest-jpg)
--Thanks:--
Thanks to the whole ownedcore community, especially mem edit section. You guys are awesome and very helpful.
Last edited by Empted; 10-27-2012 at 04:37 PM.
-
Post Thanks / Like - 1 Thanks
snake1000 (1 members gave Thanks to Empted for this useful post)
-
Contributor
+rep good tutorial for anyone who wants to learn to reverse some addresses on their own.
-
Member
Nice guide. Why in my IDA there are no function names in pseudocode view, i see only things like 'sub_<addr_here>'? Did you manually assign names to function or what?
(I know about debug symbols)
Last edited by nerexis; 10-30-2012 at 08:31 AM.
-
Originally Posted by
nerexis
Nice guide. Why in my IDA there are no function names in pseudocode view, i see only things like 'sub_<addr_here>'? Did you manually assign names to function or what?
(I know about debug symbols)
You can manually asign names to functions, by default they won't be unless the debug symbols are present. There are good IDB's released here from time to time with a lot of names, they are usually updated with bindiff (a paid IDA plugin which can compare two builds and re-name the similar functions in the newest build). There are also IDC scripts that can be used to name quite a few functions, by example the Script_* functions are named with an IDC script that checks for the "Incorect syntax" string for the name of the function.
-
Contributor
Originally Posted by
DrakeFish
There are also IDC scripts that can be used to name quite a few functions, by example the Script_* functions are named with an IDC script that checks for the "Incorect syntax" string for the name of the function.
You are going to miss quite a few script functions by only searching for the usage string. A better method is to cross reference calls to FrameScript_RegisterFunction and iterate over the function pointer tables.
-
Member
Hi, Offsets Requested by me, I have a DK tank I need this offsets to know which rune are ready. So that I can let Heart strike or Blood boil only consume the first two runes. So The death strikes can be maximum. thanks man My dk tank rotation now is quit good, most time top dps in 5man.
Can the Mac os idb used by IDA on win7 ? i tried but canot load. i downloaded ida 5.0 free version on hex-ray.
-
Contributor
Originally Posted by
iceblockman
Hi, Offsets Requested by me, I have a DK tank I need this offsets to know which rune are ready. So that I can let Heart strike or Blood boil only consume the first two runes. So The death strikes can be maximum. thanks man My dk tank rotation now is quit good, most time top dps in 5man.
Can the Mac os idb used by IDA on win7 ? i tried but canot load. i downloaded ida 5.0 free version on hex-ray.
Hello, yes you can open any idb on windows, I use IDA v 6.1.
P.S. it's cool that you bot can DPS better than players do sometimes
. Keep it going (also some video would be great).
Last edited by Empted; 11-01-2012 at 03:21 PM.
-
Member
-
Originally Posted by
casperc
Nice guide

. I tried it but It seems it changed alot
![[Guide] Finding not so simple stuff.-ida-jpg](https://www.ownedcore.com/forums/attachments/world-of-warcraft/world-of-warcraft-bots-programs/wow-memory-editing/22986d1452303141t-guide-finding-not-so-simple-stuff-ida-jpg)
The part that you want is almost the exact same :| Line 31 to 33 in your image are the ones in red http://www.ownedcore.com/forums/atta...luareturns.jpg Is that what your looking for?
-
Member
Yes but it just seems more confusing and lasttimeused isnt there
So Im kinda stuck now. Guides for wow and ida is rare stuff.. If you ask google XD