故事的起源: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
編譯成功的。
希望大家順利編譯:
基本用法#
使用下邊脫殼實驗的目標《網上國網》做演示(沒日過,只因為他有 Anti Root 和加殼)
1. 感染目標應用#
感染目標就是對目標進行二次打包,其運行在沙箱環境中。
在可感染列表中,選中:
這裡還有點用,gda 識別不到這個 apk 的包名,所以直接看這裡也可以。
選中以後會自動重打包。
感染成功:
先卸載之前安裝的原版 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:
這個插件結構,和 xposed 模塊一樣,方便上手:
對 xposed 不熟悉的可以看看我年輕的時候寫的文章 https://www.freebuf.com/articles/terminal/248675.html。
脫殼#
這個目標 app 加殼的,並且有 anti root, 開了 Magisk Hide 才勉強能運行。
所以用 frida-dexdump 比較困難...
直接反編譯,可以看到加殼了:
接下來需要脫殼,脫殼插件代碼:
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:
在終端中輸入 adb logcat -s unpack
, 可以查看脫殼狀態
確認模塊已開啟
在感染應用中點擊目標應用 -> 強殺進程,然後重新運行目標應用。
在脫殼過程中的 constructUnpackedApk 步驟中,總是報錯:
不過最終,還是生成了 apk 給俺:
adb pull /sdcard/wsgw-unpack.apk ./
拖到 gda 中打開,說實話這個脫殼效果,還真不錯...:
抓包#
利用 vpn 抓包,提示證書驗證異常,應該是用了 ssl pining 或者 https 雙向認證:
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: 根據文件創建日期可能對確定請求有幫助誒
Warning: 此處沒測試有沒有對 native 進行處理.. 另外沒有測試是否支持證書導出,文檔好少
讀取目標 app 私有文件#
這種需求也經常有,個人覺得所有免 root 方案都應該考慮這個問題,看看 Ratel 怎麼用吧。
repo 地址:https://github.com/virjarRatel/sshdroid
文檔可以看 Readme 和 http://ratel-doc.virjar.com/04_ecology/SSHdroid.html:
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 打開並編寫配置文件,配置完直接運行:
在 RM 的模塊中開啟此模塊,啟動目標 app
# 端口轉發
adb forward tcp:3478 tcp:3478
# ssh登錄
ssh 127.0.0.1 -p 3478
目前的 shell 命令交互展示還未進行優化
確實沒優化,不過能用。
TIPS:密碼直接回車即可
scp 也支持,體驗還不錯
1. 獲取文件夾
2. 獲取單個文件
cat 也支持
其餘的命令用到的時候再說吧,確實很不人性化,不過這個 shell 用在自動化腳本上就很合適,毫無多餘信息,不用考慮自動補全什麼的。
Hook#
隨便找個函數 hook 一下,在之前抓包中的調用棧中找到一個函數,net.security.device.api.SecurityUtil.httpPost
:
編寫插件對該函數進行 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 效果:
沒測試 hook native,俺不會
後記#
Ratel 挺強的,但是當然不是銀彈:
但是已經很不錯了,可以考慮二開,來應對即將到來的 Anti。
參考文章: