1
0
mirror of https://github.com/areteruhiro/LIME-beta-hiro.git synced 2025-02-05 21:11:39 +09:00
This commit is contained in:
areteruhiro 2024-11-11 22:59:43 +09:00 committed by GitHub
parent 91a0b1cbbb
commit 99591ae41f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,419 +0,0 @@
package io.github.hiro.lime.hooks;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import dalvik.system.DexFile;
import io.github.hiro.lime.LimeOptions;
import java.io.File;
import java.lang.reflect.Method;
import java.util.Enumeration;
public class Test implements IHook {
private boolean isButtonAdded = false; // ボタンが追加されたかどうかを追跡するフラグ
@Override
public void hook(LimeOptions limeOptions, XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
String packageName = loadPackageParam.packageName;
XposedBridge.log("Hooking package: " + packageName);
hookOnViewAdded(loadPackageParam.classLoader);
hookAllClassesInPackage(loadPackageParam.classLoader, loadPackageParam);
hookFragmentOnCreateView(loadPackageParam.classLoader);
//hookChatHistoryActivity(loadPackageParam.classLoader); // ChatHistoryActivityのフック
//hookLongClickListeners(loadPackageParam.classLoader); // 長押しリスナーのフック
}
private void hookAllClassesInPackage(ClassLoader classLoader, XC_LoadPackage.LoadPackageParam loadPackageParam) {
try {
String apkPath = loadPackageParam.appInfo.sourceDir;
if (apkPath == null) {
XposedBridge.log("Could not get APK path.");
return;
}
DexFile dexFile = new DexFile(new File(apkPath));
Enumeration<String> classNames = dexFile.entries();
while (classNames.hasMoreElements()) {
String className = classNames.nextElement();
// 指定されたパッケージで始まるクラスのみをフック
// if (className.startsWith("com.linecorp.line") || className.startsWith("jp.naver.line.android")) {
try {
Class<?> clazz = Class.forName(className, false, classLoader);
hookAllMethods(clazz);
} catch (ClassNotFoundException e) {
XposedBridge.log("Class not found: " + className);
} catch (Throwable e) {
XposedBridge.log("Error loading class " + className + ": " + e.getMessage());
}
// }
}
} catch (Throwable e) {
XposedBridge.log("Error while hooking classes: " + e.getMessage());
}
}
private void hookAllClasses(ClassLoader classLoader, XC_LoadPackage.LoadPackageParam loadPackageParam) {
try {
String apkPath = loadPackageParam.appInfo.sourceDir;
if (apkPath == null) {
XposedBridge.log("Could not get APK path.");
return;
}
DexFile dexFile = new DexFile(new File(apkPath));
Enumeration<String> classNames = dexFile.entries();
while (classNames.hasMoreElements()) {
String className = classNames.nextElement();
try {
Class<?> clazz = Class.forName(className, false, classLoader);
hookAllMethods(clazz);
} catch (ClassNotFoundException e) {
XposedBridge.log("Class not found: " + className);
} catch (Throwable e) {
XposedBridge.log("Error loading class " + className + ": " + e.getMessage());
}
}
} catch (Throwable e) {
XposedBridge.log("Error while hooking classes: " + e.getMessage());
}
}
private void hookFragmentOnCreateView(ClassLoader classLoader) {
try {
Class<?> fragmentClass = Class.forName("androidx.fragment.app.Fragment", false, classLoader);
Method onCreateViewMethod = fragmentClass.getDeclaredMethod("onCreateView", LayoutInflater.class, ViewGroup.class, Bundle.class);
XposedBridge.hookMethod(onCreateViewMethod, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log("Before calling: " + fragmentClass.getName() + ".onCreateView");
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
ViewGroup rootView = (ViewGroup) param.getResult(); // ルートのViewGroupを取得
Context context = rootView.getContext();
// IDによるビューの取得
int messageContainerId = getIdByName(context, "message_context_menu_content_container");
View messageContainer = rootView.findViewById(messageContainerId);
if (messageContainer != null) {
XposedBridge.log("messageContainer found: " + messageContainer.toString());
} else {
XposedBridge.log("messageContainer not found");
}
// 新しいビューの追加を監視
rootView.setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
@Override
public void onChildViewAdded(View parent, View child) {
XposedBridge.log("Child view added: " + child.toString());
}
@Override
public void onChildViewRemoved(View parent, View child) {
XposedBridge.log("Child view removed: " + child.toString());
}
});
}
});
} catch (ClassNotFoundException e) {
XposedBridge.log("Class not found: androidx.fragment.app.Fragment");
} catch (NoSuchMethodException e) {
XposedBridge.log("Method not found: onCreateView in Fragment");
} catch (Throwable e) {
XposedBridge.log("Error hooking onCreateView: " + e.getMessage());
}
}
private void hookOnViewAdded(ClassLoader classLoader) {
try {
Class<?> constraintLayoutClass = Class.forName("androidx.constraintlayout.widget.ConstraintLayout", false, classLoader);
Method onViewAddedMethod = constraintLayoutClass.getDeclaredMethod("onViewAdded", View.class);
XposedBridge.hookMethod(onViewAddedMethod, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
View addedView = (View) param.args[0];
XposedBridge.log(addedView.toString());
}
private boolean isButtonAdded = false; // ボタンが追加されたかどうかを追跡するフラグ
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
View addedView = (View) param.args[0];
XposedBridge.log("Called: " + constraintLayoutClass.getName() + ".onViewAdded");
// 追加されたビューの ID を取得
int addedViewId = addedView.getId();
// 親ビューを取得
ViewGroup parent = (ViewGroup) param.thisObject;
// 追加されたビューのリソース名を取得
String resourceName = parent.getContext().getResources().getResourceEntryName(addedViewId);
// リソース名が chat_ui_message_context_menu_row_container の場合
if ("chat_ui_message_context_menu_row_container".equals(resourceName) && !isButtonAdded) {
// ボタンを作成
}
}
private void createAndAddButton(ConstraintLayout parent, View referenceView) {
// ボタンを作成
Button newButton = new Button(parent.getContext());
newButton.setText("新しいボタン");
// ボタンの ID を設定
newButton.setId(View.generateViewId());
// ボタンのレイアウトパラメータを設定
ConstraintLayout.LayoutParams params = new ConstraintLayout.LayoutParams(
ConstraintLayout.LayoutParams.WRAP_CONTENT,
ConstraintLayout.LayoutParams.WRAP_CONTENT
);
// ボタンを親ビューに追加
parent.addView(newButton, params);
// 制約を設定
ConstraintSet constraintSet = new ConstraintSet();
constraintSet.clone(parent);
// ボタンに対する制約を設定
constraintSet.connect(newButton.getId(), ConstraintSet.TOP, referenceView.getId(), ConstraintSet.BOTTOM); // 上に参照ビューを設定
constraintSet.connect(newButton.getId(), ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START); // 左端に設定
constraintSet.connect(newButton.getId(), ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END); // 右端に設定
constraintSet.setHorizontalBias(newButton.getId(), 0.5f); // 中央に配置
// 制約を適用
constraintSet.applyTo(parent);
}
private void createAndAddButton(ViewGroup parent) {
// ボタンを作成
Button newButton = new Button(parent.getContext());
newButton.setText("新しいボタン"); // ボタンのテキストを設定
// ボタンのレイアウトパラメータを設定
ConstraintLayout.LayoutParams params = new ConstraintLayout.LayoutParams(
ConstraintLayout.LayoutParams.WRAP_CONTENT,
ConstraintLayout.LayoutParams.WRAP_CONTENT
);
// 親の一番右に追加するために適切な位置を設定
params.startToEnd = parent.getChildAt(parent.getChildCount() - 1).getId(); // 最後のビューの右側に配置
params.topToTop = ConstraintLayout.LayoutParams.PARENT_ID; // 上部を親の上部に固定
newButton.setLayoutParams(params);
// 親ビューにボタンを追加
parent.addView(newButton);
}
});
} catch (ClassNotFoundException e) {
XposedBridge.log("Class not found: androidx.constraintlayout.widget.ConstraintLayout");
} catch (NoSuchMethodException e) {
XposedBridge.log("Method not found: onViewAdded in ConstraintLayout");
} catch (Throwable e) {
XposedBridge.log("Error hooking onViewAdded: " + e.getMessage());
}
}
private int getIdByName(Context context, String resourceName) {
return context.getResources().getIdentifier(resourceName, "id", context.getPackageName());
}
private void hookAllMethods(Class<?> clazz) {
// クラス内のすべてのメソッドを取得
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
// 抽象メソッドをスキップ
if (java.lang.reflect.Modifier.isAbstract(method.getModifiers())) {
continue;
}
// 対象メソッドが特定のビュー関連メソッドであるか確認
if (!"invokeSuspend".equals(method.getName()) &&
!"setOnLongClickListener".equals(method.getName()) &&
!"setOnTouchListener".equals(method.getName()) &&
!"setVisibility".equals(method.getName()) &&
!"setAlpha".equals(method.getName()) &&
!"setEnabled".equals(method.getName()) &&
!"setFocusable".equals(method.getName()) &&
!"setOnClickListener".equals(method.getName()) &&
!"setBackgroundColor".equals(method.getName()) &&
!"setPadding".equals(method.getName()) &&
!"setLayoutParams".equals(method.getName()) &&
!"requestLayout".equals(method.getName()) &&
!"invalidate".equals(method.getName()) &&
!"setText".equals(method.getName()) && // 新しく追加されたメソッド
!"setTextColor".equals(method.getName()) && // 新しく追加されたメソッド
!"setHint".equals(method.getName()) && // 新しく追加されたメソッド
!"setHintTextColor".equals(method.getName()) && // 新しく追加されたメソッド
!"onStart".equals(method.getName()) &&
!"setCompoundDrawables".equals(method.getName()) &&
!"getActivity".equals(method.getName()) && // PendingIntent method
!"onViewAdded".equals(method.getName()) && // PendingIntent method
!"setState".equals(method.getName())) { // PendingIntent method
continue;
}
method.setAccessible(true); // アクセス可能に設定
try {
// メソッドをフックする
XposedBridge.hookMethod(method, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
StringBuilder argsString = new StringBuilder("Args: ");
// 引数が複数の場合すべてを追加
for (int i = 0; i < param.args.length; i++) {
Object arg = param.args[i];
argsString.append("Arg[").append(i).append("]: ")
.append(arg != null ? arg.toString() : "null")
.append(", ");
}
// メソッドに応じたログ出力
if ("invokeSuspend".equals(method.getName())) {
XposedBridge.log("Before calling invokeSuspend in class: " + clazz.getName() + " with args: " + argsString);
} else if ("setVisibility".equals(method.getName())) {
XposedBridge.log("Before calling setVisibility in class: " + clazz.getName() + " with args: " + argsString);
} else if ("setAlpha".equals(method.getName())) {
XposedBridge.log("Before calling setAlpha in class: " + clazz.getName() + " with args: " + argsString);
} else if ("setEnabled".equals(method.getName())) {
XposedBridge.log("Before calling setEnabled in class: " + clazz.getName() + " with args: " + argsString);
} else if ("setFocusable".equals(method.getName())) {
XposedBridge.log("Before calling setFocusable in class: " + clazz.getName() + " with args: " + argsString);
} else if ("setOnClickListener".equals(method.getName())) {
XposedBridge.log("Before calling setOnClickListener in class: " + clazz.getName() + " with args: " + argsString);
} else if ("setBackgroundColor".equals(method.getName())) {
XposedBridge.log("Before calling setBackgroundColor in class: " + clazz.getName() + " with args: " + argsString);
} else if ("setPadding".equals(method.getName())) {
XposedBridge.log("Before calling setPadding in class: " + clazz.getName() + " with args: " + argsString);
} else if ("setLayoutParams".equals(method.getName())) {
XposedBridge.log("Before calling setLayoutParams in class: " + clazz.getName() + " with args: " + argsString);
} else if ("requestLayout".equals(method.getName())) {
XposedBridge.log("Before calling requestLayout in class: " + clazz.getName() + " with args: " + argsString);
} else if ("invalidate".equals(method.getName())) {
XposedBridge.log("Before calling invalidate in class: " + clazz.getName() + " with args: " + argsString);
} else if ("setText".equals(method.getName())) {
XposedBridge.log("Before calling setText in class: " + clazz.getName() + " with args: " + argsString);
} else if ("setTextColor".equals(method.getName())) {
XposedBridge.log("Before calling setTextColor in class: " + clazz.getName() + " with args: " + argsString);
} else if ("setHint".equals(method.getName())) {
XposedBridge.log("Before calling setHint in class: " + clazz.getName() + " with args: " + argsString);
} else if ("setHintTextColor".equals(method.getName())) {
XposedBridge.log("Before calling setHintTextColor in class: " + clazz.getName() + " with args: " + argsString);
} else if ("setCompoundDrawables".equals(method.getName())) {
XposedBridge.log("Before calling setCompoundDrawables in class: " + clazz.getName() + " with args: " + argsString);
} else if ("onStart".equals(method.getName())) {
XposedBridge.log("Before calling onStart in class: " + clazz.getName() + " with args: " + argsString);
} else if ("getActivity".equals(method.getName())) {
XposedBridge.log("Before calling getActivity in class: " + clazz.getName() + " with args: " + argsString);
} else if ("onViewAdded".equals(method.getName())) {
XposedBridge.log("Before calling onViewAdded in class: " + clazz.getName() + " with args: " + argsString);
} else if ("getService".equals(method.getName())) {
XposedBridge.log("Before calling getService in class: " + clazz.getName() + " with args: " + argsString);
} else if ("setState".equals(method.getName())) {
XposedBridge.log("Before setState invoke in class: " + clazz.getName() + " with args: " + argsString);
}
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Object result = param.getResult();
if ("invokeSuspend".equals(method.getName())) {
XposedBridge.log("Before calling invokeSuspend in class: " + clazz.getName() + (result != null ? result.toString() : "null"));
} else if ("setVisibility".equals(method.getName())) {
XposedBridge.log("After calling setVisibility in class: " + clazz.getName() + " with result: " + (result != null ? result.toString() : "null"));
} else if ("setAlpha".equals(method.getName())) {
XposedBridge.log("After calling setAlpha in class: " + clazz.getName() + " with result: " + (result != null ? result.toString() : "null"));
} else if ("setEnabled".equals(method.getName())) {
XposedBridge.log("After calling setEnabled in class: " + clazz.getName() + " with result: " + (result != null ? result.toString() : "null"));
} else if ("setFocusable".equals(method.getName())) {
XposedBridge.log("After calling setFocusable in class: " + clazz.getName() + " with result: " + (result != null ? result.toString() : "null"));
} else if ("setOnClickListener".equals(method.getName())) {
XposedBridge.log("After calling setOnClickListener in class: " + clazz.getName() + " with result: " + (result != null ? result.toString() : "null"));
} else if ("setBackgroundColor".equals(method.getName())) {
XposedBridge.log("After calling setBackgroundColor in class: " + clazz.getName() + " with result: " + (result != null ? result.toString() : "null"));
} else if ("setPadding".equals(method.getName())) {
XposedBridge.log("After calling setPadding in class: " + clazz.getName() + " with result: " + (result != null ? result.toString() : "null"));
} else if ("setLayoutParams".equals(method.getName())) {
XposedBridge.log("After calling setLayoutParams in class: " + clazz.getName() + " with result: " + (result != null ? result.toString() : "null"));
} else if ("requestLayout".equals(method.getName())) {
XposedBridge.log("After calling requestLayout in class: " + clazz.getName() + " with result: " + (result != null ? result.toString() : "null"));
} else if ("invalidate".equals(method.getName())) {
XposedBridge.log("After calling invalidate in class: " + clazz.getName() + " with result: " + (result != null ? result.toString() : "null"));
} else if ("setText".equals(method.getName())) {
XposedBridge.log("After calling setText in class: " + clazz.getName() + " with result: " + (result != null ? result.toString() : "null"));
} else if ("setTextColor".equals(method.getName())) {
XposedBridge.log("After calling setTextColor in class: " + clazz.getName() + " with result: " + (result != null ? result.toString() : "null"));
} else if ("setHint".equals(method.getName())) {
XposedBridge.log("After calling setHint in class: " + clazz.getName() + " with result: " + (result != null ? result.toString() : "null"));
} else if ("setHintTextColor".equals(method.getName())) {
XposedBridge.log("After calling setHintTextColor in class: " + clazz.getName() + " with result: " + (result != null ? result.toString() : "null"));
} else if ("setCompoundDrawables".equals(method.getName())) {
XposedBridge.log("After calling setCompoundDrawables in class: " + clazz.getName() + " with result: " + (result != null ? result.toString() : "null"));
} else if ("onStart".equals(method.getName())) {
XposedBridge.log("Before calling onStart in class: " + clazz.getName() + " with result: " + (result != null ? result.toString() : "null"));
} else if ("getActivity".equals(method.getName())) {
XposedBridge.log("After calling getActivity in class: " + clazz.getName() + " with result: " + (result != null ? result.toString() : "null"));
} else if ("onViewAdded".equals(method.getName())) {
XposedBridge.log("After calling onViewAdded in class: " + clazz.getName() + " with result: " + (result != null ? result.toString() : "null"));
} else if ("getService".equals(method.getName())) {
XposedBridge.log("After calling getService in class: " + clazz.getName() + " with result: " + (result != null ? result.toString() : "null"));
} else if ("setState".equals(method.getName())) {
XposedBridge.log("setState " + clazz.getName() + " with result: " + (result != null ? result.toString() : "null"));
}
}
});
} catch (IllegalArgumentException e) {
XposedBridge.log("Error hooking method " + method.getName() + " in class " + clazz.getName() + " : " + e.getMessage());
} catch (Throwable e) {
XposedBridge.log("Unexpected error hooking method " + method.getName() + " in class " + clazz.getName() + " : " + Log.getStackTraceString(e));
}
}
}
private boolean isViewCreationMethod(Method method) {
// View作成に関連するメソッドを検出
String methodName = method.getName().toLowerCase();
return methodName.contains("inflate") || methodName.contains("new") || methodName.contains("create");
}
}