This guide is not for pirating a game or motivating to do something illegal. It’s purely educational and a representation of how I did a structured analysis of a program based on a real-life example.
Unfortunately, they fixed nothing and just added obfuscation “to fix the issue”… It took me like 30 minutes to get my patch working again and they even change the code so I can patch it even easier! Please do not use “Security through obscurity”!
Around a week later after releasing this post, I was really happy to see that my “patch” did not work anymore! I thought maybe they learned from it. The developers added with version 3.0 obfuscation to all DLL’s.
Yousician is an interactive music service to learn and play a musical instrument. There are several instruments to select from affecting not only the notes but also the view will be changed accordingly. Link to Yousician
I played for several years guitar and wasn’t that bad but stopped since I had too much work to do. So I haven’t played for a long time and now since I found myself in a position with
While searching for a program I found Yousician which looked promising, very modern and easy to use. I downloaded the app and tried some lessons. After a short time, it told me that my time is up and I should come back tomorrow to play further. Well, that sucks! I wanted to try out more, get more comfy with the courses and find out if it is really worth spending money on a subscription. Since it’s not super cheap.
The curiousity of an security dude
On the next day, I logged into my account and wanted to play the next lesson. Unfortunately, the software told me to wait some additional hours. Which made me curious about how they are validating their “free time”. As of then, my assumption was that they have some server-side variable which gets set if you played the free lessons and blocked the access to further once. Then at the beginning of the next day, it will reset the variable to let the user play again. -Why I thought that dunno, just thought it makes sense to implement such a check- But now it looked like they check and log the
Next, after exceeding my test period, I tried to change my local date to the next day, expecting to get nothing out of it. Crazy enough I worked!! I couldn’t believe what just happened. They trust the clients’ date/time information to control over the free trial time. 🤦 It was not really nice to change the date all time especially because browsers will just reject the requests due to the certificate which can’t be verified.
Nevertheless, it was quite fun and now I was able to learn and get to know the program as much as I want, except the premium songs/features. So I started to dig a bit deeper into the client itself.
The client has a launcher that checks for missing files and updates. Next to the launcher is a version.txt which holds the current version and a launcher-out.txt which is a debug file listing the API endpoint for downloading the latest software. With it, we are able to check for recent updates, which is quite good if we patch the software (which we will do in a minute) so we know when to rebuild our patch again.
Next, there are two folders. One is named Yousicion_Data and MonoBleedingEdge. The second one is used by Unity Games and contains the latest Runtime .dll’s. So we know now that we are again dealing with a Unity game. (More on unity reverse engineering here) My next thought is where is the Managed folder with the .dll files used by the program? If we want to manipulate the client then we need the responsible file. It’s in the Yousicion_Data folder as expected. A quick look into the folder reveals us that there are 21
We see some namespaces in the dll and try to get an idea where important functions regarding manipulating of the subscription could be.
My first guess would be Y.Premium.Gameplay(1) followed by Y.Revenue.MenuPages.EnableLicensedContent (2) and Y.Revenue.* (3).
Why is quiet simple. We try to find some premium functions so we can then trace back enums which are most likely available like premium plan or instruments to get to the subscription class.
(1) The first interesting function is the following.
// Token: 0x06002ED5 RID: 11989 RVA: 0x000ACE4A File Offset: 0x000AB04A
public static bool FICMKVB(BaseSongData XGKCbbB, KLOAIdB fBYMWcf, YHYBQUB GbIEeAB, bool UXQfcTB)
return GbIEeAB.PremiumPlusPreview && XGKCbbB.SongMeta.IsLicensed && UXQfcTB && !fBYMWcf.CurrentProfile.Value.SubscriptionData.HasLicensedContent;
Analysing the function
This method is being called with three parameters whereas we only know what one (BaseSongData) represents. The meaning of the other two is unfortunately unknown. After comparing some variables it finally returns a boolean. Thanks to the variable PremiumPlusPreview and IsLicensed we are able to guess what the function does. It most likely checks if XGKCbbB (the song) is for premium users and if we are listening to some kind of preview. We could now try to patch the method with just returning true but that would take extremely long to patch every check to get access to all paid features. Which is way more valuable here is the second parameter! fBYMWcf has some readable attributes which are really interesting. It holds the current profile with the subscription data. This is what we want to find and manipulate! Now we just have to trace back a bit and find the relevant class or namespace to dig deeper.
Unfortunately it does not look like there is something interesting here. But this interface inherits another one, so trace back a bit further.
Now that we are at the base interface we can take a look at what class (WdPHJNA) the profile represents. The result is another interface representing the current profile and with all its variables. Now we can analyse the interface and check where it is being used or referenced.
This is what I found after following the analysis for a very short time. This is gold! This method builds a new subscription and we want to change our current one! The only problem is when does it get called? On purchasing / Login / Register, we don’t know. So let’s dig a bit deeper into the type (BUeZOQB) of the subscription itself.
This is exactly what we wanted! We can set all subscription information into our profile we just have to take a look at what class is implementing this interface and we manipulating the constructor to what we want. Since we know that the software has to initiate the current profile for it to work (anonymous access is not possible) it has to execute our changed code.
How can I protect myself
- Do NOT rely on information provided by the client.
- Always check permission or authorization (for actions) on the backend.
- Write important information on the backend and provide just read access to the client.
- Request periodically information from the client to verify that the data were not modified.
- Add integrity checks to your software that blocks access if a modification is detected.
Hands On: Dynamic and Static Reverse Engineering
In this article I will show some techniques used in dynamic and static analysis and demonstrate them using a simple console game.
Structural approach of bypassing a subscription system
This guide is not for pirating a game or motivating to do something illegal. It’s purely educational and a representation of how I did a structured analysis of a program based on a real-life example. UPDATE #2 Unfortunately, they fixed nothing and just added obfuscation “to fix the issue”… It took me like 30 minutes to…
Disclosing a Severe Vulnerability in a Unity Game
Disclaimer: this article is about a vulnerability I found in a Unity game. I disclosed this to the developers of the game which approved of this post but asked me to censor it so there would not be instructions to pirating their game associated with its name publicly. Some time ago after a long day…
Best Case Hacking: A Take On Teeworlds
Having fun hacking an open source game!
1 thought on “Structural approach of bypassing a subscription system”
I haven’t looked at the game in a while. They have luckily improved their security as far as I can tell.
Nevertheless, the approach which is the lesson learned here is still valid and useful for this kind of system.