📔
HackTricks - Boitatech
  • HackTricks
  • About the author
  • Getting Started in Hacking
  • Pentesting Methodology
  • External Recon Methodology
    • Github Leaked Secrets
  • Phishing Methodology
    • Clone a Website
    • Detecting Phising
    • Phishing Documents
  • Exfiltration
  • Tunneling and Port Forwarding
  • Brute Force - CheatSheet
  • Search Exploits
  • Shells
    • Shells (Linux, Windows, MSFVenom)
      • MSFVenom - CheatSheet
      • Shells - Windows
      • Shells - Linux
      • Full TTYs
  • Linux/Unix
    • Checklist - Linux Privilege Escalation
    • Linux Privilege Escalation
      • PAM - Pluggable Authentication Modules
      • SELinux
      • Logstash
      • AppArmor
      • Containerd (ctr) Privilege Escalation
      • Docker Breakout
      • electron/CEF/chromium debugger abuse
      • Escaping from Jails
      • Cisco - vmanage
      • D-Bus Enumeration & Command Injection Privilege Escalation
      • Interesting Groups - Linux PE
        • lxd/lxc Group - Privilege escalation
      • ld.so exploit example
      • Linux Capabilities
      • NFS no_root_squash/no_all_squash misconfiguration PE
      • Payloads to execute
      • RunC Privilege Escalation
      • Seccomp
      • Splunk LPE and Persistence
      • SSH Forward Agent exploitation
      • Socket Command Injection
      • Wildcards Spare tricks
    • Useful Linux Commands
      • Bypass Bash Restrictions
    • Linux Environment Variables
  • MacOS
    • MacOS Security & Privilege Escalation
      • Mac OS Architecture
      • MacOS MDM
        • Enrolling Devices in Other Organisations
      • MacOS Protocols
      • MacOS Red Teaming
      • MacOS Serial Number
      • MacOS Apps - Inspecting, debugging and Fuzzing
  • Windows
    • Checklist - Local Windows Privilege Escalation
    • Windows Local Privilege Escalation
      • AppendData/AddSubdirectory permission over service registry
      • Create MSI with WIX
      • DPAPI - Extracting Passwords
      • SeImpersonate from High To System
      • Access Tokens
      • ACLs - DACLs/SACLs/ACEs
      • Dll Hijacking
      • From High Integrity to SYSTEM with Name Pipes
      • Integrity Levels
      • JAWS
      • JuicyPotato
      • Leaked Handle Exploitation
      • MSI Wrapper
      • Named Pipe Client Impersonation
      • PowerUp
      • Privilege Escalation Abusing Tokens
      • Privilege Escalation with Autoruns
      • RottenPotato
      • Seatbelt
      • SeDebug + SeImpersonate copy token
      • Windows C Payloads
    • Active Directory Methodology
      • Abusing Active Directory ACLs/ACEs
      • AD information in printers
      • ASREPRoast
      • BloodHound
      • Constrained Delegation
      • Custom SSP
      • DCShadow
      • DCSync
      • DSRM Credentials
      • Golden Ticket
      • Kerberos Authentication
      • Kerberoast
      • MSSQL Trusted Links
      • Over Pass the Hash/Pass the Key
      • Pass the Ticket
      • Password Spraying
      • Force NTLM Privileged Authentication
      • Privileged Accounts and Token Privileges
      • Resource-based Constrained Delegation
      • Security Descriptors
      • Silver Ticket
      • Skeleton Key
      • Unconstrained Delegation
    • NTLM
      • Places to steal NTLM creds
      • PsExec/Winexec/ScExec
      • SmbExec/ScExec
      • WmicExec
      • AtExec / SchtasksExec
      • WinRM
    • Stealing Credentials
      • Credentials Protections
      • Mimikatz
    • Authentication, Credentials, UAC and EFS
    • Basic CMD for Pentesters
    • Basic PowerShell for Pentesters
      • PowerView
    • AV Bypass
  • Mobile Apps Pentesting
    • Android APK Checklist
    • Android Applications Pentesting
      • Android Applications Basics
      • Android Task Hijacking
      • ADB Commands
      • APK decompilers
      • AVD - Android Virtual Device
      • Burp Suite Configuration for Android
      • content:// protocol
      • Drozer Tutorial
        • Exploiting Content Providers
      • Exploiting a debuggeable applciation
      • Frida Tutorial
        • Frida Tutorial 1
        • Frida Tutorial 2
        • Frida Tutorial 3
        • Objection Tutorial
      • Google CTF 2018 - Shall We Play a Game?
      • Inspeckage Tutorial
      • Intent Injection
      • Make APK Accept CA Certificate
      • Manual DeObfuscation
      • React Native Application
      • Reversing Native Libraries
      • Smali - Decompiling/[Modifying]/Compiling
      • Spoofing your location in Play Store
      • Webview Attacks
    • iOS Pentesting Checklist
    • iOS Pentesting
      • Basic iOS Testing Operations
      • Burp Suite Configuration for iOS
      • Extracting Entitlements From Compiled Application
      • Frida Configuration in iOS
      • iOS App Extensions
      • iOS Basics
      • iOS Custom URI Handlers / Deeplinks / Custom Schemes
      • iOS Hooking With Objection
      • iOS Protocol Handlers
      • iOS Serialisation and Encoding
      • iOS Testing Environment
      • iOS UIActivity Sharing
      • iOS Universal Links
      • iOS UIPasteboard
      • iOS WebViews
  • Pentesting
    • Pentesting Network
      • Spoofing LLMNR, NBT-NS, mDNS/DNS and WPAD and Relay Attacks
      • Spoofing SSDP and UPnP Devices with EvilSSDP
      • Wifi Attacks
        • Evil Twin EAP-TLS
      • Pentesting IPv6
      • Nmap Summary (ESP)
      • Network Protocols Explained (ESP)
      • IDS and IPS Evasion
      • DHCPv6
    • Pentesting JDWP - Java Debug Wire Protocol
    • Pentesting Printers
      • Accounting bypass
      • Buffer Overflows
      • Credentials Disclosure / Brute-Force
      • Cross-Site Printing
      • Document Processing
      • Factory Defaults
      • File system access
      • Firmware updates
      • Memory Access
      • Physical Damage
      • Software packages
      • Transmission channel
      • Print job manipulation
      • Print Job Retention
      • Scanner and Fax
    • Pentesting SAP
    • Pentesting Kubernetes
      • Enumeration from a Pod
      • Hardening Roles/ClusterRoles
      • Pentesting Kubernetes from the outside
    • 7/tcp/udp - Pentesting Echo
    • 21 - Pentesting FTP
      • FTP Bounce attack - Scan
      • FTP Bounce - Download 2ºFTP file
    • 22 - Pentesting SSH/SFTP
    • 23 - Pentesting Telnet
    • 25,465,587 - Pentesting SMTP/s
      • SMTP - Commands
    • 43 - Pentesting WHOIS
    • 53 - Pentesting DNS
    • 69/UDP TFTP/Bittorrent-tracker
    • 79 - Pentesting Finger
    • 80,443 - Pentesting Web Methodology
      • 403 & 401 Bypasses
      • AEM - Adobe Experience Cloud
      • Apache
      • Artifactory Hacking guide
      • Buckets
        • Firebase Database
        • AWS-S3
      • CGI
      • Code Review Tools
      • Drupal
      • Flask
      • Git
      • Golang
      • GraphQL
      • H2 - Java SQL database
      • IIS - Internet Information Services
      • JBOSS
      • Jenkins
      • JIRA
      • Joomla
      • JSP
      • Laravel
      • Moodle
      • Nginx
      • PHP Tricks (SPA)
        • PHP - Useful Functions & disable_functions/open_basedir bypass
          • disable_functions bypass - php-fpm/FastCGI
          • disable_functions bypass - dl function
          • disable_functions bypass - PHP 7.0-7.4 (*nix only)
          • disable_functions bypass - Imagick <= 3.3.0 PHP >= 5.4 Exploit
          • disable_functions - PHP 5.x Shellshock Exploit
          • disable_functions - PHP 5.2.4 ionCube extension Exploit
          • disable_functions bypass - PHP <= 5.2.9 on windows
          • disable_functions bypass - PHP 5.2.4 and 5.2.5 PHP cURL
          • disable_functions bypass - PHP safe_mode bypass via proc_open() and custom environment Exploit
          • disable_functions bypass - PHP Perl Extension Safe_mode Bypass Exploit
          • disable_functions bypass - PHP 5.2.3 - Win32std ext Protections Bypass
          • disable_functions bypass - PHP 5.2 - FOpen Exploit
          • disable_functions bypass - via mem
          • disable_functions bypass - mod_cgi
          • disable_functions bypass - PHP 4 >= 4.2.0, PHP 5 pcntl_exec
      • Python
      • Special HTTP headers
      • Spring Actuators
      • Symphony
      • Tomcat
      • Uncovering CloudFlare
      • VMWare (ESX, VCenter...)
      • Web API Pentesting
      • WebDav
      • werkzeug
      • Wordpress
      • XSS to RCE Electron Desktop Apps
    • 88tcp/udp - Pentesting Kerberos
      • Harvesting tickets from Windows
      • Harvesting tickets from Linux
    • 110,995 - Pentesting POP
    • 111/TCP/UDP - Pentesting Portmapper
    • 113 - Pentesting Ident
    • 123/udp - Pentesting NTP
    • 135, 593 - Pentesting MSRPC
    • 137,138,139 - Pentesting NetBios
    • 139,445 - Pentesting SMB
    • 143,993 - Pentesting IMAP
    • 161,162,10161,10162/udp - Pentesting SNMP
      • SNMP RCE
    • 194,6667,6660-7000 - Pentesting IRC
    • 264 - Pentesting Check Point FireWall-1
    • 389, 636, 3268, 3269 - Pentesting LDAP
    • 500/udp - Pentesting IPsec/IKE VPN
    • 502 - Pentesting Modbus
    • 512 - Pentesting Rexec
    • 513 - Pentesting Rlogin
    • 514 - Pentesting Rsh
    • 515 - Pentesting Line Printer Daemon (LPD)
    • 548 - Pentesting Apple Filing Protocol (AFP)
    • 554,8554 - Pentesting RTSP
    • 623/UDP/TCP - IPMI
    • 631 - Internet Printing Protocol(IPP)
    • 873 - Pentesting Rsync
    • 1026 - Pentesting Rusersd
    • 1080 - Pentesting Socks
    • 1098/1099/1050 - Pentesting Java RMI - RMI-IIOP
    • 1433 - Pentesting MSSQL - Microsoft SQL Server
    • 1521,1522-1529 - Pentesting Oracle TNS Listener
      • Oracle Pentesting requirements installation
      • TNS Poison
      • Remote stealth pass brute force
      • Oracle RCE & more
    • 1723 - Pentesting PPTP
    • 1883 - Pentesting MQTT (Mosquitto)
    • 2049 - Pentesting NFS Service
    • 2301,2381 - Pentesting Compaq/HP Insight Manager
    • 2375, 2376 Pentesting Docker
    • 3128 - Pentesting Squid
    • 3260 - Pentesting ISCSI
    • 3299 - Pentesting SAPRouter
    • 3306 - Pentesting Mysql
    • 3389 - Pentesting RDP
    • 3632 - Pentesting distcc
    • 3690 - Pentesting Subversion (svn server)
    • 4369 - Pentesting Erlang Port Mapper Daemon (epmd)
    • 5000 - Pentesting Docker Registry
    • 5353/UDP Multicast DNS (mDNS)
    • 5432,5433 - Pentesting Postgresql
    • 5601 - Pentesting Kibana
    • 5671,5672 - Pentesting AMQP
    • 5800,5801,5900,5901 - Pentesting VNC
    • 5984,6984 - Pentesting CouchDB
    • 5985,5986 - Pentesting WinRM
    • 6000 - Pentesting X11
    • 6379 - Pentesting Redis
    • 8009 - Pentesting Apache JServ Protocol (AJP)
    • 8089 - Splunkd
    • 9000 - Pentesting FastCGI
    • 9001 - Pentesting HSQLDB
    • 9042/9160 - Pentesting Cassandra
    • 9100 - Pentesting Raw Printing (JetDirect, AppSocket, PDL-datastream)
    • 9200 - Pentesting Elasticsearch
    • 10000 - Pentesting Network Data Management Protocol (ndmp)
    • 11211 - Pentesting Memcache
    • 15672 - Pentesting RabbitMQ Management
    • 27017,27018 - Pentesting MongoDB
    • 44818/UDP/TCP - Pentesting EthernetIP
    • 47808/udp - Pentesting BACNet
    • 50030,50060,50070,50075,50090 - Pentesting Hadoop
  • Pentesting Web
    • Web Vulnerabilities Methodology
    • Reflecting Techniques - PoCs and Polygloths CheatSheet
      • Web Vulns List
    • 2FA/OTP Bypass
    • Abusing hop-by-hop headers
    • Bypass Payment Process
    • Captcha Bypass
    • Cache Poisoning and Cache Deception
    • Clickjacking
    • Client Side Template Injection (CSTI)
    • Command Injection
    • Content Security Policy (CSP) Bypass
    • Cookies Hacking
    • CORS - Misconfigurations & Bypass
    • CRLF (%0D%0A) Injection
    • Cross-site WebSocket hijacking (CSWSH)
    • CSRF (Cross Site Request Forgery)
    • Dangling Markup - HTML scriptless injection
    • Deserialization
      • NodeJS - __proto__ & prototype Pollution
      • Java JSF ViewState (.faces) Deserialization
      • Java DNS Deserialization, GadgetProbe and Java Deserialization Scanner
      • Basic Java Deserialization (ObjectInputStream, readObject)
      • CommonsCollection1 Payload - Java Transformers to Rutime exec() and Thread Sleep
      • Basic .Net deserialization (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)
      • Exploiting __VIEWSTATE knowing the secrets
      • Exploiting __VIEWSTATE without knowing the secrets
    • Domain/Subdomain takeover
    • Email Header Injection
    • File Inclusion/Path traversal
      • phar:// deserialization
    • File Upload
      • PDF Upload - XXE and CORS bypass
    • Formula Injection
    • HTTP Request Smuggling / HTTP Desync Attack
    • H2C Smuggling
    • IDOR
    • JWT Vulnerabilities (Json Web Tokens)
    • NoSQL injection
    • LDAP Injection
    • Login Bypass
      • Login bypass List
    • OAuth to Account takeover
    • Open Redirect
    • Parameter Pollution
    • PostMessage Vulnerabilities
    • Race Condition
    • Rate Limit Bypass
    • Registration Vulnerabilities
    • Regular expression Denial of Service - ReDoS
    • Reset/Forgotten Password Bypass
    • SAML Attacks
      • SAML Basics
    • Server Side Inclusion/Edge Side Inclusion Injection
    • SQL Injection
      • MSSQL Injection
      • Oracle injection
      • PostgreSQL injection
        • dblink/lo_import data exfiltration
        • PL/pgSQL Password Bruteforce
        • Network - Privesc, Port Scanner and NTLM chanllenge response disclosure
        • Big Binary Files Upload (PostgreSQL)
        • RCE with PostgreSQL Extensions
      • MySQL injection
        • Mysql SSRF
      • SQLMap - Cheetsheat
        • Second Order Injection - SQLMap
    • SSRF (Server Side Request Forgery)
    • SSTI (Server Side Template Injection)
      • EL - Expression Language
    • Reverse Tab Nabbing
    • Unicode Normalization vulnerability
    • Web Tool - WFuzz
    • XPATH injection
    • XSLT Server Side Injection (Extensible Stylesheet Languaje Transformations)
    • XXE - XEE - XML External Entity
    • XSS (Cross Site Scripting)
      • PDF Injection
      • DOM XSS
      • Server Side XSS (Dynamic PDF)
      • XSS Tools
    • XSSI (Cross-Site Script Inclusion)
    • XS-Search
  • Forensics
    • Basic Forensic Methodology
      • Baseline Monitoring
      • Anti-Forensic Techniques
      • Docker Forensics
      • Image Adquisition & Mount
      • Linux Forensics
      • Malware Analysis
      • Memory dump analysis
        • Volatility - CheatSheet
      • Partitions/File Systems/Carving
        • EXT
        • File/Data Carving & Recovery Tools
        • NTFS
      • Pcap Inspection
        • DNSCat pcap analysis
        • USB Keystrokes
        • Wifi Pcap Analysis
        • Wireshark tricks
      • Specific Software/File-Type Tricks
        • .pyc
        • Browser Artifacts
        • Desofuscation vbs (cscript.exe)
        • Local Cloud Storage
        • Office file analysis
        • PDF File analysis
        • PNG tricks
        • Video and Audio file analysis
        • ZIPs tricks
      • Windows Artifacts
        • Windows Processes
        • Interesting Windows Registry Keys
  • A.I. Exploiting
    • BRA.I.NSMASHER Presentation
      • Basic Bruteforcer
      • Basic Captcha Breaker
      • BIM Bruteforcer
      • Hybrid Malware Classifier Part 1
  • Blockchain
    • Blockchain & Crypto Currencies
  • Courses and Certifications Reviews
    • INE Courses and eLearnSecurity Certifications Reviews
  • Cloud Security
    • Cloud security review
    • AWS Security
  • Physical attacks
    • Physical Attacks
    • Escaping from KIOSKs
      • Show file extensions
  • Reversing
    • Reversing Tools & Basic Methods
      • Angr
        • Angr - Examples
      • Z3 - Satisfiability Modulo Theories (SMT)
      • Cheat Engine
      • Blobrunner
    • Common API used in Malware
    • Cryptographic/Compression Algorithms
      • Unpacking binaries
    • Word Macros
  • Exploiting
    • Linux Exploiting (Basic) (SPA)
      • Format Strings Template
      • ROP - call sys_execve
      • ROP - Leaking LIBC address
        • ROP - Leaking LIBC template
      • Bypassing Canary & PIE
      • Ret2Lib
      • Fusion
    • Exploiting Tools
      • PwnTools
    • Windows Exploiting (Basic Guide - OSCP lvl)
  • Cryptography
    • Certificates
    • Cipher Block Chaining CBC-MAC
    • Crypto CTFs Tricks
    • Electronic Code Book (ECB)
    • Hash Length Extension Attack
    • Padding Oracle
    • RC4 - Encrypt&Decrypt
  • BACKDOORS
    • Merlin
    • Empire
    • Salseo
    • ICMPsh
  • Stego
    • Stego Tricks
    • Esoteric languages
  • MISC
    • Basic Python
      • venv
      • Bypass Python sandboxes
      • Magic Methods
      • Web Requests
      • Bruteforce hash (few chars)
    • Other Big References
  • TODO
    • More Tools
    • MISC
    • Pentesting DNS
  • Burp Suite
  • Other Web Tricks
  • Interesting HTTP
  • Emails Vulnerabilities
  • Android Forensics
  • TR-069
  • 6881/udp - Pentesting BitTorrent
  • CTF Write-ups
    • challenge-0521.intigriti.io
    • Try Hack Me
      • hc0n Christmas CTF - 2019
      • Pickle Rick
  • 1911 - Pentesting fox
  • Online Platforms with API
  • Stealing Sensitive Information Disclosure from a Web
  • Post Exploitation
Powered by GitBook
On this page
  • Goal
  • Learning ARM Assembly
  • Introduction to the Java Native Interface (JNI)
  • References
  • Target of Analysis - Android Native Libraries
  • Loading the Library
  • The Java to Native Code Connection
  • Dynamic Linking
  • Static Linking
  • Exercise #5 - Find the Address of the Native Function
  • Reversing Android Native Libraries Code - JNIEnv
  • Exercise #6 - Find and Reverse the Native Function

Was this helpful?

  1. Mobile Apps Pentesting
  2. Android Applications Pentesting

Reversing Native Libraries

PreviousReact Native ApplicationNextSmali - Decompiling/[Modifying]/Compiling

Last updated 3 years ago

Was this helpful?

Information copied from (you can find solutions there)

Android applications can contain compiled, native libraries. Native libraries are code that the developer wrote and then compiled for a specific computer architecture. Most often, this means code that is written in C or C++. The benign, or legitimate, reasons a developer may do this is for mathematically intensive or time sensitive operations, such as graphics libraries. Malware developers have begun moving to native code because reverse engineering compiled binaries tends to be a less common skillset than analyzing DEX bytecode. This is largely due to DEX bytecode can be decompiled to Java whereas native, compiled code, often must be analyzed as assembly.

Goal

The goal of this section is not to teach you assembly (ASM) or how to reverse engineer compiled code more generally, but instead how to apply the more general binary reverse engineering skills, specifically to Android. Because the goal of this workshop is not to teach you the ASM architectures, all exercises will include an ARM and an x86 version of the library to be analyzed so that each person can choose the architecture that they are more comfortable with.

Learning ARM Assembly

If you don’t have previous binary reverse engineering/ assembly experience, here are some suggested resources. Most Android devices run on ARM, but all exercises in this workshop also include an x86 version of the library.

To learn and/or review ARM assembly, I highly suggest the from .

Introduction to the Java Native Interface (JNI)

The Java Native Interface (JNI) allows developers to declare Java methods that are implemented in native code (usually compiled C/C++). JNI interface is not Android-specific, but is available more generally to Java applications that run on different platforms.

The Android Native Development Kit (NDK) is the Android-specific toolset on top of JNI. According to the :

In Android, the Native Development Kit (NDK) is a toolset that permits developers to write C and C++ code for their Android apps.

Together, JNI and NDK allow Android developers to implement some of their app’s functionality in native code. The Java (or Kotlin) code will call a Java-declared native method which is implemented in the compiled, native library.

References

Oracle JNI Docs

Android JNI & NDK References

Target of Analysis - Android Native Libraries

For this section, we are focusing on how to reverse engineer app functionality that has been implemented in Android native libraries. When we say Android native libraries, what do we mean?

Android native libraries are included in APKs as .so, shared object libraries, in the ELF file format. If you have analyzed Linux binaries previously, it’s the same format.

These libraries by default are included in the APK at the file path /lib/<cpu>/lib<name>.so. This is the default path, but developers could also choose to include the native library in /assets/<custom_name> if they so choose. More often, we are seeing malware developers choose to include native libraries in paths other than /lib and using different file extensions to attempt to “hide” the presence of the native library.

Because native code is compiled for specific CPUs, if a developer wants their app to run on more than 1 type of hardware, they have to include each of those versions of the compiled, native library in the application. The default path mentioned above, includes a directory for each cpu type officially supported by Android.

CPU

Native Library Path

“generic” 32-bit ARM

lib/armeabi/libcalc.so

x86

lib/x86/libcalc.so

x64

lib/x86_64/libcalc.so

ARMv7

lib/armeabi-v7a/libcalc.so

ARM64

lib/arm64-v8a/libcalc.so

Loading the Library

Before an Android app can call and execute any code that is implemented in a native library, the application (Java code) must load the library into memory. There are two different API calls that will do this:

System.loadLibrary("calc")

or

System.load("lib/armeabi/libcalc.so")

The difference between the two api calls is that loadLibrary only take takes the library short name as an argument (ie. libcalc.so = “calc” & libinit.so = “init”) and the system will correctly determine the architecture it’s currently running on and thus the correct file to use. On the other hand, load requires the full path to the library. This means that the app developer has to determine the architecture and thus the correct library file to load themselves.

When either of these two (loadLibrary or load) APIs are called by the Java code, the native library that is passed as an argument executes its JNI_OnLoad if it was implemented in the native library.

To reiterate, before executing any native methods, the native library has to be loaded by calling System.loadLibrary or System.load in the Java code. When either of these 2 APIs is executed, the JNI_OnLoad function in the native library is also executed.

The Java to Native Code Connection

In order to execute a function from the native library, there must be a Java-declared native method that the Java code can call. When this Java-declared native method is called, the “paired” native function from the native library (ELF/.so) is executed.

A Java-declared native method appears in the Java code as below. It appears like any other Java method, except it includes the native keyword and has no code in its implementation, because its code is actually in the compiled, native library.

public native String doThingsInNativeLibrary(int var0);

To call this native method, the Java code would call it like any other Java method. However, in the backend, the JNI and NDK would instead execute the corresponding function in the native library. To do this, it must know the pairing between a Java-declared native method with a function in the native library.

There are 2 different ways to do this pairing, or linking:

  1. Dynamic Linking using JNI Native Method Name Resolving, or

  2. Static Linking using the RegisterNatives API call

Dynamic Linking

In order to link, or pair, the Java declared native method and the function in the native library dynamically, the developer names the method and the function according to the specs such that the JNI system can dynamically do the linking.

According to the spec, the developer would name the function as follow for the system to be able to dynamically link the native method and function. A native method name is concatenated from the following components:

  1. the prefix Java_

  2. a mangled fully-qualified class name

  3. an underscore (“_”) separator

  4. a mangled method name

  5. for overloaded native methods, two underscores (“__”) followed by the mangled argument signature

In order to do dynamic linking for the Java-declared native method below and let’s say it’s in the class com.android.interesting.Stuff

public native String doThingsInNativeLibrary(int var0);

The function in the native library would need to be named:

Java_com_android_interesting_Stuff_doThingsInNativeLibrary

If there is not a function in the native library with that name, that means that the application must be doing static linking.

Static Linking

jint RegisterNatives(JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint nMethods);

typedef struct { 
    char *name; 
    char *signature; 
    void *fnPtr; 
} JNINativeMethod;

When reverse engineering, if the application is using the static linking method, we as analysts can find the JNINativeMethod struct that is being passed to RegisterNatives in order to determine which subroutine in the native library is executed when the Java-declared native method is called.

The JNINativeMethod struct requires a string of the Java-declared native method name and a string of the method’s signature, so we should be able to find these in our native library.

Method Signature

  • Z: boolean

  • B: byte

  • C: char

  • S: short

  • I: int

  • J: long

  • F: float

  • D: double

  • L fully-qualified-class ; :fully-qualified-class

  • [ type: type[]

  • ( arg-types ) ret-type: method type

  • V: void

For the native method

public native String doThingsInNativeLibrary(int var0);

The type signature is

(I)Ljava/lang/String;

Here’s another example of a native method and its signature. For the following is the method declaration

public native long f (int n, String s, int[] arr);

It has the type signature:

(ILjava/lang/String;[I)J

Exercise #5 - Find the Address of the Native Function

In Exercise #5 we’re going to learn to load native libraries in a disassembler and identify the native function that is executed when a native method is called. For this particular exercise, the goal is not to reverse engineer the native method, just to find the link between the call to the native method in Java and the function that is executed in the native library. For this exercise, we will be using the sample Mediacode.apk. This sample is available at ~/samples/Mediacode.apk in the VM. Its SHA256 hash is a496b36cda66aaf24340941da8034bd53940d1b08d83a97f17a65ae144ebf91a.

Goal

The goal of this exercise is to:

  1. Identify declared native methods in the DEX bytecode

  2. Determine what native libraries are loaded (and thus where the native methods may be implemented)

  3. Extract the native library from the APK

  4. Load the native library into a disassembler

  5. Identify the address (or name) of the function in the native library that is executed when the native method is called

Instructions

  1. This time, if you expand the Resources tab, you will see that this APK has a lib/ directory. The native libraries for this APK are in the default CPU paths.

  2. Now we need to identify any declared native methods. In jadx, search and list all declared native methods. There should be two.

  3. Around the declared native method, see if there is anywhere that a native library is loaded. This will provide guidance of what native library to look in for the function to be implemented.

  4. Extract the native library from the APK by creating a new dir and copying the APK into that folder. Then run the command unzip Mediacode.APK. You will see all of the files extracted from APK, which includes the lib/ directory.

  5. Select the architecture of the native library you’d like to analyze.

  6. Start ghidra by running ghidraRun. This will open Ghidra.

  7. To open the native library for analysis, select “New Project”, “Non-Shared Project”, select a path to save the project to and give it a name. This creates a project that you can then load binary files into.

  8. Once you’ve created your project, select the dragon icon to open the Code Browser. The go to “File” > “Import File” to load the native library into the tool. You can leave all defaults.

  9. You will see the following screen. Select “Analyze”.

  10. Using the linking information above, identify the function in the native library that is executed when the Java-declared native method is called.

Solution

Reversing Android Native Libraries Code - JNIEnv

The C declarations of JNIEnv and JavaVM are different from the C++ declarations. The “jni.h” include file provides different typedefs depending on whether it’s included into C or C++. For this reason it’s a bad idea to include JNIEnv arguments in header files included by both languages. (Put another way: if your header file requires #ifdef __cplusplus, you may have to do some extra work if anything in that header refers to JNIEnv.)

Here are some commonly used functions (and their offsets in JNIEnv):

  • JNIEnv + 0x18: jclass (*FindClass)(JNIEnv, const char);

  • JNIEnv + 0x34: jint (*Throw)(JNIEnv*, jthrowable);

  • JNIEnv + 0x70: jobject (*NewObject)(JNIEnv*, jclass, jmethodID, …);

  • JNIEnv + 0x84: jobject (*NewObject)(JNIEnv*, jclass, jmethodID, …);

  • JNIEnv + 0x28C: jstring (*NewString)(JNIEnv, const jchar, jsize);

  • JNIEnv + 0x35C: jint (*RegisterNatives)(JNIEnv, jclass, const JNINativeMethod, jint);

When analyzing Android native libraries, the presence of JNIEnv means that:

  1. For JNI native functions, the arguments will be shifted by 2. The first argument is always JNIEnv*. The second argument will be the object that the function should be run on. For static native methods (they have the static keyword in the Java declaration) this will be NULL.

  2. You will often see indirect branches in the disassembly because the code is adding the offset to the JNIEnv* pointer, dereferencing to get the function pointer at that location, then branching to the function.

In practice, in the disassembly this shows as many different branches to indirect addresses rather than the direct function call. The image below shows one of these indirect function calls. The highlighted line in the disassembly shows a blx r3. As reversers, we need to figure out what r3 is. It’s not shown in the screenshot, but at the beginning of this function, r0 was moved into r5. Therefore, r5 is JNIEnv*. On line 0x12498 we see r3 = [r5]. Now r3 is JNIEnv (no *).

On line 0x1249e, we add 0x18 to r3 and dereference it. This means that r3 now equals whatever function pointer is at offset 0x18 in JNIEnv. We can find out by looking at the spreadsheet. [JNIEnv + 0x18] = Pointer to the FindClass method

To load it for use in Ghidra, in the Data Type Manager Window, click on the down arrow in the right-hand corner and select “Open File Archive”.

Then select jni_all.gdt file to load. Once it’s loaded, you should see jni_all in the Data Type Manager List as shown below.

Once this is loaded in Ghidra, you can then select any argument types in the decompiler and select “Retype Variable”. Set the new type to JNIEnv *. This will cause the decompiler to now show the names of the JNIFunctions called rather than the offsets from the pointer.

Exercise #6 - Find and Reverse the Native Function

We are going to point all of our previous skills together: identifying starting points for RE, reversing DEX, and reversing native code to analyze an application that may have moved its harmful behaviors in native code. The sample is ~/samples/HDWallpaper.apk.

Goal

The goal of this exercise is to put all of our Android reversing skills together to analyze an app as a whole: its DEX and native code.

Exercise Context

You are a malware analyst for Android applications. You are concerned that this sample maybe doing premium SMS fraud, meaning that it sends an SMS to a premium phone number without disclosure & user consent. In order to flag as malware, you need to determine if the Android application is:

  1. Sending an SMS message, and

  2. That SMS message is going to a premium number, and

  3. If there is an obvious disclosure, and

  4. If the SMS message is only sent to the premium number after user consent.

Instructions

Go on and reverse!

Solution

<– I always have this one open and refer to it while reversing Android native libraries

<– Highly suggest reading the “Native Libraries” section to start

<– This is guidance for how developers develop native libraries and understanding how things are built, makes it easier to reverse.

If the developer doesn’t want to or can not name the native functions according to the spec (Ex. wants to strip debug symbols), then they must use static linking with the RegisterNatives () API in order to do the pairing between the Java-declared native method and the function in the native library. The RegisterNatives function is called from the native code, not the Java code and is most often called in the JNI_OnLoad function since RegisterNatives must be executed prior to calling the Java-declared native method.

The JNINativeMethod struct requires the method signature. A method signature states the types of the arguments that the method takes and the type of what it returns. This link documents in the “Type Signatures” section.

Open Mediacode.apk in jadx. Refer back to

Loading file into Ghidra Code Browser
Screenshot of Mediacode open in jadx

When beginning to reverse engineer Android native libraries, one of the things I didn’t know I needed to know, was about JNIEnv. JNIEnv is a struct of function pointers to . Every JNI function in Android native libraries, takes JNIEnv* as the first argument.

From the Android documentation:

Here is a of the C-implementation of the JNIEnv struct to know what function pointers are at the different offsets.

Therefore blx r3 on line 0x124a4 is calling FindClass. We can look up information about FindClass (and all the other functions in JNIEnv) in the JNIFunctions documentation .

Screenshot of Disassembly Calling a function from JNIEnv

Thankfully, there’s a way to get the JNI function without doing all of this manually! In both the Ghidra and IDA Pro decompilers you can re-type the first argument in JNI functions to JNIEnv * type and it will automatically identify the JNI Functions being called. In IDA Pro, this work out of the box. In Ghidra, you have to load the JNI types (either the jni.h file or a Ghidra Data Types archive of the jni.h file) first. For ease, we will load the JNI types from the Ghidra Data Types archive (gdt) produced by Ayrx and available . For ease, this file is available in the VM at ~/jni_all.gdt.

Screenshot of Open File Archive Menu
Screenshot of jni_all Loaded in Data Type Manager
Screenshot of JNI Function names after the argument was Re-Typed to JNIEnv*
https://maddiestone.github.io/AndroidAppRE/reversing_native_libs.html
ARM Assembly Basics
Azeria Labs
docs
JNI Specification
JNI Functions
Android JNI Tips
Getting Started with the NDK
doc
JNI Type Signatures
Exercise #1
JNI Functions
JNI Tips
spreadsheet
here
here