View difference between Paste ID: WibsLyYh and hquqtHCf
SHOW: | | - or go back to the newest paste.
1
/*
2
** Stack-based Gmod script enforcer bypass
3
** (c) TEAM METALSLAVE RAGE CO.
4
**
5
** REVISION HISTORY
6
**
7
** 00/00/0000 initial implementation in private release as MSSEB.DLL
8
**
9
** MEET THE SCRIPT ENFORCER
10
**
11
** Due to a large amount of cheaters in Gmod servers running scripts like aimbots, wallhacks
12
** and so on, Garry Jewman finally decided to implement something called the Script Enforcer.
13
** Unfortunately, like everything he's created, it didn't work out as well as he had hoped.
14
**
15
** The function that blocks scripts is:
16
**
17
** bool __thiscall CScriptEnforcer::CanLoadScript( void* );
18
**
19
** THE BYPASS EXPLAINED
20
**
21
** Before the script enforcer can block a script, it first notifies us in the console via
22
** Msg. Msg will pass through some formatting functions before eventually landing at whatever
23
** has been initialized as the SpewOutputFunc. We change the SpewOutputFunc on it and when it
24
** is called, we check for returns to the script enforcer and rewrite them so the program returns
25
** into code that is specified in our bypass DLL (see below).
26
**
27
** When the Msg() call to the string is called, we catch it and redirect the code. When returning
28
** we pretend that the script was actually blocked by setting the "blocked" flag but returning 1,
29
** allowing the script to load.
30
**
31
** This only works on scripts that the server has blocked entirely. It does not work on
32
** scripts that are different from the server's due to multiple CRC and MD5 checks that
33
** run in-game.
34
**
35
** msseb.lib is cleared for public release.
36
** This source code is kept private for obvious reasons.
37
**
38
** No thanks to FPS, because we are ugly and you suck!
39
**
40
*/
41
 
42
#include <stdio.h>
43
#include <windows.h>
44
#include "convar.h"
45
#include "dbg.h"
46
 
47
static SpewOutputFunc_t ZeOldSpewOutput = 0; // the old function that handles debug msgs.
48
static UINT32 se_blockscriptaddr = 0; // the address where the script is blocked
49
static ConVar seb_enable ( "seb_enable", "0", FCVAR_SERVER_CANNOT_QUERY, "enable dat scriptenforcer bypass mufugga");
50
 
51
 
52
// GetStackPtr: obfuscated utility function for getting the stack pointer.
53
// this doesn't return the *exact* stack frame, but hey, it works.
54
static __stdcall UINT32* GetStackPointer() {
55
	UINT32 *stackptr;
56
	__asm {
57
		mov eax, esp
58
		mov stackptr, eax
59
	};
60
	return stackptr;
61
}
62
63
UINT8 SEBypass[20] = {
64
	0x83, 0xC4, 0x08,			// add esp, 8h
65
	0xC6, 0x46, 0x44, 0x01,		// set scriptenforce flag as blocked
66
	0xB0, 0x01,					// mov al, 1h to return TRUE
67
	0x5E,						// pop esi
68
	0x81, 0xC4, 0x08, 0x01, 0x00, 0x00,	// add esp, 108h
69
	0xC2, 0x08, 0x00,			// retn 8
70
};
71
72
73
/*
74
** ZeNewSpewOutput
75
** This is our new debug message handler. It just so happens that the
76
** Script Enforcer calls this before blocking a script.
77
*/
78
 
79
static SpewRetval_t ZeNewSpewOutput( SpewType_t type, const char* msg ) 
80
{
81
	if (strstr(msg,"ScriptEnforce:") && !strstr(msg, "CRC"))
82
	{
83
		Msg("ScriptEnforcer is attempting to block a script.\n");
84
		// get the stack pointer
85
		UINT32* theSp = GetStackPointer();
86
		Msg("ESP = %p\n", theSp);
87
88
		// If the script enforcer is trying to block something, step a few stack
89
		// frames and rewrite anything that's returning to the scriptenforcer
90
		// validation so it goes to the bypass code when retn is hit in Msg().
91
		// This verification is done to prevent false positives jumping into
92
		// code that crashes the thing hilariously.            
93
		int isFound = 0;
94
		for (int i = 0; i < 0x1000; i ++)
95
		{
96
			if (theSp[i] == se_blockscriptaddr)
97
			{
98
				theSp[i] = (UINT32)SEBypass;
99
				Msg("*** ScriptEnforcer tried to block a script. Stack modified.\n");
100
				isFound = 1;
101
				break;
102
			}
103
		}
104
		if (!isFound) Msg("ERROR: Couldn't find the return address in the stack!\n");
105
	}
106
107
	// jump off to the old spew output function
108
	return ZeOldSpewOutput( type, msg );
109
}
110
 
111
void SEBypasser_Init()
112
{
113
	// get the return address following the Msg()
114
	se_blockscriptaddr = (UINT32)GetModuleHandleA("client.dll");
115
	se_blockscriptaddr += 0x1CC22A;
116
117
	// get the original spew fcn using Msg (there's a pointer in there
118
	// to the output function). this is yet another module garry has no
119
	// control over so we can care less about what changes here.
120
	ZeOldSpewOutput = GetSpewOutputFunc();
121
122
	if (!ZeOldSpewOutput) {
123
		Msg("Old spew function was ZERO\n");
124
		return;
125
	}
126
127
	// Switch the output on us. All messages now go through our filter.
128
	SpewOutputFunc( ZeNewSpewOutput );
129
130
	// just let the user know that we initialized the module OK.
131
	Msg("*** msseb.lib built " __DATE__ " " __TIME__" ***\n");
132
	Msg("(c) 2010 TEAM METALSLAVE RAGE CO.\n");
133
	Msg("this software is provided to you without warranty or terms.\n");
134
	Msg("see msseb.txt for further information.\n");
135
}