-
Retail Questions
Hello, i have a few questions about retail / classic.
1: i understand some base lua functions use a func that i call lua_retcheck to see where a call is being made from, i know if we patch them out, it can be scanned by warden but i was wondering if i just patch then unpatch after calling the func will that be safe or should i just go down the nesting doll road and rebuild Pcall and LoadBuffer.
2: patching the crc checks, I've seen people patch this on different posts but isnt patching this detectable? i feel like this would be the first thing blizzard looks for when trying to detect bots.
3: may be a stupid question but if i recreate my functions and not touch anything that uses lua_retcheck, how safe would i be? or does blizzard have a way to see all registerfunctions / metatables in use and if count isnt = to set number, they detect.
4: is using kernel to bypass anti debugging the best way to get debugging working or is there other ways to do it?
-
Member
This reply is for Dragonflight, which was the last time I did this, just wanted to pickup wow again yesterday… probably still holds true, but feel free to call me out if not!
For 1. There are two things I encountered, are you talking about the range check that checks where a registered function is called from and crashed with something like Invalid Pointer or something similar? Or are you talking about the div by 0 trap?
The first can be patched and restored, which likely is monitored, haven’t found a proof for that though. I just made sure my registered functions always have been in that range.
For the div/0 crash I just reimplemented the functions that have this check, its really just a few ones, atleast for everything I’m using like pcall, createtable and pushcfunction.
Lua is very well documented and straightforward to rebuild, the only change I saw for the wow implementation is the taint stuff.
Depending on how/when you call lua be sure to do it either on from somewhere the main thread the lua state is not threadsafe. If you only call it the „regular“ way from inside a wow lua frame, you won’t have to think about this.
2. I can’t comment on, never done that.
3. I haven’t seen anything like that in the register and createtable functions, as said in 1. I recreated them and just pushed the functions/tables my self to the lua state. You can get away with only registering only a single function that can be the entry point to as many functions you need, just forward the funcname and arguments through the one and call them from inside.
4. is something I’m interested myself in, live debugging would make things a lot easier.
-
Contributor
Originally Posted by
Makkah
Hello, i have a few questions about retail / classic.
1: i understand some base lua functions use a func that i call lua_retcheck to see where a call is being made from, i know if we patch them out, it can be scanned by warden but i was wondering if i just patch then unpatch after calling the func will that be safe or should i just go down the nesting doll road and rebuild Pcall and LoadBuffer.
2: patching the crc checks, I've seen people patch this on different posts but isnt patching this detectable? i feel like this would be the first thing blizzard looks for when trying to detect bots.
3: may be a stupid question but if i recreate my functions and not touch anything that uses lua_retcheck, how safe would i be? or does blizzard have a way to see all registerfunctions / metatables in use and if count isnt = to set number, they detect.
4: is using kernel to bypass anti debugging the best way to get debugging working or is there other ways to do it?
1) unlikly this would work, the checks are run very frequently , it probably wouldnt be reliable.
2) This works but as you know is a big detection vector.
3) yes this works the only exception is the isvalidptr check is run every time its called not just on registration.
4) I attempted this with inifintyhook awhile back, I could never get it working 100%. attaching was fine but actually setting/stepping through breakpoints never worked.
-
Hey
thank you for you're response, im still learning so a lot of these things for retail are new lol.
1: ill just remake pcall and loadbuffer, seems safer.
2: thanks for clarifying
3: i know about framescript::invaildpointer, i wonder if they do a check on the size, like if i just write the values to outside the .text or main module , will they check it. i know until i hook warden, i wont be able to hide patches and patching framescript::invaildpointer is gonna be one of there detection methods.
4: do you mind if i DM you about this subject? im trying to understand it better.
-
Contributor
Originally Posted by
Makkah
Hey
thank you for you're response, im still learning so a lot of these things for retail are new lol.
1: ill just remake pcall and loadbuffer, seems safer.
2: thanks for clarifying
3: i know about framescript::invaildpointer, i wonder if they do a check on the size, like if i just write the values to outside the .text or main module , will they check it. i know until i hook warden, i wont be able to hide patches and patching framescript::invaildpointer is gonna be one of there detection methods.
4: do you mind if i DM you about this subject? im trying to understand it better.
Sure DM me.
-
Post Thanks / Like - 1 Thanks
Makkah (1 members gave Thanks to aeo for this useful post)
-
Member
Originally Posted by
Makkah
Hey
thank you for you're response, im still learning so a lot of these things for retail are new lol.
1. ill just remake pcall and loadbuffer, seems safer.
3: i know about framescript::invaildpointer, i wonder if they do a check on the size, like if i just write the values to outside the .text or main module , will they check it. i know until i hook warden, i wont be able to hide patches and patching framescript::invaildpointer is gonna be one of there detection methods.
Did you reverse how you get into the function you are naming returncheck? its an unconditonal jmp after the valid epilogue of certain lua functions, right before retn would normally be..
So that very likely means it is a return adress check for the caller of the lua function which in turn means If you just make sure you call these from inside the valid range, you don't have to do bring in your own. This needs a bit of trickery though, setting up the call correctly and then returning to your caller at the end. Also making this generic at runtime is a pita.
imho its easier to just reverse the functions, and implement them on your own, as a bonus you'll learn about how the taint for the wow lua implementation works, which is good if you want to call protected functions at a later state too.
for 3. You could edit the range to be in range of your registered functions, this works and can be tested on trial acconts. But im pretty sure those two range locations are very closely monitored.. Also I didnt check if this is correct, but if you move the range completely outside the module you would probably crash instantly since all the legit wow lua registered functions would fall outside of the range.
That range check isn't as bad as the div/0 trap with the return address check, it just checks if the func ptr is in the valid range, so if you just make sure your function starts somewhere valid, you already passed the check, doesnt matter if that function then calls into others that are outside the range.
lmk if you need more hints.
EDIT: clarified some mixups between point 1 ond 3
Last edited by joshi205; 05-09-2025 at 04:20 AM.
-
Post Thanks / Like - 1 Thanks
ncxzxcfdb8112 (1 members gave Thanks to joshi205 for this useful post)
-
Member
getting crashed with invalid ptr check, would love some hints 😁
-
Code:
int64_t invaildPtr = Memory::RebaseAddress(InternalEnums::invalidFunctionPtr);
*(int64_t*)(invaildPtr) = 1;
*(int64_t*)(invaildPtr + 0x8) = -1;
-
Member
That whole thing always felt so off to me, with the patch beeing that easy and the values both beeing global, it has to be an intentional honeypot right?
But then why bother crashing? why not flag the user and ban them later?
-
IKR! for some random reason (from old patches, not retail.) warden doesnt have a read value method, i feel like reading a global value in memory is really easy and could be added to warden without doing very much.
-
Member
how do you "make sure your function starts somewhere valid", hardware breakpoint/virtual protect doesnt work
the only thing that worked for me was changing .text boundaries but then i would get crashed in 2 minutes
(nvm found the solution)
Last edited by ncxzxcfdb8112; 05-09-2025 at 10:55 AM.
-
Established Member
So, my personal stuff, which I've been using on retail for about 5 years now, I have just taken the lua source, tweaked the structures for the changes in wow, and just use it in my code for use. No need to pattern scan or use their functions.
As far as registering functions, you can use a proxy jump from the valid game region to a location you then call the correct function from. I only write to the game memory in 3 places in the .data (which are actively changing anyway), and have an advanced unlocker that provides same functionality as the paid ones out there. You can be extremely passive, and do everything, which in turn helps with the security. The whole thing is thinking outside the box
Last edited by scizzydo; 05-10-2025 at 11:29 AM.
-
Post Thanks / Like - 3 Thanks
-
Established Member
Originally Posted by
Makkah
IKR! for some random reason (from old patches, not retail.) warden doesnt have a read value method, i feel like reading a global value in memory is really easy and could be added to warden without doing very much.
What I've seen servers do is use the byte scan to read memory. You can have it read 4 (or 8 )bytes at a location, and then use that to get the pointer of whatever is there, and then scan against that. So, in a way it does exist in all iterations of warden out there. Just depends on if the server devs are smart enough to do that.
Last edited by scizzydo; 05-10-2025 at 12:12 PM.
-
Member
Originally Posted by
scizzydo
So, my personal stuff, which I've been using on retail for about 5 years now, I have just taken the lua source, tweaked the structures for the changes in wow, and just use it in my code for use. No need to pattern scan or use their functions.
As far as registering functions, you can use a proxy jump from the valid game region to a location you then call the correct function from. I only write to the game memory in 3 places in the .data (which are actively changing anyway), and have an advanced unlocker that provides same functionality as the paid ones out there. You can be extremely passive, and do everything, which in turn helps with the security. The whole thing is thinking outside the box
Can confirm, you can achieve what most of these unlockers and more without beeing intrusive, no hooking, no wild patches etc.
No pattern scan tho.. how? Im basically doing the same what you described here, and for that I do atleast need to know where the lua_state is.
And well, I'm using a few things like the intersect of the worldframe for line of sight checks, and then some other things, but even if you don't do any of that, you still need atleast the lua_state dont you? Or am I still thinking to inside the box?
-
Contributor
Originally Posted by
joshi205
Can confirm, you can achieve what most of these unlockers and more without beeing intrusive, no hooking, no wild patches etc.
No pattern scan tho.. how? Im basically doing the same what you described here, and for that I do atleast need to know where the lua_state is.
And well, I'm using a few things like the intersect of the worldframe for line of sight checks, and then some other things, but even if you don't do any of that, you still need atleast the lua_state dont you? Or am I still thinking to inside the box?
no you still need those. But you can avoid patterns for all the push string ,number etc….
-
Post Thanks / Like - 1 Thanks
joshi205 (1 members gave Thanks to aeo for this useful post)