preface

I believe that many partners have some understanding of Xposed, Cydia Substrate, Frida and other hook tools, and used in their own work, this article mainly shares Frida environment configuration and basic use, as well as related functions in daily development and debugging help

Configure Frida’s environment

A Frida environment installation can be done by referring to the official documentation, or by referring to the practices shared online, and using a more stable specific version

# pip3 install Frida -tools # Frida --version # Frida 15.0.8 # At https://github.com/frida/frida/releases to download the corresponding server version frida - server - 15.0.8 - android - arm64. Xz # unxz unxz decompression Frida-server-15.0.8-android-arm64. Xz adb root ADB push frida-server-15.0.8-android-arm64 /data/locl/ TMP/adb shell chmod 755 /data/local/ TMP /frida-server-15.0.8-android-arm64 /data/local/ TMP /frida-server-15.0.8-android-arm64 & # Print the installed program and package name frida-ps -UaiCopy the code

The basic use

  • For Frida’s development environment, refer to the author’s Exmaple on Github

    Open the download with vscode

    git clone git://github.com/oleavr/frida-agent-example.git npm install

  • After the configuration is complete, there will be corresponding code prompt and function description when using the corresponding function

  • Refer to the official documentation for the JavaScript API for basic usage

Constructor of the Hook class

// frida -U --no-pause -f com.gio.test.three -l agent/constructor.js function main() { Java.perform(function () { Java.use( "com.growingio.android.sdk.autotrack.AutotrackConfiguration" ).$init.overload("java.lang.String", Implementation = Function (projectId, urlScheme) {var result = this.$init(projectId, urlScheme) urlScheme); Console. log("projectId, urlScheme: ", projectId, urlScheme); return result; }; }); } setImmediate(main);Copy the code

A normal function of the Hook class

// frida -U --no-pause -f com.gio.test.three -l agent/function.js function main() { Java.perform(function () { Java.use(  "com.growingio.android.sdk.CoreConfiguration" ).setDebugEnabled.implementation = function (enabled) { console.log("enabled: ", enabled); Return this.setDebugenabled (enabled); }; }); } setImmediate(main);Copy the code

Modify class/instance parameters

// Attach to the process by attach, // frida-u-n demos -l agent/instance.js function main() {java.perform (function () { Java.choose("com.growingio.android.sdk.autotrack.AutotrackConfiguration", { onMatch: function (instance) { console.log("instance.mProjectId", instance.mProjectId.value); console.log("instance.mUrlScheme", instance.mUrlScheme.value); / / modify variables through the assignment, if variables and functions with the same name, need to add '_' in front of the variables, such as: _mProjectId instance. MProjectId. Value = "t - bfc5d6a3693a110d"; instance.mUrlScheme.value = "t-growing.d80871b41ef40518"; }, onComplete: function () {}, }); }); } setImmediate(main);Copy the code

Constructing an array

Frida -u -n demos -l agent/array.js function main() {java.perform (function () {// construct byte array var byteArray = Java.array("byte", [0x46, 0x72, 0x69, 0x64, 0x61]); Log (java.use (" java.lang.string ").$new(byteArray)); / / structural var charArray = Java char array. The array (" char ", [" F ", "r", "I", "d", "a"]); console.log(Java.use("java.lang.String").$new(charArray)); }); } setImmediate(main);Copy the code

Static functions are called actively

// Attach to the process by attach, {static function.js function main() {java.perform (function ()) {static function.js {/ / setWebContentsDebuggingEnabled needed in the main thread invokes the Java. ScheduleOnMainThread (function () {the console. The log (" isMainThread ", Java.isMainThread()); / / active trigger static function calls, allowing the WebView debugging Java. Use (" android. Its. WebView). SetWebContentsDebuggingEnabled (true); }); }); } setImmediate(main);Copy the code

Dynamic function calls actively

// Attach to the process by attach, Function main() {java.perform ()  { Java.choose("com.growingio.android.sdk.autotrack.AutotrackConfiguration", { onMatch: Function (instance) {console.log(" instance.isdebugenabled: ", instance.isdebugenabled ()); console.log("instance.getChannel: ", instance.getChannel()); }, onComplete: function () {}, }); }); } setImmediate(main);Copy the code

Define a class

// Attach to the process by attach, Function main() {java.perform (function () { Var TestRunnable = java.registerClass ({name: "com.example.TestRunnable", // implements: java.registerClass [java.lang.Runnable")], // Fields: {testFields: "java.lang.String",}, methods: {// constructor $init: [ { returnType: "void", argumentTypes: ["java.lang.String"], implementation: Function (testFields) {// Call the parent constructor this.$super.$init(); // assign the value of this.testfields. Console. log("$init: ", this.testfields.value);},},], // method run: [{returnType: "void", implementation: function () { console.log( "testFields: ", this.testFields.value ); }, }, ], }, }); TestRunnable.$new("simple test").run(); }); } setImmediate(main);Copy the code

Prints the function call stack

// Attach to the process by attach, Function main() {java.perform (function ()) {mediate () {mediate ();  { Java.use( "com.growingio.android.sdk.autotrack.click.ViewClickInjector" ).viewOnClick.overload( "android.view.View$OnClickListener", "android.view.View" ).implementation = function (listener, Console.log (java.use (" android.util.log ").getStackTraceString(" android.util.log ") Java.use("java.lang.Throwable").$new() ) ); return this.viewOnClick(listener, view); }; }); } setImmediate(main);Copy the code

Enumeration this

/ / to attach additional to the process, or use setTimeout replace setImmediate / / frida - U - n demos - l agent/enumerateClassLoaders. Js / / suitable for the application of reinforcement, Find corresponding this / / usually directly in the application. The attach. The phrase "(' android. The content. The Context). Context corresponding this implementation function main() { Java.perform(function () { Java.enumerateClassLoaders({ onMatch: Function (loader) {try {// Check if there is a class in the loader that we need hook (loader.findClass("com.growingio.android.sdk.CoreConfiguration")) { console.log("found loader:", loader); Java.classFactory.loader = loader; } } catch (error) { console.log("found error: ", error); console.log("failed loader: ", loader); } }, onComplete: function () { console.log("enum completed!" ); }}); console.log( Java.use("com.growingio.android.sdk.CoreConfiguration").$className ); }); } setImmediate(main);Copy the code

Enumeration class

// Attach to the process by attach, Replacement or use setTimeout setImmediate / / frida - U - n demos - l agent/enumerateLoadedClasses. Js function main () { Java.perform(function () { Java.enumerateLoadedClasses({ onMatch: function (name, Handle) {/ / judge whether we need to find the if (name) the toString () = = ". Com. Growingio. The android SDK. CoreConfiguration ") {the console. The log (" name, handle", name, handle); Java.use(name).isDebugEnabled.implementation = function () { return true; }; } }, onComplete: function () {}, }); }); } setImmediate(main);Copy the code

Load the external dex and print the object through gson

// Attach to the process by attach, Or use setTimeout to replace setImmediate // frida-u-n demos -l agent/ printobject.js // Convert gson. Jar to classes.dex via d8 ~ / Library/Android/SDK/build - the tools / 30.0.3 / d8 - lib ~ / Library/Android/SDK/platforms/Android - 30 / Android. The jar gson - 2.8.8. Jar // If it is already available in the SDK, // adb push classes.dex /data/local/ TMP function main() {java.perform () {java.perform () { Java.choose("com.growingio.android.sdk.autotrack.AutotrackConfiguration", { onMatch: Function (instance) {/ / load the external dex Java openClassFile ("/data/local/TMP/classes. Dex "). The load (); var Gson = Java.use("com.google.gson.Gson"); // JSON.stringify: "<instance: com.growingio.android.sdk.autotrack.AutotrackConfiguration>" console.log("JSON.stringify: ", JSON.stringify(instance)); // Gson.$new().toJson: {" mImpressionScale ": 0.0," mCellularDataLimit ": 10," mDataCollectionEnabled ": true," mDataCollectionServerHost ":" http://api.gr owingio.com","mDataUploadInterval":15,"mDebugEnabled":true,"mOaidEnabled":false,"mProjectId":"bfc5d6a3693a110d","mSessio nInterval":30,"mUploadExceptionEnabled":false,"mUrlScheme":"growing.d80871b41ef40518"} console.log("Gson.$new().toJson: ", Gson.$new().toJson(instance)); }, onComplete: function () {}, }); }); } setImmediate(main);Copy the code

Usage scenarios

  1. Bypass certificate binding, verification, buried request verification

  2. During SDK development, problems reported by customers generally need to be recurred and investigated by using the customer’s APP. In this case, parameter information and return information of specific functions can be obtained through FRIda, which can effectively shorten the communication time with the customer. In this scenario, use obedience is the most convenient

  3. New customers want to see what the SDK can provide before they integrate. They can find compatibility problems in advance by loading and initializing the DEX through Frida

  4. When an app integrating with an earlier VERSION of the SDK gets feedback, replace the SDK with a Tinker hotfix idea to verify that it has been fixed in the current version

  5. Open SDK-related functions remote RPC calls, used to test buried protocols and other scenarios

Outside the chain address

  1. Frida: frida.re/docs/instal…

  2. Example github address: github.com/oleavr/frid…

  3. JavaScript API: Frida. re/docs/javasc…

  4. Demo used in the function description: github.com/growingio/g…

  5. R0capture Android Application Layer pass-through script Github address: github.com/r0ysue/r0ca…

  6. Object Github address: github.com/sensepost/o…