Solving uncrackable1
Table of Contents
bypass root#
In the root bypass segement, we can see from the decomplied code that the segment where the check is taking place is:
if (c.a() || c.b() || c.c())
a("Root detected!");
if (b.a(getApplicationContext()))
a("App is debuggable!");
super.onCreate(paramBundle);
From digging down a bit more we can locate the functions declearations are under sg.vantagepoint.a.c
. We will override all the functions so that they always return false and thus the application will believe that no su
command exists and in the system implying that the system is not rooted.
Java.perform(function() {
console.log("called...");
// bypasss root detection
const rootclassimp = Java.use("sg.vantagepoint.a.c");
rootclassimp.a.implementation = function() {
console.log("touched implimentation a");
return false;
}
rootclassimp.b.implementation = function() {
console.log("touched implimentation b");
return false;
}
rootclassimp.c.implementation = function() {
console.log("touched implimentation c");
return false;
}
})
bypass root and get the password#
Below we will not only bypass the root detection but also use a very common string comparison detection tool to see all the string comparison happening inside the application and from there we should be able to the the password becase from the decompiled version of the code we can see that the comparison is return paramString.equals(new String(arrayOfByte));
Java.perform(function() {
console.log("called...");
// bypasss root detection
const rootclassimp = Java.use("sg.vantagepoint.a.c");
rootclassimp.a.implementation = function() {
console.log("touched implimentation a");
return false;
}
rootclassimp.b.implementation = function() {
console.log("touched implimentation b");
return false;
}
rootclassimp.c.implementation = function() {
console.log("touched implimentation c");
return false;
}
var str = Java.use('java.lang.String'), objectClass = 'java.lang.Object';
str.equals.overload(objectClass).implementation = function(obj) {
var response = str.equals.overload(objectClass).call(this, obj);
if (obj) {
if (obj.toString().length > 5) {
send(str.toString.call(this) + ' == ' + obj.toString() + ' ? ' + response);
}
}
return response;
}
})
get password using overload method#
In the same way, we can also use another method to obtain the password.
Java.perform(function() {
const obj1 = Java.use("sg.vantagepoint.a.c")
obj1.a.implementation = function() {
console.log("function a");
return false;
}
obj1.b.implementation = function() {
console.log("function b");
return false;
}
obj1.c.implementation =function() {
console.log("function c");
return false;
}
const obj2 = Java.use("sg.vantagepoint.uncrackable1.a");
const base64 = Java.use("android.util.Base64");
const String = Java.use("java.lang.String");
obj2.a.implementation = function() {
console.log("overloading a");
var decodedBase64 = base64.decode("5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=", 0);
console.log("decoded base64");
var value = obj2.b("8d127684cbc37c17616d806cf50473cc")
console.log("got the value of 'value'");
const obj3 = Java.use("sg.vantagepoint.a.a");
var new_arrayOfBytes = obj3.a(value, decodedBase64)
const password = String.$new(new_arrayOfBytes);
console.log(password);
}
})
This should give you the password as shown below:
[Android SDK built for x86 64::owasp.mstg.uncrackable1 ]-> overloading a
decoded base64
got the value of 'value'
password is: I want to believe
get the password using another method#
Although the above process had a good learning experience but it is bit long and has many steps. What if we could only hook the encryption function and just get the value from there? This method was obtained from [1]. I made some small modifications for my own conveniance but the concept reamins same.
Java.perform(function() {
const obj1 = Java.use("sg.vantagepoint.a.c")
obj1.a.implementation = function() {
console.log("function a");
return false;
}
obj1.b.implementation = function() {
console.log("function b");
return false;
}
obj1.c.implementation =function() {
console.log("function c");
return false;
}
const string = Java.use("java.lang.String");
const obj2 = Java.use("sg.vantagepoint.a.a");
obj2.a.implementation = function(param1, param2){
const password = this.a(param1,param2);
console.log(string.$new(password));
}
})
[Android SDK built for x86 64::owasp.mstg.uncrackable1 ]-> function a
function b
function c
I want to believe
Error: Implementation for a expected return value compatible with [B
at ne (frida/node_modules/frida-java-bridge/lib/class-factory.js:678)
at <anonymous> (frida/node_modules/frida-java-bridge/lib/class-factory.js:655)
Process crashed: java.lang.NullPointerException: Attempt to get length of null array