Android SO逆向-对象的构造函数与析构函数

    0x00

    这一节我们主要讨论对象的构造函数和析构函数的汇编实现。


    0x01

    我们先直接看C++代码:

#include "com_example_ndkreverse4_Lesson4.h"
#include "Test.h"
#include <android/log.h>
#define LOG_TAG "lesson4"
#define ALOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))

JNIEXPORT void JNICALL Java_com_example_ndkreverse4_Lesson4_main
  (JNIEnv * env, jobject jobject) {
	Test a2(10);
	a2.Display();
}
    Test.h定义如下:

#ifndef _TEST_H_
#define _TEST_H_
class Test
{
public:
    // 如果类不提供任何一个构造函数,系统将为我们提供一个不带参数的
    // 默认的构造函数
    Test();
    Test(int num);
    void Display();
    ~Test();
private:
    int num_;
};
#endif // _TEST_H_

    Test.cpp定义如下:

#include "Test.h"
#include <iostream>
using namespace std;
// 不带参数的构造函数称为默认构造函数
Test::Test()
{
    num_ = 0;
    cout<<"Initializing Default"<<endl;
}
Test::Test(int num)
{
    num_ = num;
    cout<<"Initializing "<<num_<<endl;
}
Test::~Test()
{
    cout<<"Destroy "<<num_<<endl;
}
void Test::Display()
{
    cout<<"num="<<num_<<endl;
}


    0x02

    下面我们使用ida来打开so,对汇编代码做出解释。

.text:000109B4                 EXPORT Java_com_example_ndkreverse4_Lesson4_main
.text:000109B4 Java_com_example_ndkreverse4_Lesson4_main
.text:000109B4
.text:000109B4 var_14          = -0x14
.text:000109B4
.text:000109B4                 PUSH    {R0-R2,R4,R5,LR} ;分配堆栈,R0~R2的位置就是被分配为堆栈的空间
.text:000109B6                 LDR     R4, =(__stack_chk_guard_ptr - 0x109BE)
.text:000109B8                 MOVS    R1, #0xA  ;初始化值为10
.text:000109BA                 ADD     R4, PC ; __stack_chk_guard_ptr
.text:000109BC                 LDR     R4, [R4] ; __stack_chk_guard
.text:000109BE                 MOV     R0, SP   ;堆栈的地址赋值给R0
.text:000109C0                 LDR     R3, [R4] ;堆栈检查的信息
.text:000109C2                 STR     R3, [SP,#0x18+var_14] ;把堆栈检查的信息入栈
.text:000109C4                 BL      _ZN4TestC2Ei    ; Test::Test(int) ;此时R0为SP的地址,R1为0xA(10),调用构造函数
.text:000109C8                 MOV     R0, SP   ;把sp的地址赋值给R0
.text:000109CA                 BL      _ZN4Test7DisplayEv ; Test::Display(void) ;调用Display方法
.text:000109CE                 MOV     R0, SP          ; this  把sp的的地址赋值给R0
.text:000109D0                 BL      _ZN4TestD2Ev    ; Test::~Test()   ;调用析构函数
.text:000109D4                 LDR     R2, [SP,#0x18+var_14]
.text:000109D6                 LDR     R3, [R4]
.text:000109D8                 CMP     R2, R3
.text:000109DA                 BEQ     locret_109E0
.text:000109DC                 BL      j_j___stack_chk_fail
.text:000109E0 ; ---------------------------------------------------------------------------
.text:000109E0
.text:000109E0 locret_109E0                            ; CODE XREF: Java_com_example_ndkreverse4_Lesson4_main+26j
.text:000109E0                 POP     {R0-R2,R4,R5,PC}
    我们看到在调用构造函数,Display函数,析构函数时,R0的地址都是堆栈的地址,也就是C++层的this指针。

    下面我们接着看各个函数的实现。

    1、构造函数

.text:00010CD0 ; Test::Test(int)
.text:00010CD0                 EXPORT _ZN4TestC2Ei
.text:00010CD0 _ZN4TestC2Ei                            ; CODE XREF: Java_com_example_ndkreverse4_Lesson4_main+10p
.text:00010CD0                 PUSH    {R3-R5,LR}
.text:00010CD2                 MOVS    R5, R0   ;R0指向的地址就是刚刚分配的堆栈的地址,即C++层次上的this指针
.text:00010CD4                 LDR     R4, =(_ZSt4cout_ptr - 0x10CDE)
.text:00010CD6                 STR     R1, [R0] ;把初始化值10赋值压入堆栈,R0指向的地址就是刚刚分配的堆栈的地址
.text:00010CD8                 LDR     R1, =(aInitializing - 0x10CE2)
.text:00010CDA                 ADD     R4, PC ; _ZSt4cout_ptr
.text:00010CDC                 LDR     R4, [R4]        ; std::cout
.text:00010CDE                 ADD     R1, PC          ; "Initializing "
.text:00010CE0                 MOVS    R0, R4          ; this    ;R0和下面这个函数我们不深究
.text:00010CE2                 BL      _ZNSo14_M_put_nowidenEPKc ; std::ostream::_M_put_nowiden(char const*)
.text:00010CE6                 LDR     R1, [R5]       ;从堆栈中取出初始化值10
.text:00010CE8                 MOVS    R0, R4         ;R0和下面的函数我们不深究,总之R1做为其中一个参数,调用后面的函数是把10输出的控制台
.text:00010CEA                 BL      _ZNSt4priv9__put_numIcSt11char_traitsIcElEERSt13basic_ostreamIT_T0_ES7_T1_ ; std::priv::__put_num<char,std::char_traits<char>,long>(std::basic_ostream<char,std::char_traits<char>> &,long)
.text:00010CEE                 BL      _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ ; std::endl<char,std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &)
.text:00010CF2                 MOVS    R0, R5
.text:00010CF4                 POP     {R3-R5,PC}
    这个构造函数的主要作用是把初始化值10存放到堆栈中。


    2、Display函数

.text:00010D2C ; Test::Display(void)
.text:00010D2C                 EXPORT _ZN4Test7DisplayEv
.text:00010D2C _ZN4Test7DisplayEv                      ; CODE XREF: Java_co
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值