Disabling runtime status checks in an Android application



    In the last article I reviewed the OWASP Mobile TOP 10 and then I didn’t have a good case to demonstrate the need to protect the source code. An interesting case for the demonstration has appeared only recently and who is interested in looking at our experience in circumventing environmental checks, let’s under the cat.

    When evaluating the work of one of the projects, our team immediately realized that the case would not be easy. The developers approached well the issue of information protection in the program and implemented checks of the state of the execution environment. The application did not start under any of the following conditions:

    • the unit was rutted;
    • emulator was used;
    • USB connection;
    • using developer mode.

    The developers did not obfustirovat the source code and was not embedded test for modification of the code, which allowed me to analyze the ways in which the checks were performed and perform the necessary manipulations with them.

    So, let's begin. According to the OWASP Mobile TOP 10, which we use as a basic testing methodology at Hacken, source code analysis (Reverse Engineering) - this vulnerability includes the analysis of binary files for determining source code, libraries, algorithms, etc. Software such as IDA Pro, Hopper, otool and other reverse engineering tools can provide insight into the internal workings of an application. This can be used to search for application vulnerabilities, extract critical information such as backend server, encryption keys or intellectual property.

    For basic static analysis, I used an interesting tool such as MobSF, which performed decompilation and basic static analysis. After decompiling, I was interested in java- and smali-codes of the program. Java code is needed for analysis, and we will make changes to the smali code. In more detail, how smali and java correspond can be read here .

    After reviewing the list of classes, I found a file that is responsible for checking the phone’s rudeness (see Fig. 1) - rootingcheck / RootBeerNative.java.


    Fig. 1. List of application classes

    After analyzing the class, it became clear that you need to look further for the calls to the checkForRoot () and setLogDebugMessage () functions (see. Fig. 2).


    Fig. 2. The source code of the classroom check for rutting

    Using the grep command, we get the following results, which show us which files have a call to the checkForRoot () and setLogDebugMessage () methods.

    Search results:
    root @ kali: ~ / Desktop # grep -nr 'RootBeerNative' ******** _ v_0.9.2 /

    ********_v_0.9.2/smali/rootingcheck/RootBeerNative.smali:1:.class public Lrootingcheck/RootBeerNative;
    ********_v_0.9.2/smali/rootingcheck/RootBeerNative.smali:17:    sput-boolean v0, Lrootingcheck/RootBeerNative;->?:Z
    ********_v_0.9.2/smali/rootingcheck/RootBeerNative.smali:28:    sput-boolean v0, Lrootingcheck/RootBeerNative;->?:Z
    ********_v_0.9.2/smali/rootingcheck/RootBeerNative.smali:57:    sget-boolean v0, Lrootingcheck/RootBeerNative;->?:Z
    ********_v_0.9.2/smali/o/CM.smali:591:    new-instance v1, Lrootingcheck/RootBeerNative;
    ********_v_0.9.2/smali/o/CM.smali:593:    invoke-direct {v1}, Lrootingcheck/RootBeerNative;-><init>()V
    ********_v_0.9.2/smali/o/CM.smali:685:    new-instance v0, Lrootingcheck/RootBeerNative;
    ********_v_0.9.2/smali/o/CM.smali:687:    invoke-direct {v0}, Lrootingcheck/RootBeerNative;-><init>()V
    ********_v_0.9.2/smali/o/CM.smali:689:    invoke-static {}, Lrootingcheck/RootBeerNative;->?()Z
    ********_v_0.9.2/smali/o/CM.smali:753:    new-instance v4, Lrootingcheck/RootBeerNative;
    ********_v_0.9.2/smali/o/CM.smali:755:    invoke-direct {v4}, Lrootingcheck/RootBeerNative;-><init>()V
    ********_v_0.9.2/smali/o/CM.smali:764:    invoke-virtual {v4, v3}, Lrootingcheck/RootBeerNative;->checkForRoot([Ljava/lang/Object;)I
    ********_v_0.9.2/smali/o/xZ$5.smali:257:    new-instance v1, Lrootingcheck/RootBeerNative;
    ********_v_0.9.2/smali/o/xZ$5.smali:259:    invoke-direct {v1}, Lrootingcheck/RootBeerNative;-><init>()V
    ********_v_0.9.2/smali/o/xZ$5.smali:261:    invoke-static {}, Lrootingcheck/RootBeerNative;->?()Z
    

    root @ kali: ~ / Desktop # grep -nr 'setLogDebugMessages' ******** _ v_0.9.2 /
    
    ********_v_0.9.2/smali/o/CM.smali:599:    invoke-virtual {v1, v0}, Lrootingcheck/RootBeerNative;->setLogDebugMessages(Z)I
    ********_v_0.9.2/smali/o/CM.smali:761:    invoke-virtual {v4, v0}, Lrootingcheck/RootBeerNative;->setLogDebugMessages(Z)I

    But these were not all checks. After analyzing the class MainActivity.java, function calls were found, where the “su”, “test-keys” and “which” strings are passed, with which the test is performed (see. Fig. 3).


    Fig.3. Checks for rutting

    And again, with the grep command, we look for rootedness smali files:

    Search results:
    root @ kali: ~ / Desktop # grep -nr 'su' ******** _ v_0.9.2 /

    ********_v_0.9.2/smali/o/CM.smali:443:    const-string v2, "su"
    ********_v_0.9.2/smali/o/CM.smali:706:    const-string v2, "su"
    ********_v_0.9.2/smali/o/xZ$5.smali:172:    const-string v1, "su"
    ********_v_0.9.2/smali/o/xZ$5.smali:347:    const-string v0, "su"
    

    root @ kali: ~ / Desktop # grep -nr 'test-keys' ******** _ v_0.9.2 /

    ********_v_0.9.2/smali/o/xZ$5.smali:141:    const-string v1, "test-keys"
    ********_v_0.9.2/smali/o/xZ$5.smali:374:    const-string v0, "test-keys"


    root @ kali: ~ / Desktop # grep -nr 'which' ******** _ v_0.9.2 /

    ********_v_0.9.2/smali/o/CM.smali:437:    const-string v2, "which"

    In the article I will show only one of the found modifications of checks for rutting. After a small manipulation, namely, a shift of 1 to 0 - checks for rutovnost removed.


    Fig. 4. The value of the variable is equal to one if the phone is rotovany


    . 5. Now the value of the variable is zero, if the phone is rooted.

    After that, the program can be assembled, signed with its release key and launched on the mobile phone. But if not two BUT! Namely:

    1. check USB connection;
    2. Developer mode enable check - USB connection and enabled Developer mode enable dynamic analysis.

    The Developer mode check is turned off in the same way as the rutting check — by changing the unit to zero in the checks.

    In the MainActivity.java class, we find the line that is responsible for checking the Developer mode (see Figure 6). After this grep, we look for files in which the line “development_settings_enabled” is present and modify the check - change 1 to 0 (see Fig. 7 and 8).


    Fig. 6. Check whether Developer mode is enabled on the phone.

    Search results:
    grep -nr “development_settings_enabled” ******** _ v_0.9.2 \

    Binary file ********_v_0.9.2\/build/apk/classes.dex matches
    ********_v_0.9.2\/smali/o/xZ$1.smali:49:    const-string v1, "development_settings_enabled"
    


    Fig. 7. The place where you need to modify


    Fig. 8. Modification

    After all the manipulations, you can run the program in Developer mode.

    Next, disable the USB connection check. This check is in the class MainActivity.java (see Figure 9). Without the use of grep, we find a line in MainActivity.smali, we find a line that contains a string with a USB check — android.hardware.usb.action.USB_STATE. After that, in the smali-code, we modify the string to any other permissions, which returns “false” (see Fig. 10).


    Fig. 9. Check for USB connection in the MainActivity.java code


    . 10. Code line to be deleted in MainActivity.smali

    Now it remains to generate your release key and sign the application with it. This is done as follows:

    1. You need to install two applications: Keytool and Jarsinger.
    2. Run the application assembly command:
    3. apktool b C: \ Users \ User \ Desktop \ ********
    4. Next: cd ******** \ dist \
    5. Next: Keytool.exe -genkey -alias key.keystore -keyalg RSA -validity 20000 -keystore key.keystore
    6. Next: Jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore key.keystore ********. Apk key.keystore
    7. Next: jarsigner -verify -verbose -certs ********. Apk

    That's basically all the manipulations and finished. Now install the application on your phone using adb install or from the smartphone directory and you can conduct dynamic testing for vulnerabilities.

    After installing the application, launch it (see Fig. 11 and Fig. 12).

    Fig. 11. Turn on Developer mode and connect USB Fig. 12. Running the application

    Conclusions

    On a practical example, I showed how you can turn off some checks on the state of the execution environment. Further, with the help of other tools, we analyzed the vulnerability, but this is a different story ...

    What can the negligent attitude to code protection lead to?

    • these are roundabouts of certain checks that are invested in the program
    • the introduction of third-party code, after which the program can be published and used as malicious

    How can I defend myself? At Hacken, we decided not to reinvent the wheel and offered the client to obfuscate the source code and use functions that verify the modification of the source code.

    PS

    You can use a more advanced method of analysis - this is smali debugging. You can read more about this in the manual .

    For reference, I have formulated a list of strings that is used to check for rutting:

    • “Test-keys”;
    • "/system/app/Superuser.apk";
    • "/ sbin / su";
    • "/ system / bin / su";
    • "/ system / xbin / su";
    • "/ data / local / xbin / su";
    • "/ data / local / bin / su";
    • "/ system / sd / xbin / su";
    • "/ system / bin / failsafe / su";
    • "/ data / local / su";
    • "/ su / bin / su";
    • "/ system / xbin / which";
    • “Su”;
    • “Which".

    Also popular now: