-
Warden Private Server Script
Was reading over reliasn post about a program being detected on a private server and found it interesting.
Originally Posted by
reliasn
Code:
if(issecure())then SendAddonMessage('B7da',"teFz",'WHISPER','l0l')else SendAddonMessage('B7da',"Vgp8",'WHISPER','l0l')end
e='MACRO_ACTION_FORBIDDEN'l={GetFramesRegisteredForEvent(e)}m=getn(l)for i=1,m do l[i]:UnregisterEvent(e)end RunScript([[XxQP="/run SendAddonMessage('ymMb','o7IB','WHISPER','l0l')"]])RunMacroText(XxQP)for i=1,m do l[i]:RegisterEvent(e)end
if(PQR_EventFrame~=nil)then SendAddonMessage('jM9I',"4hJ7",'WHISPER','l0l')else SendAddonMessage('jM9I',"H9wl",'WHISPER','l0l')end
Above is a script that warden executes on the client. It looks like it does some checks and then whispers the player l0l with a tag and message. I'm guessing the tag is the check id and the message is the result.
Check 1:
Determinates if current environment is secure or "tainted." A secure environment is required to call Protected functions.
API issecure | WoWWiki | FANDOM powered by Wikia
I'm guessing that the call is from a nonsecure environment, like how an addon or macro is called. So this could detect a lua unlocker? I would think patching code would not trigger this. Or is it the other way around, does some hack disable this vs patching code?
Check 2:
Code:
GetFramesRegisteredForEven('MACRO_ACTION_FORBIDDEN')
Returns all frames registered for "event", in the order they will actually receive it.
API GetFramesRegisteredForEvent | WoWWiki | FANDOM powered by Wikia
MACRO_ACTION_FORBIDDEN Sent when a macro tries use actions that are always forbidden
Events/M | WoWWiki | FANDOM powered by Wikia
This one I'm a little lost on. Does this event get set even if you patch lua? I feel like this would only get set when wow prompts you with the protected lua error message box. I also don't get why they UnregisterEvent, whisper, then RegisterEvent again.
Check 3:
Code:
PQR_EventFrame~=nil
Straightforward I guess, a detection for a specific hack, ie pqr.
The last check could be hard to bypass if they have a bank of 100 different artifacts. The only easy way I can think of would be to proxy all requests to a clean client.
Just wanted to see if anyone had any information on it before I jump into it. Still need to get the wotlk client and a Warmane account.
---edit
Tested,
Code:
/run JumpOrAscendStart(); e='MACRO_ACTION_FORBIDDEN'l={GetFramesRegisteredForEvent(e)}m=getn(l) DEFAULT_CHAT_FRAME:AddMessage("num " .. m);
output was 0, guess I'm missing something...
Last edited by DarkLinux; 02-13-2018 at 06:59 PM.
-
Post Thanks / Like - 4 Thanks
-
Active Member
The first one checks if your environment is secure (able to use protected API). The 2nd one is to test protected API functions covertly by first unregistering all frame of the MACRO_ACTION_FORBIDDEN so that the client does not see it happen when a protected API runs (in this example RunScript and RunMacroText), and then re-registering them again. The third is quite obvious.
-
Post Thanks / Like - 2 Thanks
DarkLinux,
bynike (2 members gave Thanks to Numba1stunna1 for this useful post)
-
Originally Posted by
Numba1stunna1
The first one checks if your environment is secure (able to use protected API). The 2nd one is to test protected API functions covertly by first unregistering all frame of the MACRO_ACTION_FORBIDDEN so that the client does not see it happen when a protected API runs (in this example RunScript and RunMacroText), and then re-registering them again. The third is quite obvious.
Right, but what would be the reasoning behind checking if the environment is secure? I don't know how this script is being executed, so I don't know the environment state. Like is it a check for some lua unlocker or is it a check for RunMacroText. But I guess if they are unregistering events then calling RunMacroText would normally create an error. And if lua is patched then the script would execute and then they would get the message. So issecure must be a check for another type of unlocker, or sometimes the environment can be different voiding check 2?
Last edited by DarkLinux; 02-13-2018 at 07:55 PM.
-
I've been monitoring Warden packets for a while now and this is the entire list of strings that I have saved in my database: Paste2.org - Viewing Paste wDYINatW
It contains DLL names, drivers, Lua scripts, MPQ/ADT/M2 checks, etc.
For example, there's this script used by Tauri WoW (5.4.8 private server) that iterates all messages in your chat and checks if there's some known string, like "EWT" or "PQR".
Code:
_=(function() if ChatFrame1 == nil then return \"ENF\" end c=ChatFrame1:GetNumMessages() for i=1,c do t=ChatFrame1:GetMessageInfo(i) if string.find(t,\"\\|cFF32CD32EWT\") ~= nil then return \"EF\" end end return \"ENF\" end)()
_=(function() if ChatFrame1 == nil then return \"PNF\" end c=ChatFrame1:GetNumMessages() for i=1,c do t=ChatFrame1:GetMessageInfo(i) if string.find(t,\"\\124cffff7d0a<\\124r\\124cffffd200PQR\") ~= nil then return \"PF\" end end return \"PNF\" end)()
In Cata, Warden got upgraded to that BLL2 thing and I believe the Lua scan also changed a bit. You can see that the scripts have returns in them, so I suppose it sends back to the server the result. On 3.3.5 however, Warden doesn't send back the result and simply runs the script. I suppose this is why Warmane used SendAddonMessage to notify the server.
Anyways, all these scripts are run by FrameScript_Execute which is called by the Warden module. I've heard in the past that there was a check in Warden that used FrameScript_GetText but I haven't seen this one yet.
-
Post Thanks / Like - 4 Thanks
-
Contributor
Originally Posted by
reliasn
In Cata, Warden got upgraded to that BLL2 thing.
The GetText check is definitely possible(even on 1.12.1), If you have a working struct for whatever module is loaded you can check generally check if its being used by checking if the function pointer is set:
Code:
for 79c0768d657977d697e10bad956cced1
struct Warden
{
void *vmt;
char m_key[16];
MemoryFunctions *fnMemoryFunctions;
WardenLib *m_WardenLib;
void *m_ModRecv;
CryptState m_sCryptState;
unk_vmt **m_fnMemoryFunctions;
char m_stringsBuffer[512];
int m_dataLength;
int m_stringsLength;
char m_dataBuffer[512];
WardenPacket m_stringsPkt;
WardenPacket m_dataPkt;
WardenResponse m_response;
char data04[256];
int data04_len;
char field_770[64];
int m_pageCheck;
int field_7B4;
int m_pageCheckHandler;
FunctionPointers1 fnFunctionPointers1;
FunctionPointers2 fnFunctionPointers2;
FunctionPointers3 fnFunctionPointers3;
};
struct FunctionPointers2
{
int GetText1;
int GetText2;
};
I'm guessing there was two because of legacy support reasons since different versions of Wow seem to have different versions of the GetText function.
Code:
int (__fastcall *)(char *, _DWORD, _DWORD) // Function1
int (__cdecl *)(char *, _DWORD, _DWORD) // Function2
These function pointers are set during the module initialization packet, So if warden is loaded, and these are not set, the server obviously isn't using it.
EDIT: LightsHope has it set as 0x00703BF0 which is definitely the real GetText:
Code:
00703BF0 const char *__fastcall FrameScript_GetText(const char *, int, int)
EDIT2: I forgot to point out, I've seen allot of private servers that use a copy paste of tom_rus warden implementation and never update the offset for GetText used in his source code:
Code:
Request.Command2 = WARDEN_SMSG_MODULE_INITIALIZE;
Request.Size2 = 8;
Request.CheckSumm2 = BuildChecksum(&Request.Unk2, 8);
Request.Unk3 = 4;
Request.Unk4 = 0;
Request.String_library2 = 0;
Request.Function2 = 0x00419D40; // 0x00400000 + 0x00419D40 FrameScript::GetText
Request.Function2_set = 1;
So sometimes the function may be set but not valid.
Last edited by danwins; 02-14-2018 at 12:44 AM.
-
Post Thanks / Like - 6 Thanks
-
Prior to Cataclysm, Warden has only a FrameScript::GetText function. In TBC and Wotlk (but not Classic), that scan can be co-opted to use FrameScript::Execute instead. You have two choices for calling convention:
Code:
const char * (__fastcall *)(str, 0, 0)
const char * (__cdecl *)(str, 0, 0)
Neither of these are compatible with FrameScript::Execute in classic, which is:
Code:
int FrameScript_Execute(int a1, int a2, const char *a3, ...)
Cataclysm saw the introduction of ASLR, which presumably necessitated an update to Warden. I assume when they dusted off the Warden code, they saw fit to add two new checks. One of them gives the ability to call FrameScript::Execute directly, and report back the value of a given variable.
Last edited by namreeb; 02-14-2018 at 03:46 AM.
-
Post Thanks / Like - 5 Thanks
-
Member
On one of the servers WoW-Circle installed warden anti-cheat on pqr you can like that this unit can even be bypassed and for money I have nothing to do with programming I want to ask maybe this?
-
Originally Posted by
namreeb
Code:
const char * (__fastcall *)(str, 0, 0)
const char * (__cdecl *)(str, 0, 0)
Never noticed that you could set the environment state when calling FrameScript::Execute. So they are limited to what macros can do. But still, OP if you ask me, having access to thing like SetCVar/GetCVar.
-
Originally Posted by
DarkLinux
Never noticed that you could set the environment state when calling FrameScript::Execute. So they are limited to what macros can do. But still, OP if you ask me, having access to thing like SetCVar/GetCVar.
You can't really. To clarify, the zeros in my previous post indicate how Warden calls the function pointers. It means that the second and third arguments passed are always zero. This means:
In classic, state (which I think is the first argument?) is the only thing you could set. You couldn't give any code to execute.
In TBC and WotLK, state is the third parameter, which is always set to zero. I think this corresponds to protected execution.
There is no way to set both the state and the code to execute.
-
I tested in classic,
Code:
FrameScript__Execute(command, command);
vs
Code:
FrameScript__Execute(command, 0);
When the 2nd arg is 0 I cant execute protected lua APIs. So I guess it's not setting the sate but executing it from a different environment, I should really revers how it works. And classic is not the best example as warden does not even support it.
-
Originally Posted by
reliasn
Code:
_=(function() if ChatFrame1 == nil then return \"ENF\" end c=ChatFrame1:GetNumMessages() for i=1,c do t=ChatFrame1:GetMessageInfo(i) if string.find(t,\"\\|cFF32CD32EWT\") ~= nil then return \"EF\" end end return \"ENF\" end)()
_=(function() if ChatFrame1 == nil then return \"PNF\" end c=ChatFrame1:GetNumMessages() for i=1,c do t=ChatFrame1:GetMessageInfo(i) if string.find(t,\"\\124cffff7d0a<\\124r\\124cffffd200PQR\") ~= nil then return \"PF\" end end return \"PNF\" end)()
Was thinking about this more, they must auto ban for typing that into trade chat. I remember seeing some gold spammer use different colored text in global chat so I would think you could also.
-
Contributor
Originally Posted by
namreeb
Prior to Cataclysm, Warden has only a FrameScript::GetText function. In TBC and Wotlk (but not Classic), that scan can be co-opted to use FrameScript::Execute instead. You have two choices for calling convention:
Code:
const char * (__fastcall *)(str, 0, 0)
const char * (__cdecl *)(str, 0, 0)
Neither of these are compatible with FrameScript::Execute in classic, which is:
Code:
int FrameScript_Execute(int a1, int a2, const char *a3, ...)
...
Originally Posted by
DarkLinux
I tested in classic,
Code:
FrameScript__Execute(command, command);
vs
...
It seems that there are more than one Framescript_Execute functions (at least 4 for the patch 3368 and 2 for the rest).
The mentioned two above are as follows:
Code:
int FrameScript_Execute(FrameScript_Object *frame, void *handler, const char *formatted_string, ...) @0x007026F0
, used at frame update, resize, onKeyPress, mouseClick, scroll, etc.
And the second one mentioned by dark (should be called global?) is:
Code:
int __fastcall FrameScript__Execute(const char *script, const char *script_name) @0x00704CD0
Thanks for the good topic btw.
Last edited by tutrakan; 02-15-2018 at 06:05 PM.
-
Post Thanks / Like - 1 Thanks
DarkLinux (1 members gave Thanks to tutrakan for this useful post)
-
Contributor
Originally Posted by
DarkLinux
Was thinking about this more, they must auto ban for typing that into trade chat. I remember seeing some gold spammer use different colored text in global chat so I would think you could also.
I'm not sure what you mean by trade chat, those are the messages displayed in the chat frame when you load them, usually just a lua script like:
Code:
DEFAULT_CHAT_FRAME:AddMessage("something something");
or
print("something something");
They are never sent to any chat channels, they are only added to the chat frame locally. hence why they enumerate the chat frame looking for known "XXX loaded" messages.
The ones he linked are looking for the "PQR loaded" or "EWT loaded" messages(or something similar).
Code:
string.find(t,\"\\|cFF32CD32EWT\")
string.find(t,\"\\124cffff7d0a<\\124r\\124cffffd200PQR\")
Id expect allot of false positives if you just blanket searched for the use of colors in chat channels since things like boss mods do this all the time.
Last edited by danwins; 02-15-2018 at 08:16 PM.
-
@danwins
My point was I could go write that to public chat and get other users flagged. I would hope they have a filter to not broadcast selected messages. Unless you cant send such colors.
-
Contributor
I guess its possible, but they could always filter :GetMessageInfo to include the channel its found in.
Code:
text, accessID, lineID, extraData = ScrollingMessageFrame:GetMessageInfo(index [, accessID])
Code:
chatType, chatTarget = ChatHistory_GetChatType(accessID)