Skip to content
Permalink
d45151d558
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
293 lines (245 sloc) 13.9 KB
package org.mewx.ace.xposedtutorial;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.JavascriptInterface;
import android.webkit.ValueCallback;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.TextView;
import com.google.common.io.BaseEncoding;
import java.io.InputStream;
import java.security.Key;
import java.security.KeyStore;
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 wendu.dsbridge.DWebView;
/**
* Created by MewX on 12/12/2017.
* The entrance of MewX Xposed Tutorial module.
*/
public class MewXposedTutorial implements IXposedHookLoadPackage {
private boolean versionOK = false;
private Context appContext = null;
private void checkWeChatVersion(String real, String target) {
if (real.contains(target)) {
XposedBridge.log(String.format("WeChat Version is ok: %s, and expecting %s.", real, target));
versionOK = true;
} else {
XposedBridge.log(String.format("WeChat Version is not ok: %s, but expecting %s.", real, target));
versionOK = false;
}
}
class MyJavaScriptInterface {
MyJavaScriptInterface() {
}
@JavascriptInterface
@SuppressWarnings("unused")
public void sendValueFromHtml(String html) {
String filePath = "/data/system/mewx/ace/dump/html/"; // This folder is created in advance
XposedBridge.log("Dumped html files are stored in: " + filePath);
LightCache.saveFile(filePath, "" + System.currentTimeMillis() + ".html", html.getBytes(), true);
}
}
@Override
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
// switches
final boolean HIJACK_WECHAT = true;
final boolean HIJACK_TRANSORKS = false;
if (HIJACK_TRANSORKS && lpparam.packageName.contains("fobwifi")) {
// for hijacking the bks keystore password
XposedBridge.log("MewX outputs, loaded app: " + lpparam.packageName);
XposedHelpers.findAndHookMethod("java.security.KeyStore", lpparam.classLoader, "load", InputStream.class, char[].class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
if (((char[]) param.args[1]).length > 0) {
XposedBridge.log("GOT IT");
char[] pass = (char[]) param.args[1];
XposedBridge.log("GOT IT: " + new String(pass));
Key key = ((KeyStore) param.thisObject).getKey("new", pass);
Log.e("MEWX", "-----BEGIN PRIVATE KEY-----");
Log.e("MEWX", BaseEncoding.base64().encode(key.getEncoded()));
Log.e("MEWX", "-----END PRIVATE KEY-----");
}
}
});
}
else if (lpparam.packageName.equals("com.android.systemui")) {
// system ui hook, used to detecting the module is actually running
XposedBridge.log("MewX outputs, loaded app: " + lpparam.packageName);
XposedHelpers.findAndHookMethod("com.android.systemui.statusbar.policy.Clock", lpparam.classLoader, "updateClock", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
TextView tv = (TextView) param.thisObject;
String text = tv.getText().toString();
tv.setText(text + " :-)");
tv.setTextColor(Color.parseColor("#2196F3"));
}
});
} else if (HIJACK_WECHAT && lpparam.packageName.equals("com.tencent.mm")) {
XposedBridge.log("MewX outputs, loaded app: " + lpparam.packageName);
final String SUPPORTTED_WECHAT_VERSION = "6.5.23";
XposedHelpers.findAndHookMethod("com.tencent.mm.ui.LauncherUI", lpparam.classLoader, "onCreate", Bundle.class, new XC_MethodHook() {
String wechatVersion = "unknown";
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
if (appContext != null) {
return;
}
XposedBridge.log("LauncherUI hooked.");
appContext = ((Activity) param.thisObject).getApplicationContext();
PackageInfo pInfo = appContext.getPackageManager().getPackageInfo(lpparam.packageName, 0);
if (pInfo != null)
wechatVersion = pInfo.versionName;
XposedBridge.log("WeChat version=" + wechatVersion);
checkWeChatVersion(wechatVersion, SUPPORTTED_WECHAT_VERSION);
if (!versionOK) return;
XposedBridge.log("Everything is ok!");
// hookMethods(lpparam);
}
});
// hooking `onCreate` cannot get WebView!
XposedHelpers.findAndHookMethod("com.tencent.mm.plugin.appbrand.ui.AppBrandUI", lpparam.classLoader, "onCreate", Bundle.class, new XC_MethodHook() {
void recursiveLoopChildren(ViewGroup parent) {
for (int i = parent.getChildCount() - 1; i >= 0; i--) {
final View child = parent.getChildAt(i);
if (child instanceof WebView) {
// WebView.setWebContentsDebuggingEnabled(true); // API: 19
XposedBridge.log("Found Webview!!! - " + child.getClass().getName());
recursiveLoopChildren((ViewGroup) child);
XposedHelpers.callStaticMethod(((WebView) child).getClass(), "setWebContentsDebuggingEnabled", true);
} else if (child instanceof ViewGroup) {
XposedBridge.log("Found a ViewGroup - " + child.getClass().getName());
recursiveLoopChildren((ViewGroup) child);
} else if (child instanceof TextView) {
XposedBridge.log("TextView dump: " + ((TextView) child).getText());
}
}
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Activity activity = (Activity) param.thisObject;
XposedBridge.log("Enabled web content debugging. Current class name: " + activity.getLocalClassName());
recursiveLoopChildren((ViewGroup) activity.getWindow().getDecorView());
}
});
XposedHelpers.findAndHookMethod(ViewGroup.class, "addView", View.class, ViewGroup.LayoutParams.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
if (param.args[0] instanceof WebView) {
XposedBridge.log("Found just added Webview!!! - " + param.args[0].getClass().getName());
XposedHelpers.callStaticMethod(((WebView) param.args[0]).getClass(), "setWebContentsDebuggingEnabled", true);
Class C = param.args[0].getClass();
while (C != null) {
XposedBridge.log(" -> " + C.getName());
C = C.getSuperclass();
}
}
}
});
XposedBridge.hookAllConstructors(WebView.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
XposedHelpers.callStaticMethod(WebView.class, "setWebContentsDebuggingEnabled", true);
}
});
XposedHelpers.findAndHookMethod(WebView.class, "setWebViewClient", WebViewClient.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedHelpers.callStaticMethod(((WebView) param.thisObject).getClass(), "setWebContentsDebuggingEnabled", true);
XposedBridge.log("Setting web view client: " + param.args[0].getClass().getName());
}
});
XposedBridge.hookAllMethods(WebView.class, "setWebContentsDebuggingEnabled", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
param.args[0] = true;
}
});
XposedHelpers.findAndHookMethod("com.tencent.smtt.sdk.WebView", lpparam.classLoader, "loadUrl", String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
((WebView) param.thisObject).addJavascriptInterface(new MyJavaScriptInterface(), "interface");
}
});
XposedHelpers.findAndHookMethod("com.tencent.smtt.sdk.SystemWebViewClient", lpparam.classLoader, "onPageFinished", WebView.class, String.class, new XC_MethodHook() {
void recursiveLoopChildren(ViewGroup parent) {
for (int i = parent.getChildCount() - 1; i >= 0; i--) {
final View child = parent.getChildAt(i);
if (child instanceof ViewGroup) {
XposedBridge.log(" -> Found a ViewGroup - " + child.getClass().getName());
recursiveLoopChildren((ViewGroup) child);
} else if (child instanceof TextView) {
XposedBridge.log(" -> TextView dump: " + ((TextView) child).getText());
} else {
XposedBridge.log(" -> Found a subview: " + child.getClass().getName());
}
}
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("From WebView, after loading!!! Trying to traverse the webview.");
// trying to traverse the webview
final DWebView webview = (DWebView) param.args[0];
new WaitAndFetchViews().execute(webview);
webview.getSettings().setJavaScriptEnabled(true);
webview.setJavascriptInterface(new MyJavaScriptInterface());
// webview.addJavascriptInterface(new MyJavaScriptInterface(), "interface");
// webview.loadUrl("javascript:window.HtmlViewer.showHTML" +
// "('<html>'+document.getElementsByTagName('html')[0].innerHTML+'</html>');");
// FIXME: this is confirmed to be an issue from: com.tencent.smtt.sdk.WebView$SystemWebView
// http://bbs.mb.qq.com/thread-1944783-1-1.html
final int timeout = 0;
webview.evaluateJavascript("console.log(\"waiting\");setTimeout((function(){console.log(\"done: \" + window.document.body.outerHTML);return window.document.body.outerHTML}), " + timeout + ");",
new ValueCallback<String>() {
@Override
public void onReceiveValue(String html) {
String filePath = "/data/system/mewx/ace/dump/html/"; // This folder is created in advance
XposedBridge.log(html);
XposedBridge.log("MewX: Dumped html files are stored in: " + filePath);
LightCache.saveFile(filePath, "" + System.currentTimeMillis() + ".html", html.getBytes(), true);
}
});
}
class WaitAndFetchViews extends AsyncTask<WebView, Integer, Integer> {
@Override
protected Integer doInBackground(WebView... webViews) {
XposedBridge.log("Sleeping");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
recursiveLoopChildren(webViews[0]);
return null;
}
}
});
// not working for text view inside webview
// XposedHelpers.findAndHookMethod(TextView.class, "setText", CharSequence.class, new XC_MethodHook() {
// @Override
// protected void afterHookedMethod(MethodHookParam param) throws Throwable {
// super.afterHookedMethod(param);
// CharSequence temp = ((TextView) param.thisObject).getText();
// if (temp == null || temp.length() == 0) return;
// XposedBridge.log("From setText in TextView dump: " + temp);
// }
// });
}
}
}