blackClassList;
35 |
36 | //耗时起点方法 (不传就从范围内调用的第一个方法开始统计耗时,格式包名+$+类名+$+方法名)
37 | @Nullable
38 | public String timeStartMethod;
39 |
40 | @Nullable
41 | public String logTag;
42 |
43 | @Override
44 | public String toString() {
45 | return "TrackMethodStack{" +
46 | "enable=" + enable +
47 | ", targetPackageList=" + targetPackageList +
48 | ", targetClassList=" + targetClassList +
49 | ", blackPackageList=" + blackPackageList +
50 | ", blackClassList=" + blackClassList +
51 | ", timeStartMethod='" + timeStartMethod + '\'' +
52 | ", logTag='" + logTag + '\'' +
53 | '}';
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/XerathLib/src/main/java/com/ng/xerathlib/hook/target/plug/TargetPlugCreator.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerathlib.hook.target.plug;
2 |
3 | import com.android.annotations.NonNull;
4 | import com.android.annotations.Nullable;
5 | import com.ng.xerathlib.hook.target.base.ITargetPlug;
6 | import com.ng.xerathlib.utils.LogUtil;
7 | import org.apache.http.util.TextUtils;
8 |
9 | /**
10 | * 描述:
11 | * plug构建规则
12 | */
13 | public final class TargetPlugCreator {
14 |
15 | @Nullable
16 | public static ITargetPlug getPlug(String className) {
17 | if (TextUtils.isEmpty(className)) {
18 | return null;
19 | }
20 | return TargetPlugCreator.createPlug(className);
21 | }
22 |
23 | /**
24 | * 判断当前类/(方法待做)是否需要修改
25 | * [ Xerath ] --- 开始 hook className: com.ng.xerath.func.DataMethodUtil
26 | * [ Xerath ] XerathHookHelper-onVisitClass-清空
27 | *
28 | * [ Xerath ] className: com/ng/xerath/func/DataMethodUtil
29 | *
30 | * [ Xerath ] targetClassList: [DataMethodUtil]
31 | * [ Xerath ] targetPackageList: [com.ng.xerath.asm.func]
32 | */
33 | @Nullable
34 | public static ITargetPlug createPlug(@NonNull String owner) {
35 | //LogUtil.print("TargetPlugCreator createPlug, owner:" + owner);
36 | ITargetPlug resultPlug = null;
37 | if (TargetPlugFilter.isNeedTrackMethodStack(owner)) {
38 | resultPlug = new TrackMethodStackPlug();
39 | //LogUtil.print("TargetPlugCreator 符合条件:" + owner);
40 | }
41 | return resultPlug;
42 | }
43 |
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ng/xerath/asm/ASMShow.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerath.asm;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.annotation.Nullable;
5 |
6 | import com.ng.xerathcore.CoreHelper;
7 |
8 | import org.json.JSONException;
9 | import org.json.JSONObject;
10 |
11 | /**
12 | * @author : jiangzhengnan.jzn
13 | * @creation : 2021/09/16
14 | * @description :
15 | */
16 | public class ASMShow {
17 |
18 | public void test() {
19 | // JSONObject testJson = new JSONObject();
20 | // try {
21 | // testJson.put("name", "jzn");
22 | // testJson.put("age", "26");
23 | // testJson.put("height", "178");
24 | // } catch (JSONException e) {
25 | // e.printStackTrace();
26 | // }
27 | }
28 |
29 | // @NonNull
30 | // public JSONObject put(@NonNull String name, boolean value) throws JSONException {
31 | // return null;
32 | // }
33 | //
34 | // @NonNull
35 | // public JSONObject put(@NonNull String name, double value) throws JSONException {
36 | // return null;
37 | // }
38 | //
39 | // @NonNull
40 | // public JSONObject put(@NonNull String name, int value) throws JSONException {
41 | // return null;
42 | //
43 | // }
44 | //
45 | // @NonNull
46 | // public JSONObject put(@NonNull String name, long value) throws JSONException {
47 | // return null;
48 | //
49 | // }
50 | //
51 | // @NonNull
52 | // public JSONObject putObj(@NonNull String name, @Nullable Object value) throws JSONException {
53 | // return null;
54 | // }
55 | }
56 |
--------------------------------------------------------------------------------
/XerathLib/src/main/java/com/ng/xerathlib/hook/target/base/TargetPlug.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerathlib.hook.target.base;
2 |
3 | import com.ng.xerathlib.hook.params.HookParams;
4 |
5 | import org.objectweb.asm.MethodVisitor;
6 | import org.objectweb.asm.Opcodes;
7 | import org.objectweb.asm.commons.LocalVariablesSorter;
8 |
9 | /**
10 | * 描述:
11 | *
12 | * @author Jzn
13 | * @date 2021/9/14
14 | */
15 | public abstract class TargetPlug implements ITargetPlug {
16 | // 方法返回值类型描述符
17 | protected int mMethodAccess;
18 | protected String mMethodDesc;
19 | protected String mOwner;
20 | protected String mMethodName;
21 | protected LocalVariablesSorter mAdapter;
22 |
23 | @Override
24 | public void init(HookParams params) {
25 | this.mMethodAccess = params.mMethodAccess;
26 | this.mAdapter = params.mAdapter;
27 | this.mOwner = params.mOwner;
28 | this.mMethodName = params.mMethodName;
29 | this.mMethodDesc = params.mMethodDesc;
30 | }
31 |
32 | protected boolean isStaticMethod() {
33 | return ((Opcodes.ACC_STATIC & mMethodAccess) != 0);
34 | }
35 |
36 | @Override
37 | public void onHookMethodStart(MethodVisitor mv) {
38 |
39 | }
40 |
41 | @Override
42 | public void onHookMethodReturn(int opcode, MethodVisitor mv) {
43 |
44 | }
45 |
46 | @Override
47 | public void onHookMethodEnd(MethodVisitor mv) {
48 |
49 | }
50 |
51 | @Override
52 | public boolean onVisitMethodInsn(MethodVisitor mv, int opcode, String owner, String name, String desc, boolean itf) {
53 | return false;
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/XerathLib/src/main/java/com/ng/xerathlib/hook/XerathHookManager.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerathlib.hook;
2 |
3 | import java.util.concurrent.ConcurrentHashMap;
4 |
5 | import com.android.annotations.NonNull;
6 | import com.android.annotations.Nullable;
7 | import com.ng.xerathlib.utils.LogUtil;
8 |
9 | /**
10 | * 避免多线程紊乱
11 | * 维护所有的XerathHookHelper
12 | */
13 | public class XerathHookManager {
14 | private static XerathHookManager mInstance;
15 |
16 | private XerathHookManager() {
17 | mXerathHookHelperMap = new ConcurrentHashMap<>();
18 | }
19 |
20 | public static XerathHookManager getInstance() {
21 | if (mInstance == null) {
22 | synchronized (XerathHookManager.class) {
23 | if (mInstance == null) {
24 | mInstance = new XerathHookManager();
25 | }
26 | }
27 | }
28 | return mInstance;
29 | }
30 |
31 | @NonNull
32 | private final ConcurrentHashMap mXerathHookHelperMap;
33 |
34 | @Nullable
35 | public XerathHookHelper getHelper(@Nullable String owner) {
36 | if (owner == null || owner.length() == 0) {
37 | return null;
38 | }
39 | if (mXerathHookHelperMap.get(owner) == null) {
40 | mXerathHookHelperMap.put(owner, new XerathHookHelper());
41 | }
42 | return mXerathHookHelperMap.get(owner);
43 | }
44 |
45 | public void removeHelper(@Nullable String owner) {
46 | if (owner == null || owner.length() == 0) {
47 | return;
48 | }
49 | mXerathHookHelperMap.remove(owner);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | }
4 | apply plugin: 'kotlin-android'
5 | repositories {
6 | mavenCentral()
7 | }
8 |
9 | android {
10 | compileSdkVersion 31
11 |
12 | defaultConfig {
13 | applicationId "com.ng.xerath"
14 | minSdkVersion 16
15 | targetSdkVersion 31
16 | versionCode 1
17 | versionName "1.0"
18 |
19 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
20 | }
21 |
22 | buildTypes {
23 | release {
24 | minifyEnabled false
25 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
26 | }
27 | }
28 | compileOptions {
29 | sourceCompatibility JavaVersion.VERSION_1_8
30 | targetCompatibility JavaVersion.VERSION_1_8
31 | }
32 | }
33 |
34 | dependencies {
35 |
36 | implementation 'androidx.appcompat:appcompat:1.3.1'
37 | implementation 'com.google.android.material:material:1.4.0'
38 | implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
39 |
40 | //asm
41 | implementation 'org.ow2.asm:asm:9.2'
42 | implementation 'org.ow2.asm:asm-commons:9.1'
43 |
44 | implementation "androidx.core:core-ktx:1.7.0"
45 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.31"
46 |
47 | if (project.BUILD_DEV) {
48 | api project(':XerathCore')
49 | } else {
50 | //core 引入注解依赖
51 | implementation 'com.ng.xerathlib:XerathCore:1.0.0'
52 | }
53 |
54 | implementation 'com.github.bumptech.glide:glide:4.9.0'
55 |
56 |
57 | }
58 |
59 | //引入插件
60 | apply from: project.file('plugin-rule.gradle')
61 |
--------------------------------------------------------------------------------
/XerathLib/src/main/java/com/ng/xerathlib/hook/annotation/plug/CallChainPlug.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerathlib.hook.annotation.plug;
2 |
3 | import com.ng.xerathlib.hook.annotation.plug.base.AnnotationPlug;
4 | import com.ng.xerathlib.hook.params.HookParams;
5 | import com.ng.xerathlib.utils.LogUtil;
6 |
7 | import org.objectweb.asm.Label;
8 | import org.objectweb.asm.MethodVisitor;
9 | import org.objectweb.asm.Opcodes;
10 | import org.objectweb.asm.commons.LocalVariablesSorter;
11 |
12 | /**
13 | * @author : jiangzhengnan.jzn
14 | * @creation : 2021/09/20
15 | * @description :
16 | * 完整链路hook
17 | */
18 | public class CallChainPlug extends AnnotationPlug {
19 |
20 | @Override
21 | public void init(HookParams params) {
22 | super.init(params);
23 | LogUtil.print("access:" + mParams.mMethodAccess);
24 | LogUtil.print("owner:" + mParams.mOwner);
25 | LogUtil.print("name:" + mParams.mMethodName);
26 | LogUtil.print("methodDesc:" + mParams.mMethodDesc);
27 | }
28 |
29 | @Override
30 | public void onHookMethodStart(MethodVisitor mv) {
31 | if (isStaticMethod()) {
32 | //防止静态方法下造成的crash
33 | return;
34 | }
35 | Label label0 = new Label();
36 | mv.visitLabel(label0);
37 | mv.visitLineNumber(19, label0);
38 | mv.visitVarInsn(Opcodes.ALOAD, 0);
39 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/ng/xerathcore/CoreHelper", "catchCallChain", "(Ljava/lang/Object;)V", false);
40 | }
41 |
42 | @Override
43 | public void onHookMethodReturn(int opcode, MethodVisitor mv) {
44 |
45 | }
46 |
47 | @Override
48 | public void onHookMethodEnd(MethodVisitor mv) {
49 |
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/XerathLib/src/main/java/com/ng/xerathlib/asm/jar/JarClassVisitor.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerathlib.asm.jar;
2 |
3 | import org.objectweb.asm.ClassVisitor;
4 | import org.objectweb.asm.FieldVisitor;
5 | import org.objectweb.asm.MethodVisitor;
6 | import org.objectweb.asm.Opcodes;
7 |
8 | import static org.objectweb.asm.Opcodes.ACC_INTERFACE;
9 | import static org.objectweb.asm.Opcodes.ASM6;
10 |
11 | /**
12 | * 处理jar包里的方法
13 | */
14 | public final class JarClassVisitor extends ClassVisitor {
15 | private boolean isInterface;
16 |
17 | private String owner;
18 |
19 | JarClassVisitor(final ClassVisitor cv) {
20 | super(Opcodes.ASM6, cv);
21 | }
22 |
23 | @Override
24 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
25 | super.visit(version, access, name, signature, superName, interfaces);
26 | this.owner = name;
27 | isInterface = (access & ACC_INTERFACE) != 0;
28 |
29 | }
30 |
31 | @Override
32 | public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
33 | return super.visitField(access, name, descriptor, signature, value);
34 | }
35 |
36 | @Override
37 | public MethodVisitor visitMethod(final int access, final String name,
38 | final String desc, final String signature, final String[] exceptions) {
39 | MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
40 | if (!isInterface && mv != null && !name.equals("")
41 | ) {
42 | return new JarCatchMethodVisitor(ASM6, access, owner, name, desc, signature, mv);
43 | }
44 | return mv;
45 | }
46 |
47 | @Override
48 | public void visitEnd() {
49 | super.visitEnd();
50 | }
51 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
14 |
19 |
20 |
29 |
30 |
39 |
40 |
49 |
50 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ng/xerath/ui/adapter/MyViewPagerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerath.ui.adapter;
2 |
3 | /**
4 | * 描述:
5 | *
6 | * @author Jzn
7 | * @date 2020-04-11
8 | */
9 |
10 | import android.view.ViewGroup;
11 |
12 | import androidx.annotation.NonNull;
13 | import androidx.fragment.app.Fragment;
14 | import androidx.fragment.app.FragmentManager;
15 | import androidx.fragment.app.FragmentPagerAdapter;
16 |
17 | import java.util.List;
18 |
19 | public class MyViewPagerAdapter extends FragmentPagerAdapter {
20 |
21 | private List infoLost;
22 |
23 | public void setInfoLost(List infoLost) {
24 | this.infoLost = infoLost;
25 | }
26 |
27 | public MyViewPagerAdapter(FragmentManager fm, List infoLost) {
28 | super(fm);
29 | this.infoLost = infoLost;
30 | }
31 |
32 | @Override
33 | public long getItemId(int position) {
34 | return infoLost.get(position).hashCode();
35 | }
36 |
37 |
38 | @Override
39 | public int getItemPosition(Object object) {
40 | return POSITION_NONE;
41 | }
42 |
43 | /**
44 | * 得到每个页面
45 | */
46 | @Override
47 | public Fragment getItem(int arg0) {
48 | return (infoLost == null || infoLost.size() == 0) ? null : infoLost.get(arg0).fragment;
49 | }
50 |
51 | @NonNull
52 | @Override
53 | public Object instantiateItem(@NonNull ViewGroup container, int position) {
54 | return super.instantiateItem(container, position);
55 | }
56 |
57 | /**
58 | * 每个页面的title
59 | */
60 | @Override
61 | public CharSequence getPageTitle(int position) {
62 | return (infoLost.size() > position) ? infoLost.get(position).name : "";
63 | }
64 |
65 | /**
66 | * 页面的总个数
67 | */
68 | @Override
69 | public int getCount() {
70 | return infoLost == null ? 0 : infoLost.size();
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/XerathCore/src/main/java/com/ng/xerathcore/bean/ObjectNode.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerathcore.bean;
2 |
3 |
4 | import androidx.annotation.NonNull;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | /*
10 | * Copyright (C) 2004 - 2021 UCWeb Inc. All Rights Reserved.
11 | * Description : 描述当前文件的功能和使用范围
12 | * Attention: 如果是公共类,仔细说明使用方法和注意事项:特别是一些设计上的职责边界
13 | *
14 | * Created by ksl on 2021/3/30
15 | */
16 | public class ObjectNode {
17 | private Object mSelf;
18 | private ObjectNode mParent;
19 | private String mFieldName;
20 | private List mChilds = new ArrayList<>();
21 |
22 | public void setSelf(@NonNull Object self) {
23 | mSelf = self;
24 | }
25 |
26 | public Object getSelf() {
27 | return mSelf;
28 | }
29 |
30 | public void setParent(@NonNull ObjectNode parent) {
31 | mParent = parent;
32 | }
33 |
34 | public Object getParent() {
35 | return mParent;
36 | }
37 |
38 | public void addChild(@NonNull ObjectNode child) {
39 | mChilds.add(child);
40 | }
41 |
42 | public List getChilds() {
43 | return mChilds;
44 | }
45 |
46 | public boolean isFathersObject(@NonNull Object object) {
47 | if (mSelf == object) {
48 | return true;
49 | } else if (mParent == null){
50 | return false;
51 | } else {
52 | return mParent.isFathersObject(object);
53 | }
54 | }
55 |
56 | public void setFieldName(@NonNull String fieldName) {
57 | mFieldName = fieldName;
58 | }
59 |
60 | public String getFieldName() {
61 | return mFieldName;
62 | }
63 |
64 | public String getGeneticInfo() {
65 | if (mParent == null) {
66 | return mFieldName;
67 | } else {
68 | return mParent.getGeneticInfo() + "->" + mFieldName;
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/XerathLib/src/main/groovy/com/ng/xerathlib/transform/util/TransformUtil.groovy:
--------------------------------------------------------------------------------
1 | package com.ng.xerathlib.transform.util
2 |
3 | import com.android.build.api.transform.Format
4 | import com.android.build.api.transform.JarInput
5 | import com.android.build.api.transform.TransformOutputProvider
6 | import com.android.utils.FileUtils
7 | import org.apache.commons.codec.digest.DigestUtils
8 | /**
9 | * Transform工具类
10 | */
11 | class TransformUtil {
12 |
13 | //默认排除
14 | public static final DEFAULT_EXCLUDE = [
15 | '^android\\..*',
16 | '^androidx\\..*',
17 | '.*\\.R$',
18 | '.*\\.R\\$.*$',
19 | '.*\\.BuildConfig$',
20 | ]
21 |
22 | //获取类名
23 | static String getClassName(String root, String classPath) {
24 | return classPath.substring(root.length() + 1, classPath.length() - 6)
25 | .replaceAll("/", ".") // unix/linux
26 | .replaceAll("\\\\", ".") //windows
27 | }
28 |
29 | static boolean isSystemClass(String fileName) {
30 | for (def exclude : DEFAULT_EXCLUDE) {
31 | if (fileName.matches(exclude)) return true
32 | }
33 | return false
34 | }
35 |
36 | static void copyFile(JarInput jarInput, TransformOutputProvider outputProvider) {
37 | def dest = getDestFile(jarInput, outputProvider)
38 | FileUtils.copyFile(jarInput.file, dest)
39 | }
40 |
41 | static File getDestFile(JarInput jarInput, TransformOutputProvider outputProvider) {
42 | def destName = jarInput.name
43 | // 重名名输出文件,因为可能同名,会覆盖
44 | def hexName = DigestUtils.md5Hex(jarInput.file.absolutePath)
45 | if (destName.endsWith(".jar")) {
46 | destName = destName.substring(0, destName.length() - 4)
47 | }
48 | // 获得输出文件
49 | File dest = outputProvider.getContentLocation(destName + "_" + hexName, jarInput.contentTypes, jarInput.scopes, Format.JAR)
50 | return dest
51 | }
52 |
53 |
54 | }
--------------------------------------------------------------------------------
/XerathLib/src/main/java/com/ng/xerathlib/utils/ASMUtil.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerathlib.utils;
2 |
3 | import org.objectweb.asm.Opcodes;
4 |
5 |
6 | public final class ASMUtil {
7 |
8 | private ASMUtil() {
9 | }
10 |
11 | /**
12 | * 是否包含权限
13 | */
14 | public static boolean hasAccess(int accessed, int flag) {
15 | return (accessed & flag) != 0;
16 | }
17 |
18 | /**
19 | * 根据方法描述符获取返回类型和默认值
20 | */
21 | public static Pair getDefaultByDesc(String methodDesc) {
22 | Pair pair = null;
23 | int value = -1;
24 | int opcode = -1;
25 |
26 | if (methodDesc.endsWith("[Z") ||
27 | methodDesc.endsWith("[I") ||
28 | methodDesc.endsWith("[S") ||
29 | methodDesc.endsWith("[B") ||
30 | methodDesc.endsWith("[C")) {
31 | value = Opcodes.ACONST_NULL;
32 | opcode = Opcodes.ARETURN;
33 |
34 | } else if (methodDesc.endsWith("Z") ||
35 | methodDesc.endsWith("I") ||
36 | methodDesc.endsWith("S") ||
37 | methodDesc.endsWith("B") ||
38 | methodDesc.endsWith("C")) {
39 | value = Opcodes.ICONST_0;
40 | opcode = Opcodes.IRETURN;
41 |
42 | } else if (methodDesc.endsWith("J")) {
43 | value = Opcodes.LCONST_0;
44 | opcode = Opcodes.LRETURN;
45 |
46 | } else if (methodDesc.endsWith("F")) {
47 | value = Opcodes.FCONST_0;
48 | opcode = Opcodes.FRETURN;
49 |
50 | } else if (methodDesc.endsWith("D")) {
51 | value = Opcodes.DCONST_0;
52 | opcode = Opcodes.DRETURN;
53 |
54 | } else if (methodDesc.endsWith("V")) {
55 | opcode = Opcodes.RETURN;
56 |
57 | } else {
58 | value = Opcodes.ACONST_NULL;
59 | opcode = Opcodes.ARETURN;
60 | }
61 |
62 | pair = new Pair(value, opcode);
63 | return pair;
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/XerathLib/src/main/java/com/ng/xerathlib/hook/target/plug/TargetPlugFilter.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerathlib.hook.target.plug;
2 |
3 | import java.util.List;
4 |
5 | import com.android.annotations.NonNull;
6 | import com.ng.xerathlib.extension.ExtConstant;
7 | import com.ng.xerathlib.utils.TxtUtils;
8 | import org.apache.http.util.TextUtils;
9 |
10 | /**
11 | * @author : jiangzhengnan.jzn@alibaba-inc.com
12 | * @creation : 2022/05/31
13 | * @description :
14 | */
15 | public class TargetPlugFilter {
16 |
17 | public static boolean isNeedHack(@NonNull String owner) {
18 | return isNeedTrackMethodStack(owner);
19 | }
20 |
21 | public static boolean isNeedTrackMethodStack(@NonNull String owner) {
22 | if (!ExtConstant.sTrackMethodStack.enable) {
23 | return false;
24 | }
25 | String fullClassName = TxtUtils.getFullClassNameForOwner(owner);
26 | List targetPkgList = ExtConstant.sTrackMethodStack.targetPackageList;
27 | List targetClassList = ExtConstant.sTrackMethodStack.targetClassList;
28 |
29 | boolean needTrackMethodStack = false;
30 | if (targetPkgList != null) {
31 | //LogUtil.print("targetPkgList: " + targetPkgList);
32 | for (String pkgName : targetPkgList) {
33 | if (!TextUtils.isEmpty(pkgName) && fullClassName.startsWith(pkgName)) {
34 | needTrackMethodStack = true;
35 | break;
36 | }
37 | }
38 | }
39 | if (!needTrackMethodStack && targetClassList != null) {
40 | //LogUtil.print("targetClassList: " + targetClassList);
41 | for (String className : targetClassList) {
42 | //包含内部类
43 | if (!TextUtils.isEmpty(className) && fullClassName.startsWith(className)) {
44 | needTrackMethodStack = true;
45 | break;
46 | }
47 | }
48 | }
49 | return needTrackMethodStack;
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ng/xerath/asm/Main.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerath.asm;
2 |
3 |
4 | import com.ng.xerath.asm.visitor.TestClassVisitor;
5 | import com.ng.xerath.asm.visitor.TestPreLoadClassVisitor;
6 | import com.ng.xerath.func.chain.ChainD;
7 | import com.ng.xerathcore.CoreHelper;
8 |
9 | import org.objectweb.asm.ClassReader;
10 | import org.objectweb.asm.ClassWriter;
11 |
12 | import java.io.FileOutputStream;
13 |
14 |
15 | /**
16 | * @author : jiangzhengnan
17 | * @creation : 2021/08/23
18 | * @description :
19 | * ASM的最简单用法
20 | * Child 有 phone 可以 call
21 | */
22 | public class Main {
23 |
24 | public static void main(String[] args) {
25 | //testChild();
26 | startHook();
27 |
28 | }
29 |
30 | //Child 的 class文件路径
31 | public static final String LOCAL_PATH = "/Users/xiaoguagua/AndroidProjects/MyProjects/" +
32 | "ng_projects/Xerath/app/build/intermediates/javac/debug/classes/com/ng/xerath/asm";
33 |
34 | public static final String HOME_PATH = "/Users/pumpkin/AndroidPro/AndroidStudioPrivate/Xerath/app/build/" +
35 | "intermediates/javac/debug/classes/com/ng/xerath";
36 |
37 | private static void startHook() {
38 | try {
39 |
40 | ClassReader cr = new ClassReader(ASMShow.class.getName());
41 | ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
42 |
43 | //预加载参数
44 | TestPreLoadClassVisitor preCv = new TestPreLoadClassVisitor(cw);
45 | cr.accept(preCv, ClassReader.EXPAND_FRAMES);
46 |
47 | TestClassVisitor cv = new TestClassVisitor(cw);
48 | cr.accept(cv, ClassReader.EXPAND_FRAMES);
49 |
50 |
51 | // 获取生成的class文件对应的二进制流
52 | byte[] code = cw.toByteArray();
53 | //将二进制流写到out/下
54 | FileOutputStream fos = new FileOutputStream(LOCAL_PATH + "/ASMShow.class");
55 | fos.write(code);
56 | fos.close();
57 | } catch (Exception e) {
58 | e.printStackTrace();
59 | }
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/XerathLib/src/main/java/com/ng/xerathlib/utils/TxtUtils.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerathlib.utils;
2 |
3 | import com.android.annotations.NonNull;
4 | import com.android.annotations.Nullable;
5 |
6 | /**
7 | * @author : jiangzhengnan.jzn@alibaba-inc.com
8 | * @creation : 2022/05/25
9 | * @description :
10 | */
11 | public class TxtUtils {
12 |
13 | @NonNull
14 | public static String getFullClassNameForOwner(@Nullable String owner) {
15 | if (owner == null || owner.length() == 0) {
16 | return "";
17 | }
18 | if (!owner.contains("/")) {
19 | return owner;
20 | }
21 | String[] tempArray = owner.split("/");
22 | return owner.replaceAll("/", ".");
23 | }
24 |
25 | /**
26 | * 传入格式:
27 | * owner:
28 | * com/ng/xerath/func/DataMethodUtil
29 | * com/ng/xerath/func/DataMethodUtil$TestClass
30 | * 返回格式:
31 | * com.ng.xerath.func
32 | */
33 | @NonNull
34 | public static String getPkgNameFromOwner(@Nullable String owner) {
35 | if (owner == null || owner.length() == 0 || !owner.contains("/")) {
36 | return "";
37 | }
38 | String[] tempArray = owner.split("/");
39 | int classNameStrLength = tempArray[tempArray.length - 1].length();
40 | return owner.replaceAll("/", ".")
41 | .substring(0, owner.length() - classNameStrLength - 1);
42 | }
43 |
44 | /**
45 | * 传入格式:
46 | * owner: com/ng/xerath/func/DataMethodUtil
47 | * 返回格式:
48 | * DataMethodUtil
49 | */
50 | @NonNull
51 | public static String getClassNameFromOwner(@Nullable String owner) {
52 | if (owner == null || owner.length() == 0 || !owner.contains("/")) {
53 | return "";
54 | }
55 | String[] tempArray = owner.split("/");
56 | int classNameStrLength = tempArray[tempArray.length - 1].length();
57 | return owner.replaceAll("/", ".")
58 | .substring(owner.length() - classNameStrLength, owner.length());
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ng/xerath/asm/ASMUtil.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerath.asm;
2 |
3 | import android.util.Pair;
4 |
5 | import org.objectweb.asm.Opcodes;
6 |
7 |
8 | public final class ASMUtil {
9 |
10 | private ASMUtil() {
11 | }
12 |
13 | /**
14 | * 是否包含权限
15 | */
16 | public static boolean hasAccess(int accessed, int flag) {
17 | return (accessed & flag) != 0;
18 | }
19 |
20 | /**
21 | * 根据方法描述符获取返回类型和默认值
22 | */
23 | public static Pair getDefaultByDesc(String methodDesc) {
24 | Pair pair = null;
25 | int value = -1;
26 | int opcode = -1;
27 |
28 | if (methodDesc.endsWith("[Z") ||
29 | methodDesc.endsWith("[I") ||
30 | methodDesc.endsWith("[S") ||
31 | methodDesc.endsWith("[B") ||
32 | methodDesc.endsWith("[C")) {
33 | value = Opcodes.ACONST_NULL;
34 | opcode = Opcodes.ARETURN;
35 |
36 | } else if (methodDesc.endsWith("Z") ||
37 | methodDesc.endsWith("I") ||
38 | methodDesc.endsWith("S") ||
39 | methodDesc.endsWith("B") ||
40 | methodDesc.endsWith("C")) {
41 | value = Opcodes.ICONST_0;
42 | opcode = Opcodes.IRETURN;
43 |
44 | } else if (methodDesc.endsWith("J")) {
45 | value = Opcodes.LCONST_0;
46 | opcode = Opcodes.LRETURN;
47 |
48 | } else if (methodDesc.endsWith("F")) {
49 | value = Opcodes.FCONST_0;
50 | opcode = Opcodes.FRETURN;
51 |
52 | } else if (methodDesc.endsWith("D")) {
53 | value = Opcodes.DCONST_0;
54 | opcode = Opcodes.DRETURN;
55 |
56 | } else if (methodDesc.endsWith("V")) {
57 | opcode = Opcodes.RETURN;
58 |
59 | } else {
60 | value = Opcodes.ACONST_NULL;
61 | opcode = Opcodes.ARETURN;
62 | }
63 |
64 | pair = new Pair<>(value, opcode);
65 | return pair;
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ng/xerath/asm/Utils.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerath.asm;
2 |
3 | import org.objectweb.asm.Opcodes;
4 | import org.objectweb.asm.Type;
5 |
6 | public final class Utils implements Opcodes {
7 |
8 |
9 | public static int getLoadOpcodeFromDesc(String desc){
10 | int opcode = ILOAD;
11 | if("F".equals(desc)) {
12 | opcode = FLOAD;
13 | } else if("J".equals(desc)) {
14 | opcode = LLOAD;
15 | } else if("D".equals(desc)) {
16 | opcode = DLOAD;
17 | } else if(desc.startsWith("L")) { //object
18 | opcode = ALOAD;
19 | } else if(desc.startsWith("[")) { //array
20 | opcode = ALOAD;
21 | }
22 | return opcode;
23 | }
24 |
25 | public static int getStoreOpcodeFromType(Type type){
26 | int opcode = ISTORE;
27 | switch (type.getSort()) {
28 | case Type.LONG:
29 | opcode = LSTORE;
30 | break;
31 | case Type.FLOAT:
32 | opcode = FSTORE;
33 | break;
34 | case Type.DOUBLE:
35 | opcode = DSTORE;
36 | break;
37 | case Type.OBJECT:
38 | opcode = ASTORE;
39 | break;
40 | case Type.ARRAY:
41 | opcode = ASTORE;
42 | break;
43 | }
44 | return opcode;
45 | }
46 |
47 | public static int getLoadOpcodeFromType(Type type){
48 | int opcode = ILOAD;
49 | switch (type.getSort()) {
50 | case Type.LONG:
51 | opcode = LLOAD;
52 | break;
53 | case Type.FLOAT:
54 | opcode = FLOAD;
55 | break;
56 | case Type.DOUBLE:
57 | opcode = DLOAD;
58 | break;
59 | case Type.OBJECT:
60 | opcode = ALOAD;
61 | break;
62 | case Type.ARRAY:
63 | opcode = ALOAD;
64 | break;
65 | }
66 | return opcode;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_home_page.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
23 |
24 |
25 |
26 |
31 |
32 |
40 |
41 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/XerathCore/src/main/java/com/ng/xerathcore/utils/LineNumberLog.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerathcore.utils;
2 |
3 | import android.util.Log;
4 |
5 | /**
6 | * Created by Quinn on 15/09/2018.
7 | *
8 | * interface bo replace the android logcat call
9 | */
10 | public class LineNumberLog {
11 |
12 | public static int i(String tag, String msg, String linenumber) {
13 | return Log.i(tag + "[" + linenumber + "]", msg);
14 | }
15 |
16 | public static int i(String tag, String msg, Throwable e, String linenumber) {
17 | return Log.i(tag + "[" + linenumber + "]", msg, e);
18 | }
19 |
20 | public static int d(String tag, String msg, String linenumber) {
21 | return Log.d(tag + "[" + linenumber + "]", msg);
22 | }
23 |
24 | public static int d(String tag, String msg, Throwable e, String linenumber) {
25 | return Log.d(tag + "[" + linenumber + "]", msg, e);
26 | }
27 |
28 | public static int v(String tag, String msg, String linenumber) {
29 | return Log.v(tag + "[" + linenumber + "]", msg);
30 | }
31 |
32 | public static int v(String tag, String msg, Throwable e, String linenumber) {
33 | return Log.v(tag + "[" + linenumber + "]", msg, e);
34 | }
35 |
36 | public static int e(String tag, String msg, String linenumber) {
37 | return Log.e(tag + "[" + linenumber + "]", msg);
38 | }
39 |
40 | public static int e(String tag, String msg, Throwable e, String linenumber) {
41 | return Log.e(tag + "[" + linenumber + "]", msg, e);
42 | }
43 |
44 | public static int w(String tag, String msg, String linenumber) {
45 | return Log.w(tag + "[" + linenumber + "]", msg);
46 | }
47 |
48 | public static int w(String tag, String msg, Throwable e, String linenumber) {
49 | return Log.w(tag + "[" + linenumber + "]", msg, e);
50 | }
51 |
52 | public static int w(String tag, Throwable e, String linenumber) {
53 | return Log.w(tag + "[" + linenumber + "]", e);
54 | }
55 |
56 | public static int println(int priority, String tag, String msg, String linenumber) {
57 | return Log.println(priority, tag + "[" + linenumber + "]", msg);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ng/xerath/ui/fragment/FunctionFragment.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerath.ui.fragment;
2 |
3 | import android.view.View;
4 |
5 | import com.ng.xerath.R;
6 | import com.ng.xerath.func.FuncMethodUtil;
7 | import com.ng.xerath.func.ViewMethodUtil;
8 | import com.ng.xerathcore.CoreHelper;
9 |
10 | import org.jetbrains.annotations.NotNull;
11 |
12 | /**
13 | * @author : jiangzhengnan.jzn@alibaba-inc.com
14 | * @creation : 2022/03/09
15 | * @description :
16 | * 功能模块
17 | */
18 | public class FunctionFragment extends BaseFragment{
19 | private CoreHelper.CoreHelperListener mLogListener;
20 |
21 | public void setLogListener(CoreHelper.CoreHelperListener mLogListener) {
22 | this.mLogListener = mLogListener;
23 | }
24 |
25 | @Override
26 | public void initViewsAndEvents(@NotNull View v) {
27 | initFunc(v);
28 | }
29 |
30 | @Override
31 | public int getLayoutId() {
32 | return R.layout.layout_func;
33 | }
34 |
35 |
36 | /**
37 | * 功能
38 | */
39 | private void initFunc(View view) {
40 | //限频调用
41 | view.findViewById(R.id.btn1_layout_fuc).setOnClickListener(v -> {
42 | pushNewLine();
43 | FuncMethodUtil.doubleClick();
44 | });
45 | //异常捕获
46 | view.findViewById(R.id.btn2_layout_fuc).setOnClickListener(v -> {
47 | pushNewLine();
48 | FuncMethodUtil.tryCatchMethod();
49 | });
50 | //方法移除
51 | view.findViewById(R.id.btn3_layout_fuc).setOnClickListener(v -> {
52 | pushNewLine();
53 | //FuncMethodUtil.tryRemoveMethod(MainActivity.this);
54 | FuncMethodUtil.tryRemoveCompleteMethod(getActivity());
55 | });
56 | //方法替换
57 | view.findViewById(R.id.btn4_layout_fuc).setOnClickListener(v -> {
58 | pushNewLine();
59 | FuncMethodUtil.tryExtendMethod();
60 | });
61 | //弹出toast
62 | view.findViewById(R.id.btn5_layout_fuc).setOnClickListener(v -> {
63 | pushNewLine();
64 | ViewMethodUtil.popToast();
65 | });
66 | }
67 |
68 | private void pushNewLine() {
69 | mLogListener.onCatchLog("\n");
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/XerathLib/src/main/java/com/ng/xerathlib/asm/jar/JarCatchMethodVisitor.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerathlib.asm.jar;
2 |
3 | import org.objectweb.asm.MethodVisitor;
4 | import org.objectweb.asm.Opcodes;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 |
10 | /**
11 | * @author : jiangzhengnan
12 | * @creation : 2021/08/25
13 | * @description :
14 | * 负责分析
15 | */
16 | public class JarCatchMethodVisitor extends MethodVisitor implements Opcodes {
17 | private int mMethodAccess;
18 | private boolean isStaticMethod;
19 |
20 | //参数
21 | private String mClassName;
22 | private String mMethodName;
23 | private String mMethodDesc;
24 | private String mMethodSignature;
25 |
26 | private List varList = new ArrayList<>();
27 |
28 | protected JarCatchMethodVisitor(int api, int access, String className, String methodName, String descriptor,
29 | String signature, MethodVisitor methodVisitor) {
30 | super(api, methodVisitor);
31 | mClassName = className;
32 | mMethodName = methodName;
33 | mMethodDesc = descriptor;
34 | mMethodSignature = signature;
35 | mMethodAccess = access;
36 | isStaticMethod = ((Opcodes.ACC_STATIC & access) != 0);
37 | }
38 |
39 | @Override
40 | public void visitCode() {
41 | super.visitCode();
42 | varList = new ArrayList<>();
43 | }
44 |
45 | @Override
46 | public void visitVarInsn(int opcode, int var) {
47 | super.visitVarInsn(opcode, var);
48 | if ((opcode >= IRETURN && opcode <= RETURN) || opcode == ATHROW) {
49 | return;
50 | }
51 |
52 | }
53 |
54 |
55 | @Override
56 | public void visitEnd() {
57 | varList.clear();
58 | super.visitEnd();
59 | }
60 |
61 | @Override
62 | public void visitInsn(int opcode) {
63 | // 收集局部变量
64 | if ((opcode >= IRETURN && opcode <= RETURN) || opcode == ATHROW) {
65 | //mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/noah/sdk/business/monitor/HookCatchHelper", "onCatchTempJsonFileFinish", "()V", false);
66 | //mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/noah/sdk/business/monitor/HookCatchHelper", "catchTest", "()V", false);
67 | }
68 | super.visitInsn(opcode);
69 | }
70 |
71 | }
--------------------------------------------------------------------------------
/XerathLib/src/main/java/com/ng/xerathlib/hook/annotation/plug/LimitCallPlug.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerathlib.hook.annotation.plug;
2 |
3 | import com.ng.xerathlib.hook.annotation.plug.base.AnnotationPlug;
4 | import com.ng.xerathlib.utils.ASMUtil;
5 | import com.ng.xerathlib.utils.Pair;
6 | import org.objectweb.asm.Label;
7 | import org.objectweb.asm.MethodVisitor;
8 | import org.objectweb.asm.Opcodes;
9 |
10 |
11 | /**
12 | * @author : jiangzhengnan.jzn
13 | * @creation : 2021/09/19
14 | * @description :
15 | */
16 | public class LimitCallPlug extends AnnotationPlug {
17 | //判断语句
18 | private final Label judgeLabel = new Label();
19 |
20 | //else
21 | private final Label elseLabel = new Label();
22 |
23 | //if
24 | private final Label ifLabel = new Label();
25 |
26 | private long clickTime = 0;
27 |
28 | @Override
29 | public void onHookMethodStart(MethodVisitor mv) {
30 | Long clickTimeL = (Long) mParams.getAnnotationParams("time");
31 | if (clickTimeL != null) {
32 | clickTime = clickTimeL;
33 | }
34 | mv.visitLabel(judgeLabel);
35 | mv.visitLineNumber(0, judgeLabel);
36 |
37 | mv.visitLdcInsn(clickTime);
38 |
39 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/ng/xerathcore/utils/CoreUtils",
40 | "needLimitCall", "(J)Z", false);
41 |
42 | mv.visitJumpInsn(Opcodes.IFEQ, elseLabel);
43 |
44 | mv.visitLabel(ifLabel);
45 | mv.visitLineNumber(1, ifLabel);
46 | mv.visitLdcInsn("阻止频繁调用");
47 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/ng/xerathcore/CoreHelper", "catchLog", "(Ljava/lang/String;)V", false);
48 |
49 | //方法返回默认值
50 | Pair defaultVo = ASMUtil.getDefaultByDesc(mParams.mMethodDesc);
51 | int value = defaultVo.key;
52 | int opcode = defaultVo.value;
53 | if (value >= 0) {
54 | mv.visitInsn(value);
55 | }
56 | mv.visitInsn(opcode);
57 |
58 | mv.visitLabel(elseLabel);
59 | mv.visitLineNumber(3, elseLabel);
60 | mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
61 | }
62 |
63 | @Override
64 | public void onHookMethodReturn(int opcode, MethodVisitor mv) {
65 | }
66 |
67 | @Override
68 | public void onHookMethodEnd(MethodVisitor mv) {
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/repo/ivy-1.0.0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ng/xerath/ui/view/rounded/RoundedFrameLayout.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerath.ui.view.rounded;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.util.AttributeSet;
6 | import android.view.ViewGroup;
7 | import android.widget.FrameLayout;
8 |
9 | public class RoundedFrameLayout extends FrameLayout implements RoundedLayoutHelper.RoundedLayoutDelegate {
10 |
11 | private RoundedLayoutHelper mHelper;
12 |
13 | public RoundedFrameLayout(Context context) {
14 | this(context, null);
15 | }
16 |
17 | public RoundedFrameLayout(Context context, AttributeSet attrs) {
18 | this(context, attrs, 0);
19 | }
20 |
21 | public RoundedFrameLayout(Context context, AttributeSet attrs, int defStyle) {
22 | super(context, attrs, defStyle);
23 | mHelper = new RoundedLayoutHelper(this);
24 | }
25 |
26 | /**
27 | * @param radius px
28 | */
29 | public void setRadius(int radius) {
30 | setRadius(radius, radius, radius, radius);
31 | }
32 |
33 | public void setRadius(float radius) {
34 | setRadius((int) (radius + 0.5));
35 | }
36 |
37 | public void setRadius(int topLeftRadius, int topRightRadius, int bottomLeftRadius, int bottomRightRadius) {
38 | mHelper.setRadius(topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
39 | }
40 |
41 | /**
42 | * @return {mTopRightRadius, mTopRightRadius, mBottomLeftRadius, mBottomRightRadius}
43 | */
44 | public int[] getRadius() {
45 | return mHelper.getRadius();
46 | }
47 |
48 |
49 | public void setRadiusEnable(boolean enable){
50 | mHelper.setRadiusEnable(enable);
51 | }
52 |
53 | public boolean isRadiusEnable() {
54 | return mHelper.isRadiusEnable();
55 | }
56 |
57 | @Override
58 | protected void dispatchDraw(Canvas canvas) {
59 | mHelper.dispatchDraw(canvas);
60 | }
61 |
62 | @Override
63 | public void rLayoutInvalidate() {
64 | invalidate();
65 | }
66 |
67 | @Override
68 | public void rLayoutDispatchDraw(Canvas canvas) {
69 | super.dispatchDraw(canvas);
70 | }
71 |
72 | @Override
73 | public ViewGroup rLayoutSelf() {
74 | return this;
75 | }
76 |
77 | public void setStroke(boolean enableStroke, float strokeWidth, int strokeColor) {
78 | mHelper.setStroke(enableStroke, strokeWidth, strokeColor);
79 | }
80 | }
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/XerathLib/src/main/java/com/ng/xerathlib/asm/core/CoreClassVisitor.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerathlib.asm.core;
2 |
3 | import com.ng.xerathlib.asm.base.BaseClassVisitor;
4 | import com.ng.xerathlib.hook.XerathHookManager;
5 | import org.objectweb.asm.ClassVisitor;
6 | import org.objectweb.asm.FieldVisitor;
7 | import org.objectweb.asm.MethodVisitor;
8 |
9 | import static org.objectweb.asm.Opcodes.ACC_STATIC;
10 |
11 | /**
12 | * @Project ASMCostTime
13 | * @date 2020/6/22
14 | * @describe
15 | */
16 | public class CoreClassVisitor extends BaseClassVisitor {
17 |
18 | public CoreClassVisitor(ClassVisitor visitor) {
19 | super(visitor);
20 | }
21 |
22 | @Override
23 | public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) {
24 | super.visit(version, access, name, signature, superName, interfaces);
25 | if (mHookHelper != null) {
26 | mHookHelper.onVisitClass(version, access, name, signature, superName, interfaces);
27 | }
28 | }
29 |
30 | @Override
31 | public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
32 | if (mHookHelper != null) {
33 | //成员变量抓取
34 | if ("Lorg/json/JSONObject;".equals(descriptor)) {
35 | String temp = owner + " " + name + " " + descriptor;
36 | if ((access & ACC_STATIC) != 0) {
37 | //LogUtil.print("抓取 [类] 变量: owner:" + owner + " name:" + name + " desc:" + descriptor);
38 | mHookHelper.getParams().getStaticFiledList().add(temp);
39 | } else {
40 | //LogUtil.print("抓取 [成员] 变量: owner:" + owner + " name:" + name + " desc:" + descriptor);
41 | mHookHelper.getParams().getFiledList().add(temp);
42 | }
43 | }
44 | }
45 | return super.visitField(access, name, descriptor, signature, value);
46 | }
47 |
48 | @Override
49 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
50 | MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
51 | if (!isInterface && mv != null && !name.equals("")) {
52 | //LogUtil.print("方法:" + name + " des:" + descriptor + " ");
53 | mv = new CoreMethodAdapter(mHookHelper, access, name, descriptor, mv, owner);
54 | }
55 | return mv;
56 | }
57 |
58 | @Override
59 | public void visitEnd() {
60 | super.visitEnd();
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/XerathLib/src/main/groovy/com/ng/xerathlib/transform/util/ClassLoaderHelper.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerathlib.transform.util;
2 |
3 | import com.android.build.api.transform.DirectoryInput;
4 | import com.android.build.api.transform.JarInput;
5 | import com.android.build.api.transform.TransformInput;
6 | import com.android.build.gradle.AppExtension;
7 | import com.google.common.collect.ImmutableList;
8 | import com.google.common.collect.Iterables;
9 |
10 | import org.gradle.api.Project;
11 |
12 | import java.io.File;
13 | import java.net.MalformedURLException;
14 | import java.net.URL;
15 | import java.net.URLClassLoader;
16 | import java.util.Collection;
17 |
18 | /**
19 | * @author : jiangzhengnan.jzn@alibaba-inc.com
20 | * @creation : 2021/09/24
21 | * @description :
22 | */
23 | public class ClassLoaderHelper {
24 |
25 | public static URLClassLoader getClassLoader(Collection inputs,
26 | Collection referencedInputs,
27 | Project project) throws MalformedURLException {
28 | ImmutableList.Builder urls = new ImmutableList.Builder<>();
29 | String androidJarPath = getAndroidJarPath(project);
30 | File file = new File(androidJarPath);
31 | URL androidJarURL = file.toURI().toURL();
32 | urls.add(androidJarURL);
33 | for (TransformInput totalInputs : Iterables.concat(inputs, referencedInputs)) {
34 | for (DirectoryInput directoryInput : totalInputs.getDirectoryInputs()) {
35 | if (directoryInput.getFile().isDirectory()) {
36 | urls.add(directoryInput.getFile().toURI().toURL());
37 | }
38 | }
39 | for (JarInput jarInput : totalInputs.getJarInputs()) {
40 | if (jarInput.getFile().isFile()) {
41 | urls.add(jarInput.getFile().toURI().toURL());
42 | }
43 | }
44 | }
45 | ImmutableList allUrls = urls.build();
46 | URL[] classLoaderUrls = allUrls.toArray(new URL[0]);
47 | return new URLClassLoader(classLoaderUrls);
48 | }
49 |
50 | private static String getAndroidJarPath(Project project) {
51 | AppExtension appExtension = (AppExtension)project.getProperties().get("android");
52 | //LibraryExtension appExtension = project.getExtensions().getByType(LibraryExtension.class);
53 | String sdkDirectory = appExtension.getSdkDirectory().getAbsolutePath();
54 | String compileSdkVersion = appExtension.getCompileSdkVersion();
55 | sdkDirectory = sdkDirectory + File.separator + "platforms" + File.separator;
56 | return sdkDirectory + compileSdkVersion + File.separator + "android.jar";
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ng/xerath/asm/visitor/TestPreLoadAdviceAdapter.java:
--------------------------------------------------------------------------------
1 | package com.ng.xerath.asm.visitor;
2 |
3 | import com.ng.xerath.asm.Parameter;
4 | import com.ng.xerathcore.utils.LogUtil;
5 |
6 | import org.objectweb.asm.Label;
7 | import org.objectweb.asm.MethodVisitor;
8 | import org.objectweb.asm.Opcodes;
9 | import org.objectweb.asm.Type;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 |
15 | /**
16 | * @author : jiangzhengnan
17 | * @creation : 2021/08/25
18 | * @description :
19 | * 使用 AdviceAdapter 是 MethodVisitor 的子类,功能更全
20 | */
21 | public class TestPreLoadAdviceAdapter extends MethodVisitor implements Opcodes {
22 | private static final String TAG = "预加载";
23 |
24 | private MethodVisitor methodVisitor;
25 | private List