1
0
mirror of https://github.com/areteruhiro/LIME-beta-hiro.git synced 2025-02-06 05:21:37 +09:00
This commit is contained in:
areteruhiro 2024-11-05 22:41:33 +09:00
parent 7dab21f2b6
commit 5cd5f96594
5 changed files with 345 additions and 167 deletions

View File

@ -10,7 +10,7 @@ android {
minSdk 28
targetSdk 34
versionCode 15
versionName "1.12.5c1"
versionName "1.12.test"
multiDexEnabled false
proguardFiles += 'proguard-rules.pro'
buildConfigField 'String', 'HOOK_TARGET_VERSION', '"141700420"'

View File

@ -23,6 +23,7 @@ import io.github.hiro.lime.hooks.KeepUnread;
import io.github.hiro.lime.hooks.KeepUnreadLSpatch;
import io.github.hiro.lime.hooks.ModifyRequest;
import io.github.hiro.lime.hooks.ModifyResponse;
import io.github.hiro.lime.hooks.MyHook;
import io.github.hiro.lime.hooks.OutputRequest;
import io.github.hiro.lime.hooks.OutputResponse;
import io.github.hiro.lime.hooks.PreventMarkAsRead;
@ -38,11 +39,12 @@ import io.github.hiro.lime.hooks.Ringtone;
import io.github.hiro.lime.hooks.SendMuteMessage;
import io.github.hiro.lime.hooks.SpoofAndroidId;
import io.github.hiro.lime.hooks.SpoofUserAgent;
import io.github.hiro.lime.hooks.Test;
import io.github.hiro.lime.hooks.UnsentRec;
import io.github.hiro.lime.hooks.Archived;
import io.github.hiro.lime.hooks.ReadChecker;
import io.github.hiro.lime.hooks.NaviColor;
import io.github.hiro.lime.hooks.test;
public class Main implements IXposedHookLoadPackage, IXposedHookInitPackageResources, IXposedHookZygoteInit {
@ -82,7 +84,8 @@ public class Main implements IXposedHookLoadPackage, IXposedHookInitPackageResou
new KeepUnreadLSpatch(),
new AutomaticBackup(),
new RemoveNotification(),
// new test(),
///new MyHook(),
new Test()
};
public void handleLoadPackage(@NonNull XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {

View File

@ -314,7 +314,9 @@ public class ReadChecker implements IHook {
private void fetchDataAndSave(SQLiteDatabase db3, SQLiteDatabase db4, String paramValue) {
// param1, param2, param3をそれぞれ抽出
if (paramValue == null) {
return;
}
String serverId = extractServerId(paramValue);
String checkedUser = extractCheckedUser(paramValue);

View File

@ -0,0 +1,336 @@
package io.github.hiro.lime.hooks;
import android.content.Context;
import android.os.Bundle;
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);
// hookAllClasses(loadPackageParam.classLoader, loadPackageParam);
// hookFragmentOnCreateView(loadPackageParam.classLoader);
//hookChatHistoryActivity(loadPackageParam.classLoader); // ChatHistoryActivityのフック
//hookLongClickListeners(loadPackageParam.classLoader); // 長押しリスナーのフック
}
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());
}
}
// jp.naver.line.android.activity.chathistory.ChatHistoryActivityをフックするメソッドを追加
private void hookChatHistoryActivity(ClassLoader classLoader) {
try {
Class<?> chatHistoryActivityClass = Class.forName("jp.naver.line.android.activity.chathistory.ChatHistoryActivity", false, classLoader);
Method onCreateMethod = chatHistoryActivityClass.getDeclaredMethod("onCreate", Bundle.class);
XposedBridge.hookMethod(onCreateMethod, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log("ChatHistoryActivity onCreate called");
// 必要に応じて追加の処理を行う
}
});
} catch (ClassNotFoundException e) {
XposedBridge.log("Class not found: jp.naver.line.android.activity.chathistory.ChatHistoryActivity");
} catch (NoSuchMethodException e) {
XposedBridge.log("Method not found: onCreate in ChatHistoryActivity");
} catch (Throwable e) {
XposedBridge.log("Error hooking onCreate in ChatHistoryActivity: " + e.getMessage());
}
}
// 長押しリスナーをフックするメソッドを追加
private void hookLongClickListeners(ClassLoader classLoader) {
try {
// 長押しリスナーを持つビューのクラスを取得
Class<?> viewClass = Class.forName("android.view.View", false, classLoader);
Method setOnLongClickListenerMethod = viewClass.getDeclaredMethod("setOnLongClickListener", View.OnLongClickListener.class);
XposedBridge.hookMethod(setOnLongClickListenerMethod, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
View.OnLongClickListener listener = (View.OnLongClickListener) param.args[0];
XposedBridge.log("Setting OnLongClickListener: " + listener.getClass().getName());
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
// 実際の長押しイベント処理のための追加処理が必要な場合
XposedBridge.log("OnLongClickListener set on view.");
}
});
} catch (ClassNotFoundException e) {
XposedBridge.log("Class not found: android.view.View");
} catch (NoSuchMethodException e) {
XposedBridge.log("Method not found: setOnLongClickListener in View");
} catch (Throwable e) {
XposedBridge.log("Error hooking setOnLongClickListener: " + 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())) {
XposedBridge.log("Skipping abstract method: " + method.getName() + " in class: " + clazz.getName());
continue;
}
if (!isViewRelatedMethod(method)) {
continue;
}
try {
XposedBridge.hookMethod(method, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
String methodName = method.getName();
String className = clazz.getName();
Object[] args = param.args;
StringBuilder argsString = new StringBuilder();
for (Object arg : args) {
argsString.append(arg).append(", ");
}
XposedBridge.log("Before calling: " + className + "." + methodName + " with args: " + argsString.toString());
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
String methodName = method.getName();
String className = clazz.getName();
XposedBridge.log("Called: " + className + "." + methodName);
// View作成メソッドの出力
if (isViewCreationMethod(method)) {
XposedBridge.log("View creation method detected: " + className + "." + methodName);
}
}
});
} catch (Throwable e) {
XposedBridge.log("Error hooking method " + method.getName() + " in class " + clazz.getName() + ": " + e.getMessage());
}
}
}
private boolean isViewRelatedMethod(Method method) {
String methodName = method.getName().toLowerCase();
String[] viewRelatedTerms = {
"view", "onclick", "setvisibility", "setenabled", "settext", "getview", "addview", "removeview"
};
for (String term : viewRelatedTerms) {
if (methodName.contains(term)) {
return true;
}
}
return false;
}
private boolean isViewCreationMethod(Method method) {
// View作成に関連するメソッドを検出
String methodName = method.getName().toLowerCase();
return methodName.contains("inflate") || methodName.contains("new") || methodName.contains("create");
}
}

View File

@ -1,163 +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 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 {
@Override
public void hook(LimeOptions limeOptions, XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
String packageName = loadPackageParam.packageName;
XposedBridge.log("Hooking package: " + packageName);
hookAllClasses(loadPackageParam.classLoader, loadPackageParam);
hookFragmentOnCreateView(loadPackageParam.classLoader);
}
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 afterHookedMethod(MethodHookParam param) throws Throwable {
ViewGroup rootView = (ViewGroup) param.getResult(); // ルートのViewGroupを取得
Context context = rootView.getContext();
int messageContainerId = getIdByName(context, "message_context_menu_content_container");
View messageContainer = rootView.findViewById(messageContainerId);
if (messageContainer instanceof ViewGroup) {
Button button = new Button(context);
button.setText("New Button");
button.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
));
((ViewGroup) messageContainer).addView(button);
XposedBridge.log("Button added to message_context_menu_content_container");
XposedBridge.log("Current child count: " + ((ViewGroup) messageContainer).getChildCount());
} else {
XposedBridge.log("messageContainer is not an instance of ViewGroup");
}
}
});
} 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 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())) {
// XposedBridge.log("Skipping abstract method: " + method.getName() + " in class: " + clazz.getName());
continue;
}
if (!isViewRelatedMethod(method)) {
continue;
}
try {
XposedBridge.hookMethod(method, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
String methodName = method.getName();
String className = clazz.getName();
Object[] args = param.args;
StringBuilder argsString = new StringBuilder();
for (Object arg : args) {
argsString.append(arg).append(", ");
}
XposedBridge.log("Before calling: " + className + "." + methodName + " with args: " + argsString.toString());
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
String methodName = method.getName();
String className = clazz.getName();
XposedBridge.log("Called: " + className + "." + methodName);
}
});
} catch (Throwable e) {
// XposedBridge.log("Error hooking method " + method.getName() + " in class " + clazz.getName() + ": " + e.getMessage());
}
}
}
private boolean isViewRelatedMethod(Method method) {
String methodName = method.getName().toLowerCase();
String[] viewRelatedTerms = {
"view", "onclick", "setvisibility", "setenabled", "settext", "getview", "addview", "removeview"
};
for (String term : viewRelatedTerms) {
if (methodName.contains(term)) {
return true;
}
}
return false;
}
}