feat:框架测试正常
This commit is contained in:
parent
e46e6bacf8
commit
17304cf0f0
16
README.md
16
README.md
@ -20,36 +20,52 @@
|
||||
|
||||
> 公共类
|
||||
- commons
|
||||
|
||||
> 统一日志类
|
||||
- Logger
|
||||
|
||||
> 入口类
|
||||
- entry
|
||||
|
||||
> Hook第一层入口(包括免重启等功能)
|
||||
- BaseEntry
|
||||
|
||||
> Hook逻辑入口,由第一层入口加载,包含具体的Hook逻辑
|
||||
- RealEntry
|
||||
|
||||
> 事件处理类
|
||||
- handlers
|
||||
|
||||
> 基础处理类
|
||||
- BaseHandler
|
||||
|
||||
> 测试类
|
||||
- KuaishouHandler
|
||||
|
||||
> 初始化管理类
|
||||
- initialization
|
||||
|
||||
> 基础初始化类
|
||||
- BaseInit
|
||||
|
||||
> 注册类,管理与Sekiro服务端通信
|
||||
- Register
|
||||
|
||||
> 工具类
|
||||
- utils
|
||||
|
||||
> 类查询助手
|
||||
- ClassesReaderAssistant
|
||||
|
||||
> 通信助手
|
||||
- CommunicationAssistant
|
||||
|
||||
> 算法助手
|
||||
- AlgorithmAssistant
|
||||
|
||||
> 配置文件助手
|
||||
- PropertiesAssistant
|
||||
|
||||
- Config
|
||||
|
||||
## Install
|
||||
|
||||
@ -1 +0,0 @@
|
||||
Headwolf
|
||||
@ -1,116 +0,0 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<codeStyleSettings language="XML">
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<rules>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:android</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:id</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>style</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
@ -11,6 +11,7 @@
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
<option value="$PROJECT_DIR$/mmkv-static-1.1.2" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
|
||||
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RunConfigurationProducerService">
|
||||
<option name="ignoredProducers">
|
||||
<set>
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
@ -20,15 +20,26 @@ android {
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
exclude 'META-INF/INDEX.LIST'
|
||||
exclude 'META-INF/io.netty.versions.properties'
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
|
||||
}
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
implementation 'com.google.code.gson:gson:2.8.6'
|
||||
implementation 'com.virjar:sekiro-api:1.0.2'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
implementation project(':mmkv-static-1.1.2')
|
||||
compileOnly 'de.robv.android.xposed:api:82'
|
||||
compileOnly 'de.robv.android.xposed:api:82:sources'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
package="com.lateautumn4lin.headwolf">
|
||||
|
||||
<application
|
||||
android:name=".MyApplication"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
@ -16,6 +17,20 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- 是否是xposed模块,xposed根据这个来判断是否是模块 -->
|
||||
<meta-data
|
||||
android:name="xposedmodule"
|
||||
android:value="true" />
|
||||
|
||||
<!-- 模块描述,显示在xposed模块列表那里第二行 -->
|
||||
<meta-data
|
||||
android:name="xposeddescription"
|
||||
android:value="基于Xposed和Sekiro搭建的敏捷开发的脚手架" />
|
||||
|
||||
<!-- 最低xposed版本号(lib文件名可知) -->
|
||||
<meta-data
|
||||
android:name="xposedminversion"
|
||||
android:value="30" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@ -1,6 +1,4 @@
|
||||
remote_server=192.144.152.23
|
||||
wechat_remote_server=182.92.212.44
|
||||
group_kuaishou_name=ks_group2
|
||||
group_taobao_name=tb_group2
|
||||
group_douyin_name=dy_group2
|
||||
group_wechat_name=wc_group2
|
||||
package_name=com.lateautumn4lin.headwolf
|
||||
package_kuaishou=com.smile.gifmaker
|
||||
package_pdd=com.xunmeng.pinduoduo
|
||||
@ -1 +1 @@
|
||||
com.lateautumn4lin.sign.entry.HookLoader
|
||||
com.lateautumn4lin.headwolf.entry.BaseEntry
|
||||
@ -7,5 +7,137 @@ package com.lateautumn4lin.headwolf;
|
||||
* @date 2020/9/10 13:40
|
||||
*/
|
||||
|
||||
import com.lateautumn4lin.headwolf.commons.Logger;
|
||||
import com.lateautumn4lin.headwolf.handlers.KuaishouHandler;
|
||||
import com.lateautumn4lin.headwolf.utils.PropertiesAssistant;
|
||||
import com.virjar.sekiro.api.SekiroRequestHandler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
|
||||
/**
|
||||
* The type Config.
|
||||
*/
|
||||
public class Config {
|
||||
private static Properties propertiesAssistant = PropertiesAssistant.getProperties();
|
||||
private static List<SekiroRequestHandler> handlers = asList(
|
||||
(SekiroRequestHandler) new KuaishouHandler()
|
||||
);
|
||||
|
||||
private static HashMap<String, SekiroRequestHandler> handlers_map = GenerateHandlersMap();
|
||||
|
||||
private static HashMap<String, SekiroRequestHandler> GenerateHandlersMap() {
|
||||
HashMap<String, SekiroRequestHandler> map = new HashMap<String, SekiroRequestHandler>();
|
||||
for (SekiroRequestHandler obj : handlers) {
|
||||
map.put(obj.getClass().getName(), obj);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private static String client_id = null;
|
||||
/**
|
||||
* The Groups.
|
||||
*/
|
||||
static private HashMap<String, String> groups = GetAllPackageGroups();
|
||||
|
||||
/**
|
||||
* Get package name string.
|
||||
*
|
||||
* @return the string
|
||||
*/
|
||||
public static String GetPackageName() {
|
||||
Properties propertiesAssistant = PropertiesAssistant.getProperties();
|
||||
return propertiesAssistant.getProperty("package_name");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets remote server.
|
||||
*
|
||||
* @return the remote server
|
||||
*/
|
||||
public static String getRemoteServer() {
|
||||
return propertiesAssistant.getProperty("remote_server");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets client id.
|
||||
*
|
||||
* @return the client id
|
||||
*/
|
||||
public static String getClientId() {
|
||||
if (client_id == null) {
|
||||
String s = UUID.randomUUID().toString();
|
||||
Config.client_id = s.substring(0, 8) + s.substring(9, 13) + s.substring(14, 18) + s.substring(19, 23) + s.substring(24);
|
||||
}
|
||||
return client_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all package hash map.
|
||||
*
|
||||
* @return the hash map
|
||||
*/
|
||||
public static HashMap<String, String> GetAllPackageGroups() {
|
||||
Properties propertiesAssistant = PropertiesAssistant.getProperties();
|
||||
HashMap<String, String> all_package_groups = new HashMap<String, String>();
|
||||
try {
|
||||
for (String name : propertiesAssistant.stringPropertyNames()) {
|
||||
if (name.contains("package_") ^ name.contains("name")) {
|
||||
all_package_groups.put(propertiesAssistant.getProperty(name), name);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logger.loge(e.toString());
|
||||
}
|
||||
return all_package_groups;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets group.
|
||||
*
|
||||
* @param type_name the type name
|
||||
* @return the group
|
||||
*/
|
||||
public static String GetGroup(String type_name) {
|
||||
return groups.get(type_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get hook packages string.
|
||||
*
|
||||
* @return the string
|
||||
*/
|
||||
public static List<String> GetHookPackages() {
|
||||
Properties propertiesAssistant = PropertiesAssistant.getProperties();
|
||||
List<String> inner_hook_packages = new ArrayList<String>();
|
||||
try {
|
||||
for (String name : propertiesAssistant.stringPropertyNames()) {
|
||||
if (name.contains("package_") ^ name.contains("name")) {
|
||||
inner_hook_packages.add(propertiesAssistant.getProperty(name));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logger.loge(e.toString());
|
||||
}
|
||||
return inner_hook_packages;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get hanler instance list.
|
||||
*
|
||||
* @param class_name the class name
|
||||
* @return the list
|
||||
*/
|
||||
public static SekiroRequestHandler GetHanlerInstance(String class_name) {
|
||||
return handlers_map.get(class_name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,11 +4,29 @@ import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.lateautumn4lin.headwolf.commons.Logger;
|
||||
import com.tencent.mmkv.MMKV;
|
||||
|
||||
|
||||
/**
|
||||
* The type Main activity.
|
||||
*/
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
Logger.logi("StartUp MainActivity");
|
||||
// try {
|
||||
// String rootDir = MMKV.initialize("/data/user/0/com.lateautumn4lin.headwolf/files/mmkv");
|
||||
// MMKV kv = MMKV.mmkvWithID("test", MMKV.MULTI_PROCESS_MODE);
|
||||
// Logger.logi("mmkv root: " + rootDir);
|
||||
// kv.encode("string", "Hello from mmkv");
|
||||
// String str = kv.decodeString("string");
|
||||
// Logger.logi("Get MMKV:" + str);
|
||||
// } catch (Exception e) {
|
||||
// Logger.loge(e.toString());
|
||||
// }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.lateautumn4lin.headwolf;
|
||||
/*
|
||||
* MyApplication
|
||||
*
|
||||
* @author lateautumn4lin
|
||||
* @github https://github.com/lateautumn4lin
|
||||
* @date 2020/9/12 3:12
|
||||
*/
|
||||
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
import com.lateautumn4lin.headwolf.commons.Logger;
|
||||
|
||||
public class MyApplication extends Application {
|
||||
private static Context context;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
context = getApplicationContext();
|
||||
Logger.logi(String.format("StartUp MyApplication And Get Context %s", context));
|
||||
}
|
||||
|
||||
public static Context getContext() {
|
||||
return context;
|
||||
}
|
||||
}
|
||||
@ -7,5 +7,64 @@ package com.lateautumn4lin.headwolf.commons;
|
||||
* @date 2020/9/10 13:54
|
||||
*/
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* The type Logger.
|
||||
*/
|
||||
public class Logger {
|
||||
private Logger() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The constant TAG.
|
||||
*/
|
||||
public static final String TAG = "headwolf";
|
||||
|
||||
/**
|
||||
* Logi.
|
||||
*
|
||||
* @param msg the msg
|
||||
*/
|
||||
public static void logi(String msg) {
|
||||
Log.i(TAG, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loge.
|
||||
*
|
||||
* @param msg the msg
|
||||
*/
|
||||
public static void loge(String msg) {
|
||||
Log.e(TAG, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logw.
|
||||
*
|
||||
* @param msg the msg
|
||||
*/
|
||||
public static void logw(String msg) {
|
||||
Log.w(TAG, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logd.
|
||||
*
|
||||
* @param msg the msg
|
||||
*/
|
||||
public static void logd(String msg) {
|
||||
Log.d(TAG, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logv.
|
||||
*
|
||||
* @param msg the msg
|
||||
*/
|
||||
public static void logv(String msg) {
|
||||
Log.v(TAG, msg);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -7,5 +7,111 @@ package com.lateautumn4lin.headwolf.entry;
|
||||
* @date 2020/9/10 13:45
|
||||
*/
|
||||
|
||||
public class BaseEntry {
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
import com.lateautumn4lin.headwolf.Config;
|
||||
import com.lateautumn4lin.headwolf.commons.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import dalvik.system.PathClassLoader;
|
||||
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;
|
||||
|
||||
/**
|
||||
* The type Base entry. 第一层Hook入口
|
||||
*/
|
||||
public class BaseEntry implements IXposedHookLoadPackage {
|
||||
private String modulePackage = null;
|
||||
private static List<String> hookPackages = null;
|
||||
private final String handleHookClass = RealEntry.class.getName();
|
||||
private final String handleHookMethod = "handleLoadPackage";
|
||||
|
||||
@Override
|
||||
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
|
||||
try {
|
||||
// 延迟初始化静态变量
|
||||
if (modulePackage == null) {
|
||||
modulePackage = Config.GetPackageName();
|
||||
}
|
||||
if (hookPackages == null) {
|
||||
hookPackages = Config.GetHookPackages();
|
||||
}
|
||||
// 包含配置文件中配置的包名则进入真正Hook逻辑
|
||||
if (hookPackages.contains(loadPackageParam.packageName)) {
|
||||
try {
|
||||
XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() {
|
||||
@Override
|
||||
protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {
|
||||
Logger.logi(String.format("Get Needed Hook Package:%s", loadPackageParam.packageName));
|
||||
Context context = (Context) param.args[0];
|
||||
loadPackageParam.classLoader = context.getClassLoader();
|
||||
invokeHandleHookMethod(context, modulePackage, handleHookClass, handleHookMethod, loadPackageParam);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Logger.loge(String.format("Invoke Hook Method Error, Package:%s", loadPackageParam.packageName));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logger.loge(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke handle hook method.
|
||||
*
|
||||
* @param context the context
|
||||
* @param modulePackageName the module package name
|
||||
* @param handleHookClass the handle hook class
|
||||
* @param handleHookMethod the handle hook method
|
||||
* @param loadPackageParam the load package param
|
||||
* @throws Throwable the throwable
|
||||
*/
|
||||
private void invokeHandleHookMethod(Context context, String modulePackageName, String handleHookClass, String handleHookMethod, XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
|
||||
try {
|
||||
File apkFile = findApkFile(context, modulePackageName);
|
||||
if (apkFile == null) {
|
||||
throw new RuntimeException("Find Apk File Error");
|
||||
}
|
||||
Logger.logi(String.format("Get Apk File:%s", apkFile.toString()));
|
||||
PathClassLoader pathClassLoader = new PathClassLoader(apkFile.getAbsolutePath(), XposedBridge.BOOTCLASSLOADER);
|
||||
Class<?> cls = Class.forName(handleHookClass, true, pathClassLoader);
|
||||
Logger.logi(String.format("Get ClassLoader:%s", apkFile.toString()));
|
||||
Object instance = cls.newInstance();
|
||||
Method method = cls.getDeclaredMethod(handleHookMethod, XC_LoadPackage.LoadPackageParam.class);
|
||||
Logger.logi(String.format("Get Needed Hook Method:%s", apkFile.toString()));
|
||||
method.invoke(instance, loadPackageParam);
|
||||
} catch (Exception e) {
|
||||
Logger.loge(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find apk file file. 获取需要Hook Apk文件地址
|
||||
*
|
||||
* @param context the context
|
||||
* @param modulePackageName the module package name
|
||||
* @return the file
|
||||
*/
|
||||
private File findApkFile(Context context, String modulePackageName) {
|
||||
if (context == null) {
|
||||
throw new RuntimeException("Can't Get Context");
|
||||
}
|
||||
try {
|
||||
Context moudleContext = context.createPackageContext(modulePackageName, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
|
||||
String apkPath = moudleContext.getPackageCodePath();
|
||||
return new File(apkPath);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Logger.loge(String.format("Find File Error,Package:%s", modulePackageName));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,5 +7,45 @@ package com.lateautumn4lin.headwolf.entry;
|
||||
* @date 2020/9/10 13:45
|
||||
*/
|
||||
|
||||
public class RealEntry {
|
||||
import android.content.Context;
|
||||
|
||||
import com.lateautumn4lin.headwolf.commons.Logger;
|
||||
import com.lateautumn4lin.headwolf.initialization.Register;
|
||||
import com.lateautumn4lin.headwolf.utils.ClassesReaderAssistant;
|
||||
import com.virjar.sekiro.api.SekiroRequestHandler;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import de.robv.android.xposed.IXposedHookLoadPackage;
|
||||
import de.robv.android.xposed.XposedHelpers;
|
||||
import de.robv.android.xposed.callbacks.XC_LoadPackage;
|
||||
|
||||
/**
|
||||
* The type Real entry.
|
||||
*/
|
||||
public class RealEntry implements IXposedHookLoadPackage {
|
||||
@Override
|
||||
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
|
||||
try {
|
||||
Logger.logi(String.format("Begin Real Hook Logic About:%s", loadPackageParam.packageName));
|
||||
// step1:获取context
|
||||
Context context = (Context) XposedHelpers.callMethod(
|
||||
XposedHelpers.callStaticMethod(
|
||||
XposedHelpers.findClass(
|
||||
"android.app.ActivityThread",
|
||||
loadPackageParam.classLoader
|
||||
),
|
||||
"currentActivityThread"
|
||||
),
|
||||
"getSystemContext"
|
||||
);
|
||||
// step2:获取包名对应的需要注册的handler以及home_class
|
||||
Class HomeClass = loadPackageParam.classLoader.loadClass("com.yxcorp.gifshow.HomeActivity");
|
||||
HashMap<String, SekiroRequestHandler> associate_handlers = ClassesReaderAssistant.reader(context, loadPackageParam.packageName);
|
||||
// step3:由注册类进行handler注册
|
||||
Register.GroupRegister(loadPackageParam, HomeClass, associate_handlers);
|
||||
} catch (Exception e) {
|
||||
Logger.loge(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,5 +7,24 @@ package com.lateautumn4lin.headwolf.handlers;
|
||||
* @date 2020/9/10 13:44
|
||||
*/
|
||||
|
||||
public class BaseHandler {
|
||||
|
||||
/**
|
||||
* The type Base handler.
|
||||
*/
|
||||
public abstract class BaseHandler {
|
||||
/**
|
||||
* Gets belong.
|
||||
*
|
||||
* @return the belong
|
||||
*/
|
||||
public abstract String getBelong();
|
||||
|
||||
/**
|
||||
* Gets action.
|
||||
*
|
||||
* @return the action
|
||||
*/
|
||||
public abstract String getAction();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -7,5 +7,43 @@ package com.lateautumn4lin.headwolf.handlers;
|
||||
* @date 2020/9/10 15:39
|
||||
*/
|
||||
|
||||
public class KuaishouHandler {
|
||||
import com.google.gson.Gson;
|
||||
import com.virjar.sekiro.api.SekiroRequest;
|
||||
import com.virjar.sekiro.api.SekiroRequestHandler;
|
||||
import com.virjar.sekiro.api.SekiroResponse;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The type Kuaishou handler.
|
||||
*/
|
||||
public class KuaishouHandler implements SekiroRequestHandler {
|
||||
/**
|
||||
* Gets belong.
|
||||
*
|
||||
* @return the belong
|
||||
*/
|
||||
public String getBelong() {
|
||||
return "com.smile.gifmaker";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets action.
|
||||
*
|
||||
* @return the action
|
||||
*/
|
||||
public String getAction() {
|
||||
return "sign";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handleRequest(SekiroRequest sekiroRequest, SekiroResponse sekiroResponse) {
|
||||
Gson gson = new Gson();
|
||||
Map<String, String> object = new HashMap<String, String>();
|
||||
String name = sekiroRequest.getString("name");
|
||||
object.put("name", name);
|
||||
sekiroResponse.send(gson.toJson(object));
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,5 +7,8 @@ package com.lateautumn4lin.headwolf.initialization;
|
||||
* @date 2020/9/10 13:49
|
||||
*/
|
||||
|
||||
/**
|
||||
* The type Base init.
|
||||
*/
|
||||
public class BaseInit {
|
||||
}
|
||||
|
||||
@ -7,5 +7,65 @@ package com.lateautumn4lin.headwolf.initialization;
|
||||
* @date 2020/9/10 13:49
|
||||
*/
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.lateautumn4lin.headwolf.Config;
|
||||
import com.lateautumn4lin.headwolf.commons.Logger;
|
||||
import com.virjar.sekiro.api.SekiroClient;
|
||||
import com.virjar.sekiro.api.SekiroRequestHandler;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import de.robv.android.xposed.XC_MethodHook;
|
||||
import de.robv.android.xposed.XposedHelpers;
|
||||
import de.robv.android.xposed.callbacks.XC_LoadPackage;
|
||||
|
||||
/**
|
||||
* The type Register.
|
||||
*/
|
||||
public class Register {
|
||||
/**
|
||||
* Base register boolean.
|
||||
*
|
||||
* @param loadPackageParam the load package param
|
||||
* @param home_class the home class
|
||||
* @param associate_handlers the associate handlers
|
||||
* @return the boolean
|
||||
*/
|
||||
public static Boolean GroupRegister(final XC_LoadPackage.LoadPackageParam loadPackageParam, Class home_class, final HashMap<String, SekiroRequestHandler> associate_handlers) {
|
||||
final String group_name = Config.GetGroup(loadPackageParam.packageName);
|
||||
try {
|
||||
XposedHelpers.findAndHookMethod(home_class, "onCreate", Bundle.class, new XC_MethodHook() {
|
||||
@Override
|
||||
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
|
||||
Logger.logi(String.format("Group Register:%s Begin ClientId:%s", group_name, Config.getClientId()));
|
||||
final SekiroClient sekiroClient = SekiroClient.start(
|
||||
Config.getRemoteServer(),
|
||||
Config.getClientId(),
|
||||
group_name
|
||||
);
|
||||
try {
|
||||
for (Map.Entry<String, SekiroRequestHandler> entry : associate_handlers.entrySet()) {
|
||||
try {
|
||||
SekiroRequestHandler handler = entry.getValue();
|
||||
sekiroClient.registerHandler(entry.getKey(), handler);
|
||||
Logger.logi(String.format("Group Register Group:%s Action:%s Handler:%s Success ClientId:%s", group_name, entry.getKey(), handler, Config.getClientId()));
|
||||
} catch (Exception e) {
|
||||
Logger.loge(e.toString());
|
||||
}
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logger.loge(e.toString());
|
||||
}
|
||||
super.afterHookedMethod(param);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Logger.loge(String.format("Group Register Error ClientId:%s", Config.getClientId()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,38 +11,38 @@ package com.lateautumn4lin.headwolf.utils;
|
||||
import android.content.Context;
|
||||
|
||||
|
||||
import com.lateautumn4lin.headwolf.Config;
|
||||
import com.lateautumn4lin.headwolf.commons.Logger;
|
||||
import com.virjar.sekiro.api.SekiroRequestHandler;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import dalvik.system.DexFile;
|
||||
import dalvik.system.PathClassLoader;
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
|
||||
|
||||
/**
|
||||
* 类读取器<br/>
|
||||
* 读取某个包下所有类<br/>
|
||||
* The type Classes reader assistant.
|
||||
*/
|
||||
public final class ClassesReaderAssistant {
|
||||
|
||||
/**
|
||||
* 获取应用程序下的所有Dex文件
|
||||
*
|
||||
* @param context 上下文
|
||||
* @return Set<DexFile> set
|
||||
*/
|
||||
public static Set<DexFile> applicationDexFile(Context context) {
|
||||
return applicationDexFile(context.getPackageCodePath());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用程序下的所有Dex文件
|
||||
* Application dex file set.
|
||||
*
|
||||
* @param packageCodePath 包路径
|
||||
* @return Set<DexFile> set
|
||||
* @param packageCodePath the package code path
|
||||
* @return the set
|
||||
*/
|
||||
public static Set<DexFile> applicationDexFile(String packageCodePath) {
|
||||
Set<DexFile> dexFiles = new HashSet<>();
|
||||
@ -64,11 +64,12 @@ public final class ClassesReaderAssistant {
|
||||
return dexFiles;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 创建DexFile文件
|
||||
* Create dex file dex file.
|
||||
*
|
||||
* @param path 路径
|
||||
* @return DexFile dex file
|
||||
* @param path the path
|
||||
* @return the dex file
|
||||
*/
|
||||
public static DexFile createDexFile(String path) {
|
||||
try {
|
||||
@ -78,42 +79,78 @@ public final class ClassesReaderAssistant {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取类路径下的所有类
|
||||
*
|
||||
* @param packageName 包名
|
||||
* @param context 包路径
|
||||
* @return List<Class> list
|
||||
*/
|
||||
public static List<Class<?>> reader(String packageName, Context context) {
|
||||
return reader(packageName, context.getPackageCodePath());
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取类路径下的所有类
|
||||
* Reader hash map.
|
||||
*
|
||||
* @param packageName 包名
|
||||
* @param packageCodePath 上下文
|
||||
* @return List<Class> list
|
||||
* @param context the context
|
||||
* @param associateName the associate name
|
||||
* @return the hash map
|
||||
*/
|
||||
public static HashMap<String, SekiroRequestHandler> reader(Context context, String associateName) {
|
||||
String packageName = String.format("%s.handlers", Config.GetPackageName());
|
||||
HashMap<String, SekiroRequestHandler> associate_handlers = new HashMap<String, SekiroRequestHandler>();
|
||||
try {
|
||||
Context moudleContext = context.createPackageContext(Config.GetPackageName(), Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
|
||||
List<Class<?>> associate_classes = reader(packageName, moudleContext.getPackageCodePath());
|
||||
for (Class<?> cls : associate_classes)
|
||||
try {
|
||||
Logger.logi(String.format("%s,get", cls.getName()));
|
||||
if (cls.getName().equals(String.format("%s.BaseHandler", packageName))) {
|
||||
continue;
|
||||
}
|
||||
Constructor constructor = cls.getConstructor();
|
||||
Object instance = constructor.newInstance();
|
||||
Method getBelong = cls.getDeclaredMethod("getBelong");
|
||||
Object belong_name = getBelong.invoke(instance);
|
||||
Logger.logi(String.format("%s Compare %s", belong_name, associateName));
|
||||
if (((String) belong_name).equals(associateName)) {
|
||||
Method getAction = cls.getDeclaredMethod("getAction");
|
||||
Object action = getAction.invoke(instance);
|
||||
associate_handlers.put((String) action, Config.GetHanlerInstance(cls.getName()));
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
Logger.loge(String.format("Can't Find Method:getBelong For %s", packageName));
|
||||
} catch (Exception e) {
|
||||
Logger.loge(e.toString());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logger.loge(e.toString());
|
||||
}
|
||||
return associate_handlers;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reader list.
|
||||
*
|
||||
* @param packageName the package name
|
||||
* @param packageCodePath the package code path
|
||||
* @return the list
|
||||
*/
|
||||
public static List<Class<?>> reader(String packageName, String packageCodePath) {
|
||||
List<Class<?>> classes = new ArrayList<>();
|
||||
Set<DexFile> dexFiles = applicationDexFile(packageCodePath);
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
for (DexFile dexFile : dexFiles) {
|
||||
if (dexFile == null) continue;
|
||||
Enumeration<String> entries = dexFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
try {
|
||||
String currentClassPath = entries.nextElement();
|
||||
if (currentClassPath == null || currentClassPath.isEmpty() || currentClassPath.indexOf(packageName) != 0)
|
||||
continue;
|
||||
Class<?> entryClass = Class.forName(currentClassPath, true, classLoader);
|
||||
if (entryClass == null) continue;
|
||||
classes.add(entryClass);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Logger.logi(dexFile.toString());
|
||||
try {
|
||||
PathClassLoader pathClassLoader = new PathClassLoader(new File(packageCodePath).getAbsolutePath(), XposedBridge.BOOTCLASSLOADER);
|
||||
if (dexFile == null) continue;
|
||||
Enumeration<String> entries = dexFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
try {
|
||||
String currentClassPath = entries.nextElement();
|
||||
if (currentClassPath == null || currentClassPath.isEmpty() || currentClassPath.indexOf(packageName) != 0)
|
||||
continue;
|
||||
Class<?> entryClass = Class.forName(currentClassPath, true, pathClassLoader);
|
||||
if (entryClass == null) continue;
|
||||
classes.add(entryClass);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logger.loge(e.toString());
|
||||
}
|
||||
}
|
||||
return classes;
|
||||
|
||||
@ -7,5 +7,8 @@ package com.lateautumn4lin.headwolf.utils;
|
||||
* @date 2020/9/10 13:54
|
||||
*/
|
||||
|
||||
/**
|
||||
* The type Communication assistant.
|
||||
*/
|
||||
public class CommunicationAssistant {
|
||||
}
|
||||
|
||||
@ -1,13 +1,23 @@
|
||||
package com.lateautumn4lin.headwolf.utils;
|
||||
|
||||
import com.lateautumn4lin.headwolf.commons.Logger;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
public class ProperTies {
|
||||
/**
|
||||
* The type Properties assistant.
|
||||
*/
|
||||
public class PropertiesAssistant {
|
||||
/**
|
||||
* Gets properties.
|
||||
*
|
||||
* @return the properties
|
||||
*/
|
||||
public static Properties getProperties() {
|
||||
Properties props = new Properties();
|
||||
InputStream in = ProperTies.class.getResourceAsStream("/assets/config");
|
||||
try {
|
||||
InputStream in = PropertiesAssistant.class.getResourceAsStream("/assets/config");
|
||||
props.load(in);
|
||||
} catch (Exception e) {
|
||||
Logger.loge(e.toString());
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World!"
|
||||
android:text="来Github提Issue、提Pr!"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">Headwolf</string>
|
||||
<string name="app_name">Headwolf框架</string>
|
||||
</resources>
|
||||
|
||||
@ -3,9 +3,10 @@
|
||||
buildscript {
|
||||
|
||||
repositories {
|
||||
maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
|
||||
google()
|
||||
jcenter()
|
||||
|
||||
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.6.1'
|
||||
@ -20,6 +21,9 @@ allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
maven { url "https://jitpack.io" }
|
||||
maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
2
headwolf/mmkv-static-1.1.2/build.gradle
Normal file
2
headwolf/mmkv-static-1.1.2/build.gradle
Normal file
@ -0,0 +1,2 @@
|
||||
configurations.maybeCreate("default")
|
||||
artifacts.add("default", file('mmkv-static-1.1.2.aar'))
|
||||
@ -1,2 +1,2 @@
|
||||
rootProject.name='Headwolf'
|
||||
include ':app'
|
||||
include ':app', ':mmkv-static-1.1.2'
|
||||
|
||||
Loading…
Reference in New Issue
Block a user