逆向角度看JNI C++

逆向角度看JNI C++类结构

1.首先看多重继承

代码如下

classTest.h


class Base1
{
public:
    virtual void vb1f() {printf("Base1 vb1f");}
    virtual void vf() {printf("Base1 vf");}
};

class Base2
{
public:
    virtual void vb2f() {printf("Base2 vb2f");}
    virtual void vf() {printf("Base2 vf");}
};

class Drive : public Base1, Base2
{
public:
    virtual void vdf() {printf("Driver vdf");}
    virtual void vf() {printf("Driver vf");}
    void f() {printf("Driver f");}
};

classTest.cpp

#include "ClassTest.h"
#include <jni.h>

extern "C"
JNIEXPORT jint JNICALL
Java_com_example_idareversecppclass_JniPerson_createClsssTest(JNIEnv *env, jobject thiz, jlong addr,
                                                              jint age) {
    jlong result;
    result =(jlong) new Drive();//创建了一个Drive对象
    return result;
}

将生成的so 放入IDA中分析

_DWORD *Java_com_example_idareversecppclass_JniPerson_createClsssTest()
{
  _DWORD *result; // r0

  result = (_DWORD *)operator new(8u);
  *result = &off_26840;                         // 虚表1
  result[1] = &off_26854;						//虚表2
  return result;
}

off_26840 指向的地址内容

.data.rel.ro:0002683C 6C 68 02 00  DCD _ZTI5Drive                   ; `typeinfo for'Drive
.data.rel.ro:00026840 D5 28 01 00  off_26840 DCD _ZN5Base14vb1fEv+1 ; Base1::vb1f(void)
.data.rel.ro:00026844 E1 28 01 00  DCD _ZN5Drive2vfEv+1             ; Drive::vf(void)
.data.rel.ro:00026848 ED 28 01 00  DCD _ZN5Drive3vdfEv+1            ; Drive::vdf(void)
.data.rel.ro:0002684C FC           DCB 0xFC
.data.rel.ro:0002684D FF           DCB 0xFF
.data.rel.ro:0002684E FF           DCB 0xFF
.data.rel.ro:0002684F FF           DCB 0xFF

第一个函数是 Base1::vb1f(void)

第二个函数是 Drive::vf(void)

第三个函数是 Drive::vdf(void)

off_26854 指向的地址内容

.data.rel.ro:00026850 6C 68 02 00  DCD _ZTI5Drive                  ; `typeinfo for'Drive
.data.rel.ro:00026854 F9 28 01 00  off_26854 DCD _ZN5Base24vb2fEv+1; Base2::vb2f(void)
.data.rel.ro:00026858 05 29 01 00  DCD _ZThn4_N5Drive2vfEv+1       ; `non-virtual thunk to'Drive::vf(void)

第一个函数是 Base2::vb2f(void)

第二个函数是 `non-virtual thunk to’Drive::vf(void)

于是给 MyDrive建立结构体如下

struct MyDrive
{
  int driveVtable1;
  int driveVtable2;
};

struct DriveVtable1
{
  int field_0;
  int field_4;
  int field_8;
};

struct DriveVtable2
{
  int field_0;
  int field_4;
};

修改后代码

MyDrive *Java_com_example_idareversecppclass_JniPerson_createClsssTest()
{
  MyDrive *result; // r0

  result = (MyDrive *)operator new(8u);
  result->driveVtable1 = &stru_26840;           // 虚表1
                                                // 
                                                // 
                                                // 虚表2
 
  result->driveVtable2 = &stru_26854;
  return result;
}
  1. 可以看到 由于继承了 Base1 Base2 所以有两个虚表指针管理虚函数 继承多少个父类 就有多少个虚表指针
  2. 第一个虚表指针 off_26840 虚表的内容是第一个继承的类Base1里面的虚函数
  3. off_26840的第一个4字节的地址存放的是Base1类的Base1::vb1f(void) 然后才是重载的 Drive::vf(void) 最后是自己本身的虚函数 Drive::vdf(void) 由此可见,虚函数的先后顺序也是先从基类,然后是自己的函数

2.看菱形继承(虚继承)

代码


class Base
{
public:
    virtual void vbbf() {printf("base vbbf");}
    virtual void vbf() {printf("base vbf");}
};

class Base1 : virtual public Base
{
public:
    virtual void vb1f() {printf("base1 vb1f");}
    virtual void vf() {printf("base1 vf");}
};

class Base2 : virtual public Base
{
public:
    virtual void vb2f() {printf("base2 vb2f");}
    virtual void vf() {printf("base2 vf");}
};

class Drive : virtual public Base1, virtual public Base2
{
public:
    virtual void vdf() {printf("drive vdf");}
    virtual void vf() {printf("drive vf");}
    void f() {}
};
extern "C"
JNIEXPORT jint JNICALL
Java_com_example_idareversecppclass_JniPerson_createLxClsssTest(JNIEnv *env, jobject thiz) {
    jlong result;
    result =(jlong) new Drive();
    return result;
}

反汇编的代码

_DWORD *Java_com_example_idareversecppclass_JniPerson_createLxClsssTest()
{
  _DWORD *result; // r0

  result = (_DWORD *)operator new(8u);
  *result = &off_26BA0;
  result[1] = &unk_26BD0;
  return result;
}

off_26BA0指向的地址内容

.data.rel.ro:00026BA0 C1 2B 01 00 off_26BA0 DCD _ZN4Base4vbbfEv+1   ; Base::vbbf(void)
.data.rel.ro:00026BA4 CD 2B 01 00 DCD _ZN4Base3vbfEv+1              ; Base::vbf(void)
.data.rel.ro:00026BA8 65 2B 01 00 DCD _ZN5Base14vb1fEv+1            ; Base1::vb1f(void)
.data.rel.ro:00026BAC D9 2B 01 00 DCD _ZN7Drive112vfEv+1            ; Drive11::vf(void)
.data.rel.ro:00026BB0 E5 2B 01 00 DCD _ZN7Drive113vdfEv+1           ; Drive11::vdf(void)

第一个函数 Base::vbbf(void)

第二个函数 Base::vbf(void)

第三个函数 Base1::vb1f(void)

第四个函数 Drive11::vf(void)

第五个函数 Drive11::vdf(void)

unk_26BD0指向的地址内容

.data.rel.ro:00026BD0 00 00 00 00 dword_26BD0 DCD 0
.data.rel.ro:00026BD4 00 00 00 00 DCD 0
.data.rel.ro:00026BD8 89 2B 01 00 DCD _ZN5Base24vb2fEv+1           ; Base2::vb2f(void)
.data.rel.ro:00026BDC F1 2B 01 00 DCD _ZTv0_n28_N7Drive112vfEv+1   ; `virtual thunk to'Drive11::vf(void)

第一个函数 0

第二个函数 0

第三个函数 Base2::vb2f(void)

第四个函数 `virtual thunk to’Drive11::vf(void)

  1. 首先是还是只有两个虚指针
  2. off_26BA0 第一个虚表包含了Base Base1Driver的全部的虚函数
  3. unk_26BD0的前两个地址是空的,并没有将Base的虚函数放入 只存放了Base2和Drive的虚函数

猜你喜欢

转载自blog.csdn.net/qq_36535153/article/details/131125876