Android SO逆-オブジェクトの継承と虚関数
16083 ワード
0x00
この節では,オブジェクトの継承と虚関数のアセンブリ実装について論じる.
0x01
まずアセンブリコードを直接見てみましょう.
0x02
次にidaを用いてsoを開き,アセンブリコードを説明する.このアセンブリコードは、デバッグ状態のアセンブリコードを使用します.
Displayメソッドを実行する場合,まずオブジェクトのヘッダアドレスから虚表ポインタを取り出し,その後虚表ポインタが指すメモリセルから具体的なDisplay命令のアドレスを取り出し,対応する命令実行にジャンプする.
次に、解析関数を続けます.考え方はDisplayと同じです.まず、オブジェクトの先頭アドレスから虚表ポインタを取り出し、虚表ポインタ+8が指すメモリユニットから具体的なDerivedクラスの解析関数のアドレスを取り出し、対応する命令実行にジャンプします.
0x03
まとめ:親クラスのメンバーは低アドレス、子クラスのメンバーは高アドレス、虚表ポインタはオブジェクトの最初のアドレスにあり、オブジェクトを構築するときは、まず親クラスを構築し、虚表ポインタは親クラスの虚表を指し、子クラスを構築し、虚表ポインタは子クラスの虚表を指す.オブジェクトを解析するときは、まずサブクラスを解析し、虚表ポインタはサブクラスの虚表を指し、さらに親クラスを解析し、虚表ポインタは親クラスの虚表を指す.
この節では,オブジェクトの継承と虚関数のアセンブリ実装について論じる.
0x01
まずアセンブリコードを直接見てみましょう.
#include "com_example_ndkreverse6_Lesson6.h"
#include <android/log.h>
#define LOG_TAG "lesson6"
#define ALOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
class Base {
public:
virtual void display() { // ,virtual ,
ALOGD("Base:%d, BaseChar:%d", base_, baseChar_);
}
Base(int base) {
base_ = base;
baseChar_ = 8;
ALOGD("Base ...");
}
virtual ~Base() { // , virtual, ,
ALOGD("~Base ...");
}
private:
int base_;
char baseChar_;
};
class Derived: public Base {
public:
virtual void display() { //
ALOGD("Derived:%d, DerivedChar:%d", derived_, derivedChar_);
Base::display(); // , , ,
}
Derived(int derived) :
Base(derived) {
derived_ = derived;
derivedChar_ = 10;
ALOGD("Derived ...");
}
~Derived() {
ALOGD("~Derived ...");
}
private:
int derived_;
char derivedChar_;
};
JNIEXPORT void JNICALL Java_com_example_ndkreverse6_Lesson6_main
(JNIEnv * env, jobject jobject) {
Base* d = new Derived(18);
d->display();
delete d;
}
では、実行後に実行された結果は次のようになります.D/lesson6 (28959): Base ...
D/lesson6 (28959): Derived ...
D/lesson6 (28959): Derived:18, DerivedChar:10
D/lesson6 (28959): Base:18, BaseChar:8
D/lesson6 (28959): ~Derived ...
D/lesson6 (28959): ~Base ...
0x02
次にidaを用いてsoを開き,アセンブリコードを説明する.このアセンブリコードは、デバッグ状態のアセンブリコードを使用します.
.text:00003088 EXPORT Java_com_example_ndkreverse6_Lesson6_main
.text:00003088 Java_com_example_ndkreverse6_Lesson6_main
.text:00003088 PUSH {R4-R6,LR}
.text:0000308A MOVS R0, #0x14 ; unsigned int R0 20, 20
.text:0000308C BL _Znwj ; operator new(uint) 20
.text:00003090 LDR R3, =(_ZTV4Base_ptr - 0x3098) ; Base
.text:00003092 MOVS R6, #0x12 ;R6 18
.text:00003094 ADD R3, PC ; _ZTV4Base_ptr
.text:00003096 LDR R3, [R3] ; `vtable for'Base Base , .data.rel.ro, 0x70428960
.text:00003098 MOVS R4, R0 ;R0 20 , R4
.text:0000309A ADDS R3, #8 ;R3+8 R3,R3 0x70428968
.text:0000309C STR R3, [R0] ; 0x70428968 ( )
.text:0000309E MOVS R3, #8 ;R3 8
.text:000030A0 LDR R5, =(aLesson6 - 0x30AA)
.text:000030A2 LDR R2, =(aBase____0 - 0x30B0)
.text:000030A4 STR R6, [R0,#4] ; 18 +4
.text:000030A6 ADD R5, PC ; "lesson6" R5 .rodata lesson6
.text:000030A8 MOVS R1, R5 ; R5 R1
.text:000030AA STRB R3, [R0,#8] ; 8 +8
.text:000030AC ADD R2, PC ; "Base ..." R2 .rodata Base ...
.text:000030AE MOVS R0, #3 ;R0 3
.text:000030B0 BL j_j___android_log_print ; Base ...
.text:000030B4 LDR R3, =(_ZTV7Derived_ptr - 0x30BE) ; Derived
.text:000030B6 LDR R2, =(aDerived____0 - 0x30C2)
.text:000030B8 MOVS R1, R5 ;R1 R5, .rodata lesson6
.text:000030BA ADD R3, PC ; _ZTV7Derived_ptr
.text:000030BC LDR R3, [R3] ; `vtable for'Derived Derived , .data.rel.ro, 0x70428978
.text:000030BE ADD R2, PC ; "Derived ..." R2 .rodata Derived
.text:000030C0 STR R6, [R4,#0xC] ; 18 +12
.text:000030C2 ADDS R3, #8 ;R3 Derived +8, 0x70428980
.text:000030C4 STR R3, [R4] ; 0x70428980
.text:000030C6 MOVS R3, #0xA ; R3 10
.text:000030C8 MOVS R0, #3 ; R0 3
.text:000030CA STRB R3, [R4,#0x10] ; 10 +16
.text:000030CC BL j_j___android_log_print ; R0,R1,R2 , j_j___android_log_print
.text:000030D0 LDR R3, [R4] ; , .data.rel.ro 0x70428980
.text:000030D2 MOVS R0, R4 ; R0 R4, ,R4 , this
.text:000030D4 LDR R3, [R3] ; , Derived Display
.text:000030D6 BLX R3 ; Derived Display
.text:000030D8 LDR R3, [R4] ; , .data.rel.ro 0x70428980
.text:000030DA MOVS R0, R4 ; R0 R4, ,R4 , this
.text:000030DC LDR R3, [R3,#8] ; +8 , Derived ~Derived
.text:000030DE BLX R3 ; Derived ~Derived
.text:000030E0 POP {R4-R6,PC}
.text:704220E4 off_704220E4 DCD _ZTV4Base_ptr - 0x70422098
.text:704220E4 ; DATA XREF: Java_com_example_ndkreverse6_Lesson6_main+8r
.text:704220E8 off_704220E8 DCD aLesson6 - 0x704220AA
.text:704220E8 ; DATA XREF: Java_com_example_ndkreverse6_Lesson6_main+18r
.text:704220E8 ; "lesson6"
.text:704220EC off_704220EC DCD aBase____0 - 0x704220B0
.text:704220EC ; DATA XREF: Java_com_example_ndkreverse6_Lesson6_main+1Ar
.text:704220EC ; "Base ..."
.text:704220F0 off_704220F0 DCD _ZTV7Derived_ptr - 0x704220BE
.text:704220F0 ; DATA XREF: Java_com_example_ndkreverse6_Lesson6_main+2Cr
.text:704220F4 off_704220F4 DCD aDerived____0 - 0x704220C2
.text:704220F4 ; DATA XREF: Java_com_example_ndkreverse6_Lesson6_main+2Er
.text:704220F4 ; "Derived ..."
.got:70428F24 AREA .got, DATA
.got:70428F24 ; ORG 0x70428F24
.got:70428F24 _ZTV4Base_ptr DCD _ZTV4Base ; DATA XREF: Base::~Base()+Ao
.got:70428F24 ; Base::~Base()+Cr ...
.got:70428F24 ; `vtable for'Base
.got:70428F28 _ZTV7Derived_ptr DCD _ZTV7Derived ; DATA XREF: Derived::~Derived()+Ao
.got:70428F28 ; Derived::~Derived()+Cr ...
.got:70428F28 ; `vtable for'Derived
.data.rel.ro:70428960 ; `vtable for'Base
.data.rel.ro:70428960 _ZTV4Base DCB 0 ; DATA XREF: Base::~Base()+Co
.data.rel.ro:70428960 ; Java_com_example_ndkreverse6_Lesson6_main+Eo ...
.data.rel.ro:70428961 DCB 0
.data.rel.ro:70428962 DCB 0
.data.rel.ro:70428963 DCB 0
.data.rel.ro:70428964 DCD _ZTI4Base ; `typeinfo for'Base
.data.rel.ro:70428968 DCD _ZN4Base7displayEv+1
.data.rel.ro:7042896C DCD _ZN4BaseD2Ev+1
.data.rel.ro:70428970 DCD _ZN4BaseD0Ev+1
.data.rel.ro:70428974 ALIGN 8
.data.rel.ro:70428978 WEAK _ZTV7Derived
.data.rel.ro:70428978 ; `vtable for'Derived
.data.rel.ro:70428978 _ZTV7Derived DCB 0 ; DATA XREF: Derived::~Derived()+Co
.data.rel.ro:70428978 ; Java_com_example_ndkreverse6_Lesson6_main+34o ...
.data.rel.ro:70428979 DCB 0
.data.rel.ro:7042897A DCB 0
.data.rel.ro:7042897B DCB 0
.data.rel.ro:7042897C DCD _ZTI7Derived ; `typeinfo for'Derived
.data.rel.ro:70428980 DCD _ZN7Derived7displayEv+1
.data.rel.ro:70428984 DCD _ZN7DerivedD2Ev+1
.data.rel.ro:70428988 DCD _ZN7DerivedD0Ev+1
.rodata:704267B0 ; `typeinfo name for'Base
.rodata:704267B0 _ZTS4Base DCB "4Base",0 ; DATA XREF: .data.rel.ro:_ZTI4Base+4o
.rodata:704267B6 ALIGN 4
.rodata:704267B8 WEAK _ZTS7Derived
.rodata:704267B8 ; `typeinfo name for'Derived
.rodata:704267B8 _ZTS7Derived DCB "7Derived",0 ; DATA XREF: .data.rel.ro:_ZTI7Derived+4o
.rodata:704267C1 ALIGN 4
.rodata:704267C4 aLesson6 DCB "lesson6",0 ; DATA XREF: Base::display(void)+Eo
.rodata:704267C4 ; .text:off_70421FD4o ...
.rodata:704267CC aBaseDBasecharD DCB "Base:%d, BaseChar:%d",0
.rodata:704267CC ; DATA XREF: Base::display(void)+10o
.rodata:704267CC ; .text:off_70421FD8o
.rodata:704267E1 aDerivedDDerive DCB "Derived:%d, DerivedChar:%d",0
.rodata:704267E1 ; DATA XREF: Derived::display(void)+Eo
.rodata:704267E1 ; .text:off_70422000o
.rodata:704267FC aBase___ DCB "~Base ...",0 ; DATA XREF: Base::~Base()+10o
.rodata:704267FC ; .text:off_7042202Co
.rodata:70426806 aDerived___ DCB "~Derived ...",0 ; DATA XREF: Derived::~Derived()+10o
.rodata:70426806 ; .text:off_70422060o
.rodata:70426813 aBase____0 DCB "Base ...",0 ; DATA XREF: Java_com_example_ndkreverse6_Lesson6_main+24o
.rodata:70426813 ; .text:off_704220ECo
.rodata:7042681C aDerived____0 DCB "Derived ...",0 ; DATA XREF: Java_com_example_ndkreverse6_Lesson6_main+36o
.rodata:7042681C ; .text:off_704220F4o
Displayメソッドを実行する場合,まずオブジェクトのヘッダアドレスから虚表ポインタを取り出し,その後虚表ポインタが指すメモリセルから具体的なDisplay命令のアドレスを取り出し,対応する命令実行にジャンプする.
.text:70421FDC ; _DWORD Derived::display(Derived *__hidden this)
.text:70421FDC WEAK _ZN7Derived7displayEv
.text:70421FDC _ZN7Derived7displayEv ; DATA XREF: .data.rel.ro:_ZTV7Derived+8o
.text:70421FDC
.text:70421FDC var_10 = -0x10
.text:70421FDC
.text:70421FDC PUSH {R0,R1,R4,LR}
.text:70421FDE MOVS R4, R0 ;R4 R0,
.text:70421FE0 LDRB R3, [R0,#0x10] ; , DerivedChar
.text:70421FE2 LDR R1, =(aLesson6 - 0x70421FEC)
.text:70421FE4 LDR R2, =(aDerivedDDerive - 0x70421FEE)
.text:70421FE6 STR R3, [SP,#0x10+var_10] ;
.text:70421FE8 ADD R1, PC ; "lesson6"
.text:70421FEA ADD R2, PC ; "Derived:%d, DerivedChar:%d"
.text:70421FEC LDR R3, [R4,#0xC] ; , Derived
.text:70421FEE MOVS R0, #3
.text:70421FF0 BL j_j___android_log_print
.text:70421FF4 MOVS R0, R4 ; this ; this
.text:70421FF6 BL _ZN4Base7displayEv ; Base::display(void)
.text:70421FFA POP {R0,R1,R4,PC}
次に、解析関数を続けます.考え方はDisplayと同じです.まず、オブジェクトの先頭アドレスから虚表ポインタを取り出し、虚表ポインタ+8が指すメモリユニットから具体的なDerivedクラスの解析関数のアドレスを取り出し、対応する命令実行にジャンプします.
.text:70422064 ; _DWORD __fastcall Derived::~Derived(Derived *__hidden this)
.text:70422064 WEAK _ZN7DerivedD0Ev
.text:70422064 _ZN7DerivedD0Ev ; DATA XREF: .data.rel.ro:_ZTV7Derived+10o
.text:70422064 PUSH {R4,LR}
.text:70422066 MOVS R4, R0 ;R4 R0,
.text:70422068 BL _ZN7DerivedD2Ev ; Derived::~Derived()
.text:7042206C MOVS R0, R4 ; void * R0
.text:7042206E BL _ZdlPv ; operator delete(void *)
.text:70422072 MOVS R0, R4
.text:70422030 ; _DWORD __fastcall Derived::~Derived(Derived *__hidden this)
.text:70422030 WEAK _ZN7DerivedD2Ev
.text:70422030 _ZN7DerivedD2Ev ; CODE XREF: Derived::~Derived()+4p
.text:70422030 ; DATA XREF: .data.rel.ro:_ZTV7Derived+Co
.text:70422030 PUSH {R4,LR} ; Alternative name is 'Derived::~Derived()'
.text:70422032 MOVS R4, R0 ;R4 R0,
.text:70422034 LDR R3, =(_ZTV7Derived_ptr - 0x7042203E)
.text:70422036 LDR R1, =(aLesson6 - 0x70422042)
.text:70422038 LDR R2, =(aDerived___ - 0x70422044)
.text:7042203A ADD R3, PC ; _ZTV7Derived_ptr
.text:7042203C LDR R3, [R3] ; `vtable for'Derived R3 Derived , .data.rel.ro, 0x70428978
.text:7042203E ADD R1, PC ; "lesson6"
.text:70422040 ADD R2, PC ; "~Derived ..."
.text:70422042 ADDS R3, #8 ;R3 Derived +8, 0x70428980
.text:70422044 STR R3, [R0] ; 0x70428980
.text:70422046 MOVS R0, #3
.text:70422048 BL j_j___android_log_print
.text:7042204C MOVS R0, R4 ; this R0
.text:7042204E BL _ZN4BaseD2Ev ; Base::~Base()
.text:70422052 MOVS R0, R4 ;
.text:70422054 POP {R4,PC}
.text:70422004 ; _DWORD __fastcall Base::~Base(Base *__hidden this)
.text:70422004 WEAK _ZN4BaseD2Ev
.text:70422004 _ZN4BaseD2Ev ; CODE XREF: Derived::~Derived()+1Ep
.text:70422004 ; Base::~Base()+4p
.text:70422004 ; DATA XREF: ...
.text:70422004 PUSH {R4,LR} ; Alternative name is 'Base::~Base()'
.text:70422006 MOVS R4, R0 ;R4
.text:70422008 LDR R3, =(_ZTV4Base_ptr - 0x70422012)
.text:7042200A LDR R1, =(aLesson6 - 0x70422016)
.text:7042200C LDR R2, =(aBase___ - 0x70422018)
.text:7042200E ADD R3, PC ; _ZTV4Base_ptr
.text:70422010 LDR R3, [R3] ; `vtable for'Base Base , .data.rel.ro, 0x70428960
.text:70422012 ADD R1, PC ; "lesson6"
.text:70422014 ADD R2, PC ; "~Base ..."
.text:70422016 ADDS R3, #8 ;R3+8 R3,R3 0x70428968
.text:70422018 STR R3, [R0] ; 0x70428968 ( )
.text:7042201A MOVS R0, #3 ;R0 , 3
.text:7042201C BL j_j___android_log_print
.text:70422020 MOVS R0, R4 ;
.text:70422022 POP {R4,PC}
0x03
まとめ:親クラスのメンバーは低アドレス、子クラスのメンバーは高アドレス、虚表ポインタはオブジェクトの最初のアドレスにあり、オブジェクトを構築するときは、まず親クラスを構築し、虚表ポインタは親クラスの虚表を指し、子クラスを構築し、虚表ポインタは子クラスの虚表を指す.オブジェクトを解析するときは、まずサブクラスを解析し、虚表ポインタはサブクラスの虚表を指し、さらに親クラスを解析し、虚表ポインタは親クラスの虚表を指す.