Skip to content

Commit

Permalink
(fix/feat) Job handler update.
Browse files Browse the repository at this point in the history
  • Loading branch information
IPMegladon committed Oct 13, 2024
1 parent 5f22e0a commit 3ebf386
Show file tree
Hide file tree
Showing 22 changed files with 371 additions and 352 deletions.
41 changes: 8 additions & 33 deletions agent/src/android/hooking.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { colors as c } from "../lib/color.js";
import { IJob } from "../lib/interfaces.js";
import * as jobs from "../lib/jobs.js";
import { ICurrentActivityFragment } from "./lib/interfaces.js";
import {
Expand Down Expand Up @@ -67,11 +66,7 @@ const getPatternType = (pattern: string): PatternType => {
export const lazyWatchForPattern = (query: string, watch: boolean, dargs: boolean, dret: boolean, dbt: boolean): void => {
// TODO: Use param to control interval
let found = false;
const job: IJob = {
identifier: jobs.identifier(),
implementations: [],
type: `notify-class for: ${query}`,
};
const job: jobs.Job = new jobs.Job(jobs.identifier(),`notify-class for: ${query}`);

// This method loops over all enumerate matches and then calls watch
// with the arguments specified in the parent function
Expand Down Expand Up @@ -262,11 +257,7 @@ export const watch = (pattern: string, dargs: boolean, dbt: boolean, dret: boole
if (patternType === PatternType.Klass) {

// start a new job container
const job: IJob = {
identifier: jobs.identifier(),
implementations: [],
type: `watch-class for: ${pattern}`,
};
const job: jobs.Job = new jobs.Job(jobs.identifier(),`watch-class for: ${pattern}`);

const w = watchClass(pattern, job, dargs, dbt, dret);
jobs.add(job);
Expand All @@ -275,11 +266,7 @@ export const watch = (pattern: string, dargs: boolean, dbt: boolean, dret: boole
}

// assume we have PatternType.Regex
const job: IJob = {
identifier: jobs.identifier(),
implementations: [],
type: `watch-pattern for: ${pattern}`,
};
const job: jobs.Job = new jobs.Job(jobs.identifier(),`watch-pattern for: ${pattern}`);
jobs.add(job);

return new Promise((resolve, reject) => {
Expand All @@ -299,7 +286,7 @@ export const watch = (pattern: string, dargs: boolean, dbt: boolean, dret: boole
});
};

const watchClass = (clazz: string, job: IJob, dargs: boolean = false, dbt: boolean = false, dret: boolean = false): Promise<void> => {
const watchClass = (clazz: string, job: jobs.Job, dargs: boolean = false, dbt: boolean = false, dret: boolean = false): Promise<void> => {
return wrapJavaPerform(() => {
const clazzInstance: JavaClass = Java.use(clazz);

Expand Down Expand Up @@ -337,7 +324,7 @@ const watchClass = (clazz: string, job: IJob, dargs: boolean = false, dbt: boole
};

const watchMethod = (
fqClazz: string, job: IJob, dargs: boolean, dbt: boolean, dret: boolean,
fqClazz: string, job: jobs.Job, dargs: boolean, dbt: boolean, dret: boolean,
): Promise<void> => {
const [clazz, method] = splitClassMethod(fqClazz);
// send(`Attempting to watch class ${c.green(clazz)} and method ${c.green(method)}.`);
Expand Down Expand Up @@ -400,11 +387,7 @@ const watchMethod = (
};

// Push the implementation so that it can be nulled later
if (job.implementations) {
job.implementations.push(m);
} else {
job.implementations = [ m ];
}
job.addImplementation(m);

});
});
Expand Down Expand Up @@ -534,11 +517,7 @@ export const setReturnValue = (fqClazz: string, filterOverload: string | null, n
}

return wrapJavaPerform(() => {
const job: IJob = {
identifier: jobs.identifier(),
implementations: [],
type: `set-return for: ${fqClazz}`,
};
const job: jobs.Job = new jobs.Job(jobs.identifier(), `set-return for: ${fqClazz}`);

const targetClazz: JavaClass = Java.use(clazz);

Expand Down Expand Up @@ -570,11 +549,7 @@ export const setReturnValue = (fqClazz: string, filterOverload: string | null, n
};

// record override
if (job.implementations) {
job.implementations.push(m);
} else {
job.implementations = [ m ];
}
job.addImplementation(m);

});

Expand Down
21 changes: 10 additions & 11 deletions agent/src/android/keystore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
KeyStore,
SecretKeyFactory
} from "./lib/types.js";
import { IJob } from "../lib/interfaces.js";
import * as jobs from "../lib/jobs.js";

// Dump entries in the Android Keystore, together with a flag
Expand Down Expand Up @@ -181,7 +180,7 @@ export const clear = () => {

// Watch for KeyStore.load();
// TODO: Store the keystores themselves maybe?
const keystoreLoad = (ident: string): any | undefined => {
const keystoreLoad = (ident: number): Promise<any> => {
return wrapJavaPerform(() => {
const ks: KeyStore = Java.use("java.security.KeyStore");
const ksLoad = ks.load.overload("java.io.InputStream", "[C");
Expand All @@ -193,12 +192,14 @@ const keystoreLoad = (ident: string): any | undefined => {
`called, loading a ${c.cyanBright(this.getType())} keystore.`);
return this.load(stream, password);
};

return ksLoad
});
};

// Watch for Keystore.getKey().
// TODO: Extract more information, like the key itself maybe?
const keystoreGetKey = (ident: string): any | undefined => {
const keystoreGetKey = (ident: number): Promise<any> => {
return wrapJavaPerform(() => {
const ks: KeyStore = Java.use("java.security.KeyStore");
const ksGetKey = ks.getKey.overload("java.lang.String", "[C");
Expand All @@ -211,20 +212,18 @@ const keystoreGetKey = (ident: string): any | undefined => {
`called, returning a ${c.greenBright(key.$className)} instance.`);
return key;
};

return ksGetKey;
});
};

// Android KeyStore watcher.
// Many, many more methods can be added here..
export const watchKeystore = (): void => {
const job: IJob = {
identifier: jobs.identifier(),
type: "android-keystore-watch",
};
job.implementations = [];
export const watchKeystore = async (): Promise<void> => {
const job: jobs.Job = new jobs.Job(jobs.identifier(), "android-keystore-watch");

job.implementations.push(keystoreLoad(job.identifier));
job.implementations.push(keystoreGetKey(job.identifier));
job.addImplementation(await keystoreLoad(job.identifier));
job.addImplementation(await keystoreGetKey(job.identifier));

jobs.add(job);
};
68 changes: 32 additions & 36 deletions agent/src/android/pinning.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { colors as c } from "../lib/color.js";
import { qsend } from "../lib/helpers.js";
import { IJob } from "../lib/interfaces.js";
import * as jobs from "../lib/jobs.js";
import { wrapJavaPerform } from "./lib/libjava.js";
import {
Expand All @@ -17,7 +16,7 @@ import {
// a simple flag to control if we should be quiet or not
let quiet: boolean = false;

const sslContextEmptyTrustManager = (ident: string): any => {
const sslContextEmptyTrustManager = (ident: number): Promise<any> => {
// -- Sample Java
//
// "Generic" TrustManager Example
Expand Down Expand Up @@ -83,7 +82,7 @@ const sslContextEmptyTrustManager = (ident: string): any => {
});
};

const okHttp3CertificatePinnerCheck = (ident: string): any | undefined => {
const okHttp3CertificatePinnerCheck = (ident: number): Promise<any | undefined> => {
// -- Sample Java
//
// Example used to test this bypass.
Expand Down Expand Up @@ -125,7 +124,7 @@ const okHttp3CertificatePinnerCheck = (ident: string): any | undefined => {
});
};

const okHttp3CertificatePinnerCheckOkHttp = (ident: string): any | undefined => {
const okHttp3CertificatePinnerCheckOkHttp = (ident: number): Promise<any | undefined> => {
// -- Sample Java
//
// Example used to test this bypass.
Expand Down Expand Up @@ -167,7 +166,7 @@ const okHttp3CertificatePinnerCheckOkHttp = (ident: string): any | undefined =>
});
};

const appceleratorTitaniumPinningTrustManager = (ident: string): any | undefined => {
const appceleratorTitaniumPinningTrustManager = (ident: number): Promise<any | undefined> => {
return wrapJavaPerform(() => {
try {
const pinningTrustManager: PinningTrustManager = Java.use("appcelerator.https.PinningTrustManager");
Expand Down Expand Up @@ -204,7 +203,7 @@ const appceleratorTitaniumPinningTrustManager = (ident: string): any | undefined
// blogs/2017/november/bypassing-androids-network-security-configuration/
//
// More information: https://sensepost.com/blog/2018/tip-toeing-past-android-7s-network-security-configuration/
const trustManagerImplVerifyChainCheck = (ident: string): any | undefined => {
const trustManagerImplVerifyChainCheck = (ident: number): Promise<any> => {
return wrapJavaPerform(() => {
try {
const trustManagerImpl: TrustManagerImpl = Java.use("com.android.org.conscrypt.TrustManagerImpl");
Expand Down Expand Up @@ -241,7 +240,7 @@ const trustManagerImplVerifyChainCheck = (ident: string): any | undefined => {
// Android 7+ TrustManagerImpl.checkTrustedRecursive()
// The work in the following method is based on:
// https://techblog.mediaservice.net/2018/11/universal-android-ssl-pinning-bypass-2/
const trustManagerImplCheckTrustedRecursiveCheck = (ident: string): any | undefined => {
const trustManagerImplCheckTrustedRecursiveCheck = (ident: number): Promise<any> => {
return wrapJavaPerform(() => {
try {
const arrayList: ArrayList = Java.use("java.util.ArrayList");
Expand Down Expand Up @@ -276,7 +275,7 @@ const trustManagerImplCheckTrustedRecursiveCheck = (ident: string): any | undefi
});
};

const phoneGapSSLCertificateChecker = (ident: string): any | undefined => {
const phoneGapSSLCertificateChecker = (ident: number): Promise<any> => {
return wrapJavaPerform(() => {
try {
const sslCertificateChecker: SSLCertificateChecker = Java.use("nl.xservices.plugins.SSLCertificateChecker");
Expand All @@ -285,20 +284,20 @@ const phoneGapSSLCertificateChecker = (ident: string): any | undefined => {
`overriding SSLCertificateChecker.execute()`),
);

const SSLCertificateCheckerExecute = sslCertificateChecker.execute;

SSLCertificateCheckerExecute.overload(
"java.lang.String", "org.json.JSONArray", "org.apache.cordova.CallbackContext").implementation =
// tslint:disable-next-line:only-arrow-functions
function (str, jsonArray, callBackContext) {
qsend(quiet,
c.blackBright(`[${ident}] `) + `Called ` +
c.green(`SSLCertificateChecker.execute()`) +
`, not throwing an exception.`,
);
callBackContext.success("CONNECTION_SECURE");
return true;
};
const SSLCertificateCheckerExecute = sslCertificateChecker.execute.overload("java.lang.String",
"org.json.JSONArray", "org.apache.cordova.CallbackContext");

SSLCertificateCheckerExecute.implementation = function (str, jsonArray, callBackContext) {
qsend(quiet,
c.blackBright(`[${ident}] `) + `Called ` +
c.green(`SSLCertificateChecker.execute()`) +
`, not throwing an exception.`,
);
callBackContext.success("CONNECTION_SECURE");
return true;
};

return SSLCertificateCheckerExecute;

} catch (err) {
if ((err as Error).message.indexOf("ClassNotFoundException") === 0) {
Expand All @@ -309,25 +308,22 @@ const phoneGapSSLCertificateChecker = (ident: string): any | undefined => {
};

// the main exported function to run all of the pinning bypass methods known
export const disable = (q: boolean): void => {
export const disable = async (q: boolean): Promise<void> => {
if (q) {
send(c.yellow(`Quiet mode enabled. Not reporting invocations.`));
quiet = true;
}

const job: IJob = {
identifier: jobs.identifier(),
type: "android-sslpinning-disable",
};

job.implementations = [];
const job: jobs.Job = new jobs.Job(jobs.identifier(), "android-sslpinning-disable");

job.addImplementation(await sslContextEmptyTrustManager(job.identifier));
// Exceptions can cause undefined values if classes are not found. Thus addImplementation only adds if function was hooked
job.addImplementation(await okHttp3CertificatePinnerCheck(job.identifier));
job.addImplementation(await okHttp3CertificatePinnerCheckOkHttp(job.identifier));
job.addImplementation(await appceleratorTitaniumPinningTrustManager(job.identifier));
job.addImplementation(await trustManagerImplVerifyChainCheck(job.identifier));
job.addImplementation(await trustManagerImplCheckTrustedRecursiveCheck(job.identifier));
job.addImplementation(await phoneGapSSLCertificateChecker(job.identifier));

job.implementations.push(sslContextEmptyTrustManager(job.identifier));
job.implementations.push(okHttp3CertificatePinnerCheck(job.identifier));
job.implementations.push(okHttp3CertificatePinnerCheckOkHttp(job.identifier));
job.implementations.push(appceleratorTitaniumPinningTrustManager(job.identifier));
job.implementations.push(trustManagerImplVerifyChainCheck(job.identifier));
job.implementations.push(trustManagerImplCheckTrustedRecursiveCheck(job.identifier));
job.implementations.push(phoneGapSSLCertificateChecker(job.identifier));
jobs.add(job);
};
Loading

0 comments on commit 3ebf386

Please sign in to comment.