Objects and Methods

  • Objects and methods provide the ability to modify or insert code, enabling dynamic changes to the behavior of an application.

  • In SMALI

    • invoke-virtual: Indicates that the method being called is a public method.

    • invoke-direct: Refers to constructors or private methods.

    • new-instance vx, type: Creates a new instance of a specified type (e.g., java.io.FileInputStream) and stores it in a register (e.g., v0).

      • This is particularly powerful because it allows the use of classes like FileOutputStream to interact with files, enabling the search for or manipulation of sensitive information.

  • Important Blocks

    • Java code

      public void helloWorld() {
          String text = "Hello World!";
          System.out.println(text);
      }
    • SMALI Code:

      const-string v0, "Hello World!"
      
      sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
      
      invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
      • const-string v0, "Hello World!": This loads the string "Hello World!" into the register v0.

      • sget-object: It retrieves the static field System.out (which is a PrintStream) and stores it in register v1.

      • invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V: This invokes the println method on the PrintStream object in v1, passing the string in v0 as an argument.

  • Useful SMALI snippets

    1. Printing Variables/Return Values via System.out.println

      • Java Code:

        String password = "Pa%%w0rd!";
        System.out.println(password);
      • Corresponding SMALI Code:

        .line 14
        const-string v0, "Pa%%w0rd!"  # Load the string "Pa%%w0rd!" into register v0
        .line 15
        .local v0, "password":Ljava/lang/String;  # Declare v0 as a local variable named "password" of type String
        
        sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;  # Retrieve the static field System.out (PrintStream) and store it in v1
        
        invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V  # Invoke the println method on System.out, passing the string in v0
      • Usage:

        • To print any variable or return value, place the object or value you want to print into v0 (or another register), then use sget-object and invoke-virtual as shown above.

        • After modifying the SMALI code, run the app and check the logcat output to see the printed value:

          $ adb logcat
    2. Printing Byte Values as Base64 Encoded Strings

      • When working with cryptographic functions, keys or initialization vectors (IVs) are often stored as byte arrays. To print these byte arrays in a readable text format, you can encode them as Base64 strings. Here's how you can achieve this in both Java and SMALI:

      • Java Code:

        System.out.println(Base64.encodeToString(<byteArray>, 0));
      • Corresponding SMALI Code:

        const/4 v5, 0x0 
        invoke-static {v2, v5}, Landroid/util/Base64;->encodeToString([BI)Ljava/lang/String;  # Encode the byte array in v2 to a Base64 string
        move-result-object v5  # Store the resulting Base64 string in v5
        
        sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;  # Get the System.out PrintStream object
        invoke-virtual {v1, v5}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V  # Print the Base64 string
      • Usage:

        • Insert this SMALI snippet into the existing SMALI code of the application at the point where you want to print the byte array as a Base64 string.

        • Adjust the register v2 to point to the byte array you want to encode and print.

        • After running the app, check the logcat output to see the printed Base64 string:

          $ adb logcat

📍We have an encrypted message, and we aim to display it as plain text.

There are two approaches to achieve this:

  1. Use System.out.println() to Display the Decrypted Message in Logcat:

    • By inserting System.out.println() in the code, we can print the decrypted message to the logcat output. This is useful for debugging and verifying the decryption process.

  2. Identify the Register Containing the Decrypted Message:

    • Determine which register holds the decrypted message and use it to display the message on the screen. For example, if register v0 contains the decrypted message and register v2 contains the encrypted message, we can modify the code to invoke v0 instead of v2 to show the decrypted message on the screen.

  • To achieve the first approach

    1. Identify the Register Holding the Decrypted Message

    2. Insert SMALI Code to Print the Message:

      • Use sget-object to get the System.out PrintStream object.

      • Use invoke-virtual to call println and print the decrypted message.

    3. Place the Code in the Correct Location:

      • Insert the SMALI code immediately after the decryption logic to ensure the decrypted message is printed.

  • Example in SMALI

    # Assume v0 contains the decrypted message
    .line 42
    .local v0, "decryptedMessage":Ljava/lang/String;  # Declare v0 as the decrypted message
    
    # Print the decrypted message to Logcat
    sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;  # Get System.out
    invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V  # Print v0
  • How to Test:

    1. Rebuild the APK with the modified SMALI code.

    2. Install the APK on a device or emulator.

    3. Run the app and monitor the Logcat output:

      adb logcat
    4. Look for the decrypted message in the logs.


Last updated