Playername from cache? menu

User Tag List

Results 1 to 4 of 4
  1. #1
    chaosrage's Avatar Site Donator
    Reputation
    24
    Join Date
    Dec 2007
    Posts
    77
    Thanks G/R
    8/2
    Trade Feedback
    1 (100%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Playername from cache?

    Hello,

    im having some trouble figuring out how the name cache is structured and how to grab a player name from it. is there anyone who could help me understand it? i've been staring at it in IDA for hours and i've tried bruteforcing but my brain is starting to hurt.

    Playername from cache?
  2. #2
    charles420's Avatar Elite User
    Reputation
    335
    Join Date
    Jun 2009
    Posts
    337
    Thanks G/R
    25/123
    Trade Feedback
    0 (0%)
    Mentioned
    10 Post(s)
    Tagged
    0 Thread(s)
    doing this while rolling so mind the meh but its basically a object manager loop as well used a few other things

    Code:
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
            struct PlayerCacheEntry
            {
                public IntPtr next;
                public UInt128 guid;
                public Byte pad;
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x30)]
                public Byte[] name;
            }
            public override string Name
            {
                get
                {
                    try
                    {
                        int count = ProcessMemory.Read<int>(ProcessMemory.BaseAddress + (int)Pointers.UnitName.PlayerNameCachePointer + 0x8);
                        IntPtr startAddress = ProcessMemory.Read<IntPtr>(ProcessMemory.BaseAddress + (int)Pointers.UnitName.PlayerNameCachePointer + 0x10);
    
                        IntPtr address = ProcessMemory.Read<IntPtr>(startAddress);
    
                        for (int x = 0; x < count; x++)
                        {
                            var entry = ProcessMemory.Read<PlayerCacheEntry>(ProcessMemory.Read<IntPtr>(startAddress + (0x8 * x)));
    
                            var entryName = ProcessMemory.UTF8Decoder(entry.name);
    
                            var target = entry.next;
                            while (target != IntPtr.Zero)
                            {
                                var inner = ProcessMemory.Read<PlayerCacheEntry>(target);
                                target = inner.next;
                            }
    
                            if (address == IntPtr.Zero)
                            {
                                // current entry is empty, go to the next one
                                x++;
                                address = ProcessMemory.Read<IntPtr>(startAddress + 0x8 * x);
                                //Logging.Write(string.Format("[PlayerName] address: {0}", address));
                                continue;
                            }
                            PlayerCacheEntry data = ProcessMemory.Read<PlayerCacheEntry>(address);
                            //Logging.Write(string.Format("[PlayerName] dataguid: {0}", data.guid));
                            if (data.guid == GUID)
                            {
                                String name = ProcessMemory.UTF8Decoder(data.name);
                                //Logging.Write(string.Format("[PlayerName] dataname: {0}", data.name));
                                if (name != "")
                                {
                                    return name;
                                }
                            }
                            //Logging.Write(string.Format("[PlayerName] datanext: {0}", data.name));
                            if (data.next == IntPtr.Zero)
                            {
                                // end of the current chain, go to next array entry
                                x++;
                                address = ProcessMemory.Read<IntPtr>(startAddress + 0x8 * x);
                            }
                            else
                            {
                                // go to next cache entry in this chain, do not increment x
                                address = data.next;
                            }
                            //Logging.Write(string.Format("[PlayerName] namesssssss: {0}", data.name));
                        }
    
                    }
                    catch
                    {
                        //    return "Error Reading Name";
                    }
                    return "Error Reading Name";
    
                }
            }
            //private string _name
            // public override string Name => GetPlayerNameCacheEntries().FirstOrDefault(x => x.guid == GUID).Select(x => Encoding.ASCII.GetString(x));
    
            private IEnumerable<PlayerCacheEntry> GetPlayerNameCacheEntries()
            {
                var nameCount = ProcessMemory.Read<int>(ProcessMemory.BaseAddress + (int)Pointers.UnitName.PlayerNameCachePointer + 0x8);
                var startAddress = ProcessMemory.Read<IntPtr>(ProcessMemory.BaseAddress + (int)Pointers.UnitName.PlayerNameCachePointer + 0x10);
    
                for (var i = 0; i < nameCount; i++)
                {
                    var entry = ProcessMemory.Read<PlayerCacheEntry>(ProcessMemory.Read<IntPtr>(startAddress + (0x8 * i)));
    
                    var entryName = ProcessMemory.UTF8Decoder(entry.name);
    
    
                    yield return entry;
    
                    var target = entry.next;
                    while (target != IntPtr.Zero)
                    {
                        var inner = ProcessMemory.Read<PlayerCacheEntry>(target);
                        yield return inner;
                        target = inner.next;
                    }
    
                }
    
            }
    
            private string GetNameForGuid(UInt128 guid, IEnumerable<PlayerCacheEntry> entries)
            {
                var nameCacheEntry = entries.FirstOrDefault(x => x.guid == guid);
                if (nameCacheEntry.guid == 0)
                {
                    return string.Empty;
                }
    
                return ProcessMemory.UTF8Decoder(nameCacheEntry.name);
            }
    Last edited by charles420; 05-28-2025 at 11:25 AM.

  3. Thanks chaosrage (1 members gave Thanks to charles420 for this useful post)
  4. #3
    chaosrage's Avatar Site Donator
    Reputation
    24
    Join Date
    Dec 2007
    Posts
    77
    Thanks G/R
    8/2
    Trade Feedback
    1 (100%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    thank you sooooo much!

  5. #4
    chaosrage's Avatar Site Donator
    Reputation
    24
    Join Date
    Dec 2007
    Posts
    77
    Thanks G/R
    8/2
    Trade Feedback
    1 (100%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    fiiiiiinally figured it out! the names were packed in 8-byte chunks starting at an offset within the name field, and I also had to correctly handle a leading null character before the actual name


    Code:
    public string GetName()
    {
        if (nameBytes == null) return string.Empty;
    
        // Relevant QWORDs for name data within nameBytes array:
        // QWORD0_CEPattern (often null): nameBytes[7..14]  (EntryBasePtr + 0x20)
        // QWORD1_NamePart1:              nameBytes[15..22] (EntryBasePtr + 0x28)
        // QWORD2_NamePart2:              nameBytes[23..30]
        // QWORD3_NamePart3:              nameBytes[31..38]
        // QWORD4_NamePart4:              nameBytes[39..46]
    
    
        int[] nameQwordStartOffsetsInNameBytes = { 15, 23, 31, 39 };
    
    
        List<byte> collectedCharBytes = new List<byte>(32); // Max 32 chars
        bool nameTerminatedInCache = false;
    
        for (int i = 0; i < nameQwordStartOffsetsInNameBytes.Length; i++)
        {
            int currentQwordStartOffset = nameQwordStartOffsetsInNameBytes[i];
    
            
            if (currentQwordStartOffset + 7 >= nameBytes.Length) break;
    
            for (int k = 0; k < 8; k++) 
            {
                byte charByte = nameBytes[currentQwordStartOffset + k];
    
                if (charByte == 0)
                {
                    if (i == 0 && k == 0 && collectedCharBytes.Count == 0)
                    {
                        // continue to the next byte in this QWORD
                    }
                    else
                    {
                        nameTerminatedInCache = true;
                        break; // Stop processing this QWORD
                    }
                }
                else
                {
                    
                    collectedCharBytes.Add(charByte);
                }
            }
    
            if (nameTerminatedInCache)
            {
                break; 
            }
        }
    
        if (collectedCharBytes.Count == 0)
        {
            return string.Empty;
        }
        
        return Encoding.UTF8.GetString(collectedCharBytes.ToArray(), 0, collectedCharBytes.Count);
    }
    thank you for pointing me in the right direction

Similar Threads

  1. Replies: 3
    Last Post: 09-01-2016, 07:19 AM
  2. Get Playernames only possible from Cache?
    By Holico in forum WoW Memory Editing
    Replies: 10
    Last Post: 04-02-2013, 08:47 AM
  3. Cruising the spell cache from memory
    By amadmonk in forum WoW Memory Editing
    Replies: 5
    Last Post: 12-08-2009, 08:38 PM
  4. Remove no-cache from the headers.
    By Apoc in forum Suggestions
    Replies: 18
    Last Post: 08-28-2008, 05:19 PM
All times are GMT -5. The time now is 02:58 AM. Powered by vBulletin® Version 4.2.3
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Google Authenticator verification provided by Two-Factor Authentication (Free) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search