Page cover

Android Emulator Setup

Android:

ADB:

ADB = Android Debug Bridge

  • adb consists of a client, a server, and a daemon (adbd)

  • client & server run on our computer, while the daemon runs on our device

Config:

For Windows:

First, you need to find where adb is located on your computer. If you installed Android Studio with default settings, the adb tool is usually found in the C:\Users\[Your-Username]\AppData\Local\Android\Sdk\platform-tools directory. Replace [Your-Username] with your actual username.

  • Right-click on the Start button and select System.

  • Click on Advanced system settings on the left sidebar.

  • In the System Properties window, go to the Advanced tab and click on the Environment Variables button at the bottom.

  • Edit the Path Environment Variable: In the Environment Variables window, under the System variables section, find and select the Path variable, then click Edit.

  • In the Edit Environment Variable window, click New and paste the path to the platform-tools folder where adb is located.

  • Click OK to close each of the open dialogs and apply the changes.

Commands:

root@sibi #~ adb devices

List down the devices connect to the system

root@sibi #~ adb shell

we will get the regular shell of the device

  • Specify the active device using the s parameter, for example: adb -s emulator-5554 shell

  • Specify to use a single USB device using the d parameter, for example: adb -d shell

Transfering files:

root@sibi#~ adb push <local_file_on_computer> <target_path_on_device>

root@sibi#~ adb pull <file_path_on_device> [<optional_target path_on_the_computer>]

Managing apps:

AM - Activity manager

PM - Package manager

Managing apps using adb

adb install <path to .apk>

Using adb install we can manually install packages using the command line.

adb shell pm list packages

Lists all installed packages - including system packages.

adb shell pm list packages -3

List only third party packages.

adb shell pm clear <package_name>

Clear the application data without removing the actual application.

adb shell dumpsys package <package_name>

List information such as activities and permissions of a package.

adb shell am start <package_name>/<activity_name>

Starts the activity of the specified package.

adb uninstall <package_name>

Uninstalls the specified application.

You can find the full documentation for pm here.

Logs with Logcat:

adb logcat

adb logcat -v <log_format>

Change the log format - for example using brief to get a more condensed version of the log.

Log Filtering

In some cases there can be lots of log entries which makes it hard to focus on the things that matter. For example if you are only interested in the logs produced by the MainActivity, you can use a log filter for that:

adb logcat "MainActivity:V *:S"

Filter format:

  • MainActivity:V ensures that logs from the tag MainActivity with a severity of Verbose and above are logged

  • :S Ensures that all other Tags are ignored (as nothing will log with log-level Silent or above)

Logging severities:

Log level

V

Verbose

D

Debug

I

Info

W

Warning

E

Error

F

Fatal

S

Silent

Android networking:

INTERNET Permissions

To be able to send HTTP requests or perform any other kind of network operation, the AndroidManifest.xml must include the INTERNET permission:

<uses-permission android:name="android.permission.INTERNET" />

Cleartext Traffic

Generally Android tries to prevent developers from accidentally sending cleartext http:// traffic. But if developers explicitly declare usesCleartextTraffic=true in the manifest or network security config, it is still possible.

Emulator start:

C:\Users\Rishivasan\AppData\Local\Android\Sdk\emulator\emulator.exe -tcpdump packets.cap -avd Pixel_8_API_29

Packet Logging with tcpdump

In order to capture packets you can look up the AVD id of your emulator and find the emulator binary in the Android SDK installation. Then start the emulator with packet capture enabled:

$ emulator -tcpdump packets.cap -avd Emulator_API_34

The file packets.cap will contain all raw packets sent and received by the Emulator - which obviously includes all app traffic as well.

C:\Users\Rishivasan\AppData\Local\Android\Sdk\emulator\emulator.exe -tcpdump C:\Users\Rishivasan\packets.cap -avd Pixel_8_API_30

Installing Certificate in System Store

Due to the default network security config rules, most apps only trust "system" certificates. The default configuration for apps targeting Android 9 (API level 28) and higher is as follows:

<base-config cleartextTrafficPermitted="false">
    <trust-anchors>
        <certificates src="system" />
    </trust-anchors>
</base-config>

Rooted Device

In order to install our certificate into the system store, root access is required. Thus for this method you require a rooted physical phone, rooted emulator or use a non-Google emulator image that allows root access.

Install System Certificate

If you have a device with root access follow the following steps:

  1. Install the proxy certificate as a regular user certificate

  2. Ensure you are root (adb root), and execute the following commands in adb shell:

# Backup the existing system certificates to the user certs folder
cp /system/etc/security/cacerts/* /data/misc/user/0/cacerts-added/

# Create the in-memory mount on top of the system certs folder
mount -t tmpfs tmpfs /system/etc/security/cacerts

# copy all system certs and our user cert into the tmpfs system certs folder
cp /data/misc/user/0/cacerts-added/* /system/etc/security/cacerts/

# Fix any permissions & selinux context labels
chown root:root /system/etc/security/cacerts/*
chmod 644 /system/etc/security/cacerts/*
chcon u:object_r:system_file:s0 /system/etc/security/cacerts/*

In order to install our certificate into the system store, root access is required. Thus for this method you require a rooted physical phone, rooted emulator or use a non-Google emulator image that allows root access.

Install System Certificate

If you have a device with root access follow the following steps:

  1. Install the proxy certificate as a regular user certificate

  2. Ensure you are root (adb root), and execute the following commands in adb shell:

# Backup the existing system certificates to the user certs folder
cp /system/etc/security/cacerts/* /data/misc/user/0/cacerts-added/

# Create the in-memory mount on top of the system certs folder
mount -t tmpfs tmpfs /system/etc/security/cacerts

# copy all system certs and our user cert into the tmpfs system certs folder
cp /data/misc/user/0/cacerts-added/* /system/etc/security/cacerts/

# Fix any permissions & selinux context labels
chown root:root /system/etc/security/cacerts/*
chmod 644 /system/etc/security/cacerts/*
chcon u:object_r:system_file:s0 /system/etc/security/cacerts/*

Patching Network Security Config with apktool

We have used apktool before to unpack and repack an android app. So let's use it in order to inject a permissive network security config.

# unpack the target .apk
apktool d translate.apk

# modify the AndroidManifest.com to add a networkSecurityConfig
# create a permissive xml/network_security_config.xml
cd translate

# repackage the .apk
apktool b

# ensure the .apk is zipaligned
[...]/build-tools/34.0.0/zipalign -p -f -v 4 ./dist/translate.apk translate2.apk

# create a keystore to sign the apk
keytool -genkey -v -keystore research.keystore -alias research_key -keyalg RSA -keysize 2048 -validity 10000

# sign the apk with apksigner
[...]/build-tools/34.0.0/apksigner sign --ks ./research.keystore ./translate2.apk

Advanced HTTP Interception with VPN

We are going to use an Android VPN service app in order to intercept traffic of apps, even when they ignore proxy settings.

For this purpose we can use the open source rethink app: https://github.com/celzero/rethink-app

  1. Change DNS settings to "System DNS"

  2. Add a HTTP(S) CONNECT proxy

  3. Start the "VPN"

Also make sure you have your proxy certificate installed in the system certs store.

FRIDA:

To inject Frida into an APK we can use objection:

objection patchapk -s apk_name.apk

Objection will extract, patch, re-pack, align and sign the application, and so it's a very fast and easy way to get Frida running.

Note that the application will wait on launch for Frida to connect to it, so to start the application we have to run:

frida -U FridaTarget

The -U here specifies that we want to connect by USB.

If you have a rooted device, you can also run frida-server instead of patching the APK. You can download frida-server on the Github Releases Page of Frida. Note that it comes xz compressed, so you have to extract it (xz -d on unixoid systems, 7zip on for example Windows).

To install it in an emulator we can adb push the server over:

adb push frida-server /data/local/tmp/

We chose this path because other parts, such as /sdcard, are commonly mounted no-exec.

Afterwards we want to run adb as root, and also make the server executable:

adb root
adb shell
cd /data/local/tmp
chmod +x frida-server

And then we are ready to go: We can launch the server by running

./frida-server

Now we can connect to the application by running:

frida -U FridaTarget

The Frida REPL (Read-Eval-Print-Loop) is a JavaScript interpreter, and so we can directly run JavaScript statements:

for(var i=0; i < 5; i++) { console.log(i); }

To create multi-line statements, suffix each line with a \ backslash:

for(var i=0; i < 5; i++) {\
    console.log(i);\
}

Check-out the full Frida JavaScript API documentation here!

Also you can find the APK we use again here:

We can get JavaScript wrappers for Java classes by using Java.use:

Java.use("java.lang.String")

We can then instantiate those classes by calling $new:

var string_class = Java.use("java.lang.String");
var string_instance = string_class.$new("Teststring");
string_instance.charAt(0);

We can dispose of instances (for example to free up memory) using $dispose(), however this is almost never required, as the Garbage Collector should collect unused instances.

We can also replace the implementation of a method by overwriting it on the class:

string_class.charAt.implementation = (c) => {
    console.log("charAt overridden!");
    return "X";
}

In this video we create a script to trace the active Activity:

Java.perform(() => {
    let ActivityClass = Java.use("android.app.Activity");
    ActivityClass.onResume.implementation = function() {
        console.log("Activity resumed:", this.getClass().getName());
        // Call original onResume method
        this.onResume();
    }
})