[C#/CopyPasta] Chat Buffer Memory (Updated) menu

User Tag List

Results 1 to 10 of 10
  1. #1
    Ryns's Avatar Member
    Reputation
    19
    Join Date
    Oct 2009
    Posts
    24
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    [C#/CopyPasta] Chat Buffer Memory (Updated)

    Intro

    Just helping to clear up some of the confusion around the in-memory Chat Buffer and it's offsets. JuJuBoSc posted the offsets for 3.3.2:
    Code:
    public enum WoWChat
    {
       ChatBufferStart = 0x00B0E990,   // 3.3.2
       NextMessage = 0x17C0,   // 3.3.2
    }
    And for alot of people this caused problems, until guizmows posted a new offset of 0x00B0E9CC. The problem is that alot of people expect the chat-buffer to be a neat null-terminated string like "Type: [1], Channel: [], Player Name: [Somedude], Sender GUID: [0123456789ABCDEF], Text: [gief gold plox]" when in fact its not.

    RokGFenris described the chat buffer in more detail on the 3.3.0 thread:
    Originally Posted by RoKFenris View Post
    Here is a bunch more info about the chat buffer:
    - The function that adds a new message to the buffer is at 0x004A35B0.
    - The format string for the message in the text buffer is at 0x009DC4F8 : 'Type: [%d], Channel: [%s], Player Name: [%s], Sender GUID: [%016I64X], Text: [%s]'
    - The real base address for the chat buffer is 0x00B0D948; there are 0x3c bytes before the string. The index of the first free slot in the ring buffer is at 0x00B66EDC.
    - As already said, the buffer has 60 slots.
    - The message structure is as follows:
    Code:
    0x0000 - Sender GUID
    0x0008 - Unknown
    0x003c - formatted message, 3000 bytes
    0x0bf4 - pure text, also 3000 bytes
    0x17ac - messageType
    0x17b0 - channelNumber
    0x17b4 - sequence
    0x17b8 - time
    The offset posted by guizmows (0x00B0E9CC) is actually just the original offset 0x00B0E990 + 0x3C, so you are skipping to the 'formatted message' field for each entry in the chat buffer, and on the last entry you will be reading 0x3C bytes off the end of the chat buffer's memory.

    p.s. Sednogmah has previously posted a list of known messageType's

    Code

    This is a quick-and-dirty example of how to read the chat buffer from C#, assuming you have a Memory reader utility like the one from WowStarter recently posted by Apoc. This class requires the occasional "Pulse()" call which allows it to check for and dispatch new messages.

    Code:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Runtime.InteropServices;
    
    namespace RynsChat
    {
        // the chat line structure as of 3.3.2
        [StructLayout(LayoutKind.Sequential)]
        public struct WowChatMsg
        {
            public ulong SenderGuid;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)]
            public uint[] Unknown;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 3000)]
            public string FormattedMessage;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 3000)]
            public string Text;
            public uint MessageType;
            public uint ChannelNumber;
            public uint Sequence;
            public uint Time;
        }
    
        // Simple chat monitoring and event dispatching class
        class WowChat
        {
            // Starting point of the chat buffer memory
            private static int ChatBufferStart = 0x00B0E990; // 3.3.2
    
            // The length of each record/offset to the next
            private static int ChatNextMessage = 0x17C0;     // 3.3.2
    
            // This holds the current position in the chat buffer
            private static int ChatBufferPos = 0x00B67F24;   // 3.3.2
    
            // This is the event handler other classes implement
            public delegate void ChatMessageListener(WowChatMsg msg);
            public event ChatMessageListener onChatMessage;
    
            // Used to keep track of the last buffer position
            private uint pos = 0;
    
            //
            public WowChat()
            {
                // Initialise pos with the current position from WoW
                pos = Memory.Read<UInt16>(new IntPtr(ChatBufferPos));
            }
    
            //
            public void Pulse()
            {
                // Read the current position from WoW
                uint newPos = Memory.Read<UInt16>(new IntPtr(ChatBufferPos));
    
                // nothings changed, lets get outta here
                if (newPos == pos)
                {
                    return;
                }
    
                // Handle wrap around
                if (newPos < pos)
                {
                    for (; pos < 60; pos++)
                    {
                        WowChatMsg msg = Memory.ReadStruct<WowChatMsg>(new IntPtr(ChatBufferStart + (ChatNextMessage * pos)));
                        onChatMessage(msg);
                    }
                    pos = 0;
                }
    
                // Finally, post messages
                for (; pos < newPos; pos++)
                {
                    WowChatMsg msg = Memory.ReadStruct<WowChatMsg>(new IntPtr(ChatBufferStart + (ChatNextMessage * pos)));
                    onChatMessage(msg);
                }
            }
        }
    }
    Example Usage

    Code:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    
    namespace RynsChat
    {
        class Program
        {
            // our event listener which receives new messages
            public void onChatMessage(WowChatMsg msg)
            {
                Console.WriteLine(msg.FormattedMessage);
            }
    
            // our simple run loop
            public void run(string[] args)
            {
                Win32.Native.OpenProcessHandle(<PIDOFWOW>);
                // Initialise
                WowChat chat = new WowChat();
                // Add our event listener
                chat.onChatMessage += this.onChatMessage;
                while (true)
                {
                    // Pulse to check for new messages
                    chat.Pulse();
                    // Sleep for a bit
                    Thread.Sleep(500);
                }
            }
    
            static void Main(string[] args)
            {
                (new Program()).run(args);
            }
        }
    }
    Last edited by Ryns; 02-05-2010 at 05:12 AM. Reason: added code

    [C#/CopyPasta] Chat Buffer Memory (Updated)
  2. #2
    DrakeFish's Avatar Lazy Leecher

    Reputation
    634
    Join Date
    Nov 2008
    Posts
    569
    Thanks G/R
    0/14
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks about this info, didn't know it wasn't only a string. Now this is much more useful.

  3. #3
    Sednogmah's Avatar Contributor
    Reputation
    129
    Join Date
    Oct 2009
    Posts
    158
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Here's a small update about the unknown 52 bytes. 48 of them contain the sender's name. 12 characters can be represented by up to 48 bytes in UTF-8 encoding. That leaves us with 4 unknown bytes which always seem to be 0.

    Code:
    typedef struct __attribute__ ((__packed__)) {
        uint64_t senderGUID;
        // seems to be 0 all the time
        uint8_t  unknown0[4];
        // senderName: 12 UTF-8 characters can take up to 48 bytes
        char     senderName[48];
        char     formattedMsg[3000];
        char     plaintextMsg[3000];
        uint32_t type;
        uint32_t channelNr;
        uint32_t sequence;
        uint32_t time;
    } RawChatMessage;
    Unfortunately this struct doesn't let you know whether the message is from a GM or a regular player. Maybe we can use the GUID to recognize game masters.
    Last edited by Sednogmah; 02-11-2010 at 04:42 PM.
    951388dcb8e5be825c2c10a7f53c16fcd84fc6c8b76ff0483237eeff745eaeac

  4. #4
    pendra's Avatar Active Member
    Reputation
    46
    Join Date
    Jul 2008
    Posts
    42
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by Sednogmah View Post
    Here's a small update about the unknown 52 bytes. 48 of them contain the sender's name. 12 characters can be represented by up to 48 bytes in UTF-8 encoding. That leaves us with 4 unknown bytes which always seem to be 0.

    Code:
    typedef struct __attribute__ ((__packed__)) {
        uint64_t senderGUID;
        // seems to be 0 all the time
        uint8_t  unknown0[4];
        // senderName: 12 UTF-8 characters can take up to 48 bytes
        char     senderName[48];
        char     formattedMsg[3000];
        char     plaintextMsg[3000];
        uint32_t type;
        uint32_t channelNr;
        uint32_t sequence;
        uint32_t time;
    } RawChatMessage;
    Unfortunately this struct doesn't let you know whether the message is from a GM or a regular player. Maybe we can use the GUID to recognize game masters.
    GM chat state is managed with SMSG_NOTIFICATION messages. I don't know what the client does with these precisely, but probably it sets flags on a player record that it manages somewhere.

    In other words, sometime before you got that whisper you should have gotten a notification that the sender was a GM, so you'd have to look at what the client did with that message to figure out where it stores that state...

  5. #5
    !@^^@!'s Avatar Active Member
    Reputation
    23
    Join Date
    Feb 2007
    Posts
    155
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks, this will probably be usefull for me later so have a +rep cookie

  6. #6
    dook123's Avatar Active Member
    Reputation
    21
    Join Date
    Oct 2008
    Posts
    115
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Chat offset?

    Would you be able to tell me why the chat offset both you and juju posted is different from this persons?

    Info dump page 2- guizmows post

    I am still trying to learn how to read memory properly. I understand how the chat is setup in memory. The structure helped clear some of the parts I didnt know about. I still am lost why there are two different initial offsets though.


    Im using black magic in my code.

    bm.ReadASCIIString(0x0B0E9CC + i * 0x17C0, 255));


    -D

  7. #7
    guizmows's Avatar Banned
    Reputation
    57
    Join Date
    Feb 2008
    Posts
    414
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    My offset is not the begin of the whole structure, but only the offset of the text witch is on ChatStuctureStart+0x3C

  8. #8
    bjl66733's Avatar Member
    Reputation
    1
    Join Date
    Jan 2009
    Posts
    1
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Isn't there a way to hook onto the function that handles message directly

    As the title says, this code below is what manages the in game messages.
    I've been trying to latch onto it directly, it'll work for random periods then the game crashes which I still haven't been able to track down yet. My function prototype may be incorrect. Not included here.

    Code:
    CPU Disasm
    Address   Hex dump          Command                                  Comments
    004A39D0  /$  55            PUSH EBP
    004A39D1  |.  8BEC          MOV EBP,ESP
    004A39D3  |.  53            PUSH EBX
    004A39D4  |.  33DB          XOR EBX,EBX
    004A39D6  |.  391D 287FB600 CMP DWORD PTR DS:[0B67F28],EBX
    004A39DC  |.  75 47         JNE SHORT 004A3A25
    004A39DE  |.  B8 9CE9B000   MOV EAX,OFFSET Wow.00B0E99C
    004A39E3  |>  8958 F4       /MOV DWORD PTR DS:[EAX-0C],EBX
    004A39E6  |.  8958 F8       |MOV DWORD PTR DS:[EAX-8],EBX
    004A39E9  |.  8958 FC       |MOV DWORD PTR DS:[EAX-4],EBX
    004A39EC  |.  8818          |MOV BYTE PTR DS:[EAX],BL
    004A39EE  |.  8858 30       |MOV BYTE PTR DS:[EAX+30],BL
    004A39F1  |.  8898 E80B0000 |MOV BYTE PTR DS:[EAX+0BE8],BL
    004A39F7  |.  8998 A0170000 |MOV DWORD PTR DS:[EAX+17A0],EBX
    004A39FD  |.  8998 A4170000 |MOV DWORD PTR DS:[EAX+17A4],EBX
    004A3A03  |.  8998 A8170000 |MOV DWORD PTR DS:[EAX+17A8],EBX
    004A3A09  |.  8998 AC170000 |MOV DWORD PTR DS:[EAX+17AC],EBX
    004A3A0F  |.  05 C0170000   |ADD EAX,17C0
    004A3A14  |.  3D 9C7AB600   |CMP EAX,OFFSET Wow.00B67A9C
    004A3A19  |.^ 7C C8         \JL SHORT 004A39E3
    004A3A1B  |.  C705 287FB600 MOV DWORD PTR DS:[0B67F28],1
    004A3A25  |>  8B55 08       MOV EDX,DWORD PTR SS:[ARG.1]
    004A3A28  |.  3BD3          CMP EDX,EBX
    004A3A2A  |.  0F84 DF000000 JE 004A3B0F
    004A3A30  |.  8B45 0C       MOV EAX,DWORD PTR SS:[ARG.2]
    004A3A33  |.  50            PUSH EAX                                 ; /Arg1 => [ARG.2]
    004A3A34  |.  E8 47D7FFFF   CALL 004A1180                            ; \Wow.004A1180
    004A3A39  |.  83C4 04       ADD ESP,4
    004A3A3C  |.  85C0          TEST EAX,EAX
    004A3A3E  |.  0F84 CB000000 JE 004A3B0F
    004A3A44  |.  8B4D 10       MOV ECX,DWORD PTR SS:[ARG.3]
    004A3A47  |.  56            PUSH ESI
    004A3A48  |.  8B35 247FB600 MOV ESI,DWORD PTR DS:[0B67F24]
    004A3A4E  |.  69F6 C0170000 IMUL ESI,ESI,17C0
    004A3A54  |.  81C6 90E9B000 ADD ESI,OFFSET Wow.00B0E990
    004A3A5A  |.  3BCB          CMP ECX,EBX
    004A3A5C  |.  75 05         JNE SHORT 004A3A63
    004A3A5E  |.  B9 4F749C00   MOV ECX,OFFSET Wow.009C744F
    004A3A63  |>  8B45 24       MOV EAX,DWORD PTR SS:[ARG.8]
    004A3A66  |.  3BC3          CMP EAX,EBX
    004A3A68  |.  75 05         JNE SHORT 004A3A6F
    004A3A6A  |.  B8 4F749C00   MOV EAX,OFFSET Wow.009C744F
    004A3A6F  |>  57            PUSH EDI
    004A3A70  |.  8B7D 18       MOV EDI,DWORD PTR SS:[ARG.5]
    004A3A73  |.  52            PUSH EDX
    004A3A74  |.  8B55 14       MOV EDX,DWORD PTR SS:[ARG.4]
    004A3A77  |.  57            PUSH EDI
    004A3A78  |.  52            PUSH EDX
    004A3A79  |.  51            PUSH ECX
    004A3A7A  |.  50            PUSH EAX
    004A3A7B  |.  8B45 0C       MOV EAX,DWORD PTR SS:[ARG.2]
    004A3A7E  |.  50            PUSH EAX
    004A3A7F  |.  68 98D59D00   PUSH OFFSET Wow.009DD598                 ; ASCII "Type: [%d], Channel: [%s], Player Name: [%s], Sender GUID: [%016I64X], Text: [%s]"
    004A3A84  |.  8D4E 3C       LEA ECX,[ESI+3C]
    004A3A87  |.  68 B80B0000   PUSH 0BB8
    004A3A8C  |.  51            PUSH ECX
    004A3A8D  |.  E8 9EE72500   CALL 00702230
    004A3A92  |.  8B55 08       MOV EDX,DWORD PTR SS:[ARG.1]
    004A3A95  |.  83C4 24       ADD ESP,24
    004A3A98  |.  68 B80B0000   PUSH 0BB8                                ; /Arg3 = 0BB8
    004A3A9D  |.  52            PUSH EDX                                 ; |Arg2 => [ARG.1]
    004A3A9E  |.  8D86 F40B0000 LEA EAX,[ESI+0BF4]                       ; |
    004A3AA4  |.  50            PUSH EAX                                 ; |Arg1
    004A3AA5  |.  E8 C6E42500   CALL 00701F70                            ; \Wow.00701F70
    004A3AAA  |.  53            PUSH EBX                                 ; /Arg1
    004A3AAB  |.  E8 10413C00   CALL 00867BC0                            ; \Wow.00867BC0
    004A3AB0  |.  8B4D 14       MOV ECX,DWORD PTR SS:[ARG.4]
    004A3AB3  |.  8B55 1C       MOV EDX,DWORD PTR SS:[ARG.6]
    004A3AB6  |.  8986 B8170000 MOV DWORD PTR DS:[ESI+17B8],EAX
    004A3ABC  |.  8B45 0C       MOV EAX,DWORD PTR SS:[ARG.2]
    004A3ABF  |.  8986 AC170000 MOV DWORD PTR DS:[ESI+17AC],EAX
    004A3AC5  |.  8B45 10       MOV EAX,DWORD PTR SS:[ARG.3]
    004A3AC8  |.  83C4 04       ADD ESP,4
    004A3ACB  |.  3BC3          CMP EAX,EBX
    004A3ACD  |.  890E          MOV DWORD PTR DS:[ESI],ECX
    004A3ACF  |.  8B4D 20       MOV ECX,DWORD PTR SS:[ARG.7]
    004A3AD2  |.  897E 04       MOV DWORD PTR DS:[ESI+4],EDI
    004A3AD5  |.  8956 08       MOV DWORD PTR DS:[ESI+8],EDX
    004A3AD8  |.  898E B0170000 MOV DWORD PTR DS:[ESI+17B0],ECX
    004A3ADE  |.  5F            POP EDI
    004A3ADF  |.  74 0C         JE SHORT 004A3AED
    004A3AE1  |.  6A 30         PUSH 30                                  ; /Arg3 = 30
    004A3AE3  |.  50            PUSH EAX                                 ; |Arg2 => [ARG.3]
    004A3AE4  |.  8D56 0C       LEA EDX,[ESI+0C]                         ; |
    004A3AE7  |.  52            PUSH EDX                                 ; |Arg1
    004A3AE8  |.  E8 83E42500   CALL 00701F70                            ; \Wow.00701F70
    004A3AED  |>  8B45 28       MOV EAX,DWORD PTR SS:[ARG.9]
    004A3AF0  |.  8986 B4170000 MOV DWORD PTR DS:[ESI+17B4],EAX
    004A3AF6  |.  A1 247FB600   MOV EAX,DWORD PTR DS:[0B67F24]
    004A3AFB  |.  83C0 01       ADD EAX,1
    004A3AFE  |.  83F8 3C       CMP EAX,3C
    004A3B01  |.  A3 247FB600   MOV DWORD PTR DS:[0B67F24],EAX
    004A3B06  |.  5E            POP ESI
    004A3B07  |.  7C 06         JL SHORT 004A3B0F
    004A3B09  |.  891D 247FB600 MOV DWORD PTR DS:[0B67F24],EBX
    004A3B0F  |>  5B            POP EBX
    004A3B10  |.  5D            POP EBP
    004A3B11  \.  C3            RETN
    So what I'm trying to figure out is what prototype the function might be, any suggestions ? I'm not very good at asm.

  9. #9
    deCutter's Avatar Member
    Reputation
    5
    Join Date
    Apr 2009
    Posts
    17
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    i tryed to update this to 3.3.3 and found that people in info dump thread just post ChatBufferStart and NextMessage, but skip ChatBufferPos variable.
    Is there another method to understand that we got a new message without ChatBufferPos that people use?
    Anyway, i found that for 3.3.3
    ChatBufferPos = 0xC4D4A4;

  10. #10
    WiNiFiX's Avatar Banned
    Reputation
    242
    Join Date
    Jun 2008
    Posts
    447
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Values that work for v18414 for me are, some may be slightly off but i haven't had an issue yet.

    // Starting point of the chat buffer memory
    private static int Buffer = 0xD67918;

    // The length of each record/offset to the next
    private static int MsgSize = 0x17C8;

    // This holds the current position in the chat buffer
    private static int Position = 0xDC1090;

    Code:
       [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct WowChatMsg
        {
            public UInt64 SenderGuid;  
                                    
            public UInt32 Unknown1;
            public UInt32 Unknown2;
            public UInt16 Unknown3;
            public UInt16 Unknown4;
    
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 49)]    
            public string senderName;
    
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 3000)]
            public string formattedMsg;
    
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 3000)]
            public string plaintextMsg;
    
            public UInt32 type;
            public UInt32 channelNr;
            public UInt32 time;        
        }
    to get the server time the value above I use the below code, which seems to work but does look odd to me

    Code:
    private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
    
    public static DateTime DateTimeFromUnixTimestampSeconds(long seconds)
    {
         return UnixEpoch.AddSeconds(seconds).AddHours(-13).AddMinutes(-9);
    }
    Last edited by WiNiFiX; 09-14-2014 at 04:42 AM.

Similar Threads

  1. Chat buffer and real id's
    By Vandra in forum WoW Memory Editing
    Replies: 4
    Last Post: 02-20-2012, 12:08 PM
  2. Replies: 5
    Last Post: 10-02-2009, 12:01 PM
  3. Few updates to WoW.Dev Memory Wiki
    By UnknOwned in forum WoW Memory Editing
    Replies: 11
    Last Post: 04-23-2009, 11:21 AM
  4. Memory Reading Chat, w/ help from an Add-On
    By Vector0 in forum WoW Memory Editing
    Replies: 6
    Last Post: 05-08-2008, 10:00 AM
  5. Client memory update when no focus?
    By skypa in forum WoW Memory Editing
    Replies: 0
    Last Post: 03-29-2008, 08:00 PM
All times are GMT -5. The time now is 08:42 PM. 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