Discovering the Halo Infinite API
As with most of my reverse engineering stories, this one starts with “Hmm… I wonder if I can get this data anyway?” I mentioned this in my previous blog post that I just finished the Halo Infinite campaign, and the next step was multiplayer, which also meant that I wanted to keep track of my stats to see just how bad I am playing against real people and aimbots.
The question about stats in Halo Infinite is interesting, because both Halo Waypoint website and the mobile application do not have that information at all. Not an API call, not a chart - nothing.
The game, on the other hand, has all the stats captured and shown in an easily-consumable format - both on PC and Xbox.
If there is a way to show that data in the game, surely there is a way to do that outside the game too? It very well may be that 343 Industries just hasn’t prioritized that work just yet but I am impatient - I want my game stats now. Which means that now I need to figure out how to get them out of the game. Given that this is all network-based (stats are stored somewhere and are requested dynamically), the clear next step is traffic analysis. I could either analyze the traffic from the Xbox or the PC game.
If you’ve ever tried doing traffic analysis from an Xbox, you’ll know that it’s a pretty tedious and complicated process, so that was way too much overhead for what I wanted to do here. Luckily, because Halo is also on PC that means that I can use the same standard toolkit I always use - Fiddler,
mitmproxy, and Wireshark. Surprise, surprise - nothing more special than that.
I installed Halo through the Xbox app (thank you Game Pass), fired up Fiddler, and was good to go - or so I thought. For folks that don’t know how Fiddler works, the gist of it is that it creates a local proxy on your Windows computer that all traffic passes through before going out to your router. Most applications respect the system proxy settings and make sure to send their traffic through it when it’s present. We’ll get to this point shortly.
With Fiddler running, and the root certificate installed (this will allow me to analyze encrypted HTTPS traffic), I launched Halo Infinite on the desktop and started watching network requests. There were quite a few that were going to Xbox services, even a WebSocket connection was opened for the lobby service, and then - absolute silence. No matter what options I’d choose in the game, no outbound requests were going out. That seemed suspicious, especially considering the fact that I knew there were requests happening. Is the Halo Infinite service sending data over UDP sockets, that doesn’t get captured by Fiddler?
To confirm or deny my assumption, I fired up Wireshark. Unlike Fiddler, Wireshark does not create a proxy and instead taps directly into the network stack, which allows me to track all outbound traffic. I could very clearly see that there was, in fact, a request happening to
halostats.svc.halowaypoint.com - it even used
http-over-tls as the protocol.
What gives? If this is just HTTPS traffic, why do I not see it in Fiddler with a root certificate ready? I was thinking that maybe Halo is doing something funky behind the scenes to detect Fiddler or a different certificate and route around that somehow, but that seemed like a stretch. I opened up
mitmproxy on a macOS machine, then installed its root certificate on my Windows box and started routing traffic through it, which led me to the exact same result I saw with Fiddler - some Xbox Live service calls, but nothing Halo-specific that would interest me.
What makes an application not go through the proxy? And then it clicked with me - not every application respects proxy settings. So, I can set what I want as a proxy, and an application still can tell me to buzz off and use direct routing to their services. What can I do instead? If you’re running Windows, there are two network stacks that you are dealing with - WinINet and WinHTTP. I won’t get too in-depth about those here, but you can read more about the comparison between the two in the official docs.
The problem I was encountering here is that Fiddler is setting up proxy settings for WinINet, which is fine if that’s what your application uses to communicate with the outside world, but is less so if it uses WinHTTP. Assuming that Halo Infinite uses WinHTTP behind the scenes, how do we set up the proxy in such a way that the alternative network stack uses the right settings? With
netsh, of course:
netsh winhttp import proxy source=ie
By doing this, WinHTTP will start using the same proxy settings as WinINet. Once I’ve done that, I once again launched Fiddler and Halo Infinite, and all the requests started magically appearing in Fiddler:
After hours of trying to get this working, the “Eureka!” moment was realizing that proxy settings are more like a recommended path than a requirement. I can now learn more about the Halo Infinite API and its inner workings.
In this discovery process, I also spotted a helpful endpoint that made my life easier:
This is the request that is open to everyone, and it indexes every single API endpoint that the game might use, along with the authentication requirements. More on that later - I’d love to expand on how authentication works against the Halo Infinite API. For now, I’ve started wrapping the API surface in a .NET project called Grunt API (open-source, free, named after the funniest Halo enemy, and on GitHub) to make it easier to query the data and, well, do what I started this whole project for - track match stats. It has rough edges, but it works.