Breaking the SQF Firewall
Breaking the firewall requires an in-depth knowledge of how the engine kills Threads & Events. As well, a little history lesson in the field of firewall busting.
So, we know that when connecting to an MP session, any sqf thread & event handler gets removed. You can test this with a simple OnEachFrame check. Run this code at the main menu & connect to an MP session.
You’ll notice when you enter the lobby that the text “running” stops being printed into chat. This gives us an idea of when the event handler is terminated. It is some time between clicking “join” and entering the lobby. So, if we want to get any SQF code to run from this point forward, we need to come up with a way of tricking the engine into not removing an event that we set.
As with most of my posts, I will show you the completed code & then explain how it works. Also note, by clicking on the image, it will bring up the complete script in a new tab.
There is a lot here we’ve never discussed. When I was looking into breaking through the firewall, my early attempts were based on trying to abuse a pre-existing exploit that was leaked on unknowncheats. This exploit allowed scripters to abuse the “Draw” event handler on the map to execute code in an MP session. With that in mind, I wondered “If I create a map control on every display, could I use the draw event handler to carry code through the loading process?”. Essentially, if for every display created, I create a map control with a Draw event handler, would that be enough to break the firewall?
In the code, you can see I make extensive use of this idea. On line 36, you can see the idea in action. In all displays, I store a variable pointing to the map control I generate. If a display is found that does not contain this variable (it is nil) then I generate a new map control. Look at like 59, here you can see what makes my code “tick”. Every frame, we reset the onEachFrame event & run GUI_TickThread. As well, onEachFrame fires GUI_TickThread a second time. This fires our core code twice every frame.
Now let’s look at the core exploit on lines 2 to 34, GUI_TickThread.
In the first section, lines 5 to 12, we are checking if the client state is within the “connected, ready to play” phase. This allows us to detect when the game is ready to handle code that would otherwise be run from the mission’s init.sqf file. Basically, we check if we have finished loading into the game. After that, we clear out GUI_TickThread to prevent it from continuing to run & fire “GUI_Run” which is a container for any code we want to run once we’ve bypassed the firewall.
Next, on line 15, we have the secret sauce. This is what we are really using to bypass the firewall. This is where our knowledge of past exploits comes into play. Back August 2nd, 2015, there was an exploit released on UnknownCheats. The original author of this exploit JME, published the exploit on MPGH that same day. Here is his post. When the command inGameUISetEventHandler was implemented, BI forgot to clear it’s value when connecting to an MP session. This allowed cheaters to set the value in the editor & connect to a server with their code, bypassing the firewall that should have cleared the event handler. This was quickly patched in a hotfix a few weeks later. The question is Why has this command come up again, and how does it help make my exploit work? The key is timing. When connecting to an MP session, BI removes events and kills sqf threads. However, what if we set an event after BI has cleared it, and before BI stops my sqf threads from running? This is how IGUISEH makes our code work. By setting this event handler within the setup we have surrounding it, we are able to set the value of “NextAction” before our Draw event handler & OnEachFrame are stopped, as well as after BI clears the original value of the event handler. This way, when we hit the firewall, our event handler’s value is allowed through the wall & into the server. As we load into the server, NextAction automatically fires when we are assigned a playable unit. This restarts our GUI_TickThread and we’ve successfully bypassed the firewall.
That’s a bit complex, here is a diagram that helps explain how the Firewall & SQF Engine interact during this process.
Lastly, on lines 18 to 32, we are simply checking all active displays & creating Map controls with Draw events on all of them. This keeps our code running as we navigate the main menu displays.
On the next page, we’ll review what was covered & discuss the ramifications of firewall bypassing & how servers can protect themselves.