The Black Tutorials-5)How to log client keybinds/modmenu

Get some cool tips about how to tweak your UT graphic, gameplay, and much more!
Post Reply
JackGriffin
Godlike
Posts: 3774
Joined: Fri Jan 14, 2011 1:53 pm
Personal rank: -Retired-

The Black Tutorials-5)How to log client keybinds/modmenu

Post by JackGriffin »

For this I'm going to post the code only. It's taken directly from the UTP project that Dane and I did. This code will log a joining player's list of keybinds as well as a list of his modmenu items. This will let you quickly scan for binds that are considered cheating as well as binds that would not be beneficial to allow on the server. A quick google search will show you all kinds of piped keybinds that can do behaviors you may not want on your server.

In order to log the keybinds you'll need to create two mods. One mod is public and will be shared to all joining players. It contains a few small functions that will run on the client to gather the information. The server side mod is never shared with the public and is used to parse the returns and log the information to the server.

First, lets do the client side mod. Here's the code for that:

Code: Select all

/////////////////////////////////////////
//
// UTPInfo
// Visit us at http://utrustedplayer.com/forum/
// There's nothing in here you haven't seen before...
//
// Mod fully based on HARInfo (C)2004 iDeFiX
// Used with permission, thank you sir
//
/////////////////////////////////////////

Class UTPInfo expands ReplicationInfo;

replication
{
   reliable if ( ROLE == ROLE_Authority)
      GetModMenus, GetKeyBinds;
}

simulated function GetModMenus(int k)
{
   local PlayerPawn pp;
   local int i;
   local string sEntry;
   local string sDescription;

   if (Owner!=None)
   {
      pp = PlayerPawn(Owner);
      if (pp!=None && pp.Player!=None && pp.Player.Console !=None)
      {
      	 i=0;
       	 pp.GetNextIntDesc("UMenu.UMenuModMenuItem",i,sEntry,sDescription);
       	 while (sEntry != "")
       	 {
            i++;
            if (sDescription != "")
  	    {
       	       pp.ConsoleCommand("MUTATE TP TPMM " $ k $ " " $ pp.PlayerReplicationInfo.PlayerId $ " " $ sEntry);
       	       pp.GetNextIntDesc("UMenu.UMenuModMenuItem",i,sEntry,sDescription);
      	    }
       	    else
      	    {
               pp.ConsoleCommand("MUTATE TP TPMM " $ k $ " " $ pp.PlayerReplicationInfo.PlayerId $ " " $ sEntry);
               pp.GetNextIntDesc("UMenu.UMenuModMenuItem",i,sEntry,sDescription);
            }
         }
      }
   }
}

simulated function GetKeyBinds(int k)
{
   local PlayerPawn pp;
   local int i;
   local string sKeyName;
   local string sAlias;
   local string sTemp;

   if (Owner!=None)
   {
      pp = PlayerPawn(Owner);
      if (pp!=None && pp.Player!=None && pp.Player.Console !=None)
      {
	 for (i=0; i<255; i++)
         {
            sKeyName = pp.ConsoleCommand("KEYNAME"@i);
	    if (sKeyName != "")
	    {
	       sAlias = pp.ConsoleCommand("KEYBINDING"@sKeyName);
	       if (InStr(sAlias, " ") > 0)
	       {
	          sTemp=Caps(Left(sAlias, InStr(sAlias, " ")));
	       }
	       else
               {
		  sTemp=Caps(sAlias);
	       }
	       if ( (Len(sAlias) > 0) )
	       {
		  pp.ConsoleCommand("MUTATE TP TPKB " $ k $ " " $ pp.PlayerReplicationInfo.PlayerId $ " " $ i $ ":" $ sAlias);
               }
            }
         }
      }
   }
}

defaultproperties
{
   NetPriority=10.00
}
So, what's going on here? Well this mod (when called upon by the server) will iterate through all of a player's keybinds and modmenus using the player's console. This information is replicated back to the server as each bind is opened and then closed and this allows the server to make an ordered list of them. It's all pretty straightforward.

Now the server side class:

Code: Select all

// Keybind logger
class UTP_KLMM extends Mutator config(UTP);

var bool bInitialised;
var string Players[32];


var config bool UseKeybindLogger;
Const MUTATORNAME = "UTrustedPlayers";
Const MUTATORVERSION = "0.1";

function PreBeginPlay ()
{
   Super.PreBeginPlay();
   SetTimer(1.0,True);
}

function PostBeginPlay()
{
   local int i;

   if (!bInitialised)
   {
      bInitialised = True;
      Level.Game.RegisterMessageMutator(Self);

      log("UTPv3: Keybind/ModMenu logger is active.");
   }
}

function Timer()
{
   local Pawn P;
   local int i;
   local bool bChecked;
   local UTPInfo a;

   for (P = Level.PawnList; P != None; P = P.NextPawn)
   	{
      	if ( P.IsA('PlayerPawn') )
      		{
	 	for ( i=0; i<32; i++ )
         		{
	    		if ( P.PlayerReplicationInfo.PlayerName == Players[i] )
            			{
	       			bChecked = True;
	       			break;
	    			}
	 		}
	 	if ( !bChecked )
         		{
	    		a = Spawn(class'UTPInfo',p,,p.Location);
            		if (a != None && UseKeybindLogger)
				{
               			a.GetKeyBinds(k);
               			a.GetModMenus(k);
				SkipPlayers(PlayerPawn(P));
				}
         		}
         	bChecked = False;
      		}
   	}
}

function SkipPlayers(PlayerPawn P)
{
   local int i;

   for ( i=0; i<32; i++ )
   	{
      	if ( Players[i] == "" )
      		{
         	Players[i] = P.PlayerReplicationInfo.PlayerName;
         	i = 500;	//make sure the array doesn't get full of the same players name	
      		}
   	}
}

function Mutate(string MutateString, PlayerPawn Sender)
{
   local string sArgument;
   local int iPlayerID;
   local int i;
   local int i1, i2;
   local Pawn p;
   local string sMode;
   local UTPInfo a;

   if (Left(Caps(MutateString),3) == "TP ")
   {
      // Parse mutatestring
      sArgument = Mid(MutateString, 3);

      // Info recieved from clients
      if (Left(Caps(sArgument), 5) == "TPKB ")
      {
	 sMode = Left(Caps(sArgument), 4);
	 if (sMode == "TPKB")
         {
	    sMode = "KeyBind";
	 }

         sArgument = Mid(sArgument, 5);
         i1 = InStr(sArgument, " ");
         if (i1>0)
         {
	    i2 = InStr(Mid(sArgument, i1+1), " ");
	 }
	 if ( (i1>0) && (i2>0) )
	 {
            iPlayerID = int(Mid(sArgument, i1+1, i2));
	    sArgument = Mid(sArgument, i1+i2+2);

	    if (sMode == "KeyBind")
	    {
	       p = GetPawnByPlayerID(iPlayerID);
	    }
	    if (p != None)
	    {
	       Log("** UTPv3 Report " $ sArgument $ "[" $ sMode $ "]");
	    }
         }
      }
      if (Left(Caps(sArgument), 5) == "TPMM ")
      {
         sMode = Left(Caps(sArgument), 4);
         if (sMode == "TPMM")
         {
	    sMode = "ModMenu";
         }

         sArgument = Mid(sArgument, 5);
         i1 = InStr(sArgument, " ");
	 if (i1>0)
         {
	    i2 = InStr(Mid(sArgument, i1+1), " ");
	 }
	 if ( (i1>0) && (i2>0) )
	 {
	    iPlayerID = int(Mid(sArgument, i1+1, i2));
	    sArgument = Mid(sArgument, i1+i2+2);

	    if (sMode == "ModMenu")
	    {
	       p = GetPawnByPlayerID(iPlayerID);
	    }
            if (p !=none)
            {
	       Log("** UTPv3 Report " $ sArgument $ "[" $ sMode $ "]");
	    }
	 }
      }
      if (Left(Caps(sArgument), 5) == "TPKK ")
      {
         // Message needs to be written with the kick ID
         Sender.ClientMessage("UTP has prohibited you from playing on this server.");
         Sender.Destroy();
      }
   }
   else
   {
      if (NextMutator != None)
      {
         NextMutator.Mutate(MutateString, Sender);
      }
   }
}

function Pawn GetPawnByPlayerID(int iPlayerID)
{
   local Pawn p;

   for (p=Level.PawnList; p!=None; p=p.NextPawn)
   {
      if ((p.bIsPlayer) && (p.PlayerReplicationInfo != None) && (p.PlayerReplicationInfo.PlayerID == iPlayerID))
      {
	 return (p);
      }
   }
   return (None);
}

defaultproperties
{
UseKeybindLogger=True
}
If you follow the code you'll see each player is polled to see if they have been checked or not. If they have then they are skipped, but if they haven't been checked then the call is made to run the client side code:
a.GetKeyBinds(k);
a.GetModMenus(k);

The code overall is pretty simple but it took a ton of testing to get it to perform and log correctly. Honestly I'm just too lazy to retrieve a sample log from my archive but it lists numerically into the server log file with the number of the keybind (not the letter, but that doesn't matter) and what the string value of that keybind is. For Modmenus it just lists them in order.

It used to be that older aimbots had keybinds associated with them but mainly we used this to find hacky shit people were doing with keybinds. Stuff like injecting lag or adjusting netspeed via a hotkey. Some of the things we saw were pretty scummy. Also I'd be remiss if I didn't say we found a lot of passwords people had saved into keybinds. Admin logins, things like that. People are just dumb and then they wonder why their servers were hacked. Now you see why it happens to them. SMH....

OK guys, be careful with this one. Don't do evil shit with it, please. I do feel like it's important to share this though so it doesn't get lost.
Last edited by JackGriffin on Mon May 23, 2016 2:03 pm, edited 1 time in total.
So long, and thanks for all the fish
User avatar
papercoffee
Godlike
Posts: 10443
Joined: Wed Jul 15, 2009 11:36 am
Personal rank: coffee addicted !!!
Location: Cologne, the city with the big cathedral.
Contact:

Re: The Black Tutorials-5)How to log client keybinds/modmenu

Post by papercoffee »

@Kelly
Reread your last line of text :mrgreen:
JackGriffin
Godlike
Posts: 3774
Joined: Fri Jan 14, 2011 1:53 pm
Personal rank: -Retired-

Re: The Black Tutorials-5)How to log client keybinds/modmenu

Post by JackGriffin »

I meant that as a subtle joke but yeah it reads wrong. SMH, I need to just give up humor. Changed it.
So long, and thanks for all the fish
User avatar
papercoffee
Godlike
Posts: 10443
Joined: Wed Jul 15, 2009 11:36 am
Personal rank: coffee addicted !!!
Location: Cologne, the city with the big cathedral.
Contact:

Re: The Black Tutorials-5)How to log client keybinds/modmenu

Post by papercoffee »

JackGriffin wrote:I meant that as a subtle joke but yeah it reads wrong. SMH, I need to just give up humor. Changed it.
humour is fine, but sometimes misleading or misinterpretable in a serious tutorial. :wink:
Higor
Godlike
Posts: 1866
Joined: Sun Mar 04, 2012 6:47 pm

Re: The Black Tutorials-5)How to log client keybinds/modmenu

Post by Higor »

Easiest bypass of my life.
JackGriffin
Godlike
Posts: 3774
Joined: Fri Jan 14, 2011 1:53 pm
Personal rank: -Retired-

Re: The Black Tutorials-5)How to log client keybinds/modmenu

Post by JackGriffin »

I respect you Higor but it's kind of empty bragging. Of course you can bypass anything I can put up. You are far smarter than I am, way better skilled, and have the background to support your effort.

I don't post this stuff as a "let's compare e-penis size". I'm just sharing what I personally have found over the years tinkering at the edge of what I can do. It doesn't do much good for people to keep posting "I could hack that" or "I could break that". If that's the idea here then there ought to be a contest or something. You guys can sort out who's the best. At least the discussions would follow and that's my intention here.
So long, and thanks for all the fish
MrLoathsome
Inhuman
Posts: 958
Joined: Wed Mar 31, 2010 9:02 pm
Personal rank: I am quite rank.
Location: MrLoathsome fell out of the world!

Re: The Black Tutorials-5)How to log client keybinds/modmenu

Post by MrLoathsome »

DAMN!! :mad2:

I was too slow and missed Jacks bad joke. Now it is gone....... :cry:

Bet a dollar I can bypass it also. (*I might have to ask Higor for advice......) :twisted:

I will have to sit out of any size comparisons for now, as the forum software would need larger buffers to
accommodate that.

8)
blarg
Higor
Godlike
Posts: 1866
Joined: Sun Mar 04, 2012 6:47 pm

Re: The Black Tutorials-5)How to log client keybinds/modmenu

Post by Higor »

Actually, I remember a few cases of mod menus being spawned outside of the normal .INT method, and ASC (that runs the same detection system) didn't catch it.
As far as I know TimTim fixed that up by directly scanning the mod menu list on one of his latest NewNet releases, this way there's no need to slow down the system by using .INT lookup and you catch mod menus spawned using other methods.

This bypasses the ASC method, but not TimTim's
If you take a look at it, with some reverse thinking you can actually write the NN styled detector yourself.

Code: Select all

var ViewPort Player; //Predetect it or something

function bool CreateMods()
{
	local WindowConsole C;
	local UMenuMenuBar MenuBar;
	local UMenuModMenuList NewItem;
	if ( Player == none )
		return false;
	C = WindowConsole( Player.Console);
	if ( C == none )
		return false;
	if ( UMenuRootWindow(C.Root) == none )
		return false;
	MenuBar = UMenuRootWindow(C.Root).MenuBar;

//Loop this or something
	NewItem = UMenuModMenuList(MenuBar.ModItems.Append(class'UMenuModMenuList'));
	NewItem.MenuItemClassName = "MODPACKAGE.MODCLASS";
	NewItem.MenuCaption = "VISIBLE NAME";
	NewItem.MenuHelp = "DESCRIPTION";
	NewItem.MenuItem = MenuBar.Mods.AddMenuItem(NewItem.MenuCaption, None);

	return true;
}
Post Reply