clientside sv_cheats commands and immune to triggers

Please post any questions about developing your plugin here. Please use the search function before posting!
decompile
Senior Member
Posts: 416
Joined: Sat Oct 10, 2015 10:37 am
Location: Germany
Contact:

clientside sv_cheats commands and immune to triggers

Postby decompile » Mon Jan 25, 2016 7:50 pm

Hey,

How can you give a player (for example after toggle !cheats) the ability to use clientsided sv_cheats commands?

Code: Select all

mat_wireframe
mat_fullbright
r_drawclipbrushes


And one more question:

Can you make a player immune to triggers? (toggle !triggers)

Thank you :p
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Tue Jan 26, 2016 4:09 pm

You can't give a single player the ability to use cheat commands.

You might be able to ignore triggers by playing around with collision groups. A hook would also be a possibility.
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

Postby iPlayer » Tue Jan 26, 2016 6:09 pm

Well, there're SendConVarValue and cheat control plugin on Sourcemod.

Not sure how to implement this on SP though. I guess you do something like this

Syntax: Select all

from bitbuffers import BitBufferWrite
from engines.server import server
from listeners import OnClientActive


NET_SETCONVAR = 5
NETMSG_BITS = 5


def cstrike_send_convar_value(index, cvar, value):
net_channel = server.get_client(index - 1).get_net_channel()
buffer = BitBufferWrite(256)
buffer.write_ubit_long(NET_SETCONVAR, NETMSG_BITS)
buffer.write_byte(1)

cvar = cvar + '\x00'
value = str(value) + '\x00'

buffer.write_string(cvar)
buffer.write_string(value)

net_channel.send_data(buffer) # send_data is not exported by SP right now


@OnClientActive
def listener_on_client_active(index):
cstrike_send_convar_value(index, 'sv_cheats', 1)



Edit: Updated the snippet. The only thing now is .send_data
Image /id/its_iPlayer
My plugins: Map Cycle • Killstreaker • DeadChat • Infinite Jumping • TripMines • AdPurge • Bot Damage • PLRBots • Entity AntiSpam

Hail, Companion. [...] Hands to yourself, sneak thief. Image
decompile
Senior Member
Posts: 416
Joined: Sat Oct 10, 2015 10:37 am
Location: Germany
Contact:

Postby decompile » Wed Jan 27, 2016 1:10 pm

Sounds realy interesting (Ye heard that from Sourcemod, so i Thought its also possible in SP)
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Wed Jan 27, 2016 2:06 pm

iPlayer wrote:Edit: Updated the snippet. The only thing now is .send_data
INetChannel::SendData is a virtual function, so you can easily access it with the memory module.

Syntax: Select all

send_data = memory.get_object_pointer(net_channel).make_virtual_function(
<vtable index>,
[<args ...>],
<return value>
)
Though, it might make sense to export it. But at least you can test it now without exporting and recompiling SP.
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

Postby iPlayer » Wed Jan 27, 2016 3:13 pm

Yay, thanks, Ayuto! I got it! It's working!

(Note that I changed NETMSG_BITS)

Syntax: Select all

from bitbuffers import BitBufferWrite
from engines.server import server
from listeners import OnClientPutInServer
from memory import Convention
from memory import DataType
from memory import get_object_pointer


NET_SETCONVAR = 5
NETMSG_BITS = 6


def cstrike_send_convar_value(index, cvar, value):
net_channel = server.get_client(index - 1).get_net_channel()
buffer = BitBufferWrite(256)
buffer.write_ubit_long(NET_SETCONVAR, NETMSG_BITS)
buffer.write_byte(1)

cvar = cvar + '\x00'
value = str(value) + '\x00'

buffer.write_string(cvar)
buffer.write_string(value)

net_channel_ptr = get_object_pointer(net_channel)

# virtual bool SendData(bf_write &msg, bool bReliable = true) = 0;
send_data = net_channel_ptr.make_virtual_function(
41,
Convention.THISCALL,
(DataType.POINTER, DataType.POINTER, DataType.BOOL),
DataType.BOOL
)

send_data(net_channel_ptr, buffer, True)


@OnClientPutInServer
def listener_on_put_in_server(index, name):
cstrike_send_convar_value(index, 'sv_cheats', 1)



One question, Ayuto. How do you find index for this virtual function? I only got a list like

Code: Select all

<pure virtual>
<pure virtual>
<pure virtual>
<pure virtual>

It's kinda hard to understand which one of the is SendData
Image /id/its_iPlayer
My plugins: Map Cycle • Killstreaker • DeadChat • Infinite Jumping • TripMines • AdPurge • Bot Damage • PLRBots • Entity AntiSpam

Hail, Companion. [...] Hands to yourself, sneak thief. Image
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Wed Jan 27, 2016 4:11 pm

Awesome! :)

Where did you get the list from? To find the vtable index there are multiple ways:
  1. Count by hand by using the source code (requires the source code to be up-to-date, obviously. If multiple inheritance is used, it can get difficult.)
  2. Use IDA and this vtable dump script.


If you want to use IDA you need to find the binary that contains the vtable info at first. You can easily do that by downloading the CS:S symbols:
https://github.com/SourceChanges/css

Then you need to search through all files for "::SendData(" (e.g. by using Notepad++). You will get the following output:

Code: Select all

engine_srv.txt (1 hit)
   Line 9206: t CNetChan::SendData(bf_write&, bool)
server_srv.txt (5 hits)
   Line 18452: t CBaseGameStats::SendData()
   Line 23101: t IGameStatTracker::CGameStatList<SCSSDeathData>::SendData(KeyValues*)
   Line 23104: t IGameStatTracker::CGameStatList<SCSSWeaponData>::SendData(KeyValues*)
   Line 23107: t IGameStatTracker::CGameStatList<SMarketPurchases>::SendData(KeyValues*)
   Line 26412: t CBaseGameStats_Driver::SendData()
We know that INetChannel::SendData is a pure virtual function. That means a subclass needs to implement it. CNetChan seems to be the class that implements it and it's defined in engine_srv.so. To verify that you can also use one of our new features:[PYTHON]net_channel_ptr.type_info.dump()[/PYTHON]It will print the following to your console:

Code: Select all

CNetChan
-INetChannel
--INetChannelInfo
Now, we know for sure that CNetChan is the class we are looking for. Use IDA to analyse the engine_srv.so. When IDA is ready, search for CNetChan::SendData in the function list and double-click the found entry. Now, press X on the symbol name of that function (_ZN8CNetChan8SendDataER8bf_writeb). You have now a list of everything that references this function. In this case it's just the vtable, but sometimes there is other stuff listed as well.

Code: Select all

Down o .rodata:`vtable for'CNetChan dd 0, offset _ZTI8CNetChan, offset _ZNK8CNetChan7GetNameEv; CNetChan::ResetStreaming(void)
Double-click the entry and execute the IDA Python script. It will dump the vtable to the output window.

Code: Select all

Inheritance Tree:
 CNetChan
  INetChannel
   INetChannelInfo

VTable for CNetChan: (0, 0)
 Lin  Win Function
   0    0 CNetChan::GetName(void)const
   1    1 CNetChan::GetAddress(void)const
   2    2 CNetChan::GetTime(void)const
   3    3 CNetChan::GetTimeConnected(void)const
   4    4 CNetChan::GetBufferSize(void)const
   5    5 CNetChan::GetDataRate(void)const
   6    6 CNetChan::IsLoopback(void)const
   7    7 CNetChan::IsTimingOut(void)const
   8    8 CNetChan::IsPlayback(void)const
   9    9 CNetChan::GetLatency(int)const
  10   10 CNetChan::GetAvgLatency(int)const
  11   11 CNetChan::GetAvgLoss(int)const
  12   12 CNetChan::GetAvgChoke(int)const
  13   13 CNetChan::GetAvgData(int)const
  14   14 CNetChan::GetAvgPackets(int)const
  15   15 CNetChan::GetTotalData(int)const
  16   16 CNetChan::GetSequenceNr(int)const
  17   17 CNetChan::IsValidPacket(int, int)const
  18   18 CNetChan::GetPacketTime(int, int)const
  19   19 CNetChan::GetPacketBytes(int, int, int)const
  20   20 CNetChan::GetStreamProgress(int, int *, int *)const
  21   21 CNetChan::GetTimeSinceLastReceived(void)const
  22   22 CNetChan::GetCommandInterpolationAmount(int, int)const
  23   23 CNetChan::GetPacketResponseLatency(int, int, int *, int *)const
  24   24 CNetChan::GetRemoteFramerate(float *, float *)const
  25   25 CNetChan::GetTimeoutSeconds(void)const
  26   26 CNetChan::~CNetChan()
  27   26 CNetChan::~CNetChan()
  28   27 CNetChan::SetDataRate(float)
  29   28 CNetChan::RegisterMessage(INetMessage *)
  30   29 CNetChan::StartStreaming(unsigned int)
  31   30 CNetChan::ResetStreaming(void)
  32   31 CNetChan::SetTimeout(float)
  33   32 CNetChan::SetDemoRecorder(IDemoRecorder *)
  34   33 CNetChan::SetChallengeNr(unsigned int)
  35   34 CNetChan::Reset(void)
  36   35 CNetChan::Clear(void)
  37   36 CNetChan::Shutdown(char  const*)
  38   37 CNetChan::ProcessPlayback(void)
  39   38 CNetChan::ProcessStream(void)
  40   39 CNetChan::ProcessPacket(netpacket_s *, bool)
  41   40 CNetChan::SendNetMsg(INetMessage &, bool, bool)
  42   41 CNetChan::SendData(bf_write &, bool)
  43   42 CNetChan::SendFile(char  const*, unsigned int)
  44   43 CNetChan: :D enyFile(char  const*, unsigned int)
  45   44 CNetChan::RequestFile_OLD(char  const*, unsigned int)
  46   45 CNetChan::SetChoked(void)
  47   46 CNetChan::SendDatagram(bf_write *)
  48   47 CNetChan::Transmit(bool)
  49   48 CNetChan::GetRemoteAddress(void)const
  50   49 CNetChan::GetMsgHandler(void)const
  51   50 CNetChan::GetDropNumber(void)const
  52   51 CNetChan::GetSocket(void)const
  53   52 CNetChan::GetChallengeNr(void)const
  54   53 CNetChan::GetSequenceData(int &, int &, int &)
  55   54 CNetChan::SetSequenceData(int, int, int)
  56   55 CNetChan::UpdateMessageStats(int, int)
  57   56 CNetChan::CanPacket(void)const
  58   57 CNetChan::IsOverflowed(void)const
  59   58 CNetChan::IsTimedOut(void)const
  60   59 CNetChan::HasPendingReliableData(void)
  61   60 CNetChan::SetFileTransmissionMode(bool)
  62   61 CNetChan::SetCompressionMode(bool)
  63   62 CNetChan::RequestFile(char  const*)
  64   63 CNetChan::SetMaxBufferSize(bool, int, bool)
  65   64 CNetChan::IsNull(void)const
  66   65 CNetChan::GetNumBitsWritten(bool)
  67   66 CNetChan::SetInterpolationAmount(float)
  68   67 CNetChan::SetRemoteFramerate(float, float)
  69   68 CNetChan::SetMaxRoutablePayloadSize(int)
  70   69 CNetChan::GetMaxRoutablePayloadSize(void)
  71   70 CNetChan::GetProtocolVersion(void)
User avatar
iPlayer
Developer
Posts: 590
Joined: Sat Nov 14, 2015 8:37 am
Location: Moscow
Contact:

Postby iPlayer » Wed Jan 27, 2016 4:23 pm

Thank you, Ayuto. IDA approach is very useful.

Where did you get the list from?

I used Satoon's virtual_funcs script and binaries from his dropbox.
It may have sounded kinda funny because I've found the index and asked how do you find it :) I used what you called "Count by hand by using the source code". They're 73 (starting from 0) entries in INetChannel vtable, so I decided to check how many virtual functions there are in source code. Counted only 46. Then I noticed it inherits from INetChannelInfo. Went there and counted 26 more. 46 + 26 is somewhere around 73 :) I didn't bother and tried indexes 41 and 42. 41 worked.


Edit: Maybe it's reasonable not only to export .send_data, but to somehow implement send_convar_value? Because my approach won't work for CS:GO or Dota 2, plus NET_SETCONVAR and NETMSG_BITS change from game to game.
Image /id/its_iPlayer
My plugins: Map Cycle • Killstreaker • DeadChat • Infinite Jumping • TripMines • AdPurge • Bot Damage • PLRBots • Entity AntiSpam

Hail, Companion. [...] Hands to yourself, sneak thief. Image
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Sat Feb 20, 2016 4:02 pm

Since CS:GO needs a different implementation and I have been asked to create this for CS:GO, I decided to update SP today. Here is the CS:GO version:

Syntax: Select all

from _messages import ProtobufMessage
from bitbuffers import BitBufferWrite
from engines.server import server

NET_MESSAGE_SET_CONVAR = 6

def set_client_convar(player_index, name, value):
msg = ProtobufMessage('CNETMsg_SetConVar')
cvar = msg.mutable_message('convars').add_message('cvars')
cvar.set_string('name', name)
cvar.set_string('value', value)

msg_size = msg.byte_size

buffer_size = 256
buffer = BitBufferWrite(buffer_size)
buffer.write_var_int32(NET_MESSAGE_SET_CONVAR)
buffer.write_var_int32(msg_size)
msg.serialize_to_array(buffer.data + buffer.num_bytes_written, buffer_size)
buffer.seek_to_bit((buffer.num_bytes_written + msg_size) * 8)

net_channel = server.get_client(player_index - 1).net_channel
net_channel.send_data(buffer)

from events import Event
from players.helpers import index_from_userid

@Event('player_say')
def on_player_say(event):
userid = event['userid']
index = index_from_userid(userid)
set_client_convar(index, 'sv_cheats', event['text'])
I guess we could add this feature to the Player class at some point.

Edit: Just noticed my changes don't compile well on all games... I will fix that shortly, so version 255 will be available
Edit2: Fixed not using "name" and "value" in set_client_convar()
User avatar
D3CEPTION
Senior Member
Posts: 129
Joined: Tue Jan 26, 2016 1:24 pm
Location: Switzerland

Postby D3CEPTION » Sat Feb 20, 2016 7:37 pm

dont know if im doing sthn wrong, but when i try to import ProtobufMessage with the latest build, not all class members are registered

Syntax: Select all

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_obj', '_ptr', '_size', 'add_bool', 'add_double', 'add_enum', 'add_float',
'add_int32', 'add_int64', 'add_message', 'add_string', 'add_uint32', 'add_uint64', 'debug_string', 'get_bool', 'get_double', 'get_enum', 'get_float', 'get_int32', 'get_int64', 'get_message', 'get_repeated_bool', 'get_repeated_double', 'get_repeated_enum', 'get_repeated_float', 'get_repeated_int32', 'get_repeated_int64', 'get_repeated_message', 'get_repeated_string', 'get_repeated_uint32', 'get_rep
eated_uint64', 'get_string', 'get_uint32', 'get_uint64', 'mutable_message', 'mutable_repeated_message', 'name', 'set_bool', 'set_double', 'set_enum', 'set_float', 'set_int32', 'set_int64', 'set_repeated_bool', 'set_repeated_double', 'set_repeated_enum', 'set_repeated_float', 'set_repeated_int32', 'set_repeated_int64', 'set_repeated_string', 'set_repeated_uint32', 'set_repeated_uint64', 'set_string
', 'set_uint32', 'set_uint64']
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Sat Feb 20, 2016 11:54 pm

What's missing?
User avatar
D3CEPTION
Senior Member
Posts: 129
Joined: Tue Jan 26, 2016 1:24 pm
Location: Switzerland

Postby D3CEPTION » Sat Feb 20, 2016 11:59 pm

Ayuto wrote:What's missing?


my bad, i didnt read properly..
i just realized, that i have to add the pointer for

Code: Select all

google: :p rotobuf::Message
to your code.
dont know what that is supposed to mean though, gonna test tomorrow..
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Sun Feb 21, 2016 6:02 am

No idea what you mean...
User avatar
D3CEPTION
Senior Member
Posts: 129
Joined: Tue Jan 26, 2016 1:24 pm
Location: Switzerland

Postby D3CEPTION » Sun Feb 21, 2016 10:33 am

Ayuto wrote:No idea what you mean...


https://github.com/Source-Python-Dev-Team/Source.Python/blob/d06fb86e7eadc6fbdcbf0ca5dc034d80ba66ab7f/src/core/modules/messages/messages_wrap.cpp#L164

thats one of the classmembers that i cant find. its also not documented in SP and you left that out in your code.
and as you didnt answer my question before, i thought to add a pointer and maybe register it myself.
that is what im looking for right now..
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Sun Feb 21, 2016 11:26 am

D3CEPTION wrote:thats one of the classmembers that i cant find. its also not documented in SP and you left that out in your code.

I said it will be available with version 255. The build bot hasn't finished version 255, because there was a compiler error which I have fixed yesterday and went offline. However, another job failed, because it was unable to fetch the changes from Github. I have now triggered the build again.

D3CEPTION wrote:and as you didnt answer my question before

One reason could be that you haven't asked a question. :confused:

D3CEPTION wrote:i thought to add a pointer and maybe register it myself.

I still don't know which pointer you are talking about and why you want to add something. You would just need to compile SP or wait for version 255.
User avatar
D3CEPTION
Senior Member
Posts: 129
Joined: Tue Jan 26, 2016 1:24 pm
Location: Switzerland

Postby D3CEPTION » Sun Feb 21, 2016 12:46 pm

i knew you were doing a new build, thats why i tried to help and look into it too and mentioned that protobufmsg had members missing..

Ayuto wrote:One reason could be that you haven't asked a question.

dont know if im doing sthn wrong, but when i try to import ProtobufMessage with the latest build, not all class members are registered

i stated my confusion and gave a reason why. impossible to help in this context?

i understand that it is easier for you to requireusers to ask exact questions.
but you forget, that its impossible for the user who just has a problem understanding, to ask a question that includes the correct understanding.
thats why told you in another post, that communication skills also include, trying to understand the "question behind the message".
especially when you answer a lot of people. if you dont do that, you might add even more confusion to the user and they stop using forums etc.

thats also what i felt when instead of helping you asked
Ayuto wrote:"whats missing"

as if everything was there, and my confusion unjustified?

following that confusion i looked into the source and saw that all members who werent added were using the same pointer
google: :p rotobuf::Message


so then i thought that i have to add the pointer manually and pointed it out.

but then you got me confused again and said:
No idea what you mean...


Ayuto wrote:I still don't know which pointer you are talking about and why you want to add something. You would just need to compile SP or wait for version 255.


if its not a pointer, take it for what it is, call it an address or whatever word you like.
but even better: correct me about wehre you think im wrong. otherwise again, you only increase my confusion
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Sun Feb 21, 2016 1:06 pm

You: Some class members are missing.
Me: Which one?
You: serialize_to_array

It could have been that simple! Or you could have posted the exception you get. It would be something like "AttributeError: 'ProtobufMessage' object has no attribute 'serialize_to_array'".
User avatar
satoon101
Project Leader
Posts: 2697
Joined: Sat Jul 07, 2012 1:59 am

Postby satoon101 » Sun Feb 21, 2016 1:17 pm

Also, since he stated it would be available with version 255, and you were obviously unable to get version 255 (because it errored during the build process), I am not sure why you thought it would work with the previous version.

*Edit: not trying to pile on, just want you to see how you are also helping to create the confusion.
Image
User avatar
D3CEPTION
Senior Member
Posts: 129
Joined: Tue Jan 26, 2016 1:24 pm
Location: Switzerland

Postby D3CEPTION » Sun Feb 21, 2016 1:45 pm

since ive never built sp, its a weird picture to think of a half finished class, as a user i dont know how the build process works.

i understand that he said everything ( that users ought to know about ) with : "I will fix that shortly, so version 255 will be available".

but the very :
Ayuto wrote:Edit: Just noticed my changes don't compile well on all games...

got me confused. so i wasnt sure if the missing classmembers were part of the "don't compile well".
thats why i tried to help and point out the class.

and at this point i can argue too : why not just tell me again, the missing members are part of the problem and will be added next update... ?

its not really helpful to use that argument against a user and that a devs shouldnt "doubleanswer" questions, when users get confused.

after
Ayuto wrote:whats missing?
as a user i felt pushed here, to figure out whats wrong myself, because that statement indicates to me, that everything is fine and there.

BUT if my logical conclusion after that of 1 ) "everything is fine and there" was totally unjustified and off, as you both seem to say, then why again is 2) rephrasing that a fix for the class will come next build by a dev,
an unhelpful and unnecessary reply?
User avatar
D3CEPTION
Senior Member
Posts: 129
Joined: Tue Jan 26, 2016 1:24 pm
Location: Switzerland

Postby D3CEPTION » Sun Feb 21, 2016 1:50 pm

satoon101 wrote:*Edit: not trying to pile on, just want you to see how you are also helping to create the confusion.


i do understand and appreciate that. and im only trying to share my perspective, too. if it was the first time that i realize this, i wouldnt take my time to share the view here.

Return to “Plugin Development Support”

Who is online

Users browsing this forum: No registered users and 10 guests