Prerequisite
Apkpatcher need Java JDK installed on your machine and setup your JAVA_HOME. The following example is for a debian installation
apt install -y default-jre
If you don’t want to set your JAVA_HOME it would be guess but you can specify it manually.
Then you need to set your java home to find where is you java home you could use these commands: For Linux and macOS, we’ll use grep:
java -XshowSettings:properties -version 2>&1 > /dev/null | grep 'java.home'
For Windows, we’ll use findstr:
java -XshowSettings:properties -version 2>&1 | findstr "java.home"
Then you could set your JAVA_HOME as follow:
JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64/ apkpatcher
If you want to not set JAVA_HOME at each command you can set up directly on your bashrc file
Quickstart
In its minimal form, APK Patcher can be used to extract and repackage an application with your own signature, without making any modifications. To do this, use the following command:
apkpatcher -a <apk> -s <sdktools> -b <version>
Where:
<apk> refers to the APK file of the application you want to patch.
<sdktools> is the directory containing the Android SDK tools. For detailed instructions on how to install the SDK tools, refer to this step-by-step tutorial (https://madsquirrels.gitlab.io/mobile/asthook/how.install.html#setup-sdktools).
<version> is the version of the Build Tools that was installed along with the Android SDK tools.
With this minimal version, you can patch an application without altering its behavior. If you’re interested in making further modifications, such as changing the app’s functionality, continue following the next steps in the tutorial.
Handle splits applications
Some applications are provisioned in multiple parts, known as splits. Each split is an APK file that is individually signed. These splits must be signed with the same key as the main application. To handle this, APK Patcher supports the -m parameter, allowing you to include one or more split APKs that will be signed simultaneously with the patched base application.
Here’s an example of how to use this feature:
apkpatcher -a base.apk -m split_config.arm64_v8a.apk split_config.en.apk split_config.xxhdpi.apk -b 30.0.3 -s /opt/android-sdk/ -o output.apk
In this example:
The base application (base.apk) will be patched and signed.
The splits (split_config.arm64_v8a.apk, split_config.en.apk, split_config.xxhdpi.apk) will also be signed with the same key.
The patched base APK will be saved as output.apk, while the split APKs will retain their original names but will have a postfix: _new_signed.apk.
To install the newly patched application and its corresponding splits, use the following adb command:
adb install-multiple base_patched.apk split_config.arm64_v8a_new_signed.apk split_config.en_new_signed.apk split_config.xxhdpi_new_signed.apk
This ensures that both the base APK and its associated splits are properly installed on the device.
Inject a library ie: frida-gadget
The -g option allows you to inject a library at the launch of an application. One of the most well-known examples of library injection is Frida, which enables powerful debugging and analysis without requiring privileged access (root) to the device. By simply injecting Frida into the application, it will run within the app’s context.
Frida is a dynamic instrumentation toolkit that is widely used to analyze Android applications for several reasons:
Frida allows you to hook into an application at runtime, which means you can inspect or modify the app’s behavior as it is running. This is extremely useful when you want to:
Bypass security mechanisms (e.g., root detection, SSL pinning).
Inspect function calls, methods, and parameters in real-time.
Modify the app’s internal logic dynamically without modifying its source code or binary.
To inject a library, you need to download the appropriate Frida Gadget file, which follows the naming convention:
frida-gadget-<version>-android-<arch>.so
You can then pass it as an argument to APK Patcher using the -g option. If the -a option for specifying architecture is not provided, the base name of the library must be common across all architectures and end with _<arch>.so, where <arch> denotes the architecture. For example, if you use -g gadget.so, the library paths must be:
gadget_x86_64.so
gadget_arm.so
gadget_arm64.so
gadget_x86.so
If you need to inject Frida or another gadget, it’s recommended to specify the architecture directly using -a <arch>, along with -g <gadget.so>, where gadget.so is the exact path to the library for the selected architecture.
Inject a Proxy certificate
Certificate injection simplifies the setup of a proxy for monitoring network connections between an application and its server, especially when the connections are encrypted. There are two methods to achieve this:
- Allow User Certificates:
You can configure the application to accept user-installed certificates. Once this is done, simply install the proxy certificate on the device as a user certificate. To use this method, apply the -e option alone. This method does not modify the APK’s internal certificate handling but allows for easier monitoring.
- Embed Certificate in the Application:
Alternatively, you can directly inject the certificate into the application itself. For this, use the -c option, specifying the certificate file in PEM or DER format. This method embeds the certificate within the APK, enabling network monitoring without the need to manually install certificates on the device.
Put a pause before continue the rebuid
Sometimes, manual actions may be required before repackaging the application. In such cases, you can use the -p option. This option pauses the process just before repackaging, allowing the user to perform any necessary manual operations.
Once the modifications are done, you can simply press Enter to continue with the packaging process.
This feature is particularly useful if you need to manually edit resources, Smali code, or any other files within the APK before completing the patching.
Enabling Debuggable Mode
APKPatcher includes a feature to inject the android:debuggable
option into an applications AndroidManifest.xml
, allowing users to debug applications even when they are in release mode.
Enabling the Debuggable Option
To enable the debuggable
mode, use the following flag during the patching process:
--enable-debug
This modifies the AndroidManifest.xml
to include the android:debuggable="true"
attribute, making the application debuggable.
Debugging an Application
Once the application has been patched and installed, follow these steps to debug it:
Set the application to be the debug target:
adb shell am set-debug-app --persistent <package>
Replace
<package>
with the package name of the application you want to debug.Start the applicationu2019s activity in debug mode:
adb shell am start -D -n <package>/<Activity>
Replace
<package>
with the applications package name and<Activity>
with the name of the activity you want to debug.
Using a Specific Certificate for Signing
APKPatcher allows you to specify a custom certificate for signing the APK during the patching process. To do this, the following three options must be used together:
--keycertificate
: Specifies the path to the certificate file to be used.--keyalias
: Specifies the alias name of the key within the certificate.--keypass
: Specifies the password for the key.
Generating a Certificate
If you do not already have a certificate, you can generate one using the keytool utility. Below is an example command in bash:
keytool -genkey -keyalg RSA -keysize 2048 -validity 700 -noprompt
-alias myalias -dname "CN=apk.patcher.com, OU=ID, O=APK, L=Patcher, S=Patch, C=BR"
-keystore /path/to/certificate.keystore -storepass mypassword -keypass mypassword
Replace /path/to/certificate.keystore with the desired file path for your keystore, myalias with your chosen alias, and mypassword with your chosen password.
Keeping the Certificate
The –keep-keycertificate option ensures that the automatically generated certificate is retained for future use. This can be useful for maintaining consistent signatures across multiple APKs.
Using –keep-keycertificate
When this option is specified, APKPatcher generates a certificate during the patching process and saves it for reuse.
Using V4 Signature
The –v4 option enables the use of a V4 signature file for signing APKs. If this option is not specified, only V1, V2, and V3 signatures are used by default.
Use an external script before repackaging
- In a similar way, you can automate manual tasks by using a script with the –plugin option.
This allows you to execute predefined tasks automatically, such as modifying Smali code or editing AXML files.
For example, you can use a plugin to modify the AndroidManifest.xml file before repackaging. Here’s an example of how to modify the manifest using a plugin: Example of Command to Run the Plugin:
apkpatcher -a <base.apk> -s <sdktools> -b <android_version> --plugin pyaxml_script.py
Plugin Code Example:
#!/usr/bin/env python
import pyaxml
import click
@click.command()
@click.argument('input_dir')
def exploit_axmlfile(input_dir):
path_manifest = input_dir + "/AndroidManifest.xml"
axml_object, _ = pyaxml.axml.AXML.from_axml(open(path_manifest, "rb").read())
# Convert the AXML to regular XML
xml = axml_object.to_xml()
# Define the Android namespace for the "name" attribute
android_name = "{http://schemas.android.com/apk/res/android}name"
# Find the activity with name 'activity_name' and modify it
for activity in xml.findall(f"./application/activity/[@{android_name}='activity_name']"):
activity.attrib[android_name] = "new_activity_name"
# Re-encode the XML back to AXML
axml_object = pyaxml.axml.AXML()
axml_object.from_xml(xml)
# Write the modified AXML back to the manifest file
open(path_manifest, "wb").write(axml_object.pack())
Explanation:
The input_dir is the directory where the application is unpacked.
The script opens the AndroidManifest.xml file, reads it using pyaxml, and converts it into a standard XML format.
It then searches for an activity named “activity_name” and replaces it with “new_activity_name”.
Finally, the modified XML is re-encoded back into AXML format and written back to the manifest file.
By automating tasks like these with the –plugin option, you can streamline repetitive actions such as modifying Smali code or AXML files without the need for manual intervention.
Special case when apkpatcher don’t find ENTRYPOINT
In rare cases, APK Patcher may not be able to automatically identify the desired entry point for injecting a library. If you need to specify a different entry point for library injection, you can use the –entrypoint option to indicate the exact Smali function where you want the library to be injected.
Usage Example:
apkpatcher -a <base.apk> -g <gadget.so> --entrypoint <smali_function> -b <android_version> -s <sdktools> -o <output.apk>
Explanation:
<base.apk> is the APK file you want to patch.
<gadget.so> is the path to the library you want to inject.
<smali_function> is the name of the Smali function where you want the library to be injected.
<android_version> is the version of the Android Build Tools.
<sdktools> is the path to the Android SDK tools.
<output.apk> is the name of the resulting patched APK.
By specifying the –entrypoint option, you can precisely control where the library injection occurs, ensuring that it integrates seamlessly with your application’s execution flow.
Apkpatcher as library
All of the previously mentioned options can also be utilized programmatically by integrating APK Patcher as a Python library. You need to import apkpatcher and instantiate the Patcher object with the required parameters: the APK file, the path to SDK tools, and the version of the Android Build Tools. Each of the previously discussed options is available through corresponding API functions.
Once you’ve set up the required parameters, you can invoke the patching function to apply the modifications. Below is a minimalist example:
import apkpatcher
# Instantiate the Patcher object with the necessary parameters
patcher = apkpatcher.Patcher(apk, sdktools, version_android)
# Perform the patching process, specifying the output file
patcher.patching(None, output_file=output_file)
In this example:
apk is the APK file you wish to patch.
sdktools is the directory containing Android SDK tools.
version_android is the version of the Build Tools used during patching.
output_file is the name of the resulting patched APK.
Smali Code Patching
A new feature has been added to apkpatcher that allows users to modify Smali code by replacing specific methods within an APK. This can be particularly useful for scenarios such as bypassing SSL pinning or application signature verification during security audits. Instead of using tools like Frida scripts, you can directly patch the application’s behavior by modifying the Smali code.
Example: Replacing a Method
The following example shows how to replace a method in the Smali code of an APK: Define the method prototype and the new code to replace the original method:
from apkpatcher.smalipatching import Method, get_smali_file_from_class, replace_methods
prototype = ".method public setEndColor(I)V"
patch = "return-void"
m = Method(prototype, patch)
directory = "/tmp/app/apktools/"
classname = "com.github.mikephil.charting.model.GradientColor"
fname = get_smali_file_from_class(directory, classname)
with open(f"{directory}{fname}", "r") as f:
content = f.read()
with open(f"{directory}{fname}", "w") as f:
text = apkpatcher.smalipatching.replace_methods([m], content)
content = f.write(text)
In this example:
prototype specifies the method you want to replace.
The method signature includes its visibility (public), name (setEndColor), and its argument types ((I) for an integer argument), and return type (V for void).
patch contains the Smali code that will replace the method’s original implementation. In this case, the method will be replaced with a simple return-void, which effectively removes its functionality.
If you know the class but not the exact location of the Smali file, you can use the following helper function (get_smali_file_from_class) to find the file. - directory is the folder where the APK files were extracted using apktools. - classname is the full name of the class, for example: com.github.mikephil.charting.model.GradientColor.
Once you have the Smali file, read its contents.
Replace the method in the Smali file with the patch.
In this step, replace_methods will take a list of method replacements (in this case, just m) and apply them to the file content. The modified Smali code will be stored in the text variable, ready to be written back to the APK.
Use Cases
Bypassing SSL Pinning: Modify methods responsible for SSL verification and replace them with return-void to bypass SSL pinning mechanisms.
Disabling Signature Verification: Replace methods that enforce signature checks to disable signature verification during security audits.
Custom Behavioral Modifications: Adjust the behavior of an app by altering specific methods, enabling more flexibility in testing and debugging.
This functionality is designed to streamline the process of Smali code manipulation, providing an efficient alternative to runtime instrumentation techniques like Frida.