banner
Silas

REAO

Be a better man
github

Ratel First Experience

The origin of the story: Ratel, Repackaging Sandbox

At that time, I was thinking that VirtualXposed could achieve sandbox environment + god mode hooking capability based on VA.

I think many people must have thought of this, but only virjar has achieved it, which might be what makes him a big shot.

For better understanding, I think we can understand PingTouGe as the PRO version of Taichi, with more powerful features, a better ecosystem, and more suitable for our use.

Please note that such tools are all no root required, achieving the effect of running in a sandbox by repackaging the target app.

Related files in the article: https://github.com/runtimed/useRatel

Ratel Manager#

First, we need to compile a Ratel Manager, RM is the core of PingTouGe, which can be understood as the main program of Taichi and application reincarnation, used for secondary packaging of target apps, providing sandbox environment, Xposed plugin management, etc.

I couldn't find a finished product in the boss's repo, so I guess I have to compile it myself.

RM construction requires using a script to build; otherwise, it won't support repackaging on the app side.

git clone https://github.com/virjarRatel/ratel-core

cd ratel-core
# Start compiling
./script/build_ratel_manager.sh

Next comes the error handling time!

Connection refused

IO exception while downloading manifest:
java.net.ConnectException: Connection refused (Connection refused)
        at java.net.PlainSocketImpl.socketConnect(Native Method)
        at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:476)
        at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:218)
        at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:200)
        at java.net.Socket.connect(Socket.java:606)
        at java.net.Socket.connect(Socket.java:555)
        at sun.net.NetworkClient.doConnect(NetworkClient.java:180)
        at sun.net.www.http.HttpClient.openServer(HttpClient.java:463)
        at sun.net.www.http.HttpClient$1.run(HttpClient.java:515)
        at sun.net.www.http.HttpClient$1.run(HttpClient.java:513)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.net.www.http.HttpClient.privilegedOpenServer(HttpClient.java:512)

Proxy issue, I previously set a proxy for gradle, now I remove it (because I installed a soft router at home).

## Remove proxy-related parts
vim .gradle/gradle.properties

During the troubleshooting process, I found that most issues were related to NDK.

Don't forget to add ANDROID_HOME to the environment variables, on my Mac it looks like this:

export ANDROID_HOME="/Users/{UserName}/Library/Android/sdk/"

In the end, I successfully compiled using ndk 21.1.6352462.

Hope everyone compiles smoothly:

image

image

Basic Usage#

Using the target of the shell removal experiment "Online State Grid" for demonstration (not used before, just because it has Anti Root and is packed).

1. Infect the target application#

Infecting the target means repackaging the target, which runs in a sandbox environment.

In the infectable list, select:

image

There is also some use here; gda cannot recognize the package name of this apk, so you can directly look here as well.
image

After selection, it will automatically repackage.

Infection successful:

image

First uninstall the previously installed original apk, then install the infected app.

2. Create a new plugin#

https://github.com/virjarRatel/ratel-module-template is the plugin module template of PingTouGe, used to quickly generate a plugin project.

Supports two ways to generate plugins:

./template.sh -a ~/Downloads/wsgw.apk -m crack-wsgw # -a points to the target apk (will automatically recognize its package name)
./template.sh -p com.sgcc.wsgw.cn -m crack-wsgw  # -p package name

Open with AS, if the plugin is green, it means no error:

image

This plugin structure is similar to Xposed modules, making it easy to get started:

image

For those unfamiliar with Xposed, you can check out the article I wrote when I was younger https://www.freebuf.com/articles/terminal/248675.html.

Shell Removal#

This target app is packed and has anti-root; it can barely run with Magisk Hide enabled.
So using frida-dexdump is quite difficult...

Direct decompilation shows that it is packed:

image

Next, we need to remove the shell; the shell removal plugin code:

public class HookEntry implements IRposedHookLoadPackage {
    private static final String tag = "DEMO_HOOK";

    @Override
    public void handleLoadPackage(final RC_LoadPackage.LoadPackageParam lpparam) {

        if (lpparam.packageName.equals("com.sgcc.wsgw.cn")) {
            Unpack.entry(lpparam);
        }
    }
}
public class Unpack {
    public static final String tag = "TR_HOOK";

    public static void entry(RC_LoadPackage.LoadPackageParam lpparam) {

        // TODO Enable this option to extract the shell
        UnPackerToolKit.autoEnable(true);

        UnPackerToolKit.unpack(new UnPackerToolKit.UnpackEvent() {
            @Override
            public void onFinish(File file) {
                try {
                    FileUtils.copyFile(file, new File("/sdcard/wsgw-unpack.apk")); // apk generated after shell removal
                } catch (IOException e) {
                    Log.e(tag, "unpacked error", e);
                    e.printStackTrace();
                }
            }
        });
    }
}

After editing the code, click the run button:

image

Enter adb logcat -s unpack in the terminal to check the shell removal status:

image

Confirm the module is enabled:

image
Click on the target app in the infected application -> Force kill the process, then rerun the target app.

image

During the shell removal process, the constructUnpackedApk step always reports an error:

image

However, in the end, it still generated an apk for me:

image

adb pull /sdcard/wsgw-unpack.apk ./

Drag it into GDA to open; to be honest, this shell removal effect is quite good...:

image

Packet Capture#

Using VPN for packet capture, it prompts certificate verification exception, which should be due to SSL pinning or mutual HTTPS authentication:

image

Ratel has a built-in socketMonitor (which appeared 3 years earlier than R0Capture, and even supported thread jump tracking in the early days to solve asynchronous issues)

Writing the packet capture plugin:

public class HookEntry implements IRposedHookLoadPackage {
    private static final String tag = "DEMO_HOOK";

    @Override
    public void handleLoadPackage(final RC_LoadPackage.LoadPackageParam lpparam) {

        if (lpparam.packageName.equals("com.sgcc.wsgw.cn")) {
            //Unpack.entry(lpparam);
            Monitor.entry(lpparam);
        }
    }
}
public class Monitor {
    public static void entry(RC_LoadPackage.LoadPackageParam lpparam) {

        SocketMonitor.setPacketEventObserver(new FileLogEventObserver(new File(RatelToolKit.whiteSdcardDirPath, "socketMonitor"))); 
        // The corresponding path is /sdcard/ratel_white_dir/com.sgcc.wsgw.cn/socketMonitor
    }
}

After the plugin is installed, execute the functionality we need to capture packets, and then pull it down:

adb pull /sdcard/ratel_white_dir/com.sgcc.wsgw.cn/socketMonitor ./

It looks good; requests, responses, call stacks are all there, with each file corresponding to a request:

OS: The creation date of the file may help determine the request.

image

Warning: It has not been tested whether it handles native... Also, it has not been tested whether it supports certificate export; the documentation is quite sparse.

Reading Private Files of Target App#

This need often arises, and I personally think all no-root solutions should consider this issue. Let's see how Ratel does it.

Repo address: https://github.com/virjarRatel/sshdroid

Documentation can be found in the Readme and http://ratel-doc.virjar.com/04_ecology/SSHdroid.html:

image

git clone https://github.com/virjarRatel/sshdroid.git

cd sshdroid

cp app/src/main/assets/config.template.properties  app/src/main/assets/config.properties

Open with AS and write the configuration file; after configuring, run directly:

image

image

Enable this module in RM's modules, then start the target app:

# Port forwarding
adb forward tcp:3478 tcp:3478

# SSH login
ssh 127.0.0.1 -p 3478

The current shell command interaction display has not been optimized.

Indeed, it hasn't been optimized, but it works.

image

TIPS: Just press enter for the password.

SCP is also supported, and the experience is quite good.

  1. Get a folder:

image

  1. Get a single file:

image

Cat is also supported:

image

Other commands will be discussed when needed; it is indeed very unhuman-friendly, but this shell is very suitable for automation scripts, with no extra information and no need to consider auto-completion.

Hook#

Randomly find a function to hook; find a function in the call stack from the previous packet capture, net.security.device.api.SecurityUtil.httpPost:

image

Write a plugin to hook this function:

@Override
    public void handleLoadPackage(final RC_LoadPackage.LoadPackageParam lpparam) {

        Log.i(tag, "start");

        // The API provided by Ratel automatically selects the classloader of the target class
        ClassLoadMonitor.addClassLoadMonitor("net.security.device.api.SecurityUtil", new ClassLoadMonitor.OnClassLoader() {
            @Override
            public void onClassLoad(Class<?> clazz) {
                Log.i(tag, "find class: " + clazz.getName());

                RposedHelpers.findAndHookMethod(clazz, "httpPost",
                        String.class,
                        Map.class,
                        Map.class,
                        new RC_MethodHook() {

                            @Override
                            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                                super.beforeHookedMethod(param);
                                String arg1 = (String) param.args[0];
                                String arg2 = (String) param.args[1].toString();
                                String arg3 = (String) param.args[2].toString();
                                Log.i(tag, "args1:" + arg1);
                                Log.i(tag, "args2:" + arg2);
                                Log.i(tag, "args3:" + arg3);
                            }

                            @Override
                            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                                super.afterHookedMethod(param);
                                String res = (String) param.getResult();
                                Log.i(tag, "result:" + res);
                                Log.i(tag, "-------------------------");
                            }
                        });
            }
        });
        Log.i(tag, "end");
  }

Check the hook effect:

image

I haven't tested hooking native; I don't know how.

Postscript#

Ratel is quite powerful, but of course, it is not a silver bullet:

image

But it is already quite good, and you can consider secondary development to cope with the upcoming Anti.


Reference articles:

  1. App Reverse Engineering: PingTouGe Practical (A Certain Agricultural Product App)
Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.