Last week I realized it’s been a year since my last post here. I enjoy writing my stories as much as I enjoy reading others’, but only if I consider them interesting enough, and that’s a high bar honestly. I’ve been into reverse engineering Android apps recently, so I tried to think of a project that could involve that field, along with being interesting to the readers on Medium.
Reversing the Medium Android app could be cool, but for what purpose? After some thoughts, I figured a nice goal could be making an improved version of the app, which filters out membership-required stories.
Because Medium grants the first three stories for free to new visitors, filtering the membership-required stories will be as easy as just making them free, so let’s do that instead in our new app :)
Here is what we are going to do:
All Android applications are being installed from APKs (Android PacKage). This package file format is being used by the Android operating system for distribution and installation of mobile apps, and it contains all of the application resources, assets, certificates, and so on, including the application source code — Dex files which contains Dalvik bytecode. Dalvik bytecode gets executed by the Dalvik Virtual Machine, which is like the Java Virtual Machine, but optimized for mobile phones’ hardware and needs. The Dalvik Virtual Machine is the one responsible for executing programs on the Android operating system, you can think of it as a great and efficent workhorse optimized for mobile phones’ environment.
We can easily extract Dex files from our APK (even with WinRAR, APK is a package file format that was extended from ZIP), but bytecode instructions aren’t human-readable. With Smali/Baksmali (assembler/disassembler) we can convert our Dex files into Smali files, which are written in an assembly-like syntax (still low-level, but certainty readable).
After we have our Smali files we can convert them back into Java files, but with only partial success. Some of the reasons might include usage of obfuscators by the developers (tools that meant to make the reverse engineering process harder). Still, we will try to disassemble what we can because it really ease the process of understanding what an app does.
Apktool and Jadx are two wonderful tools that help us do the above. Apktool produces Smali files, and Jadx tries to go the extra mile for those delicious Java files.
Medium grants new visitors three stories for free, and identify visitors using a session cookie that is being stored on their device. Replacing the session cookie with a new one means becoming a new visitor, as Medium’s servers see it (you can test it out by opening a new incognito window to browse Medium).
So if all of our story-fetching HTTP requests will be sent without a session cookie, we should always get the new visitors treatment, and successfully receive every story.
After a nighttime swim in the application source code, I figured the above can be done most easily by editing the default cookie-storage class OkHttp provides. OkHttp is an HTTP library for Android and Java applications, and the Medium Android app was developed using it. From what I saw on their docs it’s a quite cool library that supports a lot of functionality. Among other things, it provides a neat class named JavaNetCookieJar that can be referenced when constructing OkHttp client instances to make them store cookies persistently. Medium uses it internally, too.
API calls for fetching stories are in the form of /_/api/posts/{postId}
, let’s not serve cookies for those requests. The following picture shows the modifications we will make to JavaNetCookieJar. You can actually see the original implementation of this class here.
^https:\\/\\/api\\.medium\\.com\\/_\\/api\\/posts\\/[^\\/]+$ is a regular expression escaped as a Java string, that matches URLs with the pattern for fetching stories shown above
As mentioned before, we can’t fully obtain an application source code in Java. So in order to enable the recompiling of our app, we need to make all the changes in the assembly level (we do have the complete assembly source code of the app).
Making changes to assembly files sounds disgusting, but it’s really not that bad. Especially if we are talking about Java bytecode assembly (both Java Virtual Machine and Dalvik Virtual Machine have a relatively high-level set of instructions, this is not LC-3 or x86 here).
These are the Smali instructions that correspond to the previous Java statements we wanted to add:
Don’t worry about understanding them, but if you have some background knowledge in low level languages and trying to understand those instructions, I should tell you that v2 is the variable named “url” in the Java source, and cond_4 is a label to a code section that makes the function return an empty list of cookies.
After we add those lines to the application source, we need to recompile everything. We will use Apktool again, this time for building an APK given its Smali files. Now that we have a modifed APK, let’s sign it real quick (with the normal sign process that every Android application needs to go through) and we are done!
In a similar way to what we already did, I added a new setting option for enabling and disabling our changes. Just added some condition statements, duplicated existing settings code, and hooked it all together tightly. Our new app came out quite awesome, check it out below!
The way I most enjoy writing is by focusing on the high-level side of things, without explaining technical stuff too much (like what parameters I passed into Apktool). However, if you would like to learn the actual technical skills which were introduced on this post, I made a short list of a few of my favorite resources:
Reference to reverse engineering Android apps
Smali types, methods, and fields explained
I should probably also mention that the Medium app is fairly easy to reverse, things get more complicated when the developers actually really don’t want you to reverse their app. However, those technical difficulties usually come with a reward- unpatched bugs that remain hidden only because of those difficulties. Bugs in mobile apps are pretty common in my experience, also in big companies’ products (for example, I recently found a bug that grants unlimited amount of game coins in Zynga’s popular game “Draw Something”. I was added to their Whitehats page for that).
Hope you enjoyed our small project, I surely did :)
Medium please don’t sue 🙏🙏🙏It was all for education purposes.