0% found this document useful (0 votes)
801 views104 pages

Handbook

Uploaded by

Josep Stalin S
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
801 views104 pages

Handbook

Uploaded by

Josep Stalin S
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 104

Roman Stuehler (Udemy) Page 1 / 104

Cheatsheet - Version 1.0 (DRAFT)


1. Installation Steps 4
1.1. VM Installation 4

2. Emulator Installation Steps 8


2.1. Emulator Con guration (PATH variable) 9

2.2. Emulator Con guration (“Secret Interface”) 10

3. Android VM - ADB Connection 11


3.1. VM Settings - Network Adapter 11

3.2. Preparation - ADB 11

3.3. Connecting to the VM - ADB 12

4. Smartphone - ADB Connection 13


4.1. Enable Developer Options 13

4.2. Enable USB Debugging 14

5. Emulator - ADB Connection 17


5.1. Connecting to the Emulator 17

5.2. Network con guration of the Emulator 17

6. Rooting 19
6.1. Team Win Project (TWRP) 19

6.2. Rooting the Device - Example 20

6.3. Recover soft bricked Device 26

7. Android Debug Bridge (ADB) 28


7.1. Device Connection 28

7.2. Useful ADB commands 29

8. Tools 31
8.1. ZSH Con guration File 31

8.2. Development 31

8.3. Decompiling / Reversing 32

8.4. Special Section - Approach: „Upos“ Challenge 39

9. Apps 40
9.1. Package Structure 40

9.2. Decompiling - Building and signing Apps 41

10. App Components - Vulnerabilities 46


10.1. Activities 46

10.2. Intent 47

Roman Stuehler (Udemy) Page 2 / 104


fi
fi
fi
fi
10.3. BroadcastReceiver 48

10.4. ContentProvider 49

11. SMALI 53
11.1. Types 53

11.2. Registers / Variables / Parameters 53

11.3. Basic Commands 55

12. Man-in-the-Middle - Device 68


12.1. Setup - Real Device 68

12.3. BurpSuite 72

13. Man-in-the-Middle - Emulator 80


13.1. Setup 80

14. Certi cate Pinning 81


14.1. Patching the OKHTTP Library 81

14.2. Patching Certi cate File 84

14.3. Using Objection 85

15. Frida 86
15.1. Installation 86

15.2. Starting FRIDA 89

15.3. Interaction with FRIDA 90

15.4. Hooking Methods 91

15.5. Calling a Methods 95

15.6. Scanning for Objects 95

15.7. Timing 97

15.8. NDK 99

Roman Stuehler (Udemy) Page 3 / 104


fi
fi
1. Installation Steps
Here is a quick summary about the single steps to install the VM or the android emulator
on your system.

1.1. VM Installation
Quick summary on how to install the „Androidx86 VM“. Please make sure that you do not
install this VM within another VM. This is not working properly. For the emulator it is ok.

1.1.1. VM Settings
My recommendations regarding to the minimum of the VM settings:
• 2 CPUs
• 4K Ram
• 12 GB Storage

1.1.2. Installation Process


Please select the androidx86.iso (https://www.android-x86.org/download) as a cd le and
start the VirtualMachine (VM). Afterwards click on the “Advanced options” to extend this
view and follow these steps.

In the extended view, we have an “Auto_Installation” menu, please select this one and
click yes. That’s it :)

Roman Stuehler (Udemy) Page 4 / 104


fi
Roman Stuehler (Udemy) Page 5 / 104
1.1.3. Graphical Userinterface Bug

After starting the VirtualMachine, the Android screen might not appear. This is a common
VMPlayer bug. We have to provide a certain parameter within the init con guration le.

We start by rebooting the VirtualMachine in debug mode as shown below:

Then we wait for the system to nish the booting process and press “Enter” a few times
until we have a shell. Now we need to remount the “mnt” partition because we want to
change the “menu.lst” con guration le.

The „menu.lst“ le describes the single entries which can be selected in the
boot menu. These are just single commands with different parameters.

To remount the “/mnt” partition we use the following command.

# Terminal in the VM
$ mount -o remount,rw /mnt

Roman Stuehler (Udemy) Page 6 / 104


fi
fi
fi
fi
fi
fi
Now we can modify the “menu.lst” le which is in the “/mnt/grub” directory. VI is available
on the emulator.

$ vi /mnt/grub/menu.lst

Add the value “nomodeset xforcevesa” after the rst parameter as shown below.
Now press ESC and type “:wq!” to save these changes.

Nomodeset is a kernel con guration that prevents the graphics card


ending up in a black screen. The xforcevesa entry is used to access video
card functions in a legacy bios environment.

After the le has been successfully written and closed we can restart the system via the
VM settings.

When we now select the rst entry: “Androidx86 9.0-r2” the system is booting up with a
graphical interface.

Roman Stuehler (Udemy) Page 7 / 104


fi
fi
fi
fi
fi
2. Emulator Installation Steps
The emulator comes shipped together with the android-studio. Therefore to install it, we
simply need to install the android-studio rst. It can be found here: https://
developer.android.com/studio.

After downloading and installing it, the following window should appear. In case if you
have already created a new project, you can close the project to get this window back.

By clicking “More Actions”, we can now select the VirtualDevice Manager:

Then we have to click “Create device” on the top left and we need to make sure, that we
are selecting an image without the Google - Play Store being enabled.

Roman Stuehler (Udemy) Page 8 / 104


fi
This will ensures that we are having root access on our emulator. if we select an image
that has the Play Store enabled, we do not have automatically root access.

2.1. Emulator Con guration (PATH variable)


The emulator binary can be found in the following path:
• ~/Sdk/emulator/emulator
If we want to launch it from a terminal, we have to add this path into our PATH variable.
We can do this as follow. We need to open the ~/.zshrc or ~/.bashrc le in our editor of
choice. Afterwards we extend the $PATH variable as follow:

By opening a new terminal or using the command “source ~/.zshrc”, we can now launch
our emulator easily from a terminal.

2.1.1. Error Handling


Keep in mind. In case if you encounter some errors, launching it from the graphical user
interface in the android studio might provide you more information about the root cause
of the error.

Roman Stuehler (Udemy) Page 9 / 104


fi
fi
Therefore in case of any errors, try starting the emulator from the android-studio as shown
above. Here we can see, that the emulator did not shutdown properly and all we have to
do is removing the *.lock le to restart it.

2.2. Emulator Con guration (“Secret Interface”)


The emulator is running a service on localhost 5554 (tcp). We can connect to this service
and use additional features of the emulator as shown below:

This can be used to for additional con gurations like setting the GPS location or
redirecting the network tra c. The required token can be found in
~/.emulator_console_auth_token.
Roman Stuehler (Udemy) Page 10 / 104
fi
fi
ffi
fi
3. Android VM - ADB Connection
This part describes, how to establish a connection between the Linux system and the
Android VM / Emulator.

3.1. VM Settings - Network Adapter


Both machines need to be in the same network segment to reach each other. You have
several di erent network types which can be used in this example.

NAT
This interface provides Internet Access via the host system, but your VM is behind another
Network. If you select NAT for both machines, they can reach each other and also use the
internet via your host system.

Host Only
This is some sort of a private network with your host machine. You cannot reach the internet
via your host but if both machines are in the „host only“ network segment, they can reach
each other. I prefer this one because they also cannot send data out of my network :)

Bridged
This network mode will bind your VM into your host network segment. This means, it will be
reachable from all components in your home/company network. I do not recommend this
option! If you want to have an internet connection, check NAT - otherwise Host Only.

3.2. Preparation - ADB


After setting the network adapter to „NAT“, we check with the command „ip addr“ if we
obtained an ip address. We should also verify if both clients are in the same network
segment.

$ ip addr

In the android VM you can use the „Terminal Emulator“ app which is shown on the right.

Roman Stuehler (Udemy) Page 11 / 104


ff
The left image shows the terminal of the LinuxVM.

Ok we are in the same subnet and we can ping each other.

3.3. Connecting to the VM - ADB


Now just type „adb connect 192.168.227.2“ (IP of AndroidVM) and we are done :)

# IP address of the VM
$ adb connect 192.168.227.2
* daemon not running; starting now at tcp:5037
* daemon started successfully
connected to 192.168.227.2:5555
$ adb shell
x86:/ $

The „x86“ prompt shows that we are operating on the Androidx86 Virtual Machine.

Roman Stuehler (Udemy) Page 12 / 104


4. Smartphone - ADB Connection
Plugin your USB cable and forward the new device to your Virtual Machine (VM). You can
nd this in the Settings of VirtualBox or VMWare.

There you will also nd the USB 3.0 settings, which I highly recommend to enable it.
Having this set to USB 2.0 can cause problems with the “USB to ethernet adapter” which
will be used later in this course.

4.1. Enable Developer Options


To enable the developer options, take your smartphone and follow these steps.
• Settings
• About the phone
• Press 8 time „build number“

Afterwards a new feature „Developer Options“ is available. This can be found in the
system settings (enlarge advanced) or directly within the Settings menu. Depends on the
smartphone manufacture and the version.

There is a little „Easter Egg“ built into the Android system. If you click
multiple times on version, a short animation regarding to your OS version
appears.

Roman Stuehler (Udemy) Page 13 / 104


fi
fi
4.2. Enable USB Debugging
After enabling „Developer Option“, just plugin your USB cable and forward the device to
your VM. A popup screen appears which has to be accepted. Afterwards simply connect
to your device with the following command:

$ adb shell

4.3. Connecting via USB


Connect the Smartphone to your laptop / VM / PC. Sometimes the device is only
charging and we have to enable the data transfer.

You can do it by clicking on the noti cation bar and select:

1. Android System - Charging this device via USB”


message

2. Tab for more options and select “File transfer / Android


Auto”

Now open the terminal and establish the connection:

$ adb shell

You should see a new linux prompt regarding to your device. On a nexus 5 it will be
„hammerhead“ and on a pixel 2 it is „walleye“.

It is not necessary to use „adb start-server“ after the “adb kill-server”


command. This is being automatically performed by the command „adb
shell“.

4.4. Connecting via WiFi


To get a connection via Wi on the default port 5555 (tcp) we can use the following
command.

$ adb tcpip 5555


$ adb connect 192.168.178.10
$ adb shell

Roman Stuehler (Udemy) Page 14 / 104


fi
fi
Afterwards just simply connect with adb connect <IP of the smartphone>.

Additional information can be found here: https://developer.android.com/


studio/command-line/adb#wireless.

You can get the IP address by clicking on the WiFi symbol and extending the advanced
tab. On the bottom of the page you will see the IP address of your smartphone.

4.5. Connection Issues


If you get errors during the connection then please check out the following „trouble
shooting guide“. Here are a few examples what went wrong for me in the past, while
trying to connect to the phone.

Make sure your android device is connected to the virtual machine or host computer that
executes the „adb shell“ command.

Also make sure that USB debugging is enabled in the developer options.

If it is still not working you can try the following things :)

4.5.1. Checking if your device is connected to the right VM


You can verify this by clicking on the „Virtual Machine Tab“. If your smartphone is
connected to your VM a message like „disconnect (connect to host)“ will appear in the
USB section. If you are trying to run „adb“ from this virtual machine, you are ne :)

4.5.2. Resetting the ADB connection


Sometimes ADB just don’t work. I do not know the reason for this :) But we can simply
reset the connection and make it work again (in most cases…). Open a terminal and
enter:

$ adb kill-server
$ adb shell

This will automatically reset the adb service and reconnect to it.

4.5.3. Check your USB connection type


By connecting a device to your PC it might go into charging mode. This means that no
data transfer is possible. To enable data transport go to your smartphone and click on the
noti cation „charging …“ message.

A pop up appears that let’s you chose to switch into data transfer mode. After this restart
the ADB server and we should be good to go.

Roman Stuehler (Udemy) Page 15 / 104


fi
fi
4.5.4. Check your USB cable and also try to connect via WiFi
Try to connect to the device via wi and not via the USB cable. Make sure both clients
can see each other (ping from smartphone to the pc / vm / laptop and backwards).

4.5.5. Missing USB Debugging authorization popup


On older smartphones it happened to me that the „USB debugging popup“ has been a bit
buggy. If you do not see this screen, it is not possible to get a connection. This shouldn’t
be the case on modern smartphones.

Anyway, we can try to reset this by revoking all existing ADB permissions on the
smartphone. To do so we go into :
• Settings (sometimes extend advanced tab)
• Developer options
• Revoke USB debugging authorizations
• Press „OK“

4.5.6. Trying di erent ADB versions


This is my last attempts and it happened once to me. As a last approach it might be
possible that when you connected to your device, you are using a di erent version of
adb, which is running on the device. It has to be an old version because this is not
happening these days anymore. Try updating your adb client to the newest version or
downgrade in case if you are using a very old smartphone.

adb server version (41) doesn't match this client (39);


ERROR
killing...
* daemon started successfully
error: no devices/emulators found

Sometimes it is also required to use a certain vendor speci c adb version. This was the
case on an embedded device where the vendor has it’s own fastboot and adb binaries.

Try to contact the vendor and kindly ask if this is the case and if they can provide you the
binaries to connect to your device.

Roman Stuehler (Udemy) Page 16 / 104


ff
fi
fi
ff
5. Emulator - ADB Connection

This setup is lagging a bit in performance, due to the nested virtualisation. However it
simply works and you can also use this during the course.

5.1. Connecting to the Emulator


The ADB connection here is very simple. Fire up the emulator and connect to it by using
the following command.

$ adb kill-server
$ adb shell

5.2. Network con guration of the Emulator


The emulator is being provided with an IP Address (DHCP) from the virtual router. If we
want to use the network connection instead of USB, we have to use this ip address:
10.0.2.15.

Source: https://developer.android.com/studio/run/emulator-networking

Roman Stuehler (Udemy) Page 17 / 104


fi
In case if the device needs to access a service running on our Linux system, then we
have to use the ip address 10.0.2.2 within the smartphone app.

Example given, the “Insecure Bank” application is using a web server which is running in
our virtual machine. If the smartphone wants to connect to it, it can access the 10.0.2.2
address, which is bound to the local host of the system that is starting the emulator. See
table above.

Roman Stuehler (Udemy) Page 18 / 104


6. Rooting
Rooting has become very complex for certain android devices. It is nice to see that the
community tries its best to deal with all the security features which has been implemented
in the last couple of years. But this is of course not working for every device.

DISCLAIMER! Rooting can brick your device in a way, that you


might not be able to use it anymore. In the last eight years, I have
! hard bricked two devices, where I completely lost the access to it!
Please make sure to backup all your important data and be aware
that an unsuccessful rooting attempt might not be xable.

Unfortunately it is not possible to provide and easy solution that works for every device.
Don’t worry, rooting is not required for this course but I still want to share my experiences
with you. Especially if you have never done it. Getting into it might be a bit confusing.

If you are not able to root your smartphone, this absolutely ne! We can still
perform all the nice hacks without having root access on a real device! This
is the reason why we have the emulator in this course! :) Getting root
access on an android VM / emulator is pretty easy :).

6.1. Team Win Project (TWRP)


This is in my opinion the best solution to root your device. It is based on ashing a
custom recovery image. You can think of this like booting from a linux cd on your laptop /
pc. If your device is encrypted, you need to have the password to unlock it.

6.1.1. Preparation
To check if TWRP is available for your device, please have a look at the website:
https://twrp.me/Devices/. In my case I am using a „Google Pixel 2“ in Europe. The
corresponding link will be: https://eu.dl.twrp.me/walleye/.

I select the „twrp-3.3.0-0-walleye.img“ because I want to do the ashing on my own. I am


not using the installer version. Walleye is the code name for the “Google Pixel 2”.

To perform the ashing of a custom recovery image we have to unlock the boot loader
rst. This can be straight forward or even not possible for your device. It depends on the
manufacture.

6.1.2. Unlocking the Boot Loader


For google devices, you can nd all necessary information here: https://
developers.google.com/android/images.

Roman Stuehler (Udemy) Page 19 / 104


fi
fl
fi
fi
fi
fl
fl
Sometimes you need some sort of proprietary software to unlock your device. In this case
I recommend to take a look at the „https://www.xda-developers.com/" for further
information.

Take care! By unlocking the bootloader, all your data will be wiped

! off. This is a security feature because otherwise an attacker would be


able to restore all your data if you lose your phone. So please make
sure to backup your important data!

Finally, there are also devices where unlocking the boot loader is not possible. In this
case just stick to the provided Virtual Machine (VM). This is ne :)

6.2. Rooting the Device - Example


If you still want to root the device, here is my approach that I am using most of the time.
First of all, we need to include „fastboot“ into the $PATH variable of our Linux system.
Fastboot requires root privileges, therefore we need to add it ot the „~/.bashrc“ /
„~/.zshrc“ of your root user.

6.2.1. Adding Fastboot to the PATH variable


To edit the „~/.bashrc“ le, you can use a text editor of your choice. If you are not familiar
with VIM, you can try „gedit“. Switch to the root user and open the „~/.bashrc“ le.

$ sudo su
# gedit ~/.bashrc

add the entry „PATH=$PATH:/path-to-your-android-sdk-platform-tools-dir/„ into the le as


shown below:

This will extend the path variable with the binaries included in platform-tools directory. If
you are running a command from your shell, the system looks up all binaries included in
these directories.

Roman Stuehler (Udemy) Page 20 / 104


fi
fi
fi
fi
The change will take e ect after closing and opening the terminal, or after typing the
following command into the terminal.

# source ~/.bashrc

6.2.2. Unlocking the Bootloader


Now we can put the device into the bootloader mode and connect to it via fastboot.

$ adb shell reboot bootloader


$ sudo su
# fastboot devices

If this has worked, we get an output like shown below:

root@Hacking:/home/android# fastboot devices


FA82M1A00417 fastboot

The following command unlocks the bootloader on a Google Pixel device.

# fastboot flashing unlock

There is an information on your screen, which needs to be accepted by pressing the


volume up button and the power button. Select „Unlocking the bootloader“.

6.2.3. Flashing TWRP


After unlocking the bootloader, the device will wipe all the data and reboots. It is now in
some „factory reset“ state. We have to con gure it again and enable USB-Debugging.

After this has been done, put the device into the bootloader mode again and check the
connection with fastboot.

$ adb shell reboot bootloader


$ sudo su
# fastboot devices

Now we nally start ashing / booting from our custom recovery image which has been
downloaded from the TWRP site.

Roman Stuehler (Udemy) Page 21 / 104


fi
fl
ff
fi
# fastboot boot twrp-2.8.x.x-xxx.img
# fastboot flash recovery twrp-2.8.x.x-xxx.img #older devices

Here you have the output if it has been successful:

root@Hacking:/home/android# fastboot boot twrp-3.3.0-0-walleye.img


fastboot: error: cannot load 'twrp-3.3.0-0-walleye.img': No such
file or directory
root@Hacking:/home/android# fastboot boot /home/android/Downloads/
twrp-3.3.0-0-walleye.img
Sending 'boot.img' (32768 KB) OKAY [ 1.095s]
Booting OKAY [ 0.058s]
Finished. Total time: 1.202s

The TeamWinProject image should also appear on your smartphone now. If we have
provided a „lock“ mechanism (pin,pattern etc) we have to unlock the smartphone now,
because the data is being encrypted with this pattern/code.

If you cannot unlock the device via TWRP it might be a


known issue and we can try solving this by removing the
ERROR
protection (pin,pattern etc). After removing it, we simply
boot from the TWRP image and should be fine :)

Ok, we removed the PIN and did reboot the device into bootloader mode and also did
start the TWRP image via „fastboot“.

6.2.3.1. Installing MAGISK via TWRP


MAGISK is a rooting application, that circumvents several security features of your
system to provide you root access. It is very important, that you download MAGISK only
from the o cial source!

You should also consider that rooting the device will lower the security,
! so I highly recommend you not to root your private phone and get some
test device to play with.

To download MAGISK please take a look at the o cial repository here: https://
github.com/topjohnwu/Magisk/releases. I use the „Magisk-v21.4.zip“ archive and upload
it via adb. Remember we are still in TWRP and here we can use adb to interact with the
le system.

Roman Stuehler (Udemy) Page 22 / 104


fi
ffi
ffi
$ adb push Magisk-v21.4.zip /sdcard/
Magisk-v21.4.zip: 1 file pushed. 25.4 MB/s (6154880 bytes in 0.231s)

Now just press the install button, select your zip archive and „Swipe to con rm the ash“.

6.2.4. Flashing MAGISK


The other option is, compiling MAGISK into the o cial boot image of your vendor and
ashing the whole new image onto your smartphone. This step does not required
installing TWRP rst.
Beside having root access, TWRP also has a bunch of nice options. It can perform a full
backup of your device which functions as a snapshot. So you can revert it to a certain
state. Therefore I recommend using the TWRP approach.
However for completeness, here is also the MAGISK way to root your smartphone :).

Source: https://topjohnwu.github.io/Magisk/install.html

Roman Stuehler (Udemy) Page 23 / 104


fl
fi
ffi
fi
fl
6.2.4.1. Preparing the Image
The rst step is downloading the factory image of your device. In case of a Google Pixel,
you can nd it here: https://developers.google.com/android/images.

After downloading the image we need to put it onto the sdcard:

$ adb push boot.img /sdcard/

Now we have to install the MAGISK application (https://github.com/topjohnwu/Magisk/


releases) on our smartphone.

MAGISK is a very popular project but it is modifying your system and


weaken the security of your smartphone. I mean, this is the purpose of
! this application but please only use these type of apps on testing
devices and not on your private phones!

$ adb install Magisk-v25.1.apk

After installing the application, we have to select the boot.img which has been pushed
onto the sdcard before.

Source: https://topjohnwu.github.io/Magisk/install.html

MAGISK is doing the rest. It will inject itself into the boot.img and create a new le out of
it (magisk_patched-25100_F7lFO.img).

Roman Stuehler (Udemy) Page 24 / 104


fi
fi
fi
6.2.4.2. Flashing the image
To ash the modi ed image onto our smartphone, we have to restart it in “bootloader”
mode. We can do this by using ADB as follow:

$ adb reboot bootloader

The other way to restart your smartphone in bootloader mode depends on the
manufacture. On a Google Pixel device we have to power it o and hold the “volume
down button / up (depends on manufacture)” + “power button” simultaneously for about
10 seconds. Afterwards we can release them and should end up in the bootloader menu.

Now we can use fastboot to ash the modi ed image:

# fastboot flash boot magisk_patched-25100_F7lFO.img

//Optional) If your device has a separate vbmeta partition, you can


patch the vbmeta partition with command:
# fastboot flash vbmeta --disable-verity --disable-verification
vbmeta.img

You can nd out if you have a vbmeta partition by simply unpacking your stock image as
shown below:

If this is the case you have the fastboot command with the “vbmeta” parameter.

Roman Stuehler (Udemy) Page 25 / 104


fl
fi
fi
fl
fi
ff
6.3. Recover soft bricked Device
A soft brick means, that the device is in some kind of error state, where it does not fully
boot anymore. However, certain important features like entering the bootloader are still
available.
This could be enough to restore your device which I will describe next. If restoring is not
possible anymore the device will be “hard bricked”. This means, it is completely broken
and useless :(

6.3.1. Getting the Stock Firmware


The stock rmware is the original rmware of the device. This depends on the
manufacture you have. Some vendors provide o cial downloads. In case of Google
devices, you can simply download it from here: https://developers.google.com/
android/images.
I am not using the ash-tool so I select the „Link“ to download the zip archive. In case of
my Google Pixel it would be the following here: https://dl.google.com/dl/android/
aosp/walleye-rp1a.201005.004.a1-factory-0c23f6cf.zip.

6.3.1.1. Bootloader mode

After downloading the factory Image, enter the bootloader (volume up or down + power
for a certain amount of time) and check if the connection is successful with fastboot.

Please make sure your bootloader is still unlocked! If this is not the
! case, run „fastboot ashing unlock“.

6.3.1.2. Flashing the stock rom

Now unzip the factory image le on your laptop and start the ashing process by running
the „ ash-all.sh“ script. Once again, all data will be wiped o but if you have no access
anymore, this might be the easiest option to get at least your device back.

Roman Stuehler (Udemy) Page 26 / 104


fl
fi
fl
fl
fi
fi
ffi
ff
fl
$ unzip walleye-rp1a.201005.004.a1-factory-0c23f6cf.zip
$ sudo su
# ./flash-all.sh
Sending 'bootloader_a' (38700 KB) OKAY [ 1.688s]
Writing 'bootloader_a' FAILED (remote:
'Operation is not allowed in Lock State')
fastboot: error: Command failed
Rebooting into bootloader OKAY [ 0.001s]
Finished. Total time: 0.205s
< waiting for any device >
Sending 'radio_a' (60388 KB) OKAY [ 2.722s]
[ … shorten … ]
Allocating group tables: done
Writing inode tables: done
Creating journal (65536 blocks): done
Writing superblocks and filesystem accounting information: done

Sending 'userdata' (316 KB) OKAY [ 0.016s]


Writing 'userdata' OKAY [ 0.001s]
Rebooting OKAY [ 0.001s]
Finished. Total time: 176.136s

Now we can lock the bootloader again. We do not have to setup the whole device again
just to enable ADB.

I recommend locking the bootloader back again. Otherwise if you lose your device, an
attacker will be able to recover you data by ashing images like TWRP.
After locking it you can enjoy your freshly new installed operating system. I also
recommend ashing the stock rmware if you buy some used smartphones. Then you
can be sure that no apps / data are left on the device.

Roman Stuehler (Udemy) Page 27 / 104


fl
fi
fl
7. Android Debug Bridge (ADB)
The Android Debug Bridge (ADB) can be used for several tasks. We will have a look into
some of them while there are of course more.

7.1. Device Connection


We have already talked about the di erent connection types (Linux VM / Emulator / VM)
before, so here just a few additional information.

In case if you have multiple devices connected we need to use adb -s “serial number” of
the device to select our targeted device.

Roman Stuehler (Udemy) Page 28 / 104


ff
7.2. Useful ADB commands
This is a short cheat sheet about some useful adb commands.

Command Description

adb devices Show connected devices

adb root Get a root shell - Works only on certain images.


Example: LineageOS.

adb reboot bootloader Reboot the device into the boot loader mode

adb shell install -r Install a new package (overwrite existing one)

adb push <local> <remote> Upload a le from the laptop to the phone

adb pull <remote> <local> Download a le from the phone to the laptop

adb shell dumpsys iphonesybinfo Get the IMEI

adb get-serialno Serial number of the device

adb shell pm list features List the features of the smartphone

adb shell screencap -p „/Path/To/Save/Image.png“ Take a screenshot

adb shell screen record „/Path/ Capture a video of the device screen
CaptureRecord.mp4“

adb shell am start -W -c Simulating pressing the Home Button


android.intent.category.HOME -a
android.intent.action.MAIN

adb shell am start|startservice|broadcast <INTENT> Start an Intent / service / broadcast receiver

adb logcat System log information

adb bugreport Dump the whole device information like


dumpstate, dumpsys and logcat output.
Important to get the Bluetooth Low Energy log!

adb backup Backup all applications that have the


„backup=true“ in their Manifest.xml

fastboot devices List available devices in fastboot mode

adb shell pm reset-permissions -p Resets all the permissions of an app


your.app.package

adb shell pm path <package name> Shows the path to the APK which can be
downloaded (see adb pull) even without root
permissions.

adb input touch <x> <y> Perform a touch event at the given coordinates

This list is based on the useful commands provided here: ADB Commands.

Roman Stuehler (Udemy) Page 29 / 104


fi
fi
7.2.1. ADB Forward
If we want to enable a service running on the smartphone on our linux system, we can
use ADB forward.

This is useful specially regarding to the emulator because the emulator is running in a
“restricted” environment. This means, not all services are atomically being exposed like
this would be the case on a real smartphone. By forwarding these service we can further
investigate them.

7.2.1.1. ES File Explorer Open Port Vulnerability - CVE-2019-6447

The ES File Explorer is a very popular application which had a vulnerability in the http
server on port 59777. This web server accepted commands that gives an attacker the
ability to fetch information about the device, apps being installed and also the ability to
download les from the smartphone. Further information can be found here: https://
github.com/fs0c131y/ESFileExplorerOpenPortVuln.

This port might be blocked on the emulator, but not on a real smartphone. By having “adb
forward”, we can discover these ndings also on the emulator.

7.2.2. Touch - Events


Simple version of automatically creating touch events on the smartphone. Could be also
used to brute-force pin/swipe codes of apps. Save it onto the device in “/data/lcoal/tmp/
script.sh” and simply run it within the adb shell. (chmod +x script.sh)

Roman Stuehler (Udemy) Page 30 / 104


fi
fi
8. Tools
Here you can nd some useful commands or parameters and also some
recommendations on what tool I use for a given case.

8.1. ZSH Con guration File


This is my con guration le, that I have been using during this course. It contains all the
necessary shortcuts for the commands we are using.

$ cat ~/.zshrc

alias baksmali="java -jar /home/android/tools/baksmali/


baksmali-2.4.0.jar“
PATH=/home/android/tools/jadx/build/jadx/bin:/home/android/tools/
dex2jar:/home/android/.local/bin/:/home/android/Android/Sdk/build-
tools/30.0.2/:$PATH
alias python="/usr/bin/python3"
alias jd-gui="java -jar /home/android/tools/jd-gui/jd-gui.jar"

8.2. Development
The app development will be done in android studio. To view single les, I use the Visual
Studio Code Editor.

8.2.1. Android Studio - Creating SMALI code


Beside app development, you can also use android studio to create single SMALI
patterns. You can nd android-studio here: https://developer.android.com/studio
Let’s say we have an app, where we do not have the source code, but we want to insert
some anti debugging code. We can simply create a new project, provide the same
package and class names and create our code how it should look like after patching. We
build the project, decompile it with apktool and we have the nal SMALI code to overwrite
the existing code :)

8.2.2. Texteditor - Code Highlight


I only use Visual Studio Code to view SMALI
les, because by selecting the Syntax
„Java“ on the bottom right, we get a nice
output.

Roman Stuehler (Udemy) Page 31 / 104


fi
fi
fi
fi
fi
fi
fi
fi
There are also SMALI code highlight plugins but to me, the JAVA syntax is good enough
to see the di erences in the objects and methods. You can download Visual Studio Code
here: https://code.visualstudio.com/

8.3. Decompiling / Reversing


For decompiling I mostly use apktool. In case this does not work, I also try out JADX. If
the code is heavily obfuscated I use androguard.

8.3.1. JADX
JADX is being used to decompile an APK. It tries to generate the corresponding JAVA
code. JADX is open source and can be installed as follow:

git clone https://github.com/skylot/jadx.git


cd jadx
./gradlew dist

Also check out the project here: https://github.com/skylot/jadx.


To decompile an application with JADX on the command line, we can simply provide the
destination directory and the APK we want to decompile.

$jadx -d outdir de.fgerbig.spacepeng_1581.apk


INFO - loading ...
INFO - processing ...
ERROR - finished with errors, count: 2

We can now nd the single decompiled JAVA classes in the outdir directory. Here are also
some additional parameters, that might be helpful.

-r, --no-res - do not decode resources


--escape-unicode - escape non latin characters in strings (with \u)
-j, --threads-count - processing threads count, default: 1
--show-bad-code - show inconsistent code (incorrectly decompiled)
--log-level - set log level, values: QUIET, PROGRESS, ERROR,
WARN, INFO, DEBUG, default: PROGRESS

Roman Stuehler (Udemy) Page 32 / 104


ff
fi
Parameter „-r“

The „-r“ parameter does not decode resources, which is handy because they often cause
errors during the decompilation and are not really necessary for the reversing / patching
process. The same for the „--escape-unicode“ parameter.

Parameter „-j x“

To speed up things a little bit we can use the „-j 4“ to increase the number of thread. This
will be a lot faster because it is using more cores. The amount of possible threads is also
limited based on your CPU(s).

Example Calculation:

To get an overview about the CPU / Cores / Threads of your system we can use “lscpu”.

$ lscpu

Here is the output and we are interested in the following three parameters.

Thread(s) per core: 1


Core(s) per socket: 1
Socket(s): 4

4 CPU x 1 core per socket x 1 Thread(s) per core => 4 * 1 * 1 => 4

Therefore the max thread count is 4 and max core count is 4. We can provide „-j 4“ as
max value.

Parameter „--show-bad-code“

This parameter forces jadx to include the „bad code“ in the decompiled code. Here is an
example. On the left, we have the Spacepeng.apk with the „—show-bad-
code“ parameter and on the right without.

Roman Stuehler (Udemy) Page 33 / 104


The text in blue represents the di erence in both les. On the left (—show-bad-code)
parameter, we can see weird looking code which has been included and obviously
causing some problems. This code has been skipped in the output on the right side
(without —show-bad-code) parameter.

You can play around with this parameter if you encounter that you are missing something
which might have not been decompiled correctly. I do not use this very often but it is nice
to have. This feature is now also being included in the GUI too.

Parameter „ --log-level“

This parameter is very useful and in my opinion, it is not used very often.

$jadx -d out --log-level error de.fgerbig.spacepeng_1581.apk

We immediately see, which functions could not be correctly decompiled and also by
checking them with „jadx-gui“ we can see that we are missing some information here.

This is important for the reversing process because we might miss important information.
In this case it is not a big deal because there are only 2 errors and they are in functions
that are not really required. By checking this, we are now pretty sure that we do not miss
any important information.

Roman Stuehler (Udemy) Page 34 / 104


ff
fi
I recommend the error tap in the normal usage. If you deal with obfuscation you might
want to enable „Debug“ too. But be prepared, the output is pretty large.

Deobfuscation - Techniques

JADX also provides some deobfuscation techniques. It is summarizing single Patterns to


larger class / method names.

--deobf - activate deobfuscation


--deobf-min - min length of name, renamed if shorter, default: 3
--deobf-max - max length of name, renamed if longer, default: 64
--deobf-rewrite-cfg - force to save deobfuscation map
--deobf-use-sourcename - use source le name as class name alias
--deobf-parse-kotlin-metadata - parse kotlin metadata to class and package names

It is also doing a good job but to be honest, the code will still be obfuscated. I mean you
will not get the original class names back. Instead of a.b.c.a.aa() we might get something
like p0012.p0192().
You can also check out how the deobfuscation is working. It is an awesome open source
project: https://github.com/skylot/jadx/blob/master/jadx-core/src/main/java/jadx/
core/deobf/Deobfuscator.java.

If you have to deal with deobfuscation that cannot be handled by the tools,
I recommend creating a ow- and call graph of the application. Then we
can track down which classes are doing what and start renaming them.
This approach takes of course a lot of time.

Parameter „—cfg“

This parameter creates a ow chart (.dot - les) of all functions. This is super handy if you
have to trace back a huge function that has been obfuscated. I normally would use the
androguard feature for this process but I JADX will be a lot faster.

$ sudo apt-get install graphviz


$ pip3 install -U pydot
$ jadx -d out --cfg app-debug.apk

Now we have our decompiled code and the corresponding dot les. We need to write a
little python script to convert a .dot le into a png:

Roman Stuehler (Udemy) Page 35 / 104


fl
fl
fi
fi
fi
fi
Now we can open the „checkRootMethod3“ png le which looks like this:

On such a small function it might be not that helpful, but when you have to deal with
some obfuscation methods, this might be very handy!

8.3.2. JADX-GUI
JADX-GUI is being used to decompile and display an APK in a nice GUI window.

JADX and JADX-GUI are based on the same GitHub project. The installation process is
the same:

git clone https://github.com/skylot/jadx.git


cd jadx
./gradlew dist

Check out the project: https://github.com/skylot/jadx.


We can also start JADX-GUI with the same parameters which have been shown in the
JADX section.

8.3.3. DEX2jar
DEX2jar is being used to reconstruct the JAVA code out of the classes.dex les of the
android APK.

Roman Stuehler (Udemy) Page 36 / 104


fi
fi
You can download dex2jar here: https://sourceforge.net/projects/dex2jar/ les/. I
include dex2jar in the $PATH variable afterwards to make it easier to call. Otherwise you
would have to provide the full PATH all the time.

/home/android/tools/jadx/build/jadx/bin:/home/android/tools/dex2jar:/
home/android/.local/bin/:/home/android/.local/bin:/usr/local/sbin:/
usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/
games:/snap/bin

If you have a windows system, you want to use „d2j-dex2jar.bat“. On a Linux system we
are using d2j-dex2jar.sh.

1. Unzip the APK

$ unzip de.fgerbig.spacepeng_1581.apk

2. Decompile the classes.dex le with dex.2jar

$ d2j-dex2jar.sh classes.dex
dex2jar classes.dex -> ./classes-dex2jar.jar

3. Open the generated jar- le with jd-gui

$ jd-gui classes-dex2jar.jar

Done :)

8.3.4. JD-GUI
JD-GUI is being used to display the classes inside a JAR le in a nice GUI. There are no
special parameters which I use during my daily work with JD-GUI.

Roman Stuehler (Udemy) Page 37 / 104


fi
fi
fi
fi
8.3.5. APKTOOL
The apktool can be used to decompile a mobile application. This tool is being used very
often during this course. You can download it here: https://ibotpeaches.github.io/
Apktool/.

Update! Please make sure you are using the version 2.5.0 or newer of
the apktool. The android build system has recently changed (August
2020). Apps that have been build with the new android-studio cannot
be decompiled anymore with older versions of the apktool.

Basic Parameters

These are the common parameters of my daily work with the APKTOOL.

d Decompile an APK
b Build an APK based on a decompiled version
-r,--no-res Do not decode resources.
--force-manifest Decode the APK's compiled manifest, even if
decoding of resources is set to "false".
-d,--debug Sets android:debuggable to "true" in the APK's
compiled manifest

A basic call looks like this:

$ apktool d <APK>
$ apktool b app/

Parameter „-r“
As already mentioned in JADX, this parameter does not decompile resource les. These
les often cause problems and might hinder the APKTOOL on decompiling the app.
Beside the AndroidManifest.xml, the resource les are not really required and can be
skipped.

Parameter „--force-manifest“

It is always helpful to have the AndroidManifest.xml decompiled. But if we choose the „-r“
parameter, this does not happen because this is a resource le. To avoid decompiling the
unnecessary les and keeping the AndroidManifest.xml we can provide this parameter.

Roman Stuehler (Udemy) Page 38 / 104


fi
fi
fi
fi
fi
8.4. Special Section - Approach: „Upos“ Challenge
I stumbled across the following „Mobile Crackmes“ and many of them were pretty similar
but one was really hard. This has been also proofed by the amount of solves.
The creator itself is well known for the famous Cloak & Dagger attack on the android
system. You can nd the link here: https://mobisec.reyammer.io/challs.

After absolving this course, you will be able to solve all of his challenges.
I will not spoiler any solution but I will teach you all the techniques that are required to
solve them.

This part is only included in the video of the Udemy course:„Android


App Hacking - Black Belt Edition“. It does not contain the solution for
this challenge because this would be lame :) But it shows an
approach how to analyse and solve high obfuscated apps.

The tools that are required for this can be installed with the following commands:

$ pip install networkx==1.11


$ apt-get install openjdk-8-jdk // (required by gephi)

$ sudo update-alternatives --con g java

Roman Stuehler (Udemy) Page 39 / 104


fi
fi
9. Apps
This part provides useful information about android apps and their corresponding les
and locations.

9.1. Package Structure


Summary of the package structure of an APK if you unzip it.

Command Description

assets Pictures / Sounds / Certi cates / External les

lib Libraries ( check to see if emulator „x86“ is


supported)

META-INF Code Signature (signing)

res App Icon

AndroidManifest.xml Con guration le in binary format (not readable


by unzipping an app)

classes.dex Dalvik Bytecode of all classes

resources.arsc Compiled resources (Strings / Color etc.)

Take a look into the „lib“ directory to check, if the application is


supporting the x86 architecture. If there is a directory containing a lib
or if the app does not contain additional libraries at all, this is most
likely the case.

In the AndroidManifest.xml we look for the permissions and exported


components. We will nd out the corresponding classes which de ne
the key components and can hunt for vulnerabilities.

We should always check the assets directory. There might be certi cates or additional
data that are used in the app which cannot be seen in the decompiled java code. Of
course if this directory is not available, then we do not have to check it :)

Roman Stuehler (Udemy) Page 40 / 104


fi
fi
fi
fi
fi
fi
fi
fi
9.2. Decompiling - Building and signing Apps
Here we will have all the steps in decompiling and building back the app.

9.2.1. APKTOOL- Decompile

$ apktool d <apk file>

If you encounter some problems you can try to decompile the application with the „-
r“ parameter.

$ apktool d -r game_test.apk

The apktool will not try to decompile the resources of the app. If you still get errors try out
other decompilers like jadx or androguard.

9.2.2. APKTOOL - Compile


After performing our modi cations we can build the app back again.

$ apktool b game_test/

Even if we have decompiled the app with the „-r“ parameter, it is not required for building
it back again.
Also take care! We need to provide the directory path and not the application APK le
here. If you encounter errors have a look if this is the case.

9.2.3. Creating a new Keystore


The APK has to be signed to be installed on the device. Therefore we need to create a
keystore. We can build one with the following command:

$ keytool -genkey -v -keystore ~/android-app-hack.keystore -alias


alias_name -keyalg RSA -keysize 2048 -validity 365

Here we are creating a new keystore in our home directory with the name „android-app-
hack.keystore“.
The alias_name is not relevant. We can provide any name we want. This name will be later
used to sign the app. It identi es the correct certi cate in the keystore. The keystore can
hold more than one certi cate.

Roman Stuehler (Udemy) Page 41 / 104


fi
fi
fi
fi
fi
9.2.4. Zipalign
Android uses zipalign to make sure that all uncompressed data start with a particular
alignment relative to the start of the le (see. https://developer.android.com/studio/
command-line/zipalign). This reduces the RAM required by the application and needs to
be done, before we sign the application. The alignment is always 4 bytes (parameter 4).

$ zipalign -v 4 infile.apk outfile.apk

The le „out le.apk“ is now aligned on 4-byte boundaries and can now be signed.

9.2.5. Signing the App


After creating the keystore we sign the app with the following command:

apksigner sign --ks ~/tools/keystore/android-app-hack.keystore new-debug.apk

This will create a new application named “new-debug.apk” which has been signed and
can be installed now.

9.2.6. New Version - Steps

Update! The new build system in android - introduced in august 2020 - will
cause headache if you try to rebuild newer application. I have found a way
to handle this and I will show you here :)

Here are all the commands at one place.


• java -jar apktool_2.5.0.jar d org.secuso.privacyfriendlydicer_8.apk

Modify the SMALI content / AndroidManifest.xml and then:


• java -jar apktool_2.5.0.jar b org.secuso.privacyfriendlydicer_8
• cd dist
• zipalign 4 app-debug.apk new-debug.apk
• apksigner sign --ks ~/tools/keystore/android-app-hack.keystore new-debug.apk
• adb install -r new-debug.apk

9.2.7. Troubleshooting
This guide provides some common erros I have encountered during this process. If you
encounter a new problem, please send me a message. I try my best to support you on
that.

Roman Stuehler (Udemy) Page 42 / 104


fi
fi
fi
1. Error - Could not extract resource /prebuilt/linux/aapt64

We have decompiled the app and are now trying to build it back when we encounter this
error:

We also tried decompiling the app with the „-r“ parameter, which seems to work until we
want to install the app. Then we get this error:

This looks like an application that has been compiled with the new build system (aapt2).
The signing has also changed and zipalign is necessary. If you follow the steps above,
you shouldn’t encounter this problem. It was related to the old signing approach.

$ java -jar apktool_2.5.0.jar d org.secuso.privacyfriendlydicer_8.apk

In case of other errors try the following approach. The second command often solves the
problem. It is like cleaning the project.

$ java -jar apktool_2.5.0.jar d org.secuso.privacyfriendlydicer_8.apk


$ java -jar ~/Downloads/apktool_2.5.0.jar empty-framework-dir
$ java -jar apktool_2.5.0.jar b org.secuso.privacyfriendlydicer_8

Roman Stuehler (Udemy) Page 43 / 104


If you still get certi cate error messages, try this:

$ java -jar apktool_2.5.0.jar d org.secuso.privacyfriendlydicer_8.apk


$ java -jar ~/Downloads/apktool_2.5.0.jar empty-framework-dir
$ java -jar apktool_2.5.0.jar b org.secuso.privacyfriendlydicer_8
$ cd org.secuso.privacyfriendlydicer_8/dist
$ zipalign 4 app-debug.apk new-debug.apk
$ apksigner sign --ks ~/tools/keystore/android-app-hack.keystore new-
debug.apk
$ adb install -r new-debug.apk

2. Error - No resource identi er found for attribute 'compileSdkVersion'

In case of this error message, just try to empty the framework dir.

$ java -jar apktool_2.5.0.jar d org.secuso.privacyfriendlydicer_8.apk


$ java -jar ~/Downloads/apktool_2.5.0.jar empty-framework-dir
$ java -jar apktool_2.5.0.jar b org.secuso.privacyfriendlydicer_8

3. Error - ADB INSTALL FAILURE - INSTALL_FAILED_TEST_ONLY

This error is caused if the AndroidManifest.xml contains the following entry


android:testOnly=“true”.

/home/android/AndroidStudioProjects/ndkfrida/app/build/outputs/apk/debug/app-debug/dist $ adb
install -r new-debug.apk
adb: failed to install new-debug.apk: Failure [INSTALL_FAILED_TEST_ONLY: installPackageLI]

This means the application cannot be “regularly” installed. All we have to do is adding the
“-t” parameter as shown below:

$ adb install -r -t new-debug.apk

4. Error - Failed to extract native libraries

failed to install app-debug.apk: Failure [INSTALL_FAILED_INVALID_APK: Failed to extract native


libraries, res=-2]

This happens when we have added - modi ed some native libraries. We can solve this
issue by adding the following parameter into the AndroidManifest.xml:
android:extractNativeLibs=„true“.

Roman Stuehler (Udemy) Page 44 / 104


fi
fi
fi
5. Error - INSTALL_PARSE_FAILED_NO_CERTIFICATES

This might happened quite often and simply means, we have forgotten to sign the app or
we are trying to install the none signed version of the app :)

adb: failed to install new-debug.apk: Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES: Failed


collecting certificates for /data/app/vmdl304755566.tmp/base.apk: Failed to collect certificates
from /data/app/vmdl304755566.tmp/base.apk: Attempt to get length of null array]

Simply use the zipgalign command before and sign it afterwards.

$ zipalign 4 app-debug.apk new-debug.apk


$ apksigner sign --ks ~/tools/keystore/android-app-hack.keystore new-
debug.apk
$ adb install -r new-debug.apk

If you have signed the application then please make sure that you are using the correct
version of the app. The output le of the signing command. In this case new-debug.apk is
the signed app.

Roman Stuehler (Udemy) Page 45 / 104


fi
10. App Components - Vulnerabilities
Some quick notes on what to look for and how to exploit them :)

10.1. Activities
Have a look into the AndroidManifest.xml and check if one of them is being exported.

10.1.1.AndroidManifest.xml - What to look for?


Activities can be exported by adding the ag “export=true” or they can be implicit
exported if they are in-between “intent- lters”.

The “android:name” tag shows the Java-Class of the given activity. This is required for the
exploitation part.

10.1.2.Exploitation
Exported activities can be started via the ADB shell or by writing a custom application
which is triggering the intent. Starting via the ADB shell is enough for a PoC:

$ am start <package>/<activity - name>


$ am start -n (explicit) <package>/<activity - name>

$ am start -n com.mwr.example.sieve/.FileSelectActivity
$ am start -n com.mwr.example.sieve/.PWList

Java Code within a custom application to start an external activity.

Roman Stuehler (Udemy) Page 46 / 104


fi
fl
10.2. Intent
Intents are some sort of messaging objects that can trigger certain actions.

10.2.1.Code - What to look for?


The component receiving the intent needs to be exported.We have to look into the
AndroidManifest.xml to identify it. There we will also nd required information like: action /
category. Category is not always being required to send an intent.

We have to check the code if we can exploit this behaviour. Please search for the
following term:

Intent intent = getIntent();

In the following example the “ChangePin” activity is being started with a username
provided by the intent.

If the “ChangePin” activity is being exported, we can trigger the intent with a di erent
username. It depends on the user code what happens next.

10.2.2.Exploitation
To start the activity with a di erent username we can use the activity manager and
provide the intent information as follow:

$ adb shell
$ am start-activity -a com.apphacking.changePin —es “username” “user”
// *Note: Category could be also added with -c android.intent.category.Default

Roman Stuehler (Udemy) Page 47 / 104


ff
fi
ff
10.3. BroadcastReceiver
BroadcastReceiver are often being exported, which makes them a valuable target.

10.3.1.Code - What to look for?


The only method we are looking for is the “onReceive” method. This method gets called
by sending the BroadCast event.

Take care! Beside looking into the AndroidManifest we also have to


look into the Java Code for “registeredReceiver”! This is common
! on Android apps (Version > 11). Frameworks like DROZER or MobSF
might miss them! Please check manually if a BroadcastReceiver is
being de ned in the Java Code!

*Note: MobSF is a really nice framework and we can use this for certain tasks. But keep in
mind that it might miss something. Therefore I would like to show, how you can do all of
this by yourself to make sure, we are fetching everything.

10.3.2.Exploitation
Here we have to check the onReceive method in the Java class. This is the only code part
we can trigger by sending our event.

Roman Stuehler (Udemy) Page 48 / 104


fi
This application is listening for the intent “com.apphacking.broadcastreceiver.alarmState”.
It also takes a parameter named “status”. We can arm and disarm the system based on
this event. To send this BroadcastEvent we can use ADB as follow:

$ am broadcast -a com.apphacking.broadcastreceiver.alarmState —es “status” “arm”

10.4. ContentProvider
Within a ContentProvider we can look for SQL injections and Path-Traversal attacks.

10.4.1.Code - What to look for?


Once again, the ContentProvider needs to be exported. Sometimes the ContentProvider
can be also locked down with a certain permission. This can be circumvented if the
protectionLevel is not signature like shown below.

Source: AndroidManifest.xml - Sieve.apk

We can write our own app and use the custom permission. The user might be informed
with a popup. It depends on certain things but nevertheless, a missclick can happen and
this would provide us full access to the database.

Roman Stuehler (Udemy) Page 49 / 104


10.4.1.1. SQL Injection

We need to check if the query method (if available) is ltering our input. If this is not the
case, we are able to inject our own code into the SQL query.

The SQL syntax will be generated out of these parameters as follow:

Now we need to identify the tables in the Java code. We can look for the keyword
“content://“.

Source: DBContentProvider - Sieve.apk

Here we have the authority names of the tables.

- com.mwr.example.sieve.DBContentProvider/Keys
- com.mwr.example.sieve.DBContentProvider/Passwords

The actual table names might be different, we have to track this in the
! code because within the SQL injection attack, we have to use the correct
table names and not the authority names.

Roman Stuehler (Udemy) Page 50 / 104


fi
SQL Injection - Attack:

$ content query —uri content://com.mwr.example.sieve.DBContentPRovider/Passwords —


projection “* FROM Key--“

This leads to the following syntax:

The “- -“ (comment) will negate the rest of the original query. Therefore we are just
selecting all entries from Key.

Key is the actual table_name. The authority name is being referenced with “Keys”!
Confusing Yes! :D

SQL Queries to manipulate the database:

// Selecting
$ content query --uri content://<authority>/users

// Inserting
$ content insert --uri content://<authority>/users --bind name:s:admin

// Update - Modify
$ content update --uri content://<authority>/users --bind name:s:hacker --where
“name=‘admin’”

// Delete
$ content delete --uri content://<authority>/users --where “name=‘admin’”

Roman Stuehler (Udemy) Page 51 / 104


10.4.1.2. Path-Traversal
AndroidManifest.xml again. Exported? Alright! :)

In case of a Path-Traversal vulnerability we have to check for ParcelFileDescriptor.

If the input “uri” is not being ltered, then we can apply les like “../../../../../etc/hosts”.
This gives us the possiblity to perform an arbitrary read on possible sensitive information
which are being stored in the app directory. This directory is sandboxed and normal users
do not have access. But we are now in the context of the current application which
means, we have the ability to access them.

Path-Traversal - Attack:

$ content read —uri content://com.apphacking.musicplayer/../../../../../../etc/


hosts

The name of the ContentProvider can be fetched from the AndroidManifest.xml. If we


have a ParcelFileDescriptor openFile that takes an un ltered uri, this is all we need to do.

Roman Stuehler (Udemy) Page 52 / 104


fi
fi
fi
11. SMALI
Here we will pack together all the useful SMALI information of this course.

11.1. Types
Here is a list of types in SMALI. It takes some time but you will get familiar with these
types. I have marked the most import one which we will encounter very often.

Syntax Meaning

V Void
Boolean:
Z Boolean
0x0 = false (0)
B byte 0x1 = true (>0 is true)

S short

C char
F oat

I int

J long

D double

[descriptor (e.g „[B“ —> array byte[ ] myarry = {0x0, 0x1}


byte[]) new-array v0, v0, [B
Lfully/quali ed/Name; class name

11.2. Registers / Variables / Parameters


In dalvik, registers are always 32 bits, and can hold any type of value. Two registers are
used to hold 64 bit types (Long and Double).

Local Param The registers starting with a Vx are used as


„local“ registers. These could be local variables or values
V0 P0 that needs to be stored.
V1 P1
V2 P2 The registers starting with Px are parameters in a
V4 P3 function. The P0 is often used as the „this“ operator.
V(…) P(…)

We verify or clarify this behaviour with the following example. We will decompile this code
with the APKTOOL and walk through the output.

Roman Stuehler (Udemy) Page 53 / 104


fl
fi
Below we have the decompiled SMALI code.

Parameters - Registers:
We can see that the parameters do
start with „p1“ and end with „p9“. We
remember, „p0“ is used as „this“.

Parameters - Type:
Within the manyArgs( ) function we
see those values:
• IICICCICI (9 parameters!)
Check the list above to determine the
types of the single parameters :
• B => Byte
• I => Integer
• C => Char
• V => Void
• […]

Local - Registers
The local registers start with v0 and end with v6. But not all of them are regarding to the
variables above. We will see later :).

Local - Types
The type of the local registers all start with „L“? Take a look above at the data types!
These are the whole class names. So, „Ljava/lang/String“ simply means a String. These
are all Strings.

Locals - SMALI
You have to take a close look on line 132 above. Here we can see the word „locals“ which
refers to our local registers. But we only have v0 - v4? Yes, as local variables, but the
decompiler did need 3 additional registers to handle the whole code.

Roman Stuehler (Udemy) Page 54 / 104


You can see this behaviour in line 164. We are using v5 which is not a local (Java)
variable but a local register to save the output of the sget-object function.

Locals - JADX-GUI vs APKTOOL


If we compare the output of both decompilers (JADX-GUI left - APKTOOL right), we
barely see any di erence. But if we take ca close look onto line 20 (left) and line 132 (right)
we see something strange.

JADX-GUI is using „.registers 18“ and the APKTOOL uses „.locals 8“. These are some
sort of naming conventions. It does not make any di erence.
For me, I like the APKTOOL approach much more and I will stick to this for the rest of the
course. I just want to let you know that these outputs can di er based on the tools you
use. The SMALI code should stay the same ;)

11.3. Basic Commands


In this chapter, I have reduced the SMALI commands to a short list, which helps you to
solve most of your tasks. If you are familiar with these few commands, you are pretty
good to go to read and write SMALI code by yourself!

11.3.1.Variables - Assigning
This Table is based on this amazing website: http://pallergabor.uw.hu/androidblog/
dalvik_opcodes.html. I only changed the examples to make it easier to read. But you
should de nitely bookmark this page!

Roman Stuehler (Udemy) Page 55 / 104


fi
ff
ff
ff
Command Description Example (Java / Smali)

move vx,vy Moves the content of vy into vx. int a = 12;

mov v0, 0xc


const/4 vx,lit4 Puts the 4 bit constant into vx. int level = 3; // Max value is 7 (4 Bit)
The max value is therefore 7. If
we want to insert a higher value const/4 v0, 0x5
we have to remove the /4 part to
make it (const vx, value).

new-array vx,vy,type_id Generates a new array of type_id byte[] bArr = {0, 1, 2, 3, 4};
type and vy element size and
puts the reference to the array const/4 v0, 0x5 # Array size
into vx. new-array v0, v0, [B

const vx, lit32 Puts the integer constant into vx int level = 10000; // 32 Bit

const vx, 0x2710

const-string vx,string_id Puts reference to a string String name = „Player“;


constant identi ed by string_id
into vx. const-string v5, "Player"

iget vx, vy, eld_id Reads an instance eld into vx. return this.highScore;
The instance is referenced by vy.
iget v0, p0, Lde/fgerbig/spacepeng/
services/Pro le;->highScore:I

return v0

iput vx,vy, eld_id Puts vx into an instance eld. The this.lastPlayedLevel = lastPlayedLevel2;
instance is referenced by vy.
iput p1, p0, Lde/fgerbig/spacepeng/
services/Pro le;->lastPlayedLevel:I

If you know that „iput” stores a value into a register, then you will also now that „iput-
boolean“ does the same, but only for a boolean value.
You will have all kind of variations but these are the most basic assignments.

Roman Stuehler (Udemy) Page 56 / 104


fi
fi
fi
fi
fi
fi
fi
11.3.1.1. Reading - Directions

It is also important to understand the reading direction. What is the source and what is
the destination register. So let’s take a look at the following example:

Const/16 stores the value 0xc into const/16 v0, 0xC


the register v0 => const dst, src

Move stores the value of v0 into v1.


The value is 0xc => mov dst, src Move v1, v0

Iput stores the value of p2 into the


iput p2 p1
register of p1 => iput src, dst

Iget stores the value of p1 into the


register v0 => iget dst, src iget v0 p1

The reading direction is also considered in the reference page: http://pallergabor.uw.hu/


androidblog/dalvik_opcodes.html. Sometimes you have to read the description twice :).

Roman Stuehler (Udemy) Page 57 / 104


11.3.2.Operators
These are the most common operators.

Command Description Example (Java / Smali)

add-int vx,vy,vz Calculates vy+vz and puts the result into vx. score = score + 1

add-int/lit8 v5, v5, 0x1


sub-int vx,vy,vz Calculates vy-vz and puts the result into vx. score = score - 1

sub-int/lit8 v5, v5, 0x1


mul-int vx, vy, vz Multiplies vz with wy and puts the result int bonus = bonus * 50
vx.
mul-int/lit8 v6, v1, 0x32
div-int vx,vy,vz Divides vy with vz and puts the result into bonus = bonus / 2
vx.
div-int v4, v1, 0x2

rem-int vx,vy,vz Calculates vy % vz and puts the result into Math.abs(step2 % 4)


vx.
rem-int/lit8 v0, p1, 0x4
and-int vx, vy, vz Calculates vy AND vz and puts the result int result = b & 127;
into vx.
and-int/lit8 v1, p3, 0x1f
or-int vx, vy, vz Calculates vy OR vz and puts the result into int result = b | 127;
vx.
or-int/lit8 v1, p3, 0x1f
xor-int vx, vy, vz Calculates vy XOR vz and puts the result Key = a ^ b
into vx.
xor-int v1, v2, v3

Roman Stuehler (Udemy) Page 58 / 104


11.3.3.IF - ELSE - GOTO
These blocks are super important because you can change most of the application
behaviour by simply switching a state from „true" to „false“ and vice versa.
I have prepared this table which covers most of the important cases. You do not have to
remember all of them but having them in mind will speed up things a lot.

Syntax Description Syntax Description

if-eqz vx,target if vx == 0 if-eq vx,vy,target if vx == vy

if-nez vx,target if vx != 0 if-ne vx,vy,target if vx != vy

if-ltz vx,target if vx < 0 if-lt vx,vy,target if vx < vy

if-gez vx,target if vx >= 0 if-ge vx, vy,target if vx >= vy

if-gtz vx,target if vx > 0 if-gt vx,vy,target if vx > vy

if-lez vx,target if vx <= 0 if-le vx,vy,target if vx =< vy

Comparison against 0. Comparison against a register.

11.3.3.1. Modifying the application behavior

The program ow is based on decisions / checks which de ne if we can a ord this item
or if you lose the game because you do not have any hit points left.

The example on the left will de ne if the player


is allowed to buy the item.
The corresponding SMALI instruction is:
if-gt v0, 0x3e8, :cond_1
*Note: „cond_1“ will be the TRUE statement.

We can change the whole logic of this application by:


• (1) Switching „if-gt“ to „if-lt“. ( > to <)
• (2) Deleting the if statement in the corresponding SMALI code.

Roman Stuehler (Udemy) Page 59 / 104


fl
fi
fi
ff
How does this a ect the corresponding program ow?
1) Unless the player has less than 1000 (money) the player will be able to add this item.
2) If we delete the if clause, the player will immediately have this item no matter how
much money the player has.

11.3.3.2. Patching Debug Detection

Let’s say we have the following code. This code checks if we have the debugger
attached.

We want to make sure that we can debug this application. The function checkDebugger()
needs to return„FALSE“.
There are a lot of possibilities to bypass this check but one working solution will be
enough :) We still discuss some other solutions too.

Solutions:
1. We can change the return value of the checkDebugger() method, to always return
false (0x0).
2. We can negate line 20. This means instead of „if(check)“ we can rewrite it to „if(!
check)“. The downside of this method is, that the application is returning the
opposite, which means, if we have no debugger attached - it will show that we
have one attached. Not ideal here but often very useful. E.g rooting detections.
3. Last solution for now is rerouting the if statement. This means we are jumping over
the part we do not want to have executed.

Roman Stuehler (Udemy) Page 60 / 104


ff
fl
The best scenario does not change too much of the application behaviour. Therefore,
number 2 is out. We will stay with solution 1 and 3.

Method 1 - Changing the return value

On the left we have the decompiled


„checkDebugger“ function.
We can see that it is moving the result of the
function into v0 —> „move-result v0"?

But… We do not have a certain instruction like „move v0, v1“ or „const v0, 0x1“? How
can we easily modify this?
Solution - Method 1:
We can simply add our own code before the return v0 command. We are writing the result
into v0 but we immediately overwrite it afterwards like shown below.

The return value is a boolean value (Z). This function is now - no matter what - returning
false all the time.

Method 3 - Rerouting the IF - Statement

This time we are rerouting the execution ow via the IF statement. It might sound a little
bit complex but we can handle this :).

Roman Stuehler (Udemy) Page 61 / 104


fl
Line 46 stores the result of the function, if the debugger is attached or not. The
comparison takes place in line 50.

Line 50: If “checkDebugger” is equal Zero, we jump to :cond_0.


Solution - Method 3:

The application is printing out “No debugger attached”. This means we add the
instruction “goto :cond_0” directly after the if statement in line 53.

if-eqz v0, :cond0

.line 21
goto :cond_0
sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
[...]

Now we are redirecting the program ow always into the “correct” blocks :).
There are many methods and ways you can patch di erent things. It is often also not
possible to provide „one - best“ solution. Just remember that you have the possibilities
to :
• change the conditions in the if statements ( TRUE / FALSE)
• that you can create your own registers / overwrite existing values
• that you can add/modify existing / own code
• delete existing code :)
• change the program ow
Having this in mind, you will nd your way through these applications! :)

Roman Stuehler (Udemy) Page 62 / 104


fl
fi
fl
ff
11.4. Methods - Objects
This part is about methods and objects. There are not that many possibilities and here is
short list with the most important ones.

Command Description Example (Java / Smali)

invoke-virtual { parameters }, Invokes a virtual method with this.ds.increaseScore(value)


methodtocall parameters.
invoke-virtual {v5, v6}, Lde/
fgerbig/spacepeng/systems/
DirectorSystem;-
>increaseScore(I)V

invoke-direct { parameters }, Invokes a method with DoubleShot doubleShot = new


methodtocall parameters without the DoubleShot();
virtual method resolution.
invoke-direct {v0}, Lde/fgerbig/
spacepeng/components/
powerup/DoubleShot;-><init>()V

invoke-static {parameters}, Invokes a static method with MathUtils.random(( oat)


methodtocall parameters. MIN_DELAY, ( oat)
MAX_DELAY);

invoke-static {v0, v1}, Lcom/


example/MathUtils;-
>random(FF)F
invoke-interface Invokes an interface method. itrt.hasNext()
{parameters},methodtocall
invoke-interface {v3}, Ljava/util/
Iterator;->hasNext()Z

Sget-object

They look pretty identical but they are di erent as shown below:
• public void increaseScore(int score)
• DoubleShot doubleShot = new DoubleShot();
• public static oat random( oat x, oat y)
• public abstract boolean hasNext ()

Roman Stuehler (Udemy) Page 63 / 104


fl
fl
fl
fl
fl
ff
11.4.1.1. What does the $ mean in the SMALI les

The $ signs means inherited classes or enums. Let’s have a look at the following example:

Ok here we have a class named


„MainActivity“.

We include
„java.io.Serializable“ and created a
new object.

We also have an inherited class


named „HighScore“.

Now let’s do a „ls“ command in the decompiled code directory and see what we have.

App-debug/com/apphacking/inheritclasses$ ls
BuildConfig.smali
MainActivity$1.smali'
MainActivity$HighScore.smali'
MainActivity.smali

Inherited Class / Enum


In this case, the „MainActivity$HighScore.smali“ describes an inherit class inside the
MainActivity class. The code regarding to the variable “points“ will be included here and
not in the „MainActivity.smali“ le.

Roman Stuehler (Udemy) Page 64 / 104


fi
fi
11.4.1.2. Deep Dive - Break Down a complex syntax

Now let’s look into something, that looks a bit more complex. But based on what we have
learned so far, we are able to understand the whole syntax. We just need to do this step
by step and have a little patience. To get good in SMALI we simply have to practice. :)

Example 1:

invoke-static {v1, v2}, Lde/fgerbig/spacepeng/services/EntityFactory;->createCoin(Lcom/


artemis/World;Lde/fgerbig/spacepeng/components/powerup/Coin$Type;)Lcom/artemis/Entity;

This might look overwhelming in the beginning but just go through this - step by step:

1. Invoke-static:
invoke-static {parameters}, methodtocall.
• Ok this is a static method - we do not need to create an object rst.
• We also have two parameters, v1 and v2.
• The method that gets called is createCoin.
• This method is de ned in the EntityFactory class.
• The parameters are „com/artemis/world“ and „de/fgerbig…./coin$type“
• We know that „type“ is an inherit class of the class coin.
• The return value is a com/artemis/Entity object.

invoke-static {v1, v2}, Lde/fgerbig/spacepeng/services/EntityFactory;->createCoin(Lcom/


artemis/World;Lde/fgerbig/spacepeng/components/powerup/Coin$Type;)Lcom/artemis/Entity;

The same syntax but marked and split into single parts as described before.
The function code might look like this:

public class EntityFactory {


public static Entity createCoin(World world, Coin.Type cointype) { … };
}

And here we have the decompiled version:

Roman Stuehler (Udemy) Page 65 / 104


fi
fi
The Coin.Type might be a bit confusing because we are dealing with an enum type:

But we got a feeling what was going on there and even if we do not fully understand it in
the SMALI code, we do it now.
Beside this, we were correct on the other assumptions which is pretty amazing?! I mean
we did reconstruct the decompiled code, based on the SMALI syntax!
If this has not been the case for you, don’t worry. This topic is very complex. You need to
be patient. Do it step by step and keep practicing. I have learned it and I am not a genius.
You can learn this too!

11.4.1.3. Useful SMALI snippets

This is a short collection about some very useful SMALI snippets. These snippets helps
you to solve your tasks like CTF challenges or leaking sensitive information out of
cryptographic functions.

Printing out variables / return vales via System.out.println

I use this snippet quite often because it is an easy way to simply print out certain
variables or return vales in logcat.

This can be passwords, secrets, comparison values … whatever you want :)

String password = "Pa%%w0rd!";

System.out.println(password);

The corresponding SMALI code looks like this:

Roman Stuehler (Udemy) Page 66 / 104


.line 14

const-string v0, "Pa%%w0rd!"

.line 15

.local v0, "password":Ljava/lang/String;

sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;

invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V

We simply put our object / value we want to print into v0 and use sget-object and invoke-
virtual afterwards.

Now just simply run the app and check the logical output for our value to be printed:

$ adb logcat

Printing out byte values as Base64 encoded string.


Cryptographic functions often store their keys or IV as byte arrays. An easy way to print
them out in text form is using a base64 encoding.
• System.out.println(Base64.encodeToString(<byte Array>,0));

The corresponding SMALI code looks like this. All we need to do is inserting this piece of
code into the existing SMALI code of the application. We might have to adjust the register
v5 which is referring to the byte array, but that’s it :)

const/4 v5, 0x0


invoke-static {v2, v5}, Landroid/util/Base64;->encodeToString([BI)Ljava/lang/
String;
move-result-object v5

sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;

invoke-virtual {v1, v5}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V

Roman Stuehler (Udemy) Page 67 / 104


12. Man-in-the-Middle - Device
In this section, we will summarize the Man-in-the-Middle steps. We will take a look at the
whole setup which works super well if you stick to this description :)

12.1. Setup - Real Device


You need a router and if you want to run this setup in your Virtual Machine (VM) you also
need a USB-To-Ethernet adapter.

12.1.1.Router (1)
We start with the router. It does not really matter which router you pick. The only thing you
have to do is to disable DHCP. You will nd this in the menu of router. It should also have
WiFi :).

Steps:
1. Plugin your ethernet cable and wait until you receive an IP
2. Log into the interface of your router.
3. Search for network settings „Enable DHCP“ and uncheck this box. We need to disable
DHCP!
4. Restart your device / router.

Roman Stuehler (Udemy) Page 68 / 104


fi
12.2. Network-Connection-Editor (2/3)
After disabling DHCP we can provide our own DHCP / DNS entries to the router which
get redistributed to all connected clients. This is very simple. But before we do this,
please verify that the USB-To-Ethernet adapter is connected to your VM. Also check if
your VM supports USB-3.0.
You can verify if this adapter has been successfully connected by checking the network
interfaces, but you need the „net-tools“ package rst.

$ sudo apt-get install net-tools


$ ifconfig -a
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.240.2 netmask 255.255.255.0 broadcast
172.16.240.255
[ … shorten … ]

lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536


inet 127.0.0.1 netmask 255.0.0.0
[ … shorten … ]

Here we only see the interfaces „ens33“ and „lo“ which is loopback. So the USB-Ethernet
interface is missing. After adding the USB device to our machine, it should look like this.

If you get an error message, that the connection is not possible then
please check if you have USB 3.0 enabled. If the adapter only supports
USB 3.0 you have to plug it into a USB 3.0 port which is not always that
easy to identify on older laptops :) For more information please have a
look at the video again.

Ok after changing USB-2 to USB-3 and reconnecting the adapter it is working. We have a
new interface named „enx302303bca34c“.

$ ifconfig -a
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.240.2 netmask 255.255.255.0 broadcast
172.16.240.255

enx102303bca320: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500


ether 10:23:03:bc:a3:20 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
[… shorten …]

Roman Stuehler (Udemy) Page 69 / 104


fi
But this interface does not have an ip address? Yep, because we did not tell the network-
manager that it needs to share the connection with this adapter. This is the last step
regarding to the setup and can be done by typing in:

$ nm-connection-editor

This will open the following view:


Here we have two ( or more ) connections
listed. In my case: One is the „ens33“ and the
other one is the usb adapter named
„enx302303bca34c“.

Which one to choose?


We start with „Wired connection 2“ but it could
be also the other one :). We will nd this out by
double clicking on it which opens up another
popup shown below.

Ok now we now that this is our


connection, because we can see it in
the „Device“ name. If this is printing
out „ens33“ you have to close this
window and have to click on the other
connection. Our adapter is:
enx302303bca34c as seen on the left.
If some steps are unclear, please take
a look at the video again. I also
explain every step there and it is way
easier to follow there. This is just a
short summary if you want to look
things up again :)

Ok, we now go into IPv4 Settings and


select the tab „Shared to other
computers“. Thats it. The magic
happens in the background. The
network-manager will provide DHCP
and DNS automatically. We do not
have to con gure anything.
If everything has been successfully,
you will have a new IP address on this
interface which is „10.42.0.1/24“. You
are now a gateway!

Roman Stuehler (Udemy) Page 70 / 104


fi
fi
12.2.1. Troubleshooting:

Sometimes things are buggy but after following these steps here, it did work in 99.99% of
the time :)

$ sudo ifconfig enx302303bca34c up


$ sudo service network-manager restart
$ sudo dhclient

Check if your router has DHCP disabled. If you connect to it with your host and still
receiving an IP then DHCP is still active and we are getting con icts.
Check if your USB-To-Ethernet-Adapter is connected to a USB 3.0 port.
Check if your USB-To-Ethernet-Adapter is generally working :)
Check if your VM has USB 3.0 enabled
If you are using a docking-station, verify that you have forwarded the correct adapter.
You can check this by having a look at the MAC address of the device.
Unplug potential other devices that are providing a DHCP server (If you have more
then one router connected / docking-stations)
If you have it plugged in a USB hub, try a direct to connect to a direct port on your
laptop.
Check if NAT / HostOnly is enabled. Sometimes it does not provide the network
con guration (shared) if there is none network available.
If all of these fail, please send me a message! :) We will make it work, I am pretty sure!
I showed this setup also to my colleagues and they are using it for several years now.
We had one of the problems mentioned above, but soon or later it did work :)

12.2.2.IP Tables (4)


If you connect the smartphone to the WiFi of your router, you will see that it also receives
a 10.42.0.x address. If your Linux system has an internet connection you can also browse
on your smartphone and the tra c gets automatically routed through your laptop.
We can verify this by running Wireshark. But there is one problem for now. We cannot
modify the tra c and it might be also encrypted (HTTPS)? We will deal with https later.
For now let’s focus on modifying the tra c rst.
We need to route the tra c to a proxy where the request stops and we can take a look
into it. Afterwards it needs to be rerouted to the original target. Sounds complicated?
We can achieve this with the BurpSuite and the following IPTABLE - rules:

# iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-


destination 10.42.0.1:8080
# iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to-
destination 10.42.0.1:8080

Roman Stuehler (Udemy) Page 71 / 104


fi
ffi
ffi
ffi
ffi
fi
fl
The commands above needs to be inserted in the terminal of your laptop and they require
„root“ privileges.

12.3. BurpSuite
BurpSuite is a proxy written in Java with a lot of capabilities. There are already trainings
out there, that only handle BurpSuite and they are about 2 days long. We will only focus
on the parts that are necessary for this course.
What have we achieved so far? Let’s take a look back on this picture.

10.42.0.1:8080

The smartphone is connected to the router via WiFi. The router is providing DHCP and
DNS which will be handled by our nm-connection editor.
The ip table rules do forward all the tra c on TCP port 80 (HTTP) and TCP port 443
(HTTPS) to our USB-To-Ethernet interface (10.42.0.1:8080). This is the blue line.
If we open now a website, we will not see anything because there is nothing listening on
10.42.0.1:8080. Now we need to start our proxy (burp) on this interface / port and forward
the tra c to the original address. This is the green line

12.3.1.Starting up BurpSuite
The Burp community edition is free to use. It does not contain features like a scanner but
we will not need this and it is incredible that an awesome product with all the necessary
features is available for free. You can download an installer or use the standalone jar le
here: https://portswigger.net/burp/communitydownload.
After downloading the installer you might get this warning here:

This is ne because it has the „.sh“ extension. Click keep but before you run it, take a
look with vim. Yes a lot of stu there but this recommendation has to be given here :)

Roman Stuehler (Udemy) Page 72 / 104


ffi
fi
ff
ffi
fi
Make it executable and run it as follow:

$ chmod +x burpsuite_community_linux_v2020_12_1.sh
$ ./burpsuite_community_linux_v2020_12_1.sh

The installation process is straight forward:


• Next
• Next (or change the directory where you want to have installed)
• Next
• Finish
To start the burpsuite just go into your home directly and type „./BurpSuiteCommunity/
BurpSuiteCommunity“ into the terminal.

$ cd (press enter)
$ ./BurpSuiteCommunity/BurpSuiteCommunity

Take a look at the Terms and Conditions and if you agree you can click „I Accept“. I
normally opt out of anonymous feedback but feel free if you want to support this to make
it a even better product :)

This is the only downside in the community edition, that our requests do not get
permanently stored in a project le but we can save them later into an extra le if we want
to keep them. So also no big deal.
Ok now we are in the main window of the BurpSuite. As already mentioned, we could talk
two days about all the features and possibilities in here but we will focus on the important
parts.

Roman Stuehler (Udemy) Page 73 / 104


fi
fi
12.3.2.Configuring the BurpSuite
We will start con guring the proxy rst. To do so, click on the „proxy“ tab and then on the
„Options“ tab to get the following menu.

The BurpSuite is running in default mode on „http://127.0.0.1:8080". We can open this


URL on the machine where we are running burp to verify that it is working:

We will use this pager later to fetch the certi cate but for now, we need to run this on the
„router“ interface 10.42.0.1. To do so go into the options menu from above and click edit.
Under binding we can set the
interface and port we want to
listen to. We can be lazy and
select „All interfaces“. This will
make the BurpSuite running on
all available interfaces.
We can also say „Speci c
address“ and select our interface
with the 10.42.0.1 ip address.
This is a better solution in my
opinion because this is the only
interface we want to run the
burp. But it does not make a
di erence.

Roman Stuehler (Udemy) Page 74 / 104


ff
fi
fi
fi
fi
12.3.2.1. Invisible Mode

If you click on the next tab, „Request handling“ we can activate the invisible mode.
This mode is important because it will let the BurpSuite act as a forward proxy, that is not
„seen“ by the device. Therefore „invisible“.

By activating it, the burp will automatically reroute the generated tra c to the original
destination. We can verify that the invisible mode is active, if we get the checkbox as
shown below.

We can open our browser in the smartphone and we will be able to see HTTP tra c in the
BurpSuite proxy.

Roman Stuehler (Udemy) Page 75 / 104


ffi
ffi
But if we try to open a site via HTTPS we will get the following error:

Why? Because the BurpSuite is providing a certi cate, that is not known to the
smartphone and this is also the case if people will try to man-in-the-middle you. As a
security feature, the browser is warning us! To avoid accepting every single request, we
can install the BurpSuite certi cate as a truster cert on the device.

Roman Stuehler (Udemy) Page 76 / 104


fi
fi
But be careful! You should not do this on a smartphone where you store
your sensitive stuff. Someone might be able to man-in-the-middle the
connections of your phone if you install custom certi cates. Please take
a test device for these kind of analysis or simply take the android VM.

12.3.3.Installing the certificate on the device


We could download the certi cate from the page „http://10.42.0.1:8080" or we can use
adb shell to place it onto the device. I will stick to the adb shell because we also have to
rename it and all of this is very easy on the command line. But rst we need to export it
from the burp.

The name of the le does not matter but the ending needs to be „.crt“. I save it as
„burp.crt“. Afterwards we upload this le via adb to the smartphone.

$ adb push burp.crt /sdcard/

On the smartphone we go into:


• Settings
• Security (advanced)
• Encryption & credentials
• Install a certi cate
• CA certi cate

Roman Stuehler (Udemy) Page 77 / 104


fi
fi
fi
fi
fi
fi
fi
Now we are able intercept the HTTPS tra c.

Roman Stuehler (Udemy) Page 78 / 104


ffi
We have the picture completed. If you want to know more about the HTTPS connection
setup just take a look at the video of this course.

Please install the burp certi cate into the user storage of the
smartphone. Sometimes people give advices to put it into the system
storage but this does not work on modern smartphones anymore.
! Recon guring this is a lot of pain and required root privileges. See here:
https://chromium.googlesource.com/chromium/src/+/master/net/
docs/certi cate-transparency.md

Roman Stuehler (Udemy) Page 79 / 104


fi
fi
fi
13. Man-in-the-Middle - Emulator
To establish a Man-in-the-Middle connection on the emulator, the easiest way is using the
network proxy of it. But please keep in mind, this might only a ect HTTP/HTTPS tra c
and does not include things like MQTT / SQL / UPNP or other protocols.

The best setup would be using a real smartphone with a real router. Then we do not have
to rely on certain emulation / software aspects.

13.1. Setup
Within the con guration menu on the left, please click on the three dots and switch to
Settings.

After hitting apply the smartphone is forwarding the communication to our proxy. The ip
address needs to be the interface of our virtual machine. In my case if I am using the NAT
adapter which means, the ip address 172.16.240.129 has been assigned to my Linux
system (VM).

Roman Stuehler (Udemy) Page 80 / 104


fi
ff
ffi
14. Certi cate Pinning
Certi cate pinning is one of the most basic security mechanism we need to circumvent if
we want to analyse the network tra c of a mobile app. But what it is a certi cate pinning?

We already talked about installing our burp certi cate onto the smartphone and select it
as trustworthy. Well, certi cate pinning is exactly the same but it only validates its own
certi cate against the corresponding endpoint. Therefore our global „burp.crt“ will not
work here.

Now we try to get into a man-in-the-middle position. Our certi cate has been successfully
installed on the smartphone. We run the app, but we get an error message. Why?

Because the application is only trusting the certi cate that has been hardcoded into ithe
app. To bypass it we need to patch the application and replace it with the values from our
burp certi cate.

We will focus on the two most common libraries „okhttp“ and „retro t“. But if you can
patch them, you will be also able to patch all the other existing libraries. The schema is
always the same.

14.1. Patching the OKHTTP Library

The easiest way to patch a library is to write the code by yourself. If you know how to
write a certi cate pinning app, you will also know where you need to patch it.

But let’s assume we are not familiar with writing our own app, we can still search for the
code part: https://square.github.io/okhttp/4.x/okhttp/okhttp3/-certi cate-pinner/.

This is awesome. We already got the code snippet that also other developers will use to
perform their certi cate pinning with the OKHTTP library.

Roman Stuehler (Udemy) Page 81 / 104


fi
fi
fi
fi
fi
fi
fi
ffi
fi
fi
fi
fi
fi
fi
String hostname = "publicobject.com";

Certi catePinner certi catePinner = new Certi catePinner.Builder()

.add(hostname, "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")

.build();

OkHttpClient client = OkHttpClient.Builder()

.certi catePinner(certi catePinner)

.build();

Request request = new Request.Builder()

.url("https://" + hostname)

.build();

client.newCall(request).execute();

We de ne a new hostname „publicobject.com". Then we create the Certi catePinner


object and we use „.add(hostname, „sha256/AAA“) to add the signature of the certi cate.

So all we have to do here, is replacing the signature of the correct certi cate with the one
of burp and we are done!? A few more steps are required but this is a good start.

14.1.1.Getting the SHA256 hash from the Burp cert


To get the necessary public key of the burp certi cate we can use this openssl magic :)

$ openssl x509 -inform der -in burp.der -pubkey -noout >


burp_pub_key.pem

$ cat burp_pub_key.pem | openssl rsa -pubin -outform der | openssl


dgst -sha256 -binary | openssl enc -base64

First we take our „.der“ or „.crt“ certi cate and transform it into the public key format.

Then we use this public key format to calculate the public key hash. The output is shown
below and this is the hash we need to replace in the application or/and in the
network_security_con g.xml.

writing RSA key


G5R02srVnsgqC01Rsd2QrpBEKLXvCcXB88T5jR2ll0A=

Roman Stuehler (Udemy) Page 82 / 104


fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
If you want to learn more about this, please have look at the video again. In case if the
network_security_con g.xml is not available, we have to create our own.

14.1.2.Replacing the PublicKey


The public key of the certi cate has to be de ned in the app. We search for the following
values to identify it:
• sha256/
• Certi catePinner

We can also use the openssl command from above to identify the sha256 value of the
original certi cate and search for this value. These steps are explained in detail in the
video of the Udemy course.

14.1.2.1. Approach

• Decompile the application


• Go into the SMALI le
• Replace the string with the sha256 hash of the Burp certi cate
• const-string v2, „sha256/mM294xslEgmvDADAxWWH2DeH4/bNgPBpgZvd7SfciuA="
• const-string v2, „sha256/G5R02srVnsgqC01Rsd2QrpBEKLXvCcXB88T5jR2ll0A="
• Move on with the Trust-Anchor section

Roman Stuehler (Udemy) Page 83 / 104


fi
fi
fi
fi
fi
fi
fi
14.1.3.Trust Anchor
After we have replaced the hash, we also need to overwrite the
network_security_con g.xml. This le de nes the network security features and has been
introduced in the „Nougat“ version of Android. We de ne to trust all system and user
certi cates.

<?xml version="1.0" encoding="utf-8"?>

<network-security-con g>

<domain-con g>

<domain includeSubdomains="true" >example.com</domain>

<trust-anchors>

<certi cates src="user" />

<certi cates src="system" />

</trust-anchors>

</domain-con g>

</network-security-con g>

After installing the burp certi cate and starting the app, we can inspect the tra c of the
mobile application.

14.2. Patching Certi cate File

Sometimes the app contains the whole certi cate in it. You may nd this in the assets
directory. Patching this is more easy.

14.2.1.Approach
• Decompile the application
• Check the type of certi cate „public key“ or „.der“ format
• Generate / Transform the burp certi cate into the right format
• Copy paste / replace the burp certi cate with the correct one
• Compile the application
• Sign the application
• Done :)

Roman Stuehler (Udemy) Page 84 / 104


fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
ffi
14.2.1.1.Replace

Simply decompile the APK, replace the „server.der“ with the exported certi cate of the
BurpSuite and recompile the app.

Also take a look a the network_security_con g. There might be additional


certi cate les which are de ned here. They also need to be replaced.

14.2.2. Commands

Extract certi cates - Public Key format

openssl s_client -showcerts -connect www.example.com:443 </dev/null

Extract certi cates - DER format

openssl s_client -showcerts -connect www.example.com:443 < /dev/null


| openssl x509 -outform DER > derp.der

14.3. Using Objection


Objection is a framework based on FRIDA and also has some really nice hooks for certain
tasks like bypassing certi cate pinning. Simply try it out if it works! :)

Roman Stuehler (Udemy) Page 85 / 104


fi
fi
fi
fi
fi
fi
fi
fi
15. Frida
Frida is the most amazing framework when it comes to runtime manipulation of mobile
applications. It consists of a server running on the smartphone and a client running on our
host system.

Among others can we perform the following tasks with FRIDA:

• Observing functions (parameters / return values)


• Creating new objects
• Calling arbitrary functions
• Manipulating libraries.

15.1. Installation
The installation process is simple but there are some pitfalls we need to be aware of.

15.1.1.FRIDA - ARM vs x86 vs x64


If we take a look at the available versions we will just be overwhelmed by all these
di erent platforms that FRIDA supports:
https://github.com/frida/frida/releases/tag/14.2.5.

Roman Stuehler (Udemy) Page 86 / 104


ff
Which one should we pick?

For the smartphone we need the „FRIDA-Server“. This binary is available for several
di erent platforms as shown below:
• frida-server-14.2.5-android-arm.xz
• frida-server-14.2.5-android-arm64.xz
• frida-server-14.2.5-android-x86.xz
• frida-server-14.2.5-android-x86_64.xz

So generally speaking, there are two major di erences.


• One version is for the ARM architecture, which is the build for your smartphone.
• The other one is x86 which can be used for the VirtualMachine (VM) / emulator.

ARM and x86 are processor architectures and they are very di erent. Please take a look
into the video if you are interested to hear more about this.

Modern smartphones are most likely using 64 bit but you can determine this by typing
„cat /proc/cpuinfo“ into an adb terminal.

walleye:/ $ cat /proc/cpuinfo


Processor : AArch64 Processor rev 4 (aarch64)

On my Nexus 5 - I use the „frida-server-14.2.5-android-arm.xz" version.


On my Google Pixel 2 - I use the „frida-server-14.2.5-android-arm64.xz" version.
On the VM - I use the "frida-server-14.2.5-android-x86.xz" version.

15.1.2.FRIDA - Version
FRIDA is still being heavily improved. After so many years, there are still weekly updates
with complete new version numbers. Newer versions might be sometimes a little bit
buggy regarding to certain architectures (x86).

Roman Stuehler (Udemy) Page 87 / 104


ff
ff
ff
15.1.2.1. Stay with a „newer“ version

So in case of any errors, they might have been xed in a newer version of FRIDA so it is
really a good advice to always keep it up to date.

15.1.2.2. Until you want to use the debug feature :)

FRIDA contains a live debugging feature, where you can use google chrome to debug
your JavaScript code. This is extremely helpful, if you write more complex scripts.
Unfortunately a lot of things has changed and for me, it did not work in newer versions.
So if we want to use this feature, we have to stick to an „older“ version, which does not
really a ect our testing. We will talk about this next.

15.1.3.FRIDA - Installation
If you want to install a certain version of FRIDA (https://github.com/frida/frida/releases/
tag/14.2.5) we can simply do it with the following command:

$ pip3 install frida==14.2.5

15.1.3.1. Setting up the server

- Download the correct version for your device here:


- https://github.com/frida/frida/releases/tag/14.2.5.
- Unzip the directory
- adb push frida-gadget-14.1.2-android-arm.so /data/local/tmp
- adb chmod +x /data/local/tmp/frida-gadget-14.1.2-android-arm.so

15.1.3.2. Setting up the client (Laptop)

Now we only need to install the frida-tools package and we are done :)

$ sudo apt-get install python3-pip


$ pip3 install frida-tools

Roman Stuehler (Udemy) Page 88 / 104


ff
fi
15.1.4.FRIDA - Installation debugging version
There is only one version, where the debugging feature of FRIDA worked for me on all
platforms (VM / Android 32 bit / Android 64 bit). This is version 12.11.18.
To uninstalling the current version and installing the 12.11.18 version can be done with
one command:

$ pip3 install frida==12.11.18

Verify if the version 12.11.18 is active with „frida —version“.

15.2. Starting FRIDA


After the installation process, we connect the device with our laptop / VM and simply start
the server.

$ adb shell
$ cd /data/local/tmp
$ chmod +x /data/local/tmp/frida-server
$ su
# ./frida-server

Please make sure, that the FRIDA CLI version on your laptop / VM is the
same as the FRIDA server that is running on the smartphone. You might
encounter very strange problems if this is not the case. You can verify
this with „frida —version“ on your Laptop and compare it with the
version of the frida-server on your smartphone (banner).

We can verify if the connection is working by listing the running processes of the
smartphone. Open up a new linux terminal and run:

$ frida-ps -U

This will run the frida-ps script via the USB (-U) connection. If the server is running and
the connection is working, we will get an output of the processes running at the moment.

Roman Stuehler (Udemy) Page 89 / 104


15.3. Interaction with FRIDA
To get started with FRIDA we can use the CLI or write a whole script which can be
launched via the „-l“ (lower L) parameter.

15.3.1.Using the CLI


The CLI is running in an iPython shell, which provides syntax support by pressing the
„tab“ bar. We can also change variables on the y or start executing functions. This all
can be done even after we did start our script.

15.3.2.Using a JavaScript file


If we are writing more complex scripts, you will de nitely want to use an external script
editor. In this course we are using Visual Studio Code, but you can also use any other
editor of your choice.

Roman Stuehler (Udemy) Page 90 / 104


fl
fi
There is a website that hosts useful FRIDA scripts. This site can be found here:
https://codeshare.frida.re/@pcipolloni/universal-android-ssl-pinning-bypass-with-frida/.

This website contains useful code snippets, that other FRIDA

! enthusiasts have created. But be careful when running scripts from


the internet. You should always take a look into the code. Those
scripts are not being reviewed.

15.4. Hooking Methods


FRIDA has the power, to overwrite existing methods. Let’s take a look at an example from
the following application:
https://f-droid.org/en/packages/org.secuso.privacyfriendlydicer/.

This application is just a simply „dicer“ app. You can shake your smartphone and receive
the result which is based on a SecureRandom functionality. The developer did make
absolutely no mistake because this class provides a cryptographically strong
pseudorandomd number generator (PRNG).
Source: https://developer.android.com/reference/java/security/SecureRandom.

15.4.1.Accessing Function Parameters


We have function „rollDice“ that takes two parameters: „int i“ and „int i2“. The return value
is an int array.
We can access, control and manipulate all of these values. Let’s say we want to print out
the parameters „i“ and „i2“:

Roman Stuehler (Udemy) Page 91 / 104


Java.perform(function() {
const Dicer = Java.use('org.secuso.privacyfriendlydicer.dicer.Dicer');
Dicer.rollDice.implementation = function (param1, param2) {

send("param1: " + param1);


send("param2: " + param2);

return this.rollDice(param1,param2);
};
});

JavaScript is very unsafe regarding to types. Strings and integers can be automatically
handled. Many other things have to be casted because JavaScript is not aware of certain
Android objects.

Modi cation

Beside accessing and prtinting them, we can of course also modify them. We can also
keep track of the original values. We can do all of this on the y by simply pasting this into
the FRIDA console or reloading the script.

Java.perform(function() {
const Dicer = Java.use('org.secuso.privacyfriendlydicer.dicer.Dicer');
Dicer.rollDice.implementation = function (param1, param2) {

send("param1: " + param1);


send("param2: " + param2);

param1 = 2;
param2 = 4;

return this.rollDice(param1,param2);
};
});

15.4.2.Overloading Functions
The same function can be de ned multiple times with di erent parameters. This behavior
is called, overloading.
If we have a di erent amount of parameters, this should be not a big deal.

Roman Stuehler (Udemy) Page 92 / 104


fi
ff
fi
ff
fl
It becomes a bit harder, if there is the same amount of parameters but di erent types.
JavaScript is not aware of di erent types. But don’t worry, we will handle this.

So here we have the „removeComponent“ function twice. If we want to overwrite this


function, we have to add the „.overload“ attribute and also have to de ne the type that
FRIDA knows which one to overwrite.

Java.perform(function => {
const Entity = Java.use('com.element.Entity');
Entity.removeComponent.overload('[Lcom.example.Component').implementation =
function (param1) {

send("Overwriting removeComponent with Componnent Object: " + param1);

return this.removeComponent(param1);
};
});

If we want to provide a String, we have to use


• .overload(‚Ljava/lang/String’)

If we are dealing with Integer values it will be:


• .overload('int','int')

Roman Stuehler (Udemy) Page 93 / 104


ff
fi
ff
15.4.3.Modifying Return value
This is normally pretty straight forward. We can simply modify the return value in the same
way that we assign new values to the parameters.

But sometimes it can be a little bit tricky. Example given. The function above is returning
back a byte array. Therefore we need to declare a byte array rst, ll it with values and
then can return it back.
The JavaScript code for declaring the byte array looks as follow. I do not want to provide
a full FRIDA script here because this is part of a challenge :)

Example 1 - Dirty Solution:

var dirtySolution = [1, 2, 3, 4, 5, 6]


return dirtySolution;

Example 2 - Better Solution:


The solution above works but it would be more clear for FRIDA by using the internal
functions of the framework to create a new integer array. This can be done as follow:

// This one here is more precisive


var intArray = Java.array('int', [1, 2, 3, 4, 5, 6]);
return intArray;

Here we de ne exactly, that it is an Array from the type „[I“ (SMALI). If we want to have an
byte array („[B“) we can write: var intArray = Java.array('byte', [1, 2, 3, 4, 5, 6]);

Roman Stuehler (Udemy) Page 94 / 104


fi
fi
fi
15.5. Calling a Methods
In FRIDA we have the ability to actively call a method. here we want to call the “nextInt”
function, without triggering the button in the application all the time.

If we want to run the random function we do have to create an instance rst.

Java.perform(function() {
const secuRandom = Java.use('java.security.SecureRandom');
secuRandomInstance = secuRandom.$new();
var buffer = secuRandomInstance.nextInt(5);
send(„Random.nextInt " + buffer);
});

We get a reference to the SecureRandom class and create a new instance with $new().
Afterwards we can call the „nextInt“ function via this instance.

15.6. Scanning for Objects


We are able to call methods but it does not a ect the game? This is because the „Object“
has been already created and the attributes are bound to this object.
If there are any questions on this, please take a look at the video because I will explain
this in detail there. Let’s take a look at the following code:

Roman Stuehler (Udemy) Page 95 / 104


ff
fi
If we want to increase the highScore of the game, we need to fetch the existing
„Pro le“ instance rst. Otherwise we will create a second highScore and increase this
one, but this does not a ect our game we are playing at the moment :)

Java.perform(function () {
Java.choose("de.fgerbig.spacepeng.services.Profile", {
onMatch: function(instance) {
send('Found:'+instance)
instance.highScore.value = 1000000
},
onComplete: function() { }
});
});

We have to use „Java.choose“ to fetch all instances. In the onMatch callback, we will get
all references to all found objects. Then we get the instance variable „highScore“ via the
„.value“ param and increase it.

15.6.1.Creating new Objects


To create a new object, we simply fetch a reference of the class with „Java.use“. Then we
use the „$new()“ function to create a new instance. We also have to provide the
parameter for the constructor.

Java.perform(function () {
var getStringClass = Java.use("java.lang.String");
var stringInstance = getStringClass.$new("We have a new String Object!");
send("We can provide this Object as parameter: " + stringInstance.toString());
});

15.6.2.Providing existing Instances as parameter


The last part we have to handle for now is the problem when we have to provide an
object as parameter. Let’s create a new player —> CreatePlayer.

Roman Stuehler (Udemy) Page 96 / 104


fi
fi
ff
The world object (parameter) should only exist ones for our player / level. If we create a
new world object, the player will be generated on a „not visible“ world.
To create a new player onto our existing world, we have to scan the memory for the world
instance rst. Afterwards we can call the function “createPlayer” and provide the instance
of the existing world.

Java.perform(function () {
Java.choose("com.artemis.World", {
onMatch: function(instance) {
send('Found:'+instance);

instance.x = 120;
instance.y = 100;

var entityFactory =
Java.use("de.fgerbig.spacepeng.services.EntityFactory")

entityFactory.createPlayer(instance);

},
onComplete: function() {
send("Done!");
}
});
});

We are having a static function which means, we do not have to create an


„entityFactory“ instance rst.

15.7. Timing
Timing can be very Important in FRIDA. Generally speaking, there are two possibilities.
• We can hook into the JVM and start the application
• We can hook into an application, that is already running.

Why is it important to know, when to hook? It can happen that certain methods are not
available at the beginning. They are being loaded later on. If we try to hook these
methods before they have been loaded, our script will be useless.
If we hook into an application that is already running, we might have missed certain
checks like „Rooting Detections“ which makes our script also useless.

Roman Stuehler (Udemy) Page 97 / 104


fi
fi
15.7.1.Providing existing Instances as parameter
This depends on the code we want to hook. We need to check the source code and
libraries and trying to gure out, when it gets loaded. If you are too lazy for this, you can
simply experiment with both approaches and see how it goes. But you do not have this
advice from me ok? ;)
You can also set a breakpoint with the debugger, load your FRIDA script and resume the
program. This approach is way better :)

15.7.2.Hooking into a running app


We need to start the application and after it runs we can hook into the process as follow:

$ frida -U com.apphacking.exampleOne -l <script>

15.7.3.Hooking before the app starts


If we want to hook the application before it has been started, we have to use “-f”. This will
tell FRIDA to launch the process.

$ frida -U -f com.apphacking.exampleOne —-no-pause

I have encountered that hooking into a running process sometimes


claims “process not found”. Seems to be a FRIDA issue and might be
solved in newer versions. For now we can simply start this application
with “-f” which did work all the time for me.

Roman Stuehler (Udemy) Page 98 / 104


fi
15.8. NDK
Hooking into Native Development Kit (NDK) functions is a little bit more complex. Let’s
have a look at the following code. In line 25 we are de ning a function which will be
stored in a shared object (library) le - and not in the JavaCode. The library is named
“native-lib” which can be found in line 8.

15.8.1.Observing native methods in FRIDA


A really amazing FRIDA extension is „jnitrace“. Even the developer of FRIDA itself „Ole
André Vadla Ravnås" is contributing to this project :)
Source: https://github.com/chame1eon/jnitrace.

Installation

The installation is straight forward. Simply run this on your Linux system.

$ pip3 install jnitrace

Roman Stuehler (Udemy) Page 99 / 104


fi
fi
Some nice options of this tool:

-i INCLUDE, --include INCLUDE


A regex filter to include a JNIEnv or JavaVM method name.
-m {spawn,attach}, --inject-method {spawn,attach}
Specify how frida should inject into the process.
-p PREPEND, --prepend PREPEND
Prepend a Frida script to run before jnitrace does.
-a APPEND, --append APPEND
Append a Frida script to run after jnitrace has started.

Running jnitrace

Simply provide the library-name we want to hook with the „-l“ parameter. If you want to
hook before the apps start, then we need to add the „-m“ parameter.
Also take a look at the „Timing“ chapter if you want to know the di erence :)

$ jnitrace -l libnative-lib.so com.apphacking.ndkfrida

The output of this tool for the function above is shown below:

We get an amazing trace view about the single JNI functions in this library and we can
also see that „decryptString“ is being called.
The return value of our encrypted string will be printed below. But take a close look, it is
the value „0x69“ which seems to be a reference to the original „Yhiq…“ string. We see it
here :)

Roman Stuehler (Udemy) Page 100 / 104


ff
Why is this Useful?
Imagine you are having an application that is decrypting a static password, based on a
complex routine. We just want to know, which string will be returned from this function
and doing this with „jnitrace“ just takes a few seconds :).

You can use FRIDA CLI and jnitrace at the same time. However if you
want to combine this amazing tool with your own scripts, take a look at
the „-p“ and „-a“ parameter.

15.8.2.Interacting with native Methods (manually)


Interacting with the JAVA NDK is often not as easy as it seems. I have attached the
source code of the „decryptString“ function, that you get a better understanding on what
is happening.

So even if the calling of the „decryptString“ function only seems to require two
parameters, we need to consider two more. Please have a look at the video for a detailed
explanation.

If we want to print out the „String pw“ and the „int round“ paramter, we can do it with the
following script.

Roman Stuehler (Udemy) Page 101 / 104


If we want to print out the rst and second argument, we need to reference them with
„arg[2]“ and „arg[3]“ which is 3 and 4 (remember we count from 0-..).

Interceptor.attach(Module.findExportByName("libnative-lib.so",
"Java_com_apphacking_ndkfrida_MainActivity_decryptString"), {
onEnter: function (args) {

var password = args[2];

Java.perform( function () {
var String = Java.use("java.lang.String");
// The data type of the password is a "jstring"
// Therefore we need to cast it to a "Java String"
var javaStringArg = Java.cast(ptr(password), String)
send("Argument1: " + javaStringArg.toString());

});
// We can simply print out the integer but JSON.stringify comes handy in
the future
send("Argument2: " + JSON.stringify(args[3]));
},

onLeave: function (retval) {


send("Return Value: " + retval);
// Overwrite the return value with "My turn"
const dstAddr = Java.vm.getEnv().newStringUtf("My turn");
retval.replace(dstAddr);
}
});

The function that calls the „decryptString“ method in the app, can be triggered with a
button. We therefore don’t need to inject the script before the app starts.
We can simply inject into the already running application.

$ frida -U com.apphacking.ndkfrida -l hookDecryptString.js

The result is shown below:

We can now see the parameter „Udemy App Hacking“ and the integer value „0x4“ (4). To
get a detailed explanation of this example, please take a look into the video. We will only
discuss the most important parts here.

Roman Stuehler (Udemy) Page 102 / 104


fi
Interceptor attach:

The interceptor, intercepts function calls to the target address. We can retrieve the
address address with the „Module. ndExportByName“ function.
After getting the address, we can de ne two callbacks to interact with this function.

OnEnter - Callback:

We are entering the function and we are able to interact with the parameters. We can print
them out or modify them. But we do not have an impact on the return value.
If we want to overwrite the „pw“ (string) and the „round“ (int) parameter, we have to do it
this way:

Interceptor.attach(Module.findExportByName("libnative-lib.so",
"Java_com_apphacking_ndkfrida_MainActivity_decryptString"), {
onEnter: function (args) {
var password = args[2];
Java.perform( function () {
var String = Java.use("java.lang.String");
// The data type of the password is a "jstring"
// Therefore we need to cast it to a "Java String"
var javaStringArg = Java.cast(ptr(password), String)
send("Argument1: " + javaStringArg.toString());
});
// We can simply print out the integer but JSON.stringify comes handy in
the future
send("Argument2: " + JSON.stringify(args[3]));
// Create a new String
const myArgument = Java.vm.getEnv().newStringUtf("My Argument");
// Overwrite the password argument with "My Argument"
args[2] = myArgument
// Overwritng the round parameter with "1" (ptr stands for pointer)
args[3] = ptr("1");
},
// Return Value
onLeave: function (retval) {
send("retval: " + retval);
}
});

OnLeave:
In this part of our function, we are able to play around with the return value. We can print
it out or simply modify it as shown above:

Roman Stuehler (Udemy) Page 103 / 104


fi
fi
For more information, please have a look at: https://frida.re/docs/javascript-api/
#nativefunction.

A nal consideration. Interacting with C functions is very different from


what we have seen regarding to Java. Unfortunately we cannot simply
create new objects and overwrite existing methods in C. We can only
„touch“, „tamper“ or „modify“ them as shown in the examples above.

15.8.3.Solving CrackMe - Example


For this course, I have prepared a lot of crack me examples that gets solved with several
di erent type of techniques. Please have a look at the video at the end of the FRIDA
section, if you are interested in :).

This part is only included in the videos. It contains ton of useful FRIDA
commands and shows you how to deal with the UI Thread in FRIDA.

- END -
Roman Stuehler (Udemy) Page 104 / 104
ff
fi

You might also like