There was an interesting post on r/kappa (warning: subreddit isn’t completely SFW) today talking about unlocking colors for characters in Street Fighter V without having to really grind Survival mode, which interests me because that’s annoying to have to do it per-character and per-costume.
(I’m going to hide the remainder of this behind a jump because it’s going to get long and it’s going to have a bunch of API request dumps in it. You probably don’t want to read those if that’s not what you came here for.)
By the way, after I wrote this and before I published it, the complete list of codes was published in a thread on r/kappa as well, so now I’m pushing it out there. I was holding onto it for disclosure’s sake, but now it’s in the open and there’s no reason for me to not publish it at this point.
Here’s the bit that clues you in:
Set a breakpoint for SF5/contents/(whatever your number string is)/serviceid. Head over to survival and clear it once (preferably on easy as it is the shortest), after the congratulations screen press X, and head over to your computer . You should see the “serviceid” breakpoint pop up shortly after. Keep it on the request, and then click on the “text” tab below. Make sure to pay attention to the “SVLnnnnnn” (n’s are variable numbers for you dummies) portion of the request, the rest of the string does not matter. You will notice that the SVL portion is accompanied by HEX, which is great since we now only have to deal with 16 variables that are in pretty predictable patterns.
I didn’t know what they were using, so I did some Googling and found out that you can set connection breakpoints using Charles, which seems like a pretty rad tool to have in any case to monitor net traffic if you need to see what things are doing. I grabbed a copy and started taking a look.
(If you do anything involving web connections, just based on my initial playing around with it, you should probably grab a copy of this app because it’s immediately obvious how useful it would be. And—key to this—you can set it up as a proxy server on your internal network and run other things through it.)
I set up Charles and ran my PS4 through it, which at least gave me a good indication of what was going on with the network traffic. (It’s kind of interesting to see the PSN stuff in any case.)
At a basic level, you can at least see that API requests are sent through:
If you try to access it over plain HTTP, you won’t get a response, so let’s try accessing it through HTTPS in a web browser with no request.
Hey, so this is interesting because any client worth its salt is going to reject this right out of hand. (Any web browser is going to tell you to stop looking at what you are looking at immediately.) Because:
- The certificate is expired (!!!)
- The certificate is apparently issued by Capcom and I’d be kind of surprised if they even have a root certificate
Continuing, this becomes more interesting because this means that the SFV client is specifically designed to ignore certificate warnings. If you bypass the security warning, you see this default Apache welcome screen:
We can see more interesting stuff by testing that certificate warning thing and trying to peep the HTTPS traffic from the app by using a self-signed certificate on the proxy server. Lo and behold, this works and SFV is perfectly willing to accept any self-signed cert as part of the connection, so we can now intentionally man-in-the-middle our own SFV server communication and take a look at it.
To do this, just set Charles as an SSL proxy only for content request to the CFN API.
By the way, sniffing this traffic and reverse engineering it would appear to be how V-League and before it fightinggame.community are able to pull ranked league information out of the API and do neat things with it, such as my profile on V-League.
It’s super-interesting to see those applications and realize that they are using a completely undocumented and (likely unintentional) insecure API to pull stats, when it would be completely amazing if all fighting games had a player API like this to yank information out of and do neat things with.
I’ll skip past introductory material here and get to the heart of what I wanted to show you, which is a series of API requests made from my SFV client to the CFN servers when running through Survival mode on Easy with Ibuki, and take a look at how the service communicates.
Ibuki Survival Unlocks in API Requests
If you start sniffing the traffic to take a look at it and then begin a round of Survival, the first thing you will notice is that there is a regular “heartbeat” request/response sent from your game client to the server (I won’t print that out here; it’s routine and easy to see).
Breaking this heartbeat stuff would be what “disconnects” you from the service, so it’s pretty easy to think that either max HTTPS connections or overloaded load balancers from the number of people who were playing right away. It sends this heartbeat approximately once per minute (there is some drift of a second or so between requests).
When you complete a full set of survival, nothing happens until you press a button at the congratulations screen. When you do that, your system sends an API request with the following CSV payload (for Ibuki with Battle Costume on Easy in this example):
Yes, I know that is ugly.
The response was this (I’ve removed certain identifiers for my account just in case):
After receiving this, my client sends an API request to:
GET /bentov2/sf5/contents/2791787330/entitlements HTTP/1.1
And gets this response, which seems to be the list of things my account has unlocked (and I’m assuming also includes DLC entitlements):
This response is larger than the previous entitlement response I received, which indicates that I have added unlocks to my account. Checking it through a diff tool, I found that one entitlement had been added:
Immediately after receiving this, my client sent *another* request to the API with the serviceid list:
And likewise received another response:
Running a diff between these shows the following changes:
- The Survival mode requests were not repeated.
- These entries were added:
After this, another entitlement request was sent, and received this response:
Three additional entitlements were added:
- dxRuwGB3 (“type 4”)
- fsGNNJdl (“type 7”)
- 1eZ1K105 (“type 7”)
If I compare this to the system message log, I have the following sets of additions:
- Ibuki Battle Outfit color 3 was unlocked (the entitlement from the first request)
- I received my fight money, XP, and then more fight money for the level increase and defeating Survival on Easy.
- One title was unlocked for Ibuki (I believe for passing level 10.)
- Two titles were unlocked in the Shop.
- Color 13 for Ibuki was unlocked in the Shop. (For passing level 10.)
It would be interesting to see what the various “types” of entitlements are. They are clearly stored server-side but how they are connected to your account is somewhat unclear. Are they connected to your PSN account, or only to your CFN account? If that’s the case, what happens if you lose access to your CFN account for any reason? Will your entitlements follow you to the new account?
Conjecture on Unlocks
Here’s what seems to happen with unlocks:
- All unlocking is actually client-side; this is why trainers work with the PC version. Nothing is being done to check game state during a survival run or other unlock prerequisite (except maybe trials per-level; I haven’t checked). When the mode is complete, a request is sent to the server saying “my account did this.” The server this says back “yes, we agree, your account did this.”
- This would seem to be unnecessary, but it’s possible this is what allows your account unlocks to “follow” you from PS4 to PS4 whenever you are logged in using your PSN account, which is tied to your CFN account (I think).
- If the unlock of one thing cascades into another state change, such as clearing a mode adding XP to your account that would move you past a threshold, the client takes the server response, does the math on its side, and then sends back “OK; I did these other things now” and the server says “yup, you did; here’s what you now have access to.” It does this until the API reports back that nothing new has been unlocked.
- The values for Survival unlocks appear to follow a predictable pattern that goes game mode, character value, costume value. There is another value sent along with them I’m not sure about. If you know which values to send, you could tell the service you have cleared any level of survival with any character and any costume, and it would have no choice but to trust that information.
- This probably doesn’t exactly apply to story unlocks (character or cinematic), trials, or demonstrations, though I’m assuming those are also very systemic and likewise don’t have anything other than a simple value check.
- Because of this, if you have your account information and you have a valid authentication cookie (which is how they are “securing” the API service), you can spoof mode completions to the server and it has no way of knowing whether you actually did what you are saying you did. It will simply believe your request and grant you unlocks, XP, and Fight Money.
I’m not entirely sure where the total XP value is stored. The request from the client has values that tell the server what your character and player levels are, but it would probably be easy to tell if those were fake because the XP on the server side would not match the player level on the client side. (Update: the XP is stored server-side.)
Anyway, this has been a lot of goofing around and it’s late, so I’ll stop there with just this information. If this leads you somewhere, that’s great! Leave a comment on ping me on Twitter to let me know. I’ve also set up a GitHub repository for sample data and hopefully some documentation the community can put together; if you have more data or want to contribute to that, please file a pull request.