Skip to content

QoL fixes #743

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions agent/src/android/pinning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,10 @@ const okHttp3CertificatePinnerCheck = (ident: number): Promise<any | undefined>
return CertificatePinnerCheck;

} catch (err) {
if ((err as Error).message.indexOf("ClassNotFoundException") === 0) {
if ((err as Error).message.indexOf("java.lang.ClassNotFoundException") !== 0) {
throw err;
}
return null;
}
});
};
Expand Down Expand Up @@ -162,9 +163,10 @@ const okHttp3CertificatePinnerCheckOkHttp = (ident: number): Promise<any | undef
return CertificatePinnerCheckOkHttp;

} catch (err) {
if ((err as Error).message.indexOf("ClassNotFoundException") === 0) {
if ((err as Error).message.indexOf("java.lang.ClassNotFoundException") !== 0) {
throw err;
}
return null;
}
});
};
Expand Down Expand Up @@ -192,9 +194,10 @@ const appceleratorTitaniumPinningTrustManager = (ident: number): Promise<any | u
return PinningTrustManagerCheckServerTrusted;

} catch (err) {
if ((err as Error).message.indexOf("ClassNotFoundException") === 0) {
if ((err as Error).message.indexOf("java.lang.ClassNotFoundException") !== 0) {
throw err;
}
return null;
}
});
};
Expand Down Expand Up @@ -233,9 +236,10 @@ const trustManagerImplVerifyChainCheck = (ident: number): Promise<any> => {
return TrustManagerImplverifyChain;

} catch (err) {
if ((err as Error).message.indexOf("ClassNotFoundException") === 0) {
if ((err as Error).message.indexOf("java.lang.ClassNotFoundException") !== 0) {
throw err;
}
return null;
}
});
};
Expand Down Expand Up @@ -271,9 +275,10 @@ const trustManagerImplCheckTrustedRecursiveCheck = (ident: number): Promise<any>
return TrustManagerImplcheckTrustedRecursive;

} catch (err) {
if ((err as Error).message.indexOf("ClassNotFoundException") === 0) {
if ((err as Error).message.indexOf("java.lang.ClassNotFoundException") !== 0) {
throw err;
}
return null;
}
});
};
Expand Down Expand Up @@ -303,9 +308,10 @@ const phoneGapSSLCertificateChecker = (ident: number): Promise<any> => {
return SSLCertificateCheckerExecute;

} catch (err) {
if ((err as Error).message.indexOf("ClassNotFoundException") === 0) {
if ((err as Error).message.indexOf("java.lang.ClassNotFoundException") !== 0) {
throw err;
}
return null;
}
});
};
Expand Down
189 changes: 123 additions & 66 deletions agent/src/android/root.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,18 @@ const testKeysCheck = (success: boolean, ident: number): any => {
send(c.blackBright(`[${ident}] `) + `Marking "test-keys" check as ` + c.green(`failed`) + `.`);
return false;
};

return JavaString.contains;
});
};

const execSuCheck = (success: boolean, ident: number): any => {
return wrapJavaPerform(() => {
const JavaRuntime: Runtime = Java.use("java.lang.Runtime");
const iOException: IOException = Java.use("java.io.IOException");
const JavaRuntime_exec = JavaRuntime.exec.overload("java.lang.String");

JavaRuntime.exec.overload("java.lang.String").implementation = function (command: string) {
JavaRuntime_exec.implementation = function (command: string) {
if (command.endsWith("su")) {
if (success) {
send(c.blackBright(`[${ident}] `) + `Check for 'su' using command exec detected, allowing.`);
Expand All @@ -66,6 +69,8 @@ const execSuCheck = (success: boolean, ident: number): any => {
// call the original method
return this.exec.overload("java.lang.String").call(this, command);
};

return JavaRuntime_exec;
});
};

Expand Down Expand Up @@ -93,6 +98,8 @@ const fileExistsCheck = (success: boolean, ident: number): any => {
// call the original method
return this.exists.call(this);
};

return JavaFile.exists;
});
};

Expand All @@ -101,7 +108,9 @@ const fileExistsCheck = (success: boolean, ident: number): any => {
const rootBeerIsRooted = (success: boolean, ident: number): any => {
return wrapJavaPerform(() => {
const RootBeer = Java.use("com.scottyab.rootbeer.RootBeer");
RootBeer.isRooted.overload().implementation = function () {
const RootBeer_isRooted = RootBeer.isRooted.overload();

RootBeer_isRooted.implementation = function () {
if (success) {
send(
c.blackBright(`[${ident}] `) +
Expand All @@ -116,6 +125,8 @@ const rootBeerIsRooted = (success: boolean, ident: number): any => {
);
return false;
};

return RootBeer_isRooted;
});
};

Expand All @@ -137,6 +148,8 @@ const rootBeerCheckForBinary = (success: boolean, ident: number): any => {
);
return false;
};

return RootBeer.checkForBinary;
});
};

Expand All @@ -158,13 +171,17 @@ const rootBeerCheckForDangerousProps = (success: boolean, ident: number): any =>
);
return false;
};

return RootBeer.checkForDangerousProps;
});
};

const rootBeerDetectRootCloakingApps = (success: boolean, ident: number): any => {
return wrapJavaPerform(() => {
const RootBeer = Java.use("com.scottyab.rootbeer.RootBeer");
RootBeer.detectRootCloakingApps.overload().implementation = function () {
const RootBeer_detectRootCloakingApps = RootBeer.detectRootCloakingApps.overload();

RootBeer_detectRootCloakingApps.implementation = function () {
if (success) {
send(
c.blackBright(`[${ident}] `) +
Expand All @@ -179,6 +196,8 @@ const rootBeerDetectRootCloakingApps = (success: boolean, ident: number): any =>
);
return false;
};

return RootBeer_detectRootCloakingApps;
});
};

Expand All @@ -200,6 +219,8 @@ const rootBeerCheckSuExists = (success: boolean, ident: number): any => {
);
return false;
};

return RootBeer.checkSuExists;
});
};

Expand All @@ -221,34 +242,46 @@ const rootBeerDetectTestKeys = (success: boolean, ident: number): any => {
);
return false;
};

return RootBeer.detectTestKeys;
});
};

const rootBeerCheckSeLinux = (success: boolean, ident: number): any => {
return wrapJavaPerform(() => {
const Util = Java.use("com.scottyab.rootbeer.util");
Util.isSelinuxFlagInEnabled.overload().implementation = function () {
if (success) {
try {
const Util = Java.use("com.scottyab.rootbeer.util");
Util.isSelinuxFlagInEnabled.overload().implementation = function () {
if (success) {
send(
c.blackBright(`[${ident}]`) +
`Rootbeer.util->isSelinuxFlagInEnabled() check detected, marking as ${c.green("true")}`,
);
return true;
}

send(
c.blackBright(`[${ident}]`) +
`Rootbeer.util->isSelinuxFlagInEnabled() check detected, marking as ${c.green("true")}`,
c.blackBright(`[${ident}] `) +
`Rootbeer.util->isSelinuxFlagInEnabled() check detected, marking as ${c.green("false")}`,
);
return true;
}

send(
c.blackBright(`[${ident}] `) +
`Rootbeer.util->isSelinuxFlagInEnabled() check detected, marking as ${c.green("false")}`,
);
return false;
};
return false;
};

return Util.isSelinuxFlagInEnabled;
} catch (err) {
if ((err as Error).message.indexOf("java.lang.ClassNotFoundException") === 0) {
return null;
};
throw err;
}
});
};

const rootBeerNative = (success: boolean, ident: number): any => {
return wrapJavaPerform(() => {
const RootBeerNative = Java.use("com.scottyab.rootbeer.RootBeerNative");
RootBeerNative.checkForRoot.overload('[Ljava.lang.Object;').implementation = function () {
const RootBeerNative_checkForRoot = RootBeerNative.checkForRoot.overload('[Ljava.lang.Object;');
RootBeerNative_checkForRoot.implementation = function () {
if (success) {
send(
c.blackBright(`[${ident}] `) +
Expand All @@ -263,74 +296,98 @@ const rootBeerNative = (success: boolean, ident: number): any => {
);
return 0;
};

return RootBeerNative_checkForRoot;
});
};

// ref: https://www.ayrx.me/gantix-jailmonkey-root-detection-bypass/
const jailMonkeyBypass = (success: boolean, ident: number): any => {
const jailMonkeyBypass = (success: boolean, ident: number): Promise<any> => {
return wrapJavaPerform(() => {
const JavaJailMonkeyModule = Java.use("com.gantix.JailMonkey.JailMonkeyModule");
const JavaHashMap = Java.use("java.util.HashMap");
const JavaFalseObject = Java.use("java.lang.Boolean").FALSE.value;

JavaJailMonkeyModule.getConstants.implementation = function () {
send(
c.blackBright(`[${ident}] `) +
`JailMonkeyModule.getConstants() called, returning false for all keys.`
);

const hm = JavaHashMap.$new();
hm.put("isJailBroken", JavaFalseObject);
hm.put("hookDetected", JavaFalseObject);
hm.put("canMockLocation", JavaFalseObject);
hm.put("isOnExternalStorage", JavaFalseObject);
hm.put("AdbEnabled", JavaFalseObject);

return hm;
};
try {
const JavaJailMonkeyModule = Java.use("com.gantix.JailMonkey.JailMonkeyModule");
const JavaHashMap = Java.use("java.util.HashMap");
const JavaBoolean = Java.use("java.lang.Boolean")
const JavaFalseObject = JavaBoolean.FALSE.value;
const JavaTrueObject = JavaBoolean.TRUE.value;

JavaJailMonkeyModule.getConstants.implementation = function () {
if (success) {
send(
c.blackBright(`[${ident}] `) +
`RootBeer->checkForDangerousProps() check detected, marking as ${c.green("true")} for all keys.`,
);
const hm = JavaHashMap.$new();
hm.put("isJailBroken", JavaTrueObject);
hm.put("hookDetected", JavaTrueObject);
hm.put("canMockLocation", JavaTrueObject);
hm.put("isOnExternalStorage", JavaTrueObject);
hm.put("AdbEnabled", JavaTrueObject);

return hm;
}
send(
c.blackBright(`[${ident}] `) +
`JailMonkeyModule.getConstants() called, returning ${c.green("false")} for all keys.`
);

return JavaJailMonkeyModule;
const hm = JavaHashMap.$new();
hm.put("isJailBroken", JavaFalseObject);
hm.put("hookDetected", JavaFalseObject);
hm.put("canMockLocation", JavaFalseObject);
hm.put("isOnExternalStorage", JavaFalseObject);
hm.put("AdbEnabled", JavaFalseObject);

return hm;
};

return JavaJailMonkeyModule.getConstants;
} catch (err) {
if ((err as Error).message.indexOf("java.lang.ClassNotFoundException") === 0) {
return null;
};
throw err;
}
});
};

export const disable = (): void => {
export const disable = async (): Promise<void> => {
const job: jobs.Job = new jobs.Job(jobs.identifier(), 'root-detection-disable');

job.addImplementation(testKeysCheck(false, job.identifier));
job.addImplementation(execSuCheck(false, job.identifier));
job.addImplementation(fileExistsCheck(false, job.identifier));
job.addImplementation(jailMonkeyBypass(false, job.identifier));

job.addImplementation(await testKeysCheck(false, job.identifier));
job.addImplementation(await execSuCheck(false, job.identifier));
job.addImplementation(await fileExistsCheck(false, job.identifier));
job.addImplementation(await jailMonkeyBypass(false, job.identifier));
// RootBeer functions
job.addImplementation(rootBeerIsRooted(false, job.identifier));
job.addImplementation(rootBeerCheckForBinary(false, job.identifier));
job.addImplementation(rootBeerCheckForDangerousProps(false, job.identifier));
job.addImplementation(rootBeerDetectRootCloakingApps(false, job.identifier));
job.addImplementation(rootBeerCheckSuExists(false, job.identifier));
job.addImplementation(rootBeerDetectTestKeys(false, job.identifier));
job.addImplementation(rootBeerNative(false, job.identifier));
job.addImplementation(rootBeerCheckSeLinux(false, job.identifier));
job.addImplementation(await rootBeerIsRooted(false, job.identifier));
job.addImplementation(await rootBeerCheckForBinary(false, job.identifier));
job.addImplementation(await rootBeerCheckForDangerousProps(false, job.identifier));
job.addImplementation(await rootBeerDetectRootCloakingApps(false, job.identifier));
job.addImplementation(await rootBeerCheckSuExists(false, job.identifier));
job.addImplementation(await rootBeerDetectTestKeys(false, job.identifier));
job.addImplementation(await rootBeerNative(false, job.identifier));
job.addImplementation(await rootBeerCheckSeLinux(false, job.identifier));

jobs.add(job);
};

export const enable = (): void => {
export const enable = async (): Promise<void> => {
const job: jobs.Job = new jobs.Job(jobs.identifier(), "root-detection-enable");

job.addImplementation(testKeysCheck(true, job.identifier));
job.addImplementation(execSuCheck(true, job.identifier));
job.addImplementation(fileExistsCheck(true, job.identifier));
job.addImplementation(jailMonkeyBypass(true, job.identifier));
job.addImplementation(await testKeysCheck(true, job.identifier));
job.addImplementation(await execSuCheck(true, job.identifier));
job.addImplementation(await fileExistsCheck(true, job.identifier));
job.addImplementation(await jailMonkeyBypass(true, job.identifier));

// RootBeer functions
job.addImplementation(rootBeerIsRooted(true, job.identifier));
job.addImplementation(rootBeerCheckForBinary(true, job.identifier));
job.addImplementation(rootBeerCheckForDangerousProps(true, job.identifier));
job.addImplementation(rootBeerDetectRootCloakingApps(true, job.identifier));
job.addImplementation(rootBeerCheckSuExists(true, job.identifier));
job.addImplementation(rootBeerDetectTestKeys(true, job.identifier));
job.addImplementation(rootBeerNative(true, job.identifier));
job.addImplementation(rootBeerCheckSeLinux(false, job.identifier));
job.addImplementation(await rootBeerIsRooted(true, job.identifier));
job.addImplementation(await rootBeerCheckForBinary(true, job.identifier));
job.addImplementation(await rootBeerCheckForDangerousProps(true, job.identifier));
job.addImplementation(await rootBeerDetectRootCloakingApps(true, job.identifier));
job.addImplementation(await rootBeerCheckSuExists(true, job.identifier));
job.addImplementation(await rootBeerDetectTestKeys(true, job.identifier));
job.addImplementation(await rootBeerNative(true, job.identifier));
job.addImplementation(await rootBeerCheckSeLinux(false, job.identifier));

jobs.add(job);
};
Loading