How Bypassed KonyLab Code Protection
Hey, I’m Mahmoud Mosbah, a cyber security specialist at Isec.
I’m going to go through how I was able to bypass KonyLab’s code protection and obtain the entire source code in the Android app.
It was an engagement for one of our clients so, Keeping the application name private, we will call it APP or Victim.
I should start by mentioning the blogs that were used in this attack.
What is Kony Visualizer?
Kony Visualizer is a powerful yet easy-to-use integrated development environment (IDE) for developing, building, testing, debugging, and deploying mobile apps for multiple platforms, all from a single code base.
Because of the way the application code is packaged, reverse engineering mobile applications created using Kony might be difficult. Unlike Android apps, which compile to DEX, application code for JavaScript is packaged into the app and loaded at runtime.
Identifying a Kony mobile application
There are two ways to identify this.
At first, The Kony mobile application has Kony or KonyLabs directories and a pluginversions.properties
file in the assets/
directory.
The pluginversions.properties
file contains the version numbers of the Kony software and plugin used to build the application.
The second way using the APKid
tool as seen below.
Where is the code?
The usual way to go is to use Jadx to open the APK and view its source code.
The source code had been written using JavaScript, and its files exist in the directory js in the assets directory.
But it’s encrypted, as you can see below.
How Kony Works?
The core of the Kony framework is contained in libkonyjsvm.so
This library is loaded when the app launches.
We went through the application and found this suspicious function loadFilesToVM
We will follow its logic in depth.
According to the Maulvi blog, Kony process flow is that when the APK file is compiled, Kony would compress all Javascript files to zip, and the zip files would be encrypted.
Additionally, when we use the application, the encrypted files will be decrypted then decompressed and the JS files will be executed
We go into the deep loadFilesToVM
function using IDA Pro
.
As Maulvi blog too, after analysis libkonyjsvm.so
, we found that the application got the asset files, then used the lzf
function, then freed the memory.
what do lzf function do?
lzf
is a simple program to compress or uncompress files.
So what are the parameters it needs?
As seen in the next image, the lzf
function takes 4 parameters.
a1
: Pointer to the compressed input data.a2
: Length of the compressed input data.v64
: Pointer to the output buffer where decompressed data will be stored.v70
: Length of the output buffer.
Exploit
The idea now is to hook the input for this function after these files are decrypted; these files will be zip files, which contain the JS files.
This is the code used for this exploit.
Java.perform(() => {
var inc = 0;
function waitForLibrary(name, callback) {
var lib = null;
var interval = setInterval(() => {
try {
lib = Module.ensureInitialized(name);
console.log(`[+] ${name} is loaded`);
clearInterval(interval);
callback();
} catch (e) {
console.log(`[+] Waiting for ${name} to be loaded...`);
}
}, 100); // Check every 100ms
}
waitForLibrary("libkonyjsvm.so", () => {
Interceptor.attach(Module.getExportByName("libkonyjsvm.so", "lzf"), {
onEnter: function(args) {
console.log("[+] Hooked zip files!");
this.zipfiles = args[2];
this.ziplength = args[3];
},
onLeave: function(retval) {
send("================");
console.log("zip files length", this.ziplength);
var readzipfiles = Memory.readByteArray(this.zipfiles, this.ziplength.toInt32());
var file = new File("/data/data/com.victim.app/" + inc + ".zip", "w");
inc += 1;
file.write(readzipfiles);
}
});
});
});
This script checks the library is loaded every 100 ms, then the script hooks the input files into lzf
and saves them as zip files.
So, we will run the script and go through the application to load all encrypted js files.
The zip files collected to the path /data/data/com.victim.app/
.
We pulled these files and unzip them, as seen below.
As seen, all JS files had been collected successfully.
After some searching in these files We found some hardcoded credentials, and we found some files for encryption, which could lead to decrypting all app files in the local storage that was created in the runtime.
That’s all for today. I hope you all enjoyed it and learned something new.
For any questions just text me Xmosb7