Frida Trace (frida-trace)

frida-trace is a frida script used to trace the classes and functions within an application

Using frida-trace it is possible to create hooking functions. To use frida-trace you need to first find the functions to hook into. To do this you can use frida-ps to find the correct process running, like so:

$ frida-ps -Ua 

  PID  Name      Identifier                       
-----  --------  ---------------------------------
15929  DVIA-v2   com.highaltitudehacks.DVIAswiftv2
15916  Settings  com.apple.Preferences        

Once you have identified the application you want to hook in to you can start either tracing all of the functions within the application, which could take a long time, or you can filter them out by specifying exactly what you want to look for. frida-trace also accepts wild card searching.

$ frida-trace -U -m "*[*cryp* *]" -p 15929                                                                                                                                                        ✔ 

Instrumenting...                                                        
-[NEIKEv2EncryptionProtocol isEqual:]: Auto-generated handler at "/home/mantis/__handlers__/NEIKEv2EncryptionProtocol/isEqual_.js"
-[NEIKEv2EncryptionProtocol hash]: Auto-generated handler at "/home/mantis/__handlers__/NEIKEv2EncryptionProtocol/hash.js"
-[NEIKEv2EncryptionProtocol description]: Auto-generated handler at "/home/mantis/__handlers__/NEIKEv2EncryptionProtocol/description.js"
-[NEIKEv2EncryptionProtocol copyWithZone:]: Auto-generated handler at "/home/mantis/__handlers__/NEIKEv2EncryptionProtocol/copyWithZone_.js"
-[NEIKEv2EncryptionProtocol isAuthenticated]: Auto-generated handler at "/home/mantis/__handlers__/NEIKEv2EncryptionProtocol/isAuthenticated.js"
-[NEIKEv2EncryptionProtocol setWireType:]: Auto-generated handler at "/home/mantis/__handlers__/NEIKEv2EncryptionProtocol/setWireType_.js"
-[NEIKEv2EncryptionProtocol setIs256Bit:]: Auto-generated handler at "/home/mantis/__handlers__/NEIKEv2EncryptionProtocol/setIs256Bit_.js"
-[NEIKEv2EncryptionProtocol wireType]: Auto-generated handler at "/home/mantis/__handlers__/NEIKEv2EncryptionProtocol/wireType.js"
-[NEIKEv2EncryptionProtocol is256Bit]: Auto-generated handler at "/home/mantis/__handlers__/NEIKEv2EncryptionProtocol/is256Bit.js"
-[NEIKEv2EncryptionProtocol initWithEncryptionWireType:is256Bit:]: Auto-generated handler at "/home/mantis/__handlers__/NEIKEv2EncryptionProtocol/initWithEncryptionWireType_is256Bit_.js"
-[NEIKEv2EncryptionProtocol isGCM]: Auto-generated handler at "/home/mantis/__handlers__/NEIKEv2EncryptionProtocol/isGCM.js"
-[NEIKEv2EncryptionProtocol initWithEncryptionType:]: Auto-generated handler at "/home/mantis/__handlers__/NEIKEv2EncryptionProtocol/initWithEncryptionType_.js"
-[NEIKEv2EncryptionProtocol keyLength]: Auto-generated handler at "/home/mantis/__handlers__/NEIKEv2EncryptionProtocol/keyLength.js"
-[NEIKEv2EncryptionProtocol blockLength]: Auto-generated handler at "/home/mantis/__handlers__/NEIKEv2EncryptionProtocol/blockLength.js"
-[NEIKEv2EncryptionProtocol ccAlgorithm]: Auto-generated handler at "/home/mantis/__handlers__/NEIKEv2EncryptionProtocol/ccAlgorithm.js"
-[NEIKEv2EncryptionProtocol ivLength]: Auto-generated handler at "/home/mantis/__handlers__/NEIKEv2EncryptionProtocol/ivLength.js"
-[NEIKEv2EncryptionProtocol icvLength]: Auto-generated handler at "/home/mantis/__handlers__/NEIKEv2EncryptionProtocol/icvLength.js"
+[RNOpenSSLDecryptor decryptData:withSettings:password:error:]: Auto-generated handler at "/home/mantis/__handlers__/RNOpenSSLDecryptor/decryptData_withSettings_password_error_.js"
+[RNOpenSSLDecryptor decryptData:withPassword:error:]: Auto-generated handler at "/home/mantis/__handlers__/RNOpenSSLDecryptor/decryptData_withPassword_error_.js"
+[RNOpenSSLDecryptor decryptData:withEncryptionKey:HMACKey:error:]: Auto-generated handler at "/home/mantis/__handlers__/RNOpenSSLDecryptor/decryptData_withEncryptionKey_HM_72d173d3.js"
+[RNOpenSSLDecryptor decryptData:withSettings:encryptionKey:IV:error:]: Auto-generated handler at "/home/mantis/__handlers__/RNOpenSSLDecryptor/decryptData_withSettings_encrypt_7a7b5d2a.js"
<Removed for brevity>

Started tracing 406 functions. Press Ctrl+C to stop.                    

Once these functions have been instrumented you can go back to using the application until you find where and how these functions are called. frida-trace automatically creates a handler for each class and method it finds. This means that you can modify the handler script to do more useful actions such as dumping the arguments and return values.

The example below shows that we have instrumented all of the *[RNDecryptor *] functions.

  2110 ms  +[RNDecryptor decryptData:0x280ba1720 withPassword:0x2805fcc60 error:0x16b981d48]
  2110 ms     | -[RNDecryptor initWithPassword:0x2805fcc60 handler:0x104823378]
  2110 ms     |    | -[RNDecryptor initWithEncryptionKey:0x0 HMACKey:0x0 handler:0x104823378]
  2110 ms     | -[RNDecryptor addData:0x280ba1720]
  2110 ms     |    | -[RNDecryptor inData]
  2110 ms     |    | -[RNDecryptor inData]
  2110 ms     |    | -[RNDecryptor consumeHeaderFromData:0x2805fdcb0]
  2110 ms     |    |    | -[RNDecryptor updateOptionsForPreamble:0x280ba0880]
  2110 ms     |    |    | -[RNDecryptor settings]
  2110 ms     |    |    | -[RNDecryptor settings]
  2110 ms     |    |    | -[RNDecryptor settings]
  2110 ms     |    |    | -[RNDecryptor encryptionKey]
  2110 ms     |    |    | -[RNDecryptor HMACKey]
  2110 ms     |    |    | -[RNDecryptor settings]
  2110 ms     |    |    | -[RNDecryptor settings]
  2110 ms     |    |    | -[RNDecryptor password]
  2110 ms     |    |    | -[RNDecryptor settings]
  2118 ms     |    |    | -[RNDecryptor setEncryptionKey:0x2805fee80]
  2118 ms     |    |    | -[RNDecryptor password]
  2118 ms     |    |    | -[RNDecryptor settings]
  2126 ms     |    |    | -[RNDecryptor setHMACKey:0x28059ee80]
  2126 ms     |    |    | -[RNDecryptor setPassword:0x0]
  2126 ms     |    |    | -[RNDecryptor settings]
  2126 ms     |    |    | -[RNDecryptor settings]
  2126 ms     |    |    | -[RNDecryptor encryptionKey]
  2127 ms     |    |    | -[RNDecryptor setEncryptionKey:0x0]
  2127 ms     |    |    | -[RNDecryptor HMACKey]
  2127 ms     |    |    | -[RNDecryptor settings]
  2127 ms     |    |    | -[RNDecryptor HMACKey]
  2127 ms     |    |    | -[RNDecryptor HMACKey]
  2127 ms     |    |    | -[RNDecryptor settings]
  2127 ms     |    |    | -[RNDecryptor setHMACKey:0x0]
  2127 ms     |    |    | -[RNDecryptor hasV1HMAC]
  2127 ms     |    | -[RNDecryptor inData]
  2127 ms     |    | -[RNDecryptor inData]
  2127 ms     |    | -[RNDecryptor inData]
  2127 ms     |    | -[RNDecryptor decryptData:0x280bab120]
  2127 ms     | -[RNDecryptor finish]
           /* TID 0x11f5b */
  2127 ms  -[RNDecryptor inData]
           /* TID 0x403 */
  2127 ms     | -[RNDecryptor .cxx_destruct]

We can use the handler functions to grab the password from the password function as an example. So we open up the __handlers__/RNDecryptor/password.js file, as this is where the function can be manipulated.

As seen in the onLeave function we can log out the return value of the hooked function call. Due to the way that frida works we have to cast the return value to a string. This means that we have to use the ObjC.Object(retval).toString() method.

/*
 * Auto-generated by Frida. Please modify to match the signature of -[RNDecryptor password].
 * This stub is currently auto-generated from manpages when available.
 *
 * For full API reference, see: https://frida.re/docs/javascript-api/
 */

{
  /** 
   * Called synchronously when about to call -[RNDecryptor password].
   *
   * @this {object} - Object allowing you to store state for use in onLeave.
   * @param {function} log - Call this function with a string to be presented to the user.
   * @param {array} args - Function arguments represented as an array of NativePointer objects.
   * For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8.
   * It is also possible to modify arguments by assigning a NativePointer object to an element of this array.
   * @param {object} state - Object allowing you to keep state across function calls.
   * Only one JavaScript function will execute at a time, so do not worry about race-conditions.
   * However, do not use this to store function arguments across onEnter/onLeave, but instead
   * use "this" which is an object for keeping state local to an invocation.
   */
  onEnter(log, args, state) {
        log(`-[RNDecryptor password]`); 
  },  

  /** 
   * Called synchronously when about to return from -[RNDecryptor password].
   *
   * See onEnter for details.
   *
   * @this {object} - Object allowing you to access state stored in onEnter.
   * @param {function} log - Call this function with a string to be presented to the user.
   * @param {NativePointer} retval - Return value represented as a NativePointer object.
   * @param {object} state - Object allowing you to keep state across function calls.
   */
  onLeave(log, retval, state) {
        log("Return Value: " + ObjC.Object(retval).toString());
  }
}

When we perform the action again within the application we can see that frida-trace has successfully logged out the encryption password.

...
  1783 ms     |    |    | -[RNDecryptor setEncryptionKey:0x280513cc0]
  1783 ms     |    |    | -[RNDecryptor password]
  1783 ms     |    |    | Return Value: @daloq3as$qweasdlasasjdnj
...

Last updated