Skip to content

Commit

Permalink
add child gating (#12)
Browse files Browse the repository at this point in the history
* add child gating

* adjust quick start

* adjust docs

* improve readability of docs

* improve readability of docs

* improve readability of docs

* more doc corrections

* more doc corrections
  • Loading branch information
lico-n authored Aug 17, 2023
1 parent 42135f9 commit c8888a0
Show file tree
Hide file tree
Showing 48 changed files with 15,706 additions and 101 deletions.
66 changes: 14 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,67 +20,29 @@ using riru with an older magisk version rather than zygisk.

## How to use the module

### General Usage
### Quick start
- Download the latest release from the [Release Page](https://github.com/lico-n/ZygiskFrida/releases)\
If you are using riru instead of zygisk choose the riru-release. Otherwise choose the normal version.
- Transfer the ZygiskFrida zip file to your device and install it via Magisk.
- Reboot after install
- Update `/data/local/tmp/re.zyg.fri/target_packages` on your device with the target package names.\
Apps with matching package names will be injected with the gadget. One package name per line.\
f.e. `adb shell 'su -c "echo com.example.package > /data/local/tmp/re.zyg.fri/target_packages"'`
- Launch your app. It will pause at startup allowing you to attach
f.e. `frida -U -N com.example.package` or `frida -U -n Gadget`

### Further configuration

**Start up delay**

There are times that you might want to delay the injection of the gadget. Some applications
might run checks at start up and delaying the injection can help avoid these.

`/data/local/tmp/re.zyg.fri/target_packages` accepts a start up delay in milliseconds.
You can provide it separated by a comma from the package_name.

f.e.
- Create the config file and adjust the package name to your target app (replace `your.target.application` in the commands)
```shell
adb shell 'su -c cp /data/local/tmp/re.zyg.fri/config.json.example /data/local/tmp/re.zyg.fri/config.json'
adb shell 'su -c sed -i s/com.example.package/your.target.application/ /data/local/tmp/re.zyg.fri/config.json'
```
adb shell 'su -c "echo com.example.package,20000 > /data/local/tmp/re.zyg.fri/target_packages"'
```
would inject the gadget after a delay of 20 seconds.

You get a 10 seconds countdown to injection in the ZygiskFrida logs `adb logcat -S ZygiskFrida`.
This can help if you want to time the injection with app interactions.

**Gadget version and config**

The bundled gadget is located at `/data/local/tmp/re.zyg.fri/libgadget.so`.\
You can follow the [Gadget Docs](https://frida.re/docs/gadget/) and add additional
gadget config and scripts in that location.

In case you want to use a different gadget version than the one bundled, you can simply
replace the `libgadget.so` with your own frida gadget.

**Loading arbitrary libraries**

This module also allows you to load arbitrary .so libraries into the process.\
This can allow you to load additional helper libraries for the gadget or
enable any other use case that might need libraries loaded into the app process.
- Launch your app. It will pause at startup allowing you to attach
f.e. `frida -U -N your.target.application` or `frida -U -n Gadget`

For this you can add the file `/data/local/tmp/re.zyg.fri/injected_libraries`.\
The file should consist of file paths to libraries.
The libraries are loaded in the order they are specified in the file.
This assumes that you don't have any other frida server running (f.e. by using MagiskFrida).
You can still run it together with frida-server but you would have to configure the gadget
to use a different port.

Example file content that would first load libhelperexample.so and then the bundled frida-gadget:
```
/data/local/tmp/re.zyg.fri/libhelperexample.so
/data/local/tmp/re.zyg.fri/libgadget.so
```
### Configuration

Make sure the libraries are located somewhere accessible by the app and that
file permissions are properly set.
This module also supports adding a start up delay that can delay injection of the gadget to
avoid checks run at startup time, loading arbitrary libraries and child gating.

If you want the frida gadget to start, you need to explicitly specify the bundled frida-gadget at
`/data/local/tmp/re.zyg.fri/libgadget.so`.\
You can also choose to specify your own gadget this way or omit the gadget altogether.
Please take a look at the [configuration guide](docs/advanced_config.md) for this.

## How to build

Expand Down
23 changes: 23 additions & 0 deletions config.json.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"targets": [
{
"app_name" : "com.example.package",
"enabled": true,
"start_up_delay_ms": 0,
"injected_libraries": [
{
"path": "/data/local/tmp/re.zyg.fri/libgadget.so"
}
],
"child_gating": {
"enabled": false,
"mode": "freeze",
"injected_libraries" : [
{
"path": "/data/local/tmp/re.zyg.fri/libgadget-child.so"
}
]
}
}
]
}
155 changes: 155 additions & 0 deletions docs/advanced_config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# Advanced Config

For the previous configuration method with various files, see [simple config](simple_config.md).
It remains a valid method of configuration but the structured configuration method specified here is the preferred
method in the future and also supports more features.

Both configuration are supported with the advanced config taking precedence in case an app appears in both.

## Config File

This module is configured via a json config located at `/data/local/tmp/re.zyg.fri/config.json`.
To start off, you can copy the example config
```shell
adb shell 'su -c cp /data/local/tmp/re.zyg.fri/config.json.example /data/local/tmp/re.zyg.fri/config.json'
```

Example config
```json
{
"targets": [
{
"app_name" : "com.example.package",
"enabled": true,
"start_up_delay_ms": 0,
"injected_libraries": [
{
"path": "/data/local/tmp/re.zyg.fri/libgadget.so"
}
],
"child_gating": {
"enabled": false,
"mode": "freeze",
"injected_libraries" : [
{
"path": "/data/local/tmp/re.zyg.fri/libgadget-child.so"
}
]
}
}
]
}
```

The config contains an array of targets. A target contains the configuration for one application
you want to inject with frida.

In case things are not working as expected, check `adb logcat -s ZygiskFrida` to see if an error is logged.

## Target configuration.

### app_name
The bundle id of the application you want to inject frida into.

### enabled
If set to false, then this module will ignore this configuration.
This is useful if you want to temporarily disable a target while maintaining the config.


### start_up_delay_ms
Injection of libraries is delayed by this amount in milliseconds.

There are times that you might want to delay the injection of the gadget. Some applications
might run checks at start up and delaying the injection can help avoid these.

### injected_libraries
These are the libraries that will be injected into the process. The libraries
specified here will be loaded in the order of the array.

The module includes a bundled frida gadget at `/data/local/tmp/re.zyg.fri/libgadget.so`.
You can adjust the gadget config according to the official [Gadget Doc](https://frida.re/docs/gadget/)

If you want to use a different frida version or an alternative version you can replace this
with the path to your own gadget.

Using this you can also inject arbitrary libraries alongside the gadget or without the gadget if
you remove it.
Make sure that the libraries you provide here have the correct file permissions set and are accessible
by the app itself.

The module will setup file permissions in the complete `re.zyg.fri` directory on install. If you suspect
a file permission issue, an easy way to check is to place your libraies within the `re.zyg.fri` directory
and install the module again (without uninstalling).


## Child gating configuration (experimental)
This is an experimental feature and has a lot of caveats! Please read carefully.

This module is able to intercept fork/vfork within the process to instrument child processes.
An application might fork a child process to run checks from there that you can't intercept
without child gating.

By enabling this feature by setting `enabled` to true, you can configure how to deal
with these child processes.

There are currently 3 modes in how child gating operates. You can determine by
setting the mode to either `freeze`, `kill` or `inject`.

Using any of the child gating mode can cause issues properly shutting down the application even with a force close.
This can cause issues restarting the app. Manually killing the app can resolve this.
```
adb shell 'su -c kill -9 $(pidof com.example.package)'
```

### freeze
The child process will not return from the fork. This means that no code will
run within the child process but the process itself stays alive.

### kill
The child process will be killed as soon as it is forked. No code will
run within the child process.

### inject
This mode will inject the `injected_libraries` into the child process similiar to the target configuration.
After injection the child process will resume its normal code flow. You may fail to connect to the gadget
interactively if the child is only doing a quick check and exits.

Please be aware as the child is forked, it already contains all libraries loaded that the parent processs had.
But as only a single thread returns from the fork the loaded frida gadget thread is not present in the child process.

Reloading the same bundled gadget will fail to start. For this to work you have to load a copy of the gadget.
You can't load the same file into the process again, a symbolic link won't work either it must be a copy.
F.e.

```shell
adb shell 'su -c cp /data/local/tmp/re.zyg.fri/libgadget.so /data/local/tmp/re.zyg.fri/libgadget-child.so'
```

The default configuration of a gadget will fail to start due to port conflict with the gadget in the parent process.
So for the child process you would have to configure the gadget to use a different port.

Create a gadget configuration like this at `/data/local/tmp/re.zyg.fri/libgadget-child.config.so`.
See [Gadget Doc](https://frida.re/docs/gadget/) for reference.
```
{
"interaction": {
"type": "listen",
"address": "127.0.0.1",
"port": 27043,
"on_port_conflict": "pick-next",
"on_load": "wait"
}
}
```

Please take note of the `on_port_conflict: pick-next` which is important in case the parent process forks
multiple children.

As this is a non-default port gadget you can take a look at `adb logcat -s Frida` to see which ports the
child gadget started on.

Then you can connect it for example via
```shell
adb forward tcp:27043 tcp:27043
frida -H 127.0.0.1:27043 -n Gadget
```
64 changes: 64 additions & 0 deletions docs/simple_config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Simple Config

Please consider using the [structured config](advanced_config.md) instead.

This file is about the previous configuration method via different files
using `target_packages` and `injected_libraries` and doesn't support all the
features.

`/data/local/tmp/re.zyg.fri/target_packages` is a simple text file
containing all the package names you want to inject frida into.

It accepts one package name per line f.e.
```
adb shell 'su -c "echo com.example.package > /data/local/tmp/re.zyg.fri/target_packages"'
```

**Start up delay**

There are times that you might want to delay the injection of the gadget. Some applications
might run checks at start up and delaying the injection can help avoid these.

`/data/local/tmp/re.zyg.fri/target_packages` accepts a start up delay in milliseconds.
You can provide it separated by a comma from the package_name.

f.e.
```
adb shell 'su -c "echo com.example.package,20000 > /data/local/tmp/re.zyg.fri/target_packages"'
```
would inject the gadget after a delay of 20 seconds.

You get a 10 seconds countdown to injection in the ZygiskFrida logs `adb logcat -S ZygiskFrida`.
This can help if you want to time the injection with app interactions.

**Gadget version and config**

The bundled gadget is located at `/data/local/tmp/re.zyg.fri/libgadget.so`.\
You can follow the [Gadget Docs](https://frida.re/docs/gadget/) and add additional
gadget config and scripts in that location.

In case you want to use a different gadget version than the one bundled, you can simply
replace the `libgadget.so` with your own frida gadget.

**Loading arbitrary libraries**

This module also allows you to load arbitrary .so libraries into the process.\
This can allow you to load additional helper libraries for the gadget or
enable any other use case that might need libraries loaded into the app process.

For this you can add the file `/data/local/tmp/re.zyg.fri/injected_libraries`.\
The file should consist of file paths to libraries.
The libraries are loaded in the order they are specified in the file.

Example file content that would first load libhelperexample.so and then the bundled frida-gadget:
```
/data/local/tmp/re.zyg.fri/libhelperexample.so
/data/local/tmp/re.zyg.fri/libgadget.so
```

Make sure the libraries are located somewhere accessible by the app and that
file permissions are properly set.

If you want the frida gadget to start, you need to explicitly specify the bundled frida-gadget at
`/data/local/tmp/re.zyg.fri/libgadget.so`.\
You can also choose to specify your own gadget this way or omit the gadget altogether.
4 changes: 2 additions & 2 deletions module.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ ext {
moduleName = "ZygiskFrida"
moduleAuthor = "lico-n"
moduleDescription = "Injects frida gadget via zygisk."
moduleVersion = "v1.3.0"
moduleVersionCode = 4
moduleVersion = "v1.4.0"
moduleVersionCode = 5

// Riru
moduleMinRiruApiVersion = 24
Expand Down
4 changes: 4 additions & 0 deletions module/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ apply from: file(rootProject.file('module.gradle'))
dependencies {
implementation 'dev.rikka.ndk.thirdparty:cxx:1.2.0'
implementation("dev.rikka.ndk:riru:26.0.0")
implementation("io.github.vvb2060.ndk:dobby:1.2")
}

task downloadFrida(type: Download) {
Expand Down Expand Up @@ -109,6 +110,9 @@ afterEvaluate {
def templatePath = "$rootDir/template/magisk_module"

into magiskDir
from(rootDir) {
include 'config.json.example'
}
from(templatePath) {
exclude 'module.prop'
exclude 'riru.sh'
Expand Down
5 changes: 3 additions & 2 deletions module/src/jni/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ XDL_FILES := $(wildcard $(LOCAL_PATH)/xdl/*.c)
APP_STL=none
LOCAL_MODULE := zygiskfrida
LOCAL_C_INCLUDES := $(LOCAL_PATH)/xdl/include $(LOCAL_PATH)/include
LOCAL_SRC_FILES := inject.cpp config.cpp riru_config.cpp $(XDL_FILES:$(LOCAL_PATH)/%=%)
LOCAL_STATIC_LIBRARIES := cxx
LOCAL_SRC_FILES := inject.cpp config.cpp riru_config.cpp child_gating.cpp $(XDL_FILES:$(LOCAL_PATH)/%=%)
LOCAL_STATIC_LIBRARIES := cxx dobby
LOCAL_LDLIBS := -llog

ifeq ($(API), riru)
Expand All @@ -30,3 +30,4 @@ FORCE: ;

$(call import-module,prefab/cxx)
$(call import-module,prefab/riru)
$(call import-module,prefab/dobby)
Loading

0 comments on commit c8888a0

Please sign in to comment.