首页
社区
课程
招聘
[旧帖] [原创]C++ 对象的逆向 0.00雪花
发表于: 2013-9-26 21:24 3784

[旧帖] [原创]C++ 对象的逆向 0.00雪花

2013-9-26 21:24
3784

分析平台:VC
编译工具:vs2012
类原型:
class CAddressChain
{
public:
        CAddressChain();

        BYTE* m_pbFeatureCode;
        DWORD m_dwBaseAddress;
        DWORD m_dwOffsetAddress[20];
};
构造函数定义:
CAddressChain:: CAddressChain()
{
        m_pbFeatureCode = 0;
        m_dwBaseAddress = 0;
        for (int i = 0; i < 20; i++)
        {
                m_dwOffsetAddress[i] = -1;
        }
}
创建方式之栈中创建:
void Test()
{
        CAddressChain  acw;
        acw.m_dwBaseAddress = 1;
}
环境分析之准备环境:
void Test()
{
}
push        ebp  /*保存外层栈帧;栈帧,当前环境的栈空间的底部;栈底,空间最小值;栈帧指示了栈空间的底部,栈顶指示了栈空间的最大值;如图(在帖子最底下)

空间的顶部(esp),空间的底部(ebp) */  
mov        ebp,esp /*确定本层环境的栈空间底部;esp当前指示的是外层栈空间的顶部,本层需要拥有自己的栈空间,以方便数据的保存(局部变量),esp指示了栈空间当前的位置,顾把esp传递给ebp,用ebp来锁定本层栈空间的底部,有了底部(ebp),顶部(esp),就能确定本层栈空间的大小 */
/*这里为异常处理指令,没有深入研究,不做分析*/
push        ebx  /*保存外层寄存器,寄存器就那么几个,不够用,外层可能都用到了,所以这里先保存起来*/
push       esi  /*同上*/  
push       edi  /*同上*/

sub        esp,1C4h /*为本层栈空间分配了1C4h的空间;*/
lea        edi,[ebp+FFFFFE30h]  /* ebp,栈底;FFFFFE30h,这是补码形式,转换过来是-1C4h;即取到栈空间的顶部位置 */
mov       ecx,71h  
mov       eax,0CCCCCCCCh  
rep stos    dword ptr es:[edi]  
/*上面五条指令为本层栈空间分配空间,并初始化为CC,即int 3指令,如果不小心运行到这,即产生异常*/
至此,环境就安排好了;总结为:保护外层栈空间、寄存器;申请本层栈空间并初始化;
环境现状:
栈底 ebp
栈顶 esp
栈空间可用来申请的大小   ebp - (ebp – 1C4h)
本层栈空间总容量         ebp - esp
环境分析之退出环境:
之前有sub         esp,1C4
这里有 add         esp,1C4
之前有 push esi
这里有 pop esi
之前有 mov ebp,esp
这里又 mov esp,ebp
/*用到的寄存器,全部还原回去*/
对象创建:
CAddressChain  acw;

push       1  
lea        ecx,[ebp+FFFFFF78h] /* lea  ecx,[acw]; ebp栈底; FFFFFF78h 补码方式,转换为-88h;此处选取了栈空间ebp – 88h 的位置,栈总空间是ebp – 1C4h */
call        016D1B64 /*call   CAddressChain::__autoclassinit;  初始化对象的栈;详细代码如下:
push         ebp  
mov         ebp,esp  
sub         esp,0CCh  
push        ebx  
push        esi  
push        edi  
push        ecx  
lea          edi,[ebp+FFFFFF34h]  
mov         ecx,33h  
mov         eax,0CCCCCCCCh  
rep stos      dword ptr es:[edi]  
pop         ecx                                  ////////////////////标记A
mov         dword ptr [ebp-8],ecx  
mov         eax,dword ptr [ebp-8]  
mov         dword ptr [eax],0    ////////////////////结束标记A
pop         edi  
pop         esi  
pop         ebx  
mov         esp,ebp  
pop         ebp  
ret         4  
上面的代码跟除了对环境进行了处理外,从A标记处这里需要注意,这是这段代码的意义所在 ; 之前有句lea  ecx,[ebp+FFFFFF78h],这是在自己栈空间内找了一处地址,标记A处的指令对该地址处进行了填充,填充值为0,为什么要做这样的操作呢?继续往下看*/
lea         ecx,[ebp+FFFFFF78h]  /*再次取这个位置*/
call        016C355F        /*call  CAddressChain::CAddressChain;这里开始调用了构造函数;详细代码如下:
push        ebp  
mov         ebp,esp  
sub         esp,0D8h  
push        ebx  
push        esi  
push        edi  
push        ecx  
lea          edi,[ebp+FFFFFF28h]  
mov         ecx,36h  
mov         eax,0CCCCCCCCh  
rep stos      dword ptr es:[edi]  
pop          ecx          /*上面为环境的操作,这里的ecx是由外层获得(详情可在上面查找)*/
mov         dword ptr [ebp-8],ecx  /*将外层acw对象(ebp+FFFFF28h)所在栈空间的具体位置放入本层自己申请的栈空间内(ebp-8处),从逻辑上,构造函数内的所有操作,都且只跟自己的栈空间打交道*/
mov         eax,dword ptr [ebp-8]  /* 空间ebp-8是本层栈空间,里面放的是ecx,ecx是外层栈空间的ebp+FFFFFF78h 的位置*/
mov         dword ptr [eax],0 /*给外层acw对象所在的栈空间赋值*/
/*上面两句指令,为对象成员赋值,代码m_pbFeatureCode = 0; */
mov         eax,dword ptr [ebp-8]  
mov         dword ptr [eax+4],0
/*上面两条指令,源码m_dwBaseAddress = 0; */
/*下面部分是for循环,具体不做分析,唯一需要注意的下面已经注释;源码如下:
for (int i = 0; i < 20; i++)
{
        m_dwOffsetAddress[i] = -1;
}
*/
016E9E76  mov         dword ptr [ebp-14h],0  /*此处为i变量,需要注意这里是在构造函数自己栈空间内分配的*/
016E9E7D  jmp         016E9E88  
016E9E7F  mov         eax,dword ptr [ebp-14h]  
016E9E82  add         eax,1  
016E9E85  mov         dword ptr [ebp-14h],eax  
016E9E88  cmp         dword ptr [ebp-14h],14h  
016E9E8C  jge         016E9E9E  
016E9E8E  mov         eax,dword ptr [ebp-14h]  
016E9E91  mov         ecx,dword ptr [ebp-8]  /*这里再次用到了对象的栈空间*/
016E9E94  mov         dword ptr [ecx+eax*4+8],0FFFFFFFFh  /*+8需理解,前面已经为pbFeatureCode和dwBaseAddress各分配了4字节 */
016E9E9C  jmp         016E9E7F  
}
*/
mov         eax,dword ptr [ebp-8]  /*把对象所在栈空间的位置给了eax,这里可以说明,构造函数是带返回值的,默认就是this指针,即对象所在栈空间的位置*/
/*下面为环境还原*/
pop         edi  
pop         esi  
pop         ebx  
mov        esp,ebp  
pop         ebp  
ret  
对象创建完成,这里又回到Test函数
mov         dword ptr [ebp+FFFFFF7Ch],1 /*这里需要注意,对象的栈位置在ebp+FFFFFF78h,这里FFFFFF7Ch,即对象的第二个参数;源码为acw.m_dwBaseAddress = 1*/

OK,一个在栈中对象的对象就搞定了,下一次深入下堆上创建对象;
下面做一下总结:
之前写了1/3停电,头大了….忍住心情,调整战略,重新在Micr Word上完成
1对象名是一种 ebp+XX的人性化表示
2对象的成员变量会在定义对象的时候被规划好,用不用都在那里,编译器始终为你保留,修饰符是在语法层,引用私有成员,编译器不为你提供汇编指令,让你通不过..
3在成员方法内对对象属性进行的操作和在外部采用的都是相同的方式,操作的位置也是一样的,即完全相同..选择在成员方法和在外部,取决于面向对象设计模式
4构造函数默认有返回值,即对象的this指针
5成员方法默认都带有this参数,你用不用,它都会用ecx寄存器带入进去,并放在自己的栈空间ebp-8处
6成员方法都拥有自己的栈空间,方法内的局部变量,申请在自己维护的栈空间内,对属性的操作也是在自己栈通过引用[ebp-8]来完成
7在调用构造函数之前,调用了一个名为__autoclassinit的函数,进行的操作只是把对象的第一个参数设置成0;
8  this指针是对象在栈空间的位置


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 5
支持
分享
最新回复 (2)
雪    币: 3
活跃值: (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
谢谢楼主写了这么多,正在学习中,很详细
2013-12-15 12:12
0
雪    币: 272
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
学习,谢谢楼主!
2013-12-15 21:15
0
游客
登录 | 注册 方可回帖
返回
//