Hook.java 4.83 KB
package com.hermes.xhshook;

import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;

public class Hook implements IXposedHookLoadPackage {
    // Hermes event_server endpoint — POST xhs_params events here
    private static final String HERMES_URL = "http://127.0.0.1:8765/xhs_params";

    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        if (!lpparam.packageName.equals("com.xingin.xhs")) return;

        XposedBridge.log("[XHSHook] Loaded into XHS!");

        try {
            Class<?> clz = XposedHelpers.findClass("okhttp3.Request$Builder", lpparam.classLoader);
            XposedHelpers.findAndHookMethod(clz, "build", new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    try {
                        Object url = XposedHelpers.getObjectField(param.thisObject, "url");
                        String urlStr = url != null ? url.toString() : "null";

                        if (!urlStr.contains("edith.xiaohongshu.com")) return;

                        Object method = XposedHelpers.getObjectField(param.thisObject, "method");
                        String methodStr = method != null ? method.toString() : "GET";

                        Object headersBuilder = XposedHelpers.getObjectField(param.thisObject, "headers");
                        String headersStr = "";
                        if (headersBuilder != null) {
                            Object headers = XposedHelpers.callMethod(headersBuilder, "build");
                            headersStr = headers != null ? headers.toString() : "";
                        }

                        XposedBridge.log("[XHSHook] " + methodStr + " " + urlStr);
                        XposedBridge.log("[XHSHook] Headers:\n" + headersStr);

                        final String json = buildJson(methodStr, urlStr, headersStr);
                        new Thread(new Runnable() {
                            public void run() { postToHermes(json); }
                        }).start();

                    } catch (Throwable t) {
                        XposedBridge.log("[XHSHook] Error in hook: " + t.getMessage());
                    }
                }
            });
            XposedBridge.log("[XHSHook] OkHttp Request.Builder.build() hooked!");
        } catch (Throwable t) {
            XposedBridge.log("[XHSHook] Failed to hook OkHttp: " + t.getMessage());
            XposedBridge.log(t);
        }
    }

    private static String buildJson(String method, String url, String headersStr) {
        StringBuilder sb = new StringBuilder();
        sb.append("{");
        sb.append("\"method\":").append(jsonStr(method)).append(",");
        sb.append("\"url\":").append(jsonStr(url)).append(",");
        sb.append("\"headers\":{");
        boolean first = true;
        for (String line : headersStr.split("\n")) {
            int colon = line.indexOf(": ");
            if (colon < 0) continue;
            String k = line.substring(0, colon).trim();
            String v = line.substring(colon + 2).trim();
            if (!first) sb.append(",");
            sb.append(jsonStr(k)).append(":").append(jsonStr(v));
            first = false;
        }
        sb.append("}}");
        return sb.toString();
    }

    private static String jsonStr(String s) {
        if (s == null) return "null";
        return "\"" + s.replace("\\", "\\\\")
                       .replace("\"", "\\\"")
                       .replace("\n", "\\n")
                       .replace("\r", "\\r") + "\"";
    }

    private static void postToHermes(String json) {
        try {
            HttpURLConnection conn = (HttpURLConnection) new URL(HERMES_URL).openConnection();
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setDoOutput(true);
            conn.setConnectTimeout(1000);
            conn.setReadTimeout(1000);
            byte[] body = json.getBytes(StandardCharsets.UTF_8);
            conn.setFixedLengthStreamingMode(body.length);
            try (OutputStream os = conn.getOutputStream()) {
                os.write(body);
            }
            int code = conn.getResponseCode();
            conn.disconnect();
            if (code != 200 && code != 201 && code != 204) {
                XposedBridge.log("[XHSHook] Hermes POST " + code);
            }
        } catch (Throwable t) {
            // Hermes server not running — silent fail, logcat capture still works
        }
    }
}