MMOwned - World of Warcraft Exploits, Hacks, Bots and Guides

Homepage Register FAQ Members Mark Forums Read Advertise Marketplace FPSowned


Go Back   MMOwned - World of Warcraft Exploits, Hacks, Bots and Guides > World of Warcraft > Bots and Programs > WoW Memory Editing
Reload this Page Memory Reading Chat, w/ help from an Add-On
WoW Memory Editing WoW Memory Editing for learning purposes only.

Reply
 
LinkBack Thread Tools
Memory Reading Chat, w/ help from an Add-On
(#1)
Old
Vector0 is Offline
Private
Rep Power: 1
Reputation: 7
Vector0 is an unknown quantity at this point
 
Posts: 7
Join Date: Apr 2008
Memory Reading Chat, w/ help from an Add-On - 04-05-2008

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.
Reply With Quote

Donate to remove ads.
(#2)
Old
macintox is Offline
Site Donator
Rep Power: 2
Reputation: 30
macintox is on a distinguished road
 
Posts: 113
Join Date: Aug 2007
Location: France
04-06-2008

thanks, always dreamed of making a chat outside of the game +rape
Reply With Quote
(#3)
Old
Flos is Offline
Sergeant Major
Rep Power: 1
Reputation: 49
Flos is on a distinguished road
 
Posts: 146
Join Date: Feb 2008
04-07-2008

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
Reply With Quote
(#4)
Old
Vector0 is Offline
Private
Rep Power: 1
Reputation: 7
Vector0 is an unknown quantity at this point
 
Posts: 7
Join Date: Apr 2008
04-08-2008

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.
Reply With Quote
(#5)
Old
macintox is Offline
Site Donator
Rep Power: 2
Reputation: 30
macintox is on a distinguished road
 
Posts: 113
Join Date: Aug 2007
Location: France
04-08-2008

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
Reply With Quote
(#6)
Old
Vector0 is Offline
Private
Rep Power: 1
Reputation: 7
Vector0 is an unknown quantity at this point
 
Posts: 7
Join Date: Apr 2008
04-08-2008

Quote:
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.
Reply With Quote
(#7)
Old
lunitune is Offline
Site n00b.. (A leecher if I've been here for more than a month and can't earn 5 rep)
Rep Power: 1
Reputation: 3
lunitune is an unknown quantity at this point
 
Posts: 8
Join Date: Apr 2008
05-08-2008

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.
Reply With Quote
Reply

Donate to remove ads.

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are On



Powered by vBulletin® Version 3.7.2
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
vBulletin Skin developed by: vBStyles.com


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343