Author Topic: MultiplayerDirTest.py  (Read 785 times)

Offline Tethys

  • -=USF=- Co-Leader
  • Posts: 256
  • Cookies: 89
MultiplayerDirTest.py
« on: March 16, 2015, 01:24:21 PM »
Hello everyone, today I am looking at this file in hopes of better understanding how this works. I am throwing the idea around of an anti-cheat script that would rerun the checksum each time a player spawns on the map. So if Player A spawns 6 times during a session, the checksum for that player runs 6 times, once for every time he spawns. If the script is different (such as when someone mods it then respawns in a hacked ship) the anti-cheat script will pick this up and either prevent the ship from spawning, or disconnect the player entirely from the server (I favor the latter option). Anyone here have any experience with anything like that? Just wondering what I can do here with my limited skills.. I know I cant build a script from scratch that's for sure. I do know I would like to enhance the Bridge Commander online experience to be a little more enjoyable for everyone :) Except of course hackers ;)


Code: [Select]
from bcdebug import debug
import App
import Multiplayer
import Multiplayer.MultiplayerMenus
import MainMenu.mainmenu

badfilelist = (
"Agamemnon",
"Akira2",
"Akira",
"Alioth1",
"Alioth1_S",
"Alioth2",
"Alioth2_S",
"Alioth3",
"Alioth3_S",
"Alioth4",
"Alioth4_S",
"Alioth5",
"Alioth5_S",
"Alioth6",
"Alioth6_S",
"Alioth7",
"Alioth7_S",
"Alioth8",
"Alioth8_S",
"Alioth",
"Amagon",
"Ambassador",
"Asteroid1",
"Asteroid2",
"Asteroid3",
"Asteroidh1",
"Asteroidh2",
"Asteroidh3",
"Asteroid",
"Badlands1",
"Badlands1_S",
"Badlands",
"BiranuStation",
"BirdOfPrey",
"BombFreighter",
"BridgeHandlers",
"C2Valdore",
"CardFacility",
"CardFreighter",
"CardHybrid",
"CardOutpost",
"CardSpecificSetup",
"CardStarbase",
"CardStation",
"Cheyenne",
"CommArray",
"CommLight",
"Copy (2) of Copy of __init__",
"Copy (2) of Copy of MissionMenusShared",
"Copy (2) of Copy of MissionShared",
"Copy (2) of MultiplayerGame",
"Copy (2) of SpeciesToSystem",
"Copy (2) SFX Cortez is #1",
"Copy (3) of MultiplayerGame",
"Copy (3) of SpeciesToSystem",
"Copy (3) SFX Cortez is #1",
"Copy (4) of MultiplayerGame",
"Copy (4) of SpeciesToSystem",
"Copy (5) of MultiplayerGame",
"Copy (5) of SpeciesToSystem",
"Copy of Copy of Copy of __init__",
"Copy of Copy of Copy of MissionMenusShared",
"Copy of Copy of Copy of MissionShared",
"Copy of Copy of __init__",
"Copy of Copy of MissionMenusShared",
"Copy of Copy of MissionShared",
"Copy of Copy of Modifier",
"Copy of Copy of MultiplayerGame",
"Copy of Copy of MultiplayerMenus",
"Copy of Copy of SpeciesToShip",
"Copy of Copy of SpeciesToSystem",
"Copy of __init__",
"COPY_OF___INIT__",
"Copy of MissionMenusShared",
"COPY_OF_MISSIONMENUSSHARED",
"Copy of MissionShared",
"COPY_OF_MISSIONSHARED",
"Copy of Modifier",
"COPY_OF_MODIFIER",
"Copy of MultiplayerGame",
"COPY_OF_MULTIPLAYERGAME",
"Copy of MultiplayerMenus",
"COPY_OF_MULTIPLAYERMENUS",
"Copy of SpeciesToShip",
"COPY_OF_SPECIESTOSHIP",
"Copy of SpeciesToSystem",
"COPY_OF_SPECIESTOSYSTEM",
"Copy of SpeciesToTorp",
"COPY_OF_SPECIESTOTORP",
"CUBE",
"D-7",
"DamGalor",
"Decoy",
"DefenseNoTarget",
"Defense",
"DestroyAft",
"DestroyAftSeparate",
"DestroyFaceSide",
"DestroyForeClose",
"DestroyFore",
"DestroyFreelyClose",
"DestroyFreelyMaintain",
"DestroyFreely",
"DestroyFreelySeparate",
"DestroyFromSide",
"DisableAft",
"DisableAftSeparate",
"DisableFaceSide",
"DisableForeClose",
"DisableFore",
"DisableFreelyClose",
"DisableFreelyMaintain",
"DisableFreely",
"DisableFreelySeparate",
"DisableFromSide",
"DryDock",
"DynamicMusic",
"E2M0Warbird",
"EnterpriseB",
"Enterprise",
"EscapePod",
"Eximius",
"FedOutpost",
"FedStarbase",
"FlyForward",
"FoundationConfig",
"Freighter",
"GalaxyX",
"Galor",
"GenericTemplate",
"Geronimo",
"InterceptTarget",
"Intrepid",
"IonicTorpedo2",
"ISS",
"Itari1",
"Itari1_S",
"Itari2",
"Itari2_S",
"Itari3",
"Itari3_S",
"Itari4",
"Itari4_S",
"Itari5",
"Itari5_S",
"Itari6",
"Itari6_S",
"Itari7",
"Itari7_S",
"Itari8",
"Itari8_S",
"Itari",
"Keldon",
"KessokHeavy",
"KessokLight",
"KessokMine",
"KeyboardConfig",
"KlingonTorpedo",
"KlingTorpSound",
"LoadTacticalSounds",
"Maelstrom",
"Marauder",
"MatanKeldon",
"MatrixCube",
"MaTriXIIMenus",
"MaTriXIIName",
"MaTriXII",
"Mission1Menus",
"Mission1Name",
"Mission1",
"Mission2Menus",
"Mission2Name",
"Mission2",
"Mission3Menus",
"Mission3Name",
"Mission3",
"Mission5Menus",
"Mission5Name",
"Mission5",
"000-Fixes20030305-FoundationTriggers",
)

ET_BOX_OKAY = None

# Create a Info Box, Basics crom mainmenu.py
def CreateInfoBoxShutdown(String):
        debug(__name__ + ", CreateInfoBoxShutdown")
        pDialogWindow = CreateInfoBox(String)

        pDialogWindow.AddPythonFuncHandlerForInstance(ET_BOX_OKAY, __name__ + ".shutdown")


def CreateInfoBox(String):
    debug(__name__ + ", CreateInfoBox")
    global ET_BOX_OKAY
    ET_BOX_OKAY = App.UtopiaModule_GetNextEventType()
   
    pTopWindow = App.TopWindow_GetTopWindow()
    pDialogWindow = App.ModalDialogWindow_Cast(pTopWindow.FindMainWindow(App.MWT_MODAL_DIALOG))
   
    if (pDialogWindow):
        # Create a okay and cancel events
        pOkayEvent = App.TGIntEvent_Create()
        pOkayEvent.SetEventType(ET_BOX_OKAY)
        pOkayEvent.SetDestination(pDialogWindow)
       
        pTitle = App.TGString("Error Box")
        pOkay = App.TGString("OK")
        pText = App.TGString(String)

        pDialogWindow.Run(pTitle, pText, pOkay, pOkayEvent, None, None)
        return pDialogWindow


def check():
        debug(__name__ + ", check")
        for file in badfilelist:
                dir_dirty = 1
                try:
                        __import__("Multiplayer." + file)
                except ImportError:
                        dir_dirty = 0
                if dir_dirty == 1:
                        return 1
        return 0


def ProcessMessageHandler(pObject, pEvent):
        debug(__name__ + ", ProcessMessageHandler")
        pMessage = pEvent.GetMessage()
       
        if App.IsNull(pMessage):
                return
       
        # Get the data from the message
        # Open a buffer stream to read the data
        kStream = pMessage.GetBufferStream();
        cType = kStream.ReadChar();
        cType = ord(cType)
       
        if cType == App.FILE_MESSAGE:
                pSeq = App.TGSequence_Create()
                pSeq.AppendAction(App.TGScriptAction_Create(__name__, "AbortLoad", pObject, pEvent), 0.1)
                pSeq.AppendAction(App.TGScriptAction_Create(__name__, "AbortLoadShowInfo"), 1.0)
                pSeq.Play()

kStream.Close()


def AbortLoad(pAction, pObject, pEvent):
        #pTopWindow = App.TopWindow_GetTopWindow()
        #pPane = pTopWindow.GetFirstChild()
        #pTopWindow.DeleteChild(pPane)
       
debug(__name__ + ", AbortLoad")
pNetwork = App.g_kUtopiaModule.GetNetwork ()
if pNetwork:
pNetwork.Disconnect()

        Multiplayer.MultiplayerMenus.HandleCancelConnect(pObject, pEvent)
        MainMenu.mainmenu.g_bMultiplayerMenusRebuiltAfterResChange = 0 # yes, thats dirty
        MainMenu.mainmenu.SwitchMiddlePane("Multiplayer")

        return 0

def AbortLoadShowInfo(pAction):
        debug(__name__ + ", AbortLoadShowInfo")
        myString = "The Host you were trying to connect to, doesn't use the same version as you!\n\nTo make sure your Game keeps clean, the connection has been terminated."
        CreateInfoBox(myString)
       
        return 0


def shutdown(pObject, pEvent):
        debug(__name__ + ", shutdown")
        import sys
        sys.exit()


def do_checksum_msg(iToPlayerID, id, text1, text2, end):
# Now send a message to everybody else that the score was updated.
# allocate the message.
pMessage = App.TGMessage_Create()
pMessage.SetGuaranteed(1) # Yes, this is a guaranteed packet

# Setup the stream.
kStream = App.TGBufferStream() # Allocate a local buffer stream.
kStream.OpenBuffer(Multiplayer.MissionShared.NET_BUFFER_SIZE) # Open the buffer stream with byte buffer.

# Write relevant data to the stream.
# First write message type.
kStream.WriteChar(chr(App.DO_CHECKSUM_MESSAGE))
kStream.WriteChar(chr(id))
text = text1
kStream.WriteShort(len(text))
for i in range(len(text)):
kStream.WriteChar(text[i])
text = text2
kStream.WriteShort(len(text))
for i in range(len(text)):
kStream.WriteChar(text[i])
kStream.WriteChar(chr(end))

# Okay, now set the data from the buffer stream to the message
pMessage.SetDataFromStream(kStream)

pNetwork = App.g_kUtopiaModule.GetNetwork()
# Send the message to everybody but me.  Use the NoMe group, which
# is set up by the multiplayer game.
pNetwork.SendTGMessage(iToPlayerID, pMessage)
# We're done.  Close the buffer.
kStream.CloseBuffer()


def ObjectCreatedHandler(pObject, pEvent):
        debug(__name__ + ", ObjectCreatedHandler")

pObject.CallNextHandler(pEvent)

# We only care about ships.
pShip = App.ShipClass_Cast(pEvent.GetDestination())
if pShip and pShip.GetNetPlayerID() > 1:
#do_checksum_msg(pShip.GetNetPlayerID(), 0, "scripts/", "App.pyc", 32)
#do_checksum_msg(pShip.GetNetPlayerID(), 1, "scripts/", "Autoexec.pyc", 32)
do_checksum_msg(pShip.GetNetPlayerID(), 2, "scripts/ships", "*.pyc", 33)
#do_checksum_msg(pShip.GetNetPlayerID(), 3, "scripts/mainmenu", "*.pyc", 32)
do_checksum_msg(pShip.GetNetPlayerID(), 4, "scripts/ships/Hardpoints", "*.pyc", 33)
do_checksum_msg(pShip.GetNetPlayerID(), 5, "scripts/Tactical/Projectiles", "*.pyc", 33)
#do_checksum_msg(pShip.GetNetPlayerID(), 255, "Scripts/Multiplayer", "*.pyc", 33)


def checkMultplayerFiles():
        debug(__name__ + ", checkMultplayerFiles")
        myString = "Your Multiplayer folder is dirty!\nI can't let you play with this one.\nPlease clean it up.\n\nGame shutdown!"
        if check() == 1:
                CreateInfoBoxShutdown(myString)

        # add listener
        pTopWindow = App.TopWindow_GetTopWindow()
        pWindow = pTopWindow.FindMainWindow(App.MWT_OPTIONS)
        App.g_kEventManager.AddBroadcastPythonFuncHandler(App.ET_NETWORK_MESSAGE_EVENT, pTopWindow, __name__ + ".ProcessMessageHandler")
App.g_kEventManager.AddBroadcastPythonFuncHandler(App.ET_OBJECT_CREATED_NOTIFY, pTopWindow, __name__ + ".ObjectCreatedHandler")

Offline Defiant

  • Posts: 398
  • Cookies: 1105
    • BC: Kobayashi Maru
Re: MultiplayerDirTest.py
« Reply #1 on: March 18, 2015, 02:43:22 AM »
MultiplayerDirTest.py is the wrong corner to look. MultiplayerDirTest.py comes from the early days of BC Multiplayer where some people had the strange idea of putting random junk in scripts/ships. BC has the bad behavior that it downloads every file from the host from this folder that is not on the clients installation.

What you want to do is sadly not possible, because BCs own anti-cheat-system prevents the control of any file not under scripts/Custom.

Offline Tethys

  • -=USF=- Co-Leader
  • Posts: 256
  • Cookies: 89
Re: MultiplayerDirTest.py
« Reply #2 on: March 18, 2015, 09:30:54 AM »
You sound certain, which is not good news. I didnt want to ask you because I know you have little to no time or desire to work on BC scripts, but could you possibly point me toward the script that deals with checksumming the scripts, and the script that deals with client/player/ship spawing? Something tells me it should be possible to insert a call to the checksum before a client spawns on the map, but I was going to do some real world testing to see if its even possible to not break the script when trying...

Are you saying that any script in the Custom folder would automatically get loaded to multiplayer? What I am trying to do, is prevent hackers from hacking a server already hosted, not prevent a host from creating modified scripts during a game.

It was rumored to me that someone had already created such a script, but I have had no success in locating a copy of such script or scripts in my searching. How does the BC anti-cheat work exactly? You can PM me about it if you dont want to reveal the details publicly. If BotF can be successfully modded, BC should be much easier... ;)

Offline Defiant

  • Posts: 398
  • Cookies: 1105
    • BC: Kobayashi Maru
Re: MultiplayerDirTest.py
« Reply #3 on: March 18, 2015, 06:42:31 PM »
You sound certain, which is not good news.
I've tried..

(...) could you possibly point me toward the script that deals with checksumming the scripts, and the script that deals with client/player/ship spawing? Something tells me it should be possible to insert a call to the checksum before a client spawns on the map, but I was going to do some real world testing to see if its even possible to not break the script when trying...
Thats inside the stbc.exe. Not reachable with scripting.

Are you saying that any script in the Custom folder would automatically get loaded to multiplayer?
No, Custom/ is the only folder you can fully control from with the scripts. BC politely denies any file-action on a file outside this folder.

Offline Tethys

  • -=USF=- Co-Leader
  • Posts: 256
  • Cookies: 89
Re: MultiplayerDirTest.py
« Reply #4 on: March 18, 2015, 07:06:31 PM »
I see. Well, that is not good then. Does the ban function at least work? I think I remember boot working in multiplayer, but I never had to ban anyone. Dang man, now Im super bummed.. what about using codecaves? A .dll may be able to hook the checksum, or is that considered "frowned upon" as well? It wouldnt be changing the .exe, merely hooking to a location within it.. I only know of codecaves because I moderate on the Armada Fleet Command BotF forum (over 10,000 members) and they are constantly fixing bugs within the .exe of that game, most of which is assembly language, but they have had success replacing the combat engine with codecave dll's. I'm not sure if its worth looking into, I have 0 experience with it so I would have to ask Flocke on AFC and lol, find the time... I'll see if I can come across anything about BC becoming abandonware soon. Just not sure who to contact at the moment.. is Totally Games still around? Activision is, Gamespy obviously abandoned their part of BC. Its on my list of to-do's :)

Offline Defiant

  • Posts: 398
  • Cookies: 1105
    • BC: Kobayashi Maru
Re: MultiplayerDirTest.py
« Reply #5 on: March 19, 2015, 02:15:03 AM »
That would be a lot of work..

Offline Tethys

  • -=USF=- Co-Leader
  • Posts: 256
  • Cookies: 89
Re: MultiplayerDirTest.py
« Reply #6 on: March 19, 2015, 11:29:14 AM »
Work I would be willing to look into. If BotF can be successfully modded and improved, Im certain BC can be as well, being a newer game with superior modability. We arent talking about a series of dll's, just maybe 1 or 2 that check the scripts during certain events. I will ask around on the BotF forum and see if anyone over there knows more, Im not sure how many codecaves they used to replace the graphics engine, but it is functional and does work well. I will let you know more when I have more information. Dont expect it soon, though lol