Memory Reading Chat, w/ help from an Add-On menu

Shout-Out

User Tag List

Results 1 to 7 of 7
  1. #1
    Vector0's Avatar Member
    Reputation
    7
    Join Date
    Apr 2008
    Posts
    7
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Memory Reading Chat, w/ help from an Add-On

    Note: This is my first post. I've been exploring memory reading for about a week now. Thanks to all who provided enough information to get me started! I haven't seen this technique documented, so hopefully it will help someone out.

    I wanted to monitor chat messages from a memory reading program. But I had no idea how, couldn't find any information, and the thought of reverse-engineering WoW's chatlog memory structures seemed daunting at best.

    However, it's really easy to get chat messages in a LUA add-on - and a lot of other information too. The problem is getting that information out of the add-on. Add-ons don't provide any direct means of sending data to another program, at least while WoW is running.

    I've seen some hackish ways around it, where an add-on displays data on the screen in a way that can easily be read by an external program. For example, creating a fixed grid of 1-pixel boxes, and changing their color to send data. Or converting the data to binary, then to a string where ones are represented by periods and zeroes by spaces, then displaying that in a textbox. But neither of these methods is suited for transferring large amounts of data. They are also prone to breakage if something covers that region of the screen, or if screen resolution changes.

    What we need is a more direct method. We're memory reading, so why not read LUA variables directly?

    LUA has two basic data types: strings and floating point numbers.

    In LUA, you cannot change part of an existing string variable, you can only assign it a new value. This means it's likely that the string will be stored at a new address each time it's changed. That's no good for us.

    But an array of floating point numbers holds promise. We can put a series of unique numbers at the beginning of the array, which gives a memory reading program a way to find the array. The rest of the array can store data we want to pass.

    Let's get down to business. I loaded the simplest chat add-on I could find as a template. Then I added this to the beginning:

    Code:
       local chatbuf;
    That's going to be our array. In the add-on initialization function, I then added:

    Code:
       chatbuf={};
       chatbuf[20000]=0;
       local l1;
       for l1=1,20000,1 do
          chatbuf[l1]=0;
          incptr();
       end
       chatbuf[3]=3494.38;
       chatbuf[2]=1982.44;
       chatbuf[1]=9918.71;
    Line 1 makes chatbuf an array. Line two makes it have 20,000 elements (from 1-20,000), since LUA automatically expands arrays when you set an element outside its existing bounds. Lines 4-7 initialize all elements to zero. Lines 8-10 assign a unique series of numbers to the beginning of the array, that our memory reader can search for to find the array. Note that I assigned these numbers in reverse, so the memory reader won't accidentally find these numbers in the proper order in our code, instead of the array.

    When we run this add-on, we'll have a nice neat array in memory, and we can easily find the beginning of it by searching for the unique numbers in the proper sequence. Each number is stored as an eight-byte double-precision float. Each array element is spaced 16 bytes apart.

    For my purpose of monitoring chat messages, I implemented a ring buffer. chatbuf[4] holds the head pointer. chatbuf[5-20000] holds the actual chat messages as well as some extra formatted data and delimiters, each character stored as a number.

    I added another global variable:

    Code:
       local chatptr=5;
    A function:

    Code:
       function incptr()
          chatptr=chatptr+1;
          if chatptr == 20001 then
             chatptr=5
          end
       end
    And at the beginning of the existing event handler that receives chat messages:

    Code:
       local msg2="[Dat:"..id..","..r..","..g..","..b.."]"..msg;	
       local l1;
       for l1=1,strlen(msg2),1 do
          chatbuf[chatptr]=strbyte(msg2,l1);
          incptr();
       end
       chatbuf[chatptr]=13;
       incptr();
       chatbuf[chatptr]=10;
       incptr();
       chatbuf[4]=chatptr;
    As for the memory reading program, I'm including only a brief description. On startup, it locates the start of the array, and reads the head pointer. Any time that pointer changes, it reads data until it catches up with the new pointer. Then it parses the data to break it into lines and retrieve the Dat, r, g, and b variables.

    That's it! This technique can be used to pass lots of other data too, which is easily accessible in a LUA add-on, but hard to get with memory reading alone.

    Although I'm moving on to other challenges at the moment, here's something something interesting I'll be looking into later. It may interest you as well, and if you explore it before I do, please reply.

    Note that the array elements are stored 16 bytes apart, whereas the actual value only takes up 8 bytes. LUA arrays aren't typed and are heterogenous, meaning you can store a number or a string to any element. It's likely those 16 bytes contain a flag describing what type of data is stored in each element. In the case of a number, the actual number is stored; but in the case of a string, the string pointer may be stored. This might allow a more direct method of passing strings to a memory reading program.

    Memory Reading Chat, w/ help from an Add-On
  2. #2
    macintox's Avatar Member
    Reputation
    30
    Join Date
    Aug 2007
    Posts
    113
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    thanks, always dreamed of making a chat outside of the game +rape

  3. #3
    Flos's Avatar Member
    Reputation
    49
    Join Date
    Feb 2008
    Posts
    146
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Currently experimenting with this method. The idea is very good, but have the following problem:

    Memory-scanning is just really really slow ( specially with AutoIT - that's unfortunatly ^^ what I'm working with). So it takes a really long time to locate the array.

    Trying to minimize the search-area now - if this doesn't work.. well then I have to use another language...
    anyway + rep for the idea

  4. #4
    Vector0's Avatar Member
    Reputation
    7
    Join Date
    Apr 2008
    Posts
    7
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Experimentation continues, and I have a few more details to share.

    1) The address of each floating point number is guaranteed to be divisible by 8. This speeds up searching. In my memory reading program, I'm reading blocks of memory into an array of floats, then searching the array. This is quite fast, I'm now able to find the address of the LUA array in less than a second.

    2) You *can* put strings in LUA array elements and read them! If an array element holds a string instead of a float, read a 4-byte pointer from the same address the float would have been stored in:

    [PTR]+0x10 - Length of the string, 4-byte integer
    [PTR]+0x14 - The string, one byte per char, null terminated

    Length does not include the null terminator. I haven't looked into dynamically determining whether a LUA array element holds a float or a string, as I'll always know that in advance.

    3) Unfortunately, the LUA array occasionally moves. This is probably a result of some internal garbage collection. While playing in one area, I've seen it move as frequently as 10 minutes, or stay put for more than an hour. So now, before I read from the array, I verify that the expected unique numbers are still there. If not, I rescan.

  5. #5
    macintox's Avatar Member
    Reputation
    30
    Join Date
    Aug 2007
    Posts
    113
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    can you release the whole addon? (I don't know a single about coding add-ons) in order to try to do a pointer scan to fasten the search the thing i always wanted is to code a programme that comunicate the chat log to a website
    thanks in advance

  6. #6
    Vector0's Avatar Member
    Reputation
    7
    Join Date
    Apr 2008
    Posts
    7
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by macintox View Post
    can you release the whole addon? (I don't know a single about coding add-ons)
    I don't know much about coding add-ons either. That's why I took an existing add-on that already intercepts chat messages, and just added my own code to it.

    I'm not sure what the etiquette here is regarding posting someone else's add-on code, in its entirety, with your own changes. Also, I prefer to post code fragments rather than complete code, for my own paranoid reasons.

    But I'll tell you this. Start with an add-on called "Chat Timestamp". Take a look at how it works. It's small and easy to figure out, so it's a perfect starting point. Then add the code fragments I posted in the 1st message in the places I described, which should be obvious once you've inspected the add-on. That's it, you've just replicated my first working version.

  7. #7
    lunitune's Avatar Member
    Reputation
    3
    Join Date
    Apr 2008
    Posts
    17
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thank you for sharing that with us V0, what a great idea.

    I tried passing info like chat messages via a LUA array but got stuck as the array moves around in memory. I presumed it was to do with strings being immutable.

    This looks like it'll get around that.

    ---

    The addon need not be fancy. Unless things have changed you can easily register your addon to receive chat messages.

    Code:
    local RemoteCommanderFrame = CreateFrame("Frame");  --set up invis frame to hold me event registrations
    	RemoteCommanderFrame:SetScript("OnEvent", RemoteCommanderEvents);	--set my event handler
    	RemoteCommanderFrame:RegisterEvent("CHAT_MSG_CHANNEL");
    	RemoteCommanderFrame:RegisterEvent("UI_ERROR_MESSAGE");
    	RemoteCommanderFrame:Show();
    When one of the 2 events registered fires the following function is called.

    Code:
    function RemoteCommanderEvents()
    	if (event == "CHAT_MSG_CHANNEL") then
    		if (arg9 == "mychannelname" and gCommanded == true) then
    			  ParseIncomingChat(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9);
    		end -- end if
    	elseif (event == "UI_ERROR_MESSAGE") then
    		if (arg1 == "You must be standing to do that") then
    			gMyCharacter.Sitting = true;
    		end --end if
    	end -- end event
    	
    end  --end MyEvents
    Which can be added to the array as per the great instructions above.

Similar Threads

  1. [C#]Need help with some memory reading
    By jazerix in forum Programming
    Replies: 1
    Last Post: 10-29-2010, 09:49 AM
  2. [C#/CE help] Need help with memory reading
    By dididii in forum Programming
    Replies: 0
    Last Post: 10-07-2010, 12:26 PM
  3. [C++ Help] Memory Reading
    By snigelmannen in forum Programming
    Replies: 1
    Last Post: 10-04-2010, 05:57 PM
  4. [help] reading chat pane (for zeppelin arrivals)
    By korknob in forum WoW Memory Editing
    Replies: 2
    Last Post: 05-17-2008, 06:00 AM
All times are GMT -5. The time now is 01:06 AM. 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