[Retail] Finding Auras Applied to Units - Notes and Obstacles menu

User Tag List

Results 1 to 10 of 10
  1. #1
    CodeBytes's Avatar Member
    Reputation
    14
    Join Date
    Feb 2020
    Posts
    39
    Thanks G/R
    7/7
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    [Retail] Finding Auras Applied to Units - Notes and Obstacles

    Hello,

    I'm attempting to read all auras applied to a unit using an external application. Thus far I've had some success, but it has been unreliable. For example, my application is able to find all of the hidden auras like mastery and weapon skills, but it is unable to find proc auras like Hotstreak (48108), or Heating Up (48107). Also, the aura count is always 256, which makes me think my offsets are off.

    Running a few searches led to this forum thread which makes reference to the function Unit_GetAuraByIndex. I could not find this function using my usual methods, and later discovered that @ejt produced an application that is able to find this function via pattern search. Decompiling the function yields the following result:

    Code:
    signed __int64 __fastcall sub_B88BC0(__int64 a1, unsigned int a2)
    {
      unsigned int v2; // er8@1
      __int64 v3; // rcx@1
      unsigned int v4; // eax@2
      signed __int64 v5; // rdx@5
      signed __int64 result; // rax@7
    
      v2 = *(_DWORD *)(a1 + 4224);        // 0x1080 - Count
      v3 = a1 + 1536;                     // 0x600 - Table
    
      // If count == -1, then the AURA_MAX is at UnitBase + 0x600
      if ( v2 == -1 )
      {
        v4 = *(_DWORD *)v3;
      }
      else
      {
        // Otherwise, the AURA_MAX is at UnitBase + 0x1080
        v4 = v2;
      }
    
      // If the index is out of bounds, return 0
      if ( a2 >= v4 )
      {
        result = 0i64;
      }
      else
      {
        // The information for the current aura is at sizeof(Aura) multiplied by index
        v5 = 168i64 * a2;
    
        // If count == -1, the table is at 0x608
        if ( v2 == -1 )
          v3 = *(_QWORD *)(v3 + 8);
    
        // The aura info can be found at sizeof(Aura) + table
        result = v5 + v3;
      }
      return result;
    }
    Given that, and looking at this post, I wrote the following:

    Code:
    std::vector<Aura> MemoryMgr::GetUnitAuras(GameWindow* window, uintptr pointer)
    {
        std::vector<Aura> auras;
    
        int32 count = Read<int32>(window->m_process, pointer + 0x1080);
        uint64 table = pointer + 0x600;
    
        int32 auraMax = count;
        if (count == -1)
        {
            auraMax = Read<int32>(window->m_process, pointer + 0x600);
            table = Read<uint64>(window->m_process, pointer + 0x608);
        }
    
        for (int32 i = 0; i < auraMax; ++i)
        {
            Aura aura = Read<Aura>(window->m_process, (sizeof(Aura) * i) + table);
            auras.emplace_back(aura);
        }
    
        return auras;
    }
    Code:
    struct Aura
    {
        uint32 unknown_00;
        uint32 unknown_04;
        uint32 unknown_08;
        uint32 unknown_0C;
        uint32 unknown_10;
        uint32 unknown_14;
        uint32 unknown_18;
        uint32 unknown_1C;
        uint32 unknown_20;
        uint32 unknown_24;
        ObjectGuid CasterGuid;
        uint32 unknown_38;
        uint32 unknown_3C;
        uint32 unknown_40;
        uint32 unknown_44;
        uint32 SpellId;
        uint32 unknown_4C;
        uint32 unknown_50;
        uint32 unknown_54;
        uint32 unknown_58;
        uint32 unknown_5C;
        uint32 unknown_60;
        uint32 unknown_64;
        uint32 unknown_68;
        uint32 unknown_6C;
        uint32 unknown_70;
        uint32 unknown_74;
        uint32 unknown_78;
        uint32 unknown_7C;
        uint32 unknown_80;
        uint32 unknown_84;
        uint32 unknown_88;
        uint32 unknown_8C;
        uint32 unknown_90;
        uint32 unknown_94;
        uint32 unknown_98;
        uint32 unknown_9C;
        uint32 unknown_A0;
        uint32 unknown_A4;
    };
    The pointer in my code snippet is the base address for the current object in s_curMgr (some of you know it as ObjectMgr). When I use this address, the aura count is always 0. I also used current object + 0x18 (offset to GUID) entirely by mistake, which results in aura count always being 256, which, in turn, yields a lot of bad results. However, using this point in memory does return a lot of auras including debuffs on enemies. Unfotunately, I do not get any proc auras like Hotstreak (48108), or Heating Up (48107).

    What am I missing?

    [Retail] Finding Auras Applied to Units - Notes and Obstacles
  2. #2
    CodeBytes's Avatar Member
    Reputation
    14
    Join Date
    Feb 2020
    Posts
    39
    Thanks G/R
    7/7
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I was able to solve the issue. The above code is correct; however, the pointer should be the current object in s_curMgr minus 0x28. The Aura struct above should also be offset by 0x40; putting SpellId at offset 0x88, and CasterGuid at 0x68. Proc auras are found outside of the Unit structure, via pointer. I found two proc caches in the client, the easiest to read is at offset 0x1068 from object base.
    Last edited by CodeBytes; 05-22-2020 at 01:10 AM.

  3. #3
    counted's Avatar Contributor Authenticator enabled
    Reputation
    203
    Join Date
    Mar 2008
    Posts
    183
    Thanks G/R
    11/108
    Trade Feedback
    0 (0%)
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by CodeBytes View Post
    Hello,

    I'm attempting to read all auras applied to a unit using an external application. Thus far I've had some success, but it has been unreliable. For example, my application is able to find all of the hidden auras like mastery and weapon skills, but it is unable to find proc auras like Hotstreak (4810, or Heating Up (48107). Also, the aura count is always 256, which makes me think my offsets are off.

    Running a few searches led to this forum thread which makes reference to the function Unit_GetAuraByIndex. I could not find this function using my usual methods, and later discovered that @ejt produced an application that is able to find this function via pattern search. Decompiling the function yields the following result:

    Code:
    signed __int64 __fastcall sub_B88BC0(__int64 a1, unsigned int a2)
    {
      unsigned int v2; // er8@1
      __int64 v3; // rcx@1
      unsigned int v4; // eax@2
      signed __int64 v5; // rdx@5
      signed __int64 result; // rax@7
    
      v2 = *(_DWORD *)(a1 + 4224);        // 0x1080 - Count
      v3 = a1 + 1536;                     // 0x600 - Table
    
      // If count == -1, then the AURA_MAX is at UnitBase + 0x600
      if ( v2 == -1 )
      {
        v4 = *(_DWORD *)v3;
      }
      else
      {
        // Otherwise, the AURA_MAX is at UnitBase + 0x1080
        v4 = v2;
      }
    
      // If the index is out of bounds, return 0
      if ( a2 >= v4 )
      {
        result = 0i64;
      }
      else
      {
        // The information for the current aura is at sizeof(Aura) multiplied by index
        v5 = 168i64 * a2;
    
        // If count == -1, the table is at 0x608
        if ( v2 == -1 )
          v3 = *(_QWORD *)(v3 + 8);
    
        // The aura info can be found at sizeof(Aura) + table
        result = v5 + v3;
      }
      return result;
    }
    Given that, and looking at this post, I wrote the following:

    Code:
    std::vector<Aura> MemoryMgr::GetUnitAuras(GameWindow* window, uintptr pointer)
    {
        std::vector<Aura> auras;
    
        int32 count = Read<int32>(window->m_process, pointer + 0x1080);
        uint64 table = pointer + 0x600;
    
        int32 auraMax = count;
        if (count == -1)
        {
            auraMax = Read<int32>(window->m_process, pointer + 0x600);
            table = Read<uint64>(window->m_process, pointer + 0x608);
        }
    
        for (int32 i = 0; i < auraMax; ++i)
        {
            Aura aura = Read<Aura>(window->m_process, (sizeof(Aura) * i) + table);
            auras.emplace_back(aura);
        }
    
        return auras;
    }
    Code:
    struct Aura
    {
        uint32 unknown_00;
        uint32 unknown_04;
        uint32 unknown_08;
        uint32 unknown_0C;
        uint32 unknown_10;
        uint32 unknown_14;
        uint32 unknown_18;
        uint32 unknown_1C;
        uint32 unknown_20;
        uint32 unknown_24;
        ObjectGuid CasterGuid;
        uint32 unknown_38;
        uint32 unknown_3C;
        uint32 unknown_40;
        uint32 unknown_44;
        uint32 SpellId;
        uint32 unknown_4C;
        uint32 unknown_50;
        uint32 unknown_54;
        uint32 unknown_58;
        uint32 unknown_5C;
        uint32 unknown_60;
        uint32 unknown_64;
        uint32 unknown_68;
        uint32 unknown_6C;
        uint32 unknown_70;
        uint32 unknown_74;
        uint32 unknown_78;
        uint32 unknown_7C;
        uint32 unknown_80;
        uint32 unknown_84;
        uint32 unknown_88;
        uint32 unknown_8C;
        uint32 unknown_90;
        uint32 unknown_94;
        uint32 unknown_98;
        uint32 unknown_9C;
        uint32 unknown_A0;
        uint32 unknown_A4;
    };
    The pointer in my code snippet is the base address for the current object in s_curMgr (some of you know it as ObjectMgr). When I use this address, the aura count is always 0. I also used current object + 0x18 (offset to GUID) entirely by mistake, which results in aura count always being 256, which, in turn, yields a lot of bad results. However, using this point in memory does return a lot of auras including debuffs on enemies. Unfotunately, I do not get any proc auras like Hotstreak (4810, or Heating Up (48107).

    What am I missing?
    There are some more known fields in the Aura struct.

    Look at my post for the 27144 binary

    https://www.ownedcore.com/forums/wor...ml#post3876971

    If anyone has reversed additional struct info please contribute.

  4. #4
    CodeBytes's Avatar Member
    Reputation
    14
    Join Date
    Feb 2020
    Posts
    39
    Thanks G/R
    7/7
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by counted
    There are some more known fields in the Aura struct.

    Look at my post for the 27144 binary

    https://www.ownedcore.com/forums/wor...ml#post3876971 ([Wow] [8.0.1.27144])

    If anyone has reversed additional struct info please contribute.
    Just to add to this (and I'm sure you already fixed this in your code, but for others reading this), sizeof Aura must be 0xA8. You have 4 byte fields starting at 0x90 so Duration and EndDuration should be long--which would be consistent with Blizzard type conventions anyway. Thanks for sharing.

    Code:
    struct Aura
    {
        uint32 unknown_00;
        uint32 unknown_04;
        uint32 unknown_08;
        uint32 unknown_0C;
        uint32 unknown_10;
        uint32 unknown_14;
        uint32 unknown_18;
        uint32 unknown_1C;
        uint32 unknown_20;
        uint32 unknown_24;
        uint32 unknown_28;
        uint32 unknown_2C;
        uint32 unknown_30;
        uint32 unknown_34;
        uint32 unknown_38;
        uint32 unknown_3C;
        uint32 unknown_40;
        uint32 unknown_44;
        uint32 unknown_48;
        uint32 unknown_4C;
        uint32 unknown_50;
        uint32 unknown_54;
        uint32 unknown_58;
        uint32 unknown_5C;
        uint32 unknown_60;
        uint32 unknown_64;
        ObjectGuid CasterGuid;  // 0x68
        uint32 unknown_78;
        uint32 unknown_7C;
        uint32 unknown_80;
        uint32 unknown_84;
        uint32 SpellId;         // 0x88
        uint32 Icon;            // 0x8C
        uint8 Flags;            // 0x90
        uint8 StackCount;       // 0x91
        uint8 unknown_92;
        uint8 Level;            // 0x93
        uint64 Duration;        // 0x94
        uint64 End;             // 0x9C
    };
    Last edited by CodeBytes; 05-22-2020 at 09:04 AM.

  5. #5
    Jadd's Avatar 🐸 Premium Seller
    Reputation
    1511
    Join Date
    May 2008
    Posts
    2,432
    Thanks G/R
    81/333
    Trade Feedback
    1 (100%)
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Timestamps are generally 4 bytes (duration and expiration time included...)


  6. #6
    CodeBytes's Avatar Member
    Reputation
    14
    Join Date
    Feb 2020
    Posts
    39
    Thanks G/R
    7/7
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I was referring to duration parameters in functions like Spell_C_GetSpellCooldown. Specifically regarding the Aura struct; I'll have to look at it when I get back home. If those duration members have to be 4 bytes then the struct would require 2 more 4 byte members appended to the end to ensure it is of size 0xA8. I'm confident in my assessment that SpellId is at offset 0x88, and CasterGuid is at 0x68. So any additions to the struct must go after that.

  7. #7
    CodeBytes's Avatar Member
    Reputation
    14
    Join Date
    Feb 2020
    Posts
    39
    Thanks G/R
    7/7
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    They are indeed 4-byte members.

    Code:
    struct Aura
    {
        uint32 unknown_00;
        uint32 unknown_04;
        uint32 unknown_08;
        uint32 unknown_0C;
        uint32 unknown_10;
        uint32 unknown_14;
        uint32 unknown_18;
        uint32 unknown_1C;
        uint32 unknown_20;
        uint32 unknown_24;
        uint32 unknown_28;
        uint32 unknown_2C;
        uint32 unknown_30;
        uint32 unknown_34;
        uint32 unknown_38;
        uint32 unknown_3C;
        uint32 unknown_40;
        uint32 unknown_44;
        uint32 unknown_48;
        uint32 unknown_4C;
        uint32 unknown_50;
        uint32 unknown_54;
        uint32 unknown_58;
        uint32 unknown_5C;
        uint32 unknown_60;
        uint32 unknown_64;
        ObjectGuid CasterGuid;  // 0x68
        uint32 unknown_78;
        uint32 unknown_7C;
        uint32 unknown_80;
        uint32 unknown_84;
        uint32 SpellId;         // 0x88
        uint32 Icon;            // 0x8C
        uint8 Flags;            // 0x90
        uint8 StackCount;       // 0x91
        uint8 unknown_92;
        uint8 Level;            // 0x93
        uint32 Duration;        // 0x94
        uint32 ExpirationTime;  // 0x98
        uint32 unknown_9C;
        uint32 unknown_A0;
        uint32 unknown_A4;
    };

  8. Thanks badusername1234 (1 members gave Thanks to CodeBytes for this useful post)
  9. #8
    Jadd's Avatar 🐸 Premium Seller
    Reputation
    1511
    Join Date
    May 2008
    Posts
    2,432
    Thanks G/R
    81/333
    Trade Feedback
    1 (100%)
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Spell_C_GetSpellCooldown uses 4 byte timestamps as well. In fact, I'd be willing to say that all timestamp related functions and parameters in Wow are using 4 byte timestamps (based off GetTickCount or the low 4 bytes of QueryPerformanceCounter depending on the "timingMethod" convar.)

  10. #9
    CodeBytes's Avatar Member
    Reputation
    14
    Join Date
    Feb 2020
    Posts
    39
    Thanks G/R
    7/7
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by Jadd View Post
    based off GetTickCount or the low 4 bytes of QueryPerformanceCounter depending on the "timingMethod" convar.
    Thanks Jadd. This is where experience with the WoW client shines through. I just go by what I see in IDA (which is not always accurate, as we've recently seen).

  11. #10
    Shepy's Avatar Member
    Reputation
    1
    Join Date
    Sep 2020
    Posts
    1
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Code:
    8.3.7 35662 | Unit_GetAuraByIndex | sub_B9BEE0
    Pattern Search : 49 8B ? E8 ? ? ? FF 8B 48 20 83 F9 FF 75 04 8B 10 EB 02 8B D1 (Thanks to ejt)
    ...the pointer should be the current object in s_curMgr minus 0x28
    If your unit base pointer came from the [[s_curMgr + 0x120] - 0x18] method (as shown here (8.2.5.31960)), you can pass it directly.

Similar Threads

  1. [Trading] Looking to trade Netherwing and Northdale gold for Retail EU gold!
    By Hace in forum WoW-EU Account Buy Sell Trade
    Replies: 0
    Last Post: 03-02-2019, 04:18 AM
  2. How to find out info about my pokemons and stardust?
    By maRT_sk in forum Pokemon GO Chat
    Replies: 0
    Last Post: 08-09-2016, 01:03 PM
  3. Need help to setup PQR and find the right profile...
    By bigd in forum WoW Bots Questions & Requests
    Replies: 4
    Last Post: 12-02-2013, 09:15 AM
  4. Replies: 1
    Last Post: 09-27-2012, 08:45 AM
  5. [Help] Coding Stickey notes and Text to speech
    By Anthonyrox8 in forum Programming
    Replies: 10
    Last Post: 10-17-2008, 02:22 PM
All times are GMT -5. The time now is 08:54 PM. Powered by vBulletin® Version 4.2.3
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2024 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search