1. _cdecl: c\c++默认调用方式,调用方平衡栈,不定参数的函数可以使用  ret; 
2. _stdcall: 被调用方平衡栈,不定参数的函数不可以使用         ret 4;
3. _fastcall:寄存器方式传参,被调用方平衡栈,不定参数的函数不可以使用, cx,dx分别存储1,2参数,其余参数还是用栈

call 指令  隐含push 函数返回下一条指令地址
_cdecl 函数的结束"}" mov         esp,ebp 
           pop         ebp 
           ret     //ret指令 会把当前esp指向值更新到eip,同时esp-4, 此时一个栈帧调用完成。
           //如果函数有返回值会先赋值给eax,再执行ret.
int _fastcall fun22(int a, int b, int c,int d)
{                  F9   ecx = a, edx = b esp存储函数返回下一条指令地址 esp+4 = c esp+8 = d     
008613C0  push        ebp 
008613C1  mov         ebp,esp 
008613C3  sub         esp,0E4h      F9   ecx = a, edx = b ebp+4存储函数返回下一条指令地址 ebp+8 = c ebp+0xc = d

第七章:变量在内存中的位置和访问方式
作用域:全局变量属于进程作用域;静态变量属于文件作用域;局部变量属于函数作用域;

在大多数情况下,在PE文件中的只读数据节中,常量的节属性被修饰为不可写;而全局变量和静态变量则在属性为可读写的数据节中。
全局变量和常量类似,被写入文件中,当用户执行该文件,OS分析并加载各节到虚拟内在地址,这是全局变量已经存在了,加载完才开始执行入口点代码。
全局变量的内在地址在全局数据区中,通过栈指针是无法访问到,访问也与常量类似,都是通过立即数来访问。局部变量使用ebp或esp间接访问。
全局变量在内存中的地址顺序是先定义的变量在低地址,后定义的在高地址,局部变量刚好相反。

静态变量:全局静态变量,局部静态变量
 全局静态变量和全局变量类似,只是编译器限制外部源码文件访问的全局变量。
 局部静态变量会预先被作为全局变量处理,和全局变量都保存在执行文件中的数据区中,只是被定义在某个作用域内;
  局部静态变量的初始化只是在做赋值操作而已,c++语法规定局部静态变量只被初始化一次。
 
 在第一个局部静态变量附近分配一个地址存放标志。

void InNumber(int var)
{
    static int nInt = var;
    static int nInt2 = var+2;
    static int nInt3 = var+3;
    printf("%d,%d,%d",nInt, nInt2, nInt3);
}
static int nInt = var;
00AC1003  mov         eax,dword ptr ds:[00AC3370h] 
00AC1008  and         eax,1 
00AC100B  jne         InNumber+25h (0AC1025h) 
00AC100D  mov         ecx,dword ptr ds:[0AC3370h] 
00AC1013  or          ecx,1 
00AC1016  mov         dword ptr ds:[0AC3370h],ecx 
00AC101C  mov         edx,dword ptr [var] 
00AC101F  mov         dword ptr ds:[0AC337Ch],edx 
    static int nInt2 = var+2;
00AC1025  mov         eax,dword ptr ds:[00AC3370h] 
00AC102A  and         eax,2 
00AC102D  jne         InNumber+4Ah (0AC104Ah) 
00AC102F  mov         ecx,dword ptr ds:[0AC3370h] 
00AC1035  or          ecx,2 
00AC1038  mov         dword ptr ds:[0AC3370h],ecx 
00AC103E  mov         edx,dword ptr [var] 
00AC1041  add         edx,2 
00AC1044  mov         dword ptr ds:[0AC3374h],edx 
    static int nInt3 = var+3;
00AC104A  mov         eax,dword ptr ds:[00AC3370h] 
00AC104F  and         eax,4 
00AC1052  jne         InNumber+6Fh (0AC106Fh) 
00AC1054  mov         ecx,dword ptr ds:[0AC3370h] 
00AC105A  or          ecx,4 
00AC105D  mov         dword ptr ds:[0AC3370h],ecx 
00AC1063  mov         edx,dword ptr [var] 
00AC1066  add         edx,3 
00AC1069  mov         dword ptr ds:[0AC3378h],edx 
    printf("%d,%d,%d",nInt, nInt2, nInt3);
00AC106F  mov         eax,dword ptr ds:[00AC3378h]

如果如下
void InNumber(int var)
{
  static int nn = 33;   //nn将不再使用标志,直接当作全局变量处理,但作用域还是局部。
    static int nInt = var;

通过名字粉碎来区别作用域,UE打开.obj文件如下:
nInt3@?1??InNumber@@YAXH@Z@4HA
$?nInt@?1??InNumber@@YAXH@Z@4HA

void Show(char szBuffer[]) //数组传参
{
    int wrongSize = sizeof(szBuffer); //此时szBuffer为指针类型,并非数组, 4
    int rightSize = strlen(szBuffer); //取决外部传入
    strcpy_s(szBuffer, 20, "hello, my sunny!");
}

局部静态数组和局部静态变量有些不同,无论局部静态数组有多少个元素,也只会检查一次初始标志位。
数组的下标寻址比指针寻址高效。数组名本身就是常量地址。而指针需要取其指向的地址值。

第九章:结构体和类
空类实际长度为1字节,如果不占内存,则无法得到空类实例的地址,this指针失效,因此不能被实例化;没有数据成员,还可以有成员函数。

结构体和类中的数据成员分配内存时,结构体中的当前数据成员类型长度为M,指定的对齐值为N,那么实际对齐值为q=min(M,N),其成员的地址安排在q的倍数上。
结构体中数据成员类型最大值为M,指定的对齐值为N,那么实际对齐值为min(M,N). 结构体整体大小为min(M,N)的整数倍。
#pragma pack(N) //调整对齐大小。
当结构体中以数组作为成员时,将根据数组元素的长度计算对齐值,而不是按数组的整体大小去计算。
struct STR{
 char cChar;
 char cArray[4];
 short sShort;
};   
  STR ss = {'y',"and",4};
    //79 61 6e 64 00 cc 04 00
    //y  a  n  d        4
void *pp = &((STR*)NULL)->sShort; //取相对地址。

类的成员函数默认是thiscall调用方式,与_stdcall相同,被调用方负责平衡栈,但传参不同,第一参数(this)使用寄存器ecx传递,而非栈顶。
thiscall不是关键字,不能显示调用。

静态数据成员和静态变量原理相同(有作用域的特殊全局变量),初值会写入编译链接后的执行文件后。所以不参与对象size计算。

类对象作为参数,如果只是简单变量,真依序压栈对象的成员变量,最先定义的最后压栈。如果没有构造函数,也不会调系统默认的构造函数。

class CRet
{
public:
    int a;
    int b[8];
};

CRet GetReturn()
{
    CRet temp;
    temp.a = 3;
    for (int i = 0; i < 8; ++i)
    {
        temp.b[i] = i + 6;
    }
    return temp;
}

int _tmain(int argc, _TCHAR* argv[])
{
    CRet mobj;
  //1.此时main函数已经临时对象temp
    mobj = GetReturn(); //2.GetReturn函数结束,栈帧关闭,所以栈帧关闭前会复制到temp,3. 再次temp赋值给mobj,过了这条语句作用域,temp消失。//如果重载了“=”,这里会调用=
   
    如果为如下://定义时赋初值才会调用拷贝构造
    CRet mobj = GetReturn(); //不会有临时对象,而是直接把mobj的地址作为隐含的参数传递给GetReturn(),在GetReturn()函数内部完成拷贝构造的过程。
   
//note:
1. mobj = GetReturn(); ";"后会析构
2. mobj = GetReturn(),
 printf("hell");  则是在这里的";"后才会析构这个temp对象。
3. 当引用这个temp对象时,生命期与引用相同。
 
//下面两个有错误,不要返回局部变量
CRet* GetAA()
{
    CRet temp;
    return &temp;
}
CRet& GetBB()
{
    CRet temp;
    return temp;
}

thiscall 使用ecx传this指针, __fastcall使用ecx用来传第一个参数,所以不能作为唯一识别特征。

局部对象
堆对象  new成功后再会调构造函数
参数对象 调用拷贝构造函数,该构造函数只有一个参数,类型为对象的引用
返回对象
全局对象  //main函数退出后调用析构函数 
静态对象  //main函数退出后调用析构函数

定点断点, tools->options->debugging->symbols select Microsoft Symbols Servers to download symbols.
Ctrl+B than put in function name.
Ctrl+Alt+B list and edit all breakpoint, Condition and Hit Count.
编译器在以下两种情况下会提供默认的构造函数:
1.本类、本类中定义的成员对象或者父类中有虚函数存在;
2.父类或本类中定义的成员对象带有构造函数;
如果没有这两种情况,默认构造函数已经没有存在的意义,只会影响效率。

delete p; delete []p; 释放对象类型标志,1为单个对象,3为释放对象数组,0表示仅仅执行析构函数。
申请对象数组时,由于对象都在同一个堆空间中,编译器使用了堆空间的前4字节数据来保存对象的总个数。

析构顺序,调用自身的析构函数->声明倒序调用成员对象的析构函数->调用基类析构函数

基类声明为虚析构
CBase *psub = new CSub;
delete psub;
     mov         edx,dword ptr [ebp-0ECh]  //传递this
0039183E  mov         eax,dword ptr [edx]     //取得虚表指针
00391840  mov         ecx,dword ptr [ebp-0ECh]  //传递this
00391846  mov         edx,dword ptr [eax]     //间接调用虚析构函数
00391848  call        edx

基类声明为虚析构
CBase *psub = new CSub;
delete psub;
     mov         ecx,dword ptr [ebp-0ECh]        //传递this
012A183C  call        CBase::`scalar deleting destructor' (012A124Eh)  //直接调用基类析构函数

要习惯给析构函数加virtual

c++反汇编与逆向分析相关推荐

  1. C++反汇编与逆向分析之数据类型的基本表现学习笔记

    float GetFloat() {return 12.25f; }void Add(int &nVar) {nVar++; } int main(int argc, char* argv[] ...

  2. c++反汇编与逆向分析技术揭秘_C++反汇编与逆向分析技术揭秘

    一.单类继承 在父类中声明为私有的成员,子类对象无法直接访问,但是在子类对象的内存结构中,父类私有的成员数据依然存在.C++语法规定的访问限制仅限于编译层面,在编译过程中进行语法检查,因此访问控制不会 ...

  3. [安全攻防进阶篇] 二.如何学好逆向分析、逆向路线推荐及吕布传游戏逆向案例

    从2019年7月开始,我来到了一个陌生的专业--网络空间安全.初入安全领域,是非常痛苦和难受的,要学的东西太多.涉及面太广,但好在自己通过分享100篇"网络安全自学"系列文章,艰难 ...

  4. 逆向分析入门实战(三)

    本文由作者首发于合天智汇:http://www.heetian.com/info/840 之前两篇文章,针对恶意代码为了确保自身只有一个实例在运行进行了正向开发和逆向分析.逆向入门分析实战(一).逆向 ...

  5. 逆向分析入门实战(一)

    本文由作者首发于合天智汇,http://www.heetian.com/info/742 1.木马分析入门 大家好,我最近从Web安全开始学习二进制安全,分享一下自己学习过程的收获和心得体会.由于是入 ...

  6. 逆向分析入门实战(二)

    上次我们对主函数分析完成了,逆向入门分析实战(一)那么这次我们对子函数IsAlreadyRun进行分析. C语言代码 IsAlreadyRun函数的C语言代码如下图所示: 下面对其汇编代码进行分析: ...

  7. 【世界上最优秀的逆向分析工具】IDA Pro6.1绿色版

    [世界上最优秀的逆向分析工具]IDA Pro6.1绿色版 让编程改变世界 Change the world by program 世界上最优秀的静态逆向工具没有之一 [caption id=" ...

  8. TI(德州仪器) TMS320C674x逆向分析之一

    一.声明 作者并不懂嵌入式开发,整个逆向流程都是根据自身逆向经验,一步一步摸索出来,有什么错误请批评指正,或者有更好的方法请不吝赐教.个人写作水平有限,文中会尽量把过程写清楚,有问题或是写的不清楚的地 ...

  9. (47)逆向分析 KiSystemService 函数填充 _KTRAP_FRAME 部分

    一.回顾 之前的课程,我们学习了API系统调用在3环部分做的事情,有两种方式进0环,分别是中断门和快速调用,分别调用两个不同的函数 KiSystemService 和 KiFastCallEntry. ...

最新文章

  1. 64 安装_解决“不能安装 64 位Office,因已安装 32 位 Office 产品”问题
  2. 存款利息python题_python入门教程NO.8 用python写个存款利息计算器 已
  3. java 控制 android_Java For Android - 流程控制
  4. 收藏这些芯片原厂的代码仓库
  5. SonarQube中配置c语言/c++语言代码规则插件
  6. 【Python】Matplotlib绘制正余弦曲面图
  7. 关系型数据库与NoSQL数据库简述
  8. 跳过DOSBox映射的方法
  9. Asp.net Boilerplate 源码无法打开——找不到.net core sdk
  10. Mask R-CNN官方实现“又”来了!基于PyTorch,训练速度是原来2倍
  11. 未来的建筑行业项目管理集成系统展望
  12. 记一个单双引号的特别用法
  13. 那些年关于JavaWeb的点点滴滴,你想看的这里全都有噢~
  14. [从零开始学习FPGA编程-22]:进阶篇 - 架构 - FPGA内部硬件电路的设计与建模
  15. java 多余的空格_Java去除字符串多余空格以及首尾空格
  16. 微信小程序——“茶点错过你“奶茶店
  17. AndroidStudio软件用法详细说明
  18. 小程序picker用法
  19. Springboot 日志、配置文件、接口数据脱敏
  20. 从测序到宏基因组:聚焦菌群生信分析方法最前沿

热门文章

  1. CV之Image Caption:Image Caption算法的相关论文、设计思路、关键步骤相关配图之详细攻略
  2. Windows系统下使用protobuf:protobuf的简介、安装、使用方法之详细攻略
  3. 成功解决PermissionError(权限拒绝解决答案集锦): [Errno 13] Permission denied: ‘f:\\program files\\python\\python36\
  4. docker 如何删除<none>镜像
  5. C#实现水晶报表绑定数据并实现打印
  6. 安卓手机开机键失灵,FASTBOOT模式ADB重启
  7. 两个inline-block消除间距和对齐(vertical-align)
  8. su 与 sudo 区别
  9. duilib 自带树形控件的认识
  10. linux copy_from/to_user原理