linkedin / dexmaker

A utility for doing compile or runtime code generation targeting Android's Dalvik VM
Apache License 2.0
1.86k stars 248 forks source link

[Help] How get self method and Object #184

Closed hhhaiai closed 1 year ago

hhhaiai commented 1 year ago

I want to gneral a method,some case ,need getSelf method, Inner

target

//@ want general this class
public class Gne {

    public static String getName(String base) throws NoSuchMethodException {
        java.lang.reflect.Method method = Gne.class.getDeclaredMethod("getName", String.class);
        android.util.Log.i("demo", method.toGenericString());
        return null;
    }

}

develop use dexmaker

  public void start() throws IOException, ClassNotFoundException {

        String targetClassName = "Gne";
        DexMaker dexMaker = new DexMaker();
        // 定义类名,并生成类
        TypeId<?> classNameTypeId = TypeId.get("L" + targetClassName + ";");
        dexMaker.declare(classNameTypeId, targetClassName + ".java", PUBLIC, TypeId.OBJECT);

        //define error
        TypeId<NoSuchMethodException> errTypeId = TypeId.get(NoSuchMethodException.class);

        MethodId<?, String> methodId = classNameTypeId.getMethod(TypeId.STRING, "getName", TypeId.STRING);
        Code code = dexMaker.declare(methodId, PUBLIC);
        Local<String> argsOneLacle = code.getParameter(0, TypeId.STRING);
        Local<String> result = code.newLocal(TypeId.STRING);

        //define getDeclaredMethod
        Local<String> methodNameLocal = code.newLocal(TypeId.STRING);                       // arg1
        Local<Class[]> classArgsTypeLocal = code.newLocal(TypeId.get(Class[].class));       // arg2
        Local<Method> getMethodResultLocal = code.newLocal(TypeId.get(Method.class));       // return

        // define toGenericString
        Local<String> toGenralStringResultLocal = code.newLocal(TypeId.STRING);        // arg1

        // define log
        Local<String> logArg1Local = code.newLocal(TypeId.STRING);        // arg1
        Local<String> logArg2Local = code.newLocal(TypeId.STRING);        // arg2
        Local<Integer> logResultLocal = code.newLocal(TypeId.INT);       // return

        //call getDeclaredMethod
        MethodId getMethod = TypeId.get(Class.class).getMethod(TypeId.get(Method.class), "getDeclaredMethod", TypeId.STRING,  TypeId.get(Class[].class));
        code.loadConstant(methodNameLocal, "getName");
        code.loadConstant(classArgsTypeLocal, new Class[]{String.class});
        code.invokeStatic(getMethod, getMethodResultLocal, methodNameLocal, classArgsTypeLocal);

        //method.toGenericString()
        MethodId toGenericString = TypeId.OBJECT.getMethod(TypeId.STRING, "getDeclaredMethod");
        code.invokeVirtual(toGenericString, toGenralStringResultLocal, getMethodResultLocal);

        //log
        MethodId log = TypeId.get(Log.class).getMethod(TypeId.INT, "i", TypeId.STRING, TypeId.STRING);
        code.loadConstant(logArg1Local,"demo");
        code.loadConstant(logArg2Local,toGenralStringResultLocal.toString());
        code.invokeStatic(log,logArg1Local,logArg2Local);

        // throws NoSuchMethodException
        Local errLocal = code.newLocal(errTypeId);
        code.throwValue(errLocal);

        ClassLoader cl = dexMaker.generateAndLoad(getClass().getClassLoader(), mContext.getCacheDir());
        EL.i("classLoader:" + cl);
    }

error

java.lang.UnsupportedOperationException: Not a constant: [Ljava.lang.Class;@4146ae1
        at com.android.dx.Constants.getConstant(Constants.java:69)
        at com.android.dx.Code.loadConstantInternal(Code.java:499)
        at com.android.dx.Code.loadConstant(Code.java:479)
        at me.test.fixte.dexmkers.MethodH.start(MethodH.java:55)
        at me.test.fixte.App.generalDexMehotd(App.java:55)
        at me.test.fixte.App.hook(App.java:42)
        at me.test.fixte.App.onCreate(App.java:21)
        at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1192)
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6719)
        at android.app.ActivityThread.access$1300(ActivityThread.java:237)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1913)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7664)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
hhhaiai commented 1 year ago
  1. how get self method. I need get method(Reflect) in generate's method。
  2. how get the object in method which like no-static

please help

eirv commented 1 year ago
package defpackage;

import android.util.Log;

/* renamed from: Gne  reason: default package */
/* loaded from: /home/test.dex */
public class Gne {
    public String getName(String str) {
        Log.i("demo", Class.forName("Gne").getDeclaredMethod("getName", Class.forName("java.lang.String")).toGenericString());
        return null;
    }
}
    public void start() throws IOException, ClassNotFoundException {
        String targetClassName = "Gne";
        DexMaker dexMaker = new DexMaker();
        // 定义类名,并生成类
        TypeId<?> classNameTypeId = TypeId.get("L" + targetClassName + ";");
        dexMaker.declare(classNameTypeId, targetClassName + ".java", PUBLIC, TypeId.OBJECT);

        //define error
        // TypeId<NoSuchMethodException> errTypeId = TypeId.get(NoSuchMethodException.class);
        TypeId<Class> classTypeId = TypeId.get(Class.class);
        TypeId<Class[]> classesTypeId = TypeId.get(Class[].class);
        TypeId<Method> methodTypeId = TypeId.get(Method.class);

        MethodId<?, String> methodId = classNameTypeId.getMethod(TypeId.STRING, "getName", TypeId.STRING);
        MethodId<Class, Class> forNameMid = classTypeId.getMethod(classTypeId, "forName", TypeId.STRING);
        Code code = dexMaker.declare(methodId, PUBLIC);
        // Local<String> argsOneLacle = code.getParameter(0, TypeId.STRING);
        // Local<String> result = code.newLocal(TypeId.STRING);

        //define getDeclaredMethod
        Local<String> methodNameLocal = code.newLocal(TypeId.STRING);                       // arg1
        // Local<Class[]> classArgsTypeLocal = code.newLocal(TypeId.get(Class[].class));       // arg2
        Local<Method> getMethodResultLocal = code.newLocal(TypeId.get(Method.class));       // return

        // define toGenericString
        Local<String> toGenralStringResultLocal = code.newLocal(TypeId.STRING);        // arg1

        // define log
        Local<String> logArg1Local = code.newLocal(TypeId.STRING);        // arg1
        // Local<String> logArg2Local = code.newLocal(TypeId.STRING);        // arg2
        // Local<Integer> logResultLocal = code.newLocal(TypeId.INT);       // return
        Local<String> classNameLocal = code.newLocal(TypeId.STRING);
        Local<Class> classLocal = code.newLocal(classTypeId);
        Local<Integer> parameterCountLocal = code.newLocal(TypeId.INT);
        Local<Class[]> parameterTypesLocal = code.newLocal(TypeId.get(Class[].class));
        Local<String> stringNameLocal = code.newLocal(TypeId.STRING);
        Local<Class> stringClassLocal = code.newLocal(classTypeId);
        Local<Integer> zeroLocal = code.newLocal(TypeId.INT);
        Local<String> returnValueLocal = code.newLocal(TypeId.STRING);

        //call getDeclaredMethod
        MethodId getMethod = classTypeId.getMethod(TypeId.get(Method.class), "getDeclaredMethod", TypeId.STRING,  classesTypeId);
        code.loadConstant(classNameLocal, targetClassName);
        // 暂不支持 const-class, 只能这样了
        code.invokeStatic(forNameMid, classLocal, classNameLocal);
        code.loadConstant(methodNameLocal, "getName");
        code.loadConstant(parameterCountLocal, 1);
        code.newArray(parameterTypesLocal, parameterCountLocal);
        code.loadConstant(zeroLocal, 0);
        code.loadConstant(stringNameLocal, "java.lang.String");
        code.invokeStatic(forNameMid, stringClassLocal, stringNameLocal);
        code.aput(parameterTypesLocal, zeroLocal, stringClassLocal);
        code.invokeVirtual(getMethod, getMethodResultLocal, classLocal, methodNameLocal, parameterTypesLocal);

        // code.loadConstant(classArgsTypeLocal, new Class[]{String.class});
        // code.invokeStatic(getMethod, getMethodResultLocal, methodNameLocal, classArgsTypeLocal);

        //method.toGenericString()
        MethodId toGenericString = methodTypeId.getMethod(TypeId.STRING, "toGenericString");
        code.invokeVirtual(toGenericString, toGenralStringResultLocal, getMethodResultLocal);

        //log
        MethodId log = TypeId.get(Log.class).getMethod(TypeId.INT, "i", TypeId.STRING, TypeId.STRING);
        code.loadConstant(logArg1Local,"demo");
        // code.loadConstant(logArg2Local,toGenralStringResultLocal.toString());
        code.invokeStatic(log,null,logArg1Local,toGenralStringResultLocal);

        // throws NoSuchMethodException
        //Local errLocal = code.newLocal(errTypeId);
        //code.throwValue(errLocal);
        code.loadConstant(returnValueLocal, null);
        code.returnValue(returnValueLocal);

        FileUtils.write("/home/test.dex", dexMaker.generate());
        // ClassLoader cl = dexMaker.generateAndLoad(getClass().getClassLoader(), mContext.getCacheDir());
        // EL.i("classLoader:" + cl);
    }
hhhaiai commented 1 year ago

@mikofe 666 可以实现。

kkoser commented 1 year ago

@hhhaiai sounds like the above code works, so can we close this issue?

hhhaiai commented 1 year ago

Other : how get the object in method which like no-static

class Model{ //... // some method general by dexmaker. eg xxxx void xxx(){ // here how get this object? } } class B{

void a(){ Model m = new Model(); m.xxx();

} }

eirv commented 1 year ago
package defpackage;

/* compiled from: Model.generated */
/* renamed from: Model  reason: default package */
/* loaded from: /home/test.dex */
class Model {
    /* JADX INFO: Access modifiers changed from: package-private */
    public void xxx() {
    }
}
package defpackage;

/* compiled from: B.generated */
/* renamed from: B  reason: default package */
/* loaded from: /home/test.dex */
class B {
    B() {
    }

    void a() {
        new Model().xxx();
    }
}
public class Main {
    public static void main(String[] args) throws IOException {
        DexMaker dexMaker = new DexMaker();

        TypeId<?> modelTid = TypeId.get("LModel;");
        TypeId<?> bTid = TypeId.get("LB;");

        dexMaker.declare(modelTid, "Model.generated", 0, TypeId.OBJECT);
        dexMaker.declare(bTid, "B.generated", 0, TypeId.OBJECT);

        MethodId<Object, Void> objectInitMid = TypeId.OBJECT.getConstructor();
        MethodId<?, Void> modelInitMid = modelTid.getConstructor();
        MethodId<?, Void> bInitMid = bTid.getConstructor();
        MethodId<?, Void> xxxMid = modelTid.getMethod(TypeId.VOID, "xxx");
        MethodId<?, Void> aMid = bTid.getMethod(TypeId.VOID, "a");

        Code modelInitCode = dexMaker.declare(modelInitMid, 0);
        Local<?> modelInitThisLocal = modelInitCode.getThis(modelTid);
        modelInitCode.invokeDirect(objectInitMid, null, modelInitThisLocal);
        modelInitCode.returnVoid();

        Code bInitCode = dexMaker.declare(bInitMid, 0);
        Local<?> bInitThisLocal = bInitCode.getThis(bTid);
        bInitCode.invokeDirect(objectInitMid, null, bInitThisLocal);
        bInitCode.returnVoid();

        Code xxxCode = dexMaker.declare(xxxMid, 0);
        xxxCode.returnVoid();

        Code aCode = dexMaker.declare(aMid, 0);
        Local<?> mLocal = aCode.newLocal(modelTid);
        aCode.newInstance(mLocal, modelInitMid);
        aCode.invokeVirtual(xxxMid, null, mLocal);
        aCode.returnVoid();

        byte[] dexBytes = dexMaker.generate();
        FileUtils.write("/home/test.dex", dexBytes);
    }
}
hhhaiai commented 1 year ago

@mikofe thx. But I mean:

package defpackage;

/* compiled from: Model.generated */
/* renamed from: Model  reason: default package */
/* loaded from: /home/test.dex */
class Model {
    /* JADX INFO: Access modifiers changed from: package-private */
    public void xxx() {
       // here get this,the Instance of  this Model
    }
}

here ,I want get this model Instance ,which method be called~

eirv commented 1 year ago

@mikofe thx. But I mean:

package defpackage;

/* compiled from: Model.generated */
/* renamed from: Model  reason: default package */
/* loaded from: /home/test.dex */
class Model {
    /* JADX INFO: Access modifiers changed from: package-private */
    public void xxx() {
       // here get this,the Instance of  this Model
    }
}

here ,I want get this model Instance ,which method be called~

xxxCode.getThis(modelTid);
hhhaiai commented 1 year ago

@mikofe thx. But I mean:

package defpackage;

/* compiled from: Model.generated */
/* renamed from: Model  reason: default package */
/* loaded from: /home/test.dex */
class Model {
    /* JADX INFO: Access modifiers changed from: package-private */
    public void xxx() {
       // here get this,the Instance of  this Model
    }
}

here ,I want get this model Instance ,which method be called~

xxxCode.getThis(modelTid);

thx, I try right now

hhhaiai commented 1 year ago

@mikofe

 xxxCode.getThis(modelTid);  
// it's meam:
class Model {
    Model() {
    }

    void xxx() {
    }
}
eirv commented 1 year ago

@mikofe

 xxxCode.getThis(modelTid);  
// it's meam:
class Model {
    Model() {
    }

    void xxx() {
    }
}
class Model {
    Model() {
    }

    void xxx() {
        Object thiz = this;
    }
}
hhhaiai commented 1 year ago

@mikofe thx .very thx