-
Active Member
[Info] GetUnitAura reverse engineering notes
I was tweaking some of the code in my multiboxing “bot” today, and decided that I would like to understand more about how auras (buffs) work and how the World of Warcraft game client tracks them. In the past I have been using GetUnitAura to just retrieve the auras and not paying them much mind of how the underlying code in the game client actually worked.
I know that on these forums there have been a significant number of posts with regard to how to retrieve the auras/buffs on a particular NPC or player so I won’t iterate over how to do it in detail. This is more of a “hmm, didn’t know that…” post that others may be interested in.
My reverse engineering may be in error, so please correct me if I am wrong.
Looking at the hex dump for the function GetUnitAura, the last dozen or so bytes of the function indicate that the pointers to each aura are read slightly differently based on how many auras are on you.
It would appear, from how the code is written, that the original aura table only allowed a fixed number of auras.
Most likely due to a legacy piece of software needing to interact with the Warcraft game client, or possibly the database structure on the game servers, rather than increasing the length of the array, or changing the array to something more dynamic like a list, the technical decision was taken, and hence a technical debt was created, that increases the ability to have more than the fixed number of auras by reading from a second list. For the rest of us it just looks like quirky code, but at the time I have to presume that the technical decision was "sound," even if it was ugly.
It is this second list, when read, that uses a slightly different reading method.
The first list (call it the short list), is read merely by adding the offset of the aura table to the base address o f the unit.
Code:
C++:
uint auraAddress = unitBaseAddress + AURA_TABLE_1_OFFSET;
auraAddress += auraIndex * 24;
Aura *aura = (Aura *)(auraAddress);
C#:
uint auraAddress = unitBaseAddress + AURA_TABLE_1_OFFSET;
auraAddress += auraIndex * 24;
Aura aura = (Aura)(m_gameClient.MemoryEditor.ReadObject(auraAddress, typeof(Aura)));
The second list (call it the long list), is read by loading a pointer from the address that is found by combining the second list offset and the base address of the unit, i.e. an indirect read.
Code:
C++:
uint auraAddress = *(unitBaseAddress + AURA_TABLE_2_OFFSET);
auraAddress += auraIndex * 24;
Aura aura = (Aura *)(auraIndex);
C#:
// load the pointer to the aura table
uint auraAddress = m_gameClient.MemoryEditor.ReadUInt(unitBaseAddress + AURA_TABLE_2_OFFSET);
auraAddress += auraIndex * 24;
Aura aura = (Aura)(m_gameClient.MemoryEditor.ReadObject(auraAddress, typeof(Aura)));
To determine whether to use the first/short list or the second/long list: read the aura count for the first/short list as a 32-bit signed integer, and if it is equal to -1, then you use the second/long list.
I also wasn’t aware that the type of beast a hunter is tracking, or the benefit you get from your pet -- if you have the Focused Fire talent -- is actually an aura too. Whenever I used GetUnitAura I only ever checked for a specific range of values, i.e. Devotion Aura, or Power Word: Fortitude, and never considered what else was tucked away in the list.
This last part is speculation, so take it with a grain of salt:
It is interesting to note, as I go spelunking through the hex dump of the World of Warcraft game client, and the Descriptors posts on these forums, that there are a number of legacy, fixed length arrays in places I would not expect to see them. This gives me only three reasonably logical conclusions for the implementation decision in decreasing order of likeliness:
1) incompetent programmer
2) junior programmer
3) source code was swiped from an older project.
Hopefully this post is useful to someone, and if you find any errors in it, please let me know so that I can fix the code and my assumptions.
/emote wishes she could afford IDA.
-
Angry Penguin
Mostly common knowledge. (It's been posted in a few threads in this section)
GJ doing the reversing yourself though.
Also; passive buffs are there as well. (Any racial buffs, tracking, current buffs, etc, are all in that list.)
Most 'passive' buffs have expiration times of 0, and a flag set on them. (I forget the actual value)
-
Active Member
@Apoc: Thank you for the complement.
I kind of figured my post was commonly known. I wasn't sure about the distinction between the first list and the second list. Some posts determined which offset to use, but not the indirect read, other posts just plain ignored the second list entirely.
Searching the forums (google search is better than the built-in forum search) I could only see two posts that clearly pointed out how the code was supposed to work, one by you and one by Cypher. But I couldn't find any post that was explicitly stating the second list had to be read first through an indirect read, or why that would be.
Hopefully I am not way off base here in disassembling the code. Let me know if I misinterpreted the way it reads the lists as I have not had chance to test with more than would fit in to the first list.
-
Just in case this is not one of the threads you found, check this out:
http://www.mmowned.com/forums/wow-me...r-buffs-2.html
-
Active Member
Originally Posted by
namreeb
@namreeb: Thanks for the heads up. I did read that thread. But it also makes the same fundamental mistake (assuming that my code is not in error) of treating the second list of buffs the same as the first. The pointer to the second list of buffs is calculated incorrectly based on the disassembly of the function in the game client. I don't believe I am in error (yet).
@Apoc: I prefer figuring stuff out for myself most of the time. You cannot get respect as a software engineer and "real programmer" if you are always spoonfed.
A few helpful pointers is all I am really seeking when I browse these forums. Besides, I have not written assembly (XBOX360 and PS3 GPU code doesn't count!) in at least five years so it is fun to get back in to it.
On a completely unrelated topic, does anyone know if IDA has an academic or Open Source project license?
Last edited by EmilyStrange; 12-31-2009 at 05:41 AM.
-
Active Member
@namreeb: My mistake, there is a post in that thread that does do it correctly, by a member called "Travelformed." I must have overlooked it. But the post by Johno22 is flawed.
-
Member
-
Active Member
Also +rep on reversing this yourself. We don't have a high enough ratio of reversers to leechers around here, and it's always refreshing to see people working stuff out for themselves
Don't believe everything you think.
-
Angry Penguin
Originally Posted by
amadmonk
Also +rep on reversing this yourself. We don't have a high enough ratio of reversers to leechers around here, and it's always refreshing to see people working stuff out for themselves

/agreed
It's quite annoying to see people go 'oh, auras are at obj+0xDEADBEEF' without knowing WHY they're there. Those of us who reverse WoW on a daily basis (or somewhat-daily basis) have a far better understanding of why things are the way they are; and can quickly tear things apart. Thus; less stupid questions.
As such; I've been doing a lot of reversing from the old Alpha PDB to the newest patch; and Blizz has decided (smartly) to inline quite a few functions, and also split some apart. [As you'll see in my next info dump, which will probably be roughly twice as large.] It's quite annoying having only 9-10 people in this section who can look at a function and tell you why it's doing what it's doing.
-
Kynox's Sister's Pimp
Originally Posted by
Apoc
/agreed
It's quite annoying to see people go 'oh, auras are at obj+0xDEADBEEF' without knowing WHY they're there. Those of us who reverse WoW on a daily basis (or somewhat-daily basis) have a far better understanding of why things are the way they are; and can quickly tear things apart. Thus; less stupid questions.
As such; I've been doing a lot of reversing from the old Alpha PDB to the newest patch; and Blizz has decided (smartly) to inline quite a few functions, and also split some apart. [As you'll see in my next info dump, which will probably be roughly twice as large.] It's quite annoying having only 9-10 people in this section who can look at a function and tell you why it's doing what it's doing.
That function does what it does because that's the way God intended it. Do not question God's divine will.
P.S. I am God.
-
Active Member
Originally Posted by
Apoc
Mostly common knowledge. (It's been posted in a few threads in this section)
GJ doing the reversing yourself though.
Also; passive buffs are there as well. (Any racial buffs, tracking, current buffs, etc, are all in that list.)
Most 'passive' buffs have expiration times of 0, and a flag set on them. (I forget the actual value)
If you mean the aura flag 0x20, that just means it has no duration. Not just passives will use that, area auras and persistant area auras will too.
Edit: to find if an aura is passive, use the dbcs (attributes & 0x40 are passive spells).
I might as well list the flags since I saw someone wondering what they were in another aura post which is now too old (I've already pmed him the flags).
0x01 first effect active
0x02 second effect active
0x04 third effect active
0x08 no caster
0x10 cancellable
0x20 has duration
0x40 unk
0x80 harmful
The first 3 are really important as they are required for spells like warbringer, and juggernaught, to make spells usable while in combat or the incorrect shapeshift form.
Last edited by andy012345; 01-05-2010 at 03:19 AM.
-
Post Thanks / Like - 1 Thanks
Torpedoes (1 members gave Thanks to andy012345 for this useful post)
-
Legendary
Originally Posted by
EmilyStrange
On a completely unrelated topic, does anyone know if IDA has an academic or Open Source project license?
Who cares about license? Just download and use it :P IDA 5.5 + Hex-Rays 1.1 available for free on internet (use google).
Last edited by TOM_RUS; 01-04-2010 at 10:12 AM.
-
Active Member
You know, a lot of people have morals. Though, I'm not one of them.
-
Active Member
Originally Posted by
lanman92
You know, a lot of people have morals. Though, I'm not one of them.
Heh...
I paid out of pocket for IDA, but for a lot of folks the steep side of a thousand dollars just for a reversing tool is excessive.
Not saying I condone piracy (for legal reasons
), but I can definitely understand the drive. I think HexRays would do better if they reduced the price and relied more on volume sales, but... that's just me.
And the actual HexRays software (the "decompiler" for IDA) is just off the hook at multiple thousands of dollars.
Don't believe everything you think.
-
Active Member
Originally Posted by
Apoc
/agreed
It's quite annoying to see people go 'oh, auras are at obj+0xDEADBEEF' without knowing WHY they're there. Those of us who reverse WoW on a daily basis (or somewhat-daily basis) have a far better understanding of why things are the way they are; and can quickly tear things apart. Thus; less stupid questions.
As such; I've been doing a lot of reversing from the old Alpha PDB to the newest patch; and Blizz has decided (smartly) to inline quite a few functions, and also split some apart. [As you'll see in my next info dump, which will probably be roughly twice as large.] It's quite annoying having only 9-10 people in this section who can look at a function and tell you why it's doing what it's doing.
Hopefully they won't be inlining any of the "key" functions (enum, get by guid, you know the ones I mean). If they do, we're going to have a lot more "magic numbers" and raw asm to deal with
Don't believe everything you think.