banner
Silas

REAO

Be a better man
github

Ratel 初體驗

故事的起源:Ratel,重打包沙箱

當時我思考 VirtualXposed 可以基於 VA 實現沙箱環境 + 上帝模式的 hook 能力

我想應該很多人想到過,但是只有 virjar 做到了,這可能就是大佬吧。

為了便於理解,我覺得可以把平頭哥理解成 太極、應用轉生的 PRO 版本,功能更強大、生態更好、更適合我們使用。

請注意,該類工具都是免 root的,通過對目標 app 進行重打包來達到運行在沙箱的效果。

文中相關文件:https://github.com/runtimed/useRatel

Ratel Manager#

首先得編譯一個 Ratel Manager 出來,RM 是平頭哥的本體,這玩意可以理解成太極和應用轉生的主程序,用於對目標 app 進行二次打包、提供沙箱環境、xposed 插件管理等等。

在渣總的 repo 裡沒找到成品,應該是得自己編譯

RM 構建需要使用腳本構建,否則無法支持 app 端進行重打包

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

cd ratel-core
# 開始編譯
./script/build_ratel_manager.sh

接下來就是處理報錯時間!

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)

代理問題,我之前給 gradle 設置了代理,現在去掉(因為我在家裝了軟路由。

## 去掉代理相關的部分
vim .gradle/gradle.properties

在排錯的過程中,發現大多是 NDK 相關的問題。

別忘了在環境變量中加入 ANDROID_HOME ,在我的 mac 上是這樣的:

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

最後,我使用ndk 21.1.6352462 編譯成功的。

希望大家順利編譯:

image

image

基本用法#

使用下邊脫殼實驗的目標《網上國網》做演示(沒日過,只因為他有 Anti Root 和加殼)

1. 感染目標應用#

感染目標就是對目標進行二次打包,其運行在沙箱環境中。

在可感染列表中,選中:

image

這裡還有點用,gda 識別不到這個 apk 的包名,所以直接看這裡也可以。
image

選中以後會自動重打包。

感染成功:

image

先卸載之前安裝的原版 apk,然後安裝感染過的 app 就可以辣。

2. 新建插件#

https://github.com/virjarRatel/ratel-module-template 平頭哥的插件模塊模版,用於快速生成一個插件項目

支持兩種方式生成插件:

./template.sh -a ~/Downloads/wsgw.apk -m crack-wsgw # -a 指向目標apk(會自動識別其包名
./template.sh -p com.sgcc.wsgw.cn -m crack-wsgw  # -p 包名

使用 as 打開,插件是綠色的,說明沒 error:

image

這個插件結構,和 xposed 模塊一樣,方便上手:

image

對 xposed 不熟悉的可以看看我年輕的時候寫的文章 https://www.freebuf.com/articles/terminal/248675.html

脫殼#

這個目標 app 加殼的,並且有 anti root, 開了 Magisk Hide 才勉強能運行。
所以用 frida-dexdump 比較困難...

直接反編譯,可以看到加殼了:

image

接下來需要脫殼,脫殼插件代碼:

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 抽取殼要把這個選項打開
        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
                } catch (IOException e) {
                    Log.e(tag, "unpacked error", e);
                    e.printStackTrace();
                }
            }
        });
    }
}

代碼編輯完後,點擊運行 button:

image

在終端中輸入 adb logcat -s unpack, 可以查看脫殼狀態

image

確認模塊已開啟

image
在感染應用中點擊目標應用 -> 強殺進程,然後重新運行目標應用。

image

在脫殼過程中的 constructUnpackedApk 步驟中,總是報錯:

image

不過最終,還是生成了 apk 給俺:

image

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

拖到 gda 中打開,說實話這個脫殼效果,還真不錯...:

image

抓包#

利用 vpn 抓包,提示證書驗證異常,應該是用了 ssl pining 或者 https 雙向認證:

image

Ratel 內置 socketMonitor (比肉絲的 R0Cpature 早出現 3 年,早期甚至支持線程跳躍追蹤,用以解決異步問題)

抓包插件編寫

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"))); 
        // 對應路徑為 /sdcard/ratel_white_dir/com.sgcc.wsgw.cn/socketMonitor
    }
}

插件安裝完後,執行我們需要抓包的功能,然後將其 pull 下來:

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

看起來還可以,請求、響應、調用棧 都有,每個文件對應一個請求:

OS: 根據文件創建日期可能對確定請求有幫助誒

image

Warning: 此處沒測試有沒有對 native 進行處理.. 另外沒有測試是否支持證書導出,文檔好少

讀取目標 app 私有文件#

這種需求也經常有,個人覺得所有免 root 方案都應該考慮這個問題,看看 Ratel 怎麼用吧。

repo 地址:https://github.com/virjarRatel/sshdroid

文檔可以看 Readme 和 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

使用 as 打開並編寫配置文件,配置完直接運行:

image

image

在 RM 的模塊中開啟此模塊,啟動目標 app

# 端口轉發
adb forward tcp:3478 tcp:3478

# ssh登錄
ssh 127.0.0.1 -p 3478

目前的 shell 命令交互展示還未進行優化

確實沒優化,不過能用。

image

TIPS:密碼直接回車即可​

scp 也支持,體驗還不錯

1. 獲取文件夾

image

2. 獲取單個文件

image

cat 也支持

image

其餘的命令用到的時候再說吧,確實很不人性化,不過這個 shell 用在自動化腳本上就很合適,毫無多餘信息,不用考慮自動補全什麼的。

Hook#

隨便找個函數 hook 一下,在之前抓包中的調用棧中找到一個函數,net.security.device.api.SecurityUtil.httpPost

image

編寫插件對該函數進行 hook:

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

        Log.i(tag, "start");

        //Ratel提供的api ,自動選擇目標類的classloader
        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");
  }

看看 hook 效果:

image

沒測試 hook native,俺不會

後記#

Ratel 挺強的,但是當然不是銀彈:

image

但是已經很不錯了,可以考慮二開,來應對即將到來的 Anti。


參考文章:

  1. app 逆向 平頭哥實戰(某農產品 app)
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。