首页
社区
课程
招聘
[讨论]java方法拦截(基于ART)中,mirror::Object * 如何转化为 jobject
发表于: 2017-8-23 08:57 5857

[讨论]java方法拦截(基于ART)中,mirror::Object * 如何转化为 jobject

2017-8-23 08:57
5857

我的拦截思路如下(应用层实现):

1. 拦截ArtMethod::ART_METHOD_QUICK_CODE_OFFSET_32(以32位为例)指向的quick code,跳转到我的汇编代码——nativeBridge.s

2. 在nativeBridge.s中做这几件事:

     a 将sp作为第一个参数 (这个包含了参数数组)

     b 将ip作为第二个参数(这个包含了this指针)

     c 调用到我的C处理函数

     d 将c处理函数的返回值拷贝到 s0~s1/d0


3 在C处理函数里面:

    a 解析参数,并加工参数

    b 回调到java层

    c 解析返回值并返回。


现在在解析参数的时候遇到问题

解释一下我是如何获取参数列表的~

代码见runtime/arch/arm/quick_entrypoints_arm.S中art_quick_invoke_stub_internal

.............

    add    r4, r2, #4                      @ create space for method pointer in frame
    sub    r4, sp, r4                      @ reserve & align *stack* to 16 bytes: native calling
    and    r4, #0xFFFFFFF0                 @ convention only aligns to 8B, so we have to ensure ART
    mov    sp, r4                          @ 16B alignment ourselves.

    mov    r4, r0                          @ save method*
    add    r0, sp, #4                      @ pass stack pointer + method ptr as dest for memcpy
    bl     memcpy                          @ memcpy (dest, src, bytes)
    mov    ip, #0                          @ set ip to 0
    str    ip, [sp]                        @ store null for method* at bottom of frame


    ldr    ip, [r11, #48]                  @ load fp register argument array pointer
    vldm   ip, {s0-s15}                    @ copy s0 - s15

    ldr    ip, [r11, #44]                  @ load core register argument array pointer
    mov    r0, r4                          @ restore method*
    add    ip, ip, #4                      @ skip r0
    ldm    ip, {r1-r3}                     @ copy r1 - r3

.............


从这段代码可以看出来,参数列表存在栈中(飙红的代码),其形式如下:

ArtMethod *

thisobj

arg1

arg2

.

.

.

argn

我参考了ProxyClass中对于参数解析部分,得知根据每个参数位数不同(double、long为8字节,其他为4字节),即可解析出参数,代码如下:

......

int nativeBridge(unsigned char * args, unsigned char * srcMethod) {

    LOGI("args hex : %x %x %x %x", args[0], args[1], args[2], args[3]);
    args += sizeof(void *) * 1;

    jobject thisobj = *(jobject *)args;         //mirror::Object *    args += sizeof(void *);
    LOGI("thisobj = 0x%x", thisobj);

    jint arg1 = *(jint*)args;
    args += sizeof(void *);
    LOGI("arg1 = %d", arg1);

    jlong arg2 = *(jlong *)args;
    LOGI("arg2 = %lld", arg2);
    args += sizeof(void *) * 2;

    jfloat arg3 = *(jfloat *)args;
    LOGI("arg3 = %f", arg3);
    args += sizeof(void *);

    jdouble arg4 = *(jdouble *)args;
    LOGI("arg4 = %lf", arg4);
    args += sizeof(void *) * 2;

    args += sizeof(void *);

    jint arg5 = *(jint *)args;
    LOGI("arg5 = %d", arg5);

......

这个经过验证是可行的。


现在问题来了,参数列表的第二个——thisobj,在ART中,是一个mirror::Object*类型。因为我要把整个参数列表通过jni回传到java层——包含thisobj,而且这个thisobj我要做callOriginalMethod的receiver。但是jni是无法接受mirror::Object*,只能接受jobject。

我看代码发现ART代码对这个有专门处理:

  JNIEnvExt* env = self->GetJniEnv();
  ScopedObjectAccessUnchecked soa(env);
  ScopedJniEnvLocalRefState env_state(env);
  // Create local ref. copies of proxy method and the receiver.
  jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver);


因为我是在应用层实现,没有办法调用这样的代码;目前不知道该怎么处理。


冰天雪地全裸跪求诸位大神帮帮忙~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (5)
雪    币: 181
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
自顶~~~~~~~~~~~~~~~
2017-8-23 09:09
0
雪    币: 181
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
来人呐~~~~~~~~~~~~~~~~~~`
2017-8-23 09:25
0
雪    币: 181
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
初步思路:

ART怎么做就怎么做。
实际上ART调用的代码就是jobject  JNIEnvExt::NewLocalRef(mirror::Object*  obj)。该函数内部调用了AddLocalReference。
通过dlopen/dlsym获取_ZN3art9JNIEnvExt11NewLocalRefEPNS_6mirror6ObjectE地址,再获取JNIEnvExt,就可以完成该符号的调用。

JNIEnvExt这个东西可以从Thread中获取。
2017-8-23 15:01
0
雪    币: 181
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5

问题已经解决~


首先可以获取到

_ZN3art9JNIEnvExt11NewLocalRefEPNS_6mirror6ObjectE

地址。

差一个参数 JNIEnvExt。这个东西不好搞到,我看了一下代码:

struct JNIEnvExt : public JNIEnv {

........................................................

JNIEnv这个东西很熟悉,jni的接口;在ART里肯定不会操作JNIEnv而是操作JNIEnvExt;那么在jni中通过

AttachCurrentThread
GetEnv

得到的JNIEnv*一定是JNIEnvExt*;语法也完全没问题,基类指针指向子类对象。当然我就是猜的!!!!!!!得验证一下!!!!!!!!!!!!!!!!!!!!!


jobject (*fun)(JNIEnv *, *) = dlsym(handle, );
LOGI(, fun);
jobject a = fun(env, thisobj);

日志输出:

05-11 09:15:10.177  6575  6575 D ArtHook_native: fucking life I : handle = 0xace10e58
05-11 09:15:10.178  6575  6575 I test2:fake_dlfcn: _ZN3art9JNIEnvExt11NewLocalRefEPNS_6mirror6ObjectE found at 0xb3edffbd
05-11 09:15:10.178  6575  6575 D ArtHook_native: _ZN3art9JNIEnvExt11NewLocalRefEPNS_6mirror6ObjectE = 0xb3edffbd
05-11 09:15:10.178  6575  6575 I fucking life: this is java bridge !
05-11 09:15:10.178  6575  6575 I fucking life: originalMethodPointer = -1231585092
05-11 09:15:10.178  6575  6575 I fucking life: thisObject = class de.larma.arthook.test.MyApplication value = de.larma.arthook.test.MyApplication@8f7524c


搞定~~~~~~~~

2017-8-23 20:15
0
雪    币: 1392
活跃值: (5197)
能力值: ( LV13,RANK:240 )
在线值:
发帖
回帖
粉丝
7
楼主 在ArtMethod里面 打印参数详细信息 尝试过吗?java调用的时候把参数内容打印出来。准备在runtime里面调用java的toString方法。卡住了
2018-12-10 16:44
0
游客
登录 | 注册 方可回帖
返回
//