【读书笔记】C++反汇编与逆向分析技术揭秘2

您所在的位置:网站首页 反汇编分析 【读书笔记】C++反汇编与逆向分析技术揭秘2

【读书笔记】C++反汇编与逆向分析技术揭秘2

2023-04-13 10:49| 来源: 网络整理| 查看: 265

目录 一、准备工作         1.1.编译环境         1.2.OllyDbg         1.3.IDA 二、基本数据类型的表现形式         2.1.无符号整数         2.2.有符号正数         2.3.浮点数类型 三、认识启动函数,找用户入口         3.1.找main函数入口方法 四、观察各种表达式的求值过程         4.1.加法         4.2.减法         4.3.乘法         4.4.除法                 4.4.1.除数为无符号2的幂                 4.4.2.除数为无符号非2的幂                 4.4.3.另一种除数为无符号非2的幂                 4.4.4.除数为有符号2的幂                 4.4.5.除数为有符号非2的幂                 4.4.6.第二种除数为有符号非2的幂                 4.4.7.除数为有符号负2的幂                 4.4.8.除数为有符号负非2的幂                 4.4.9.另一种除数为有符号负非2的幂         4.5.取模         4.6.条件跳转指令表         4.7.条件表达式 五、流程控制语句的识别         5.1.if         5.2.if else         5.3.switch                 5.3.1.分支少于4个                 5.3.2.分支大于4个且值连续                 5.3.3.分支大于4个,值不连续,且最大case值和case值的差小于256                 5.3.4.分支大于4个,值不连续,且最大case值和case值的差大于256         5.4.do while         5.5.while         5.6.for 六、函数的工作原理         6.1.各种调用方式的考察         6.2.函数的参数 七、变量在内存中的位置和访问方式         7.1.全局变量和局部变量的区别         7.2.局部静态变量的工作方式         7.3.堆变量 八、数组和指针的寻址         8.1.数组在函数内         8.2.数组作为参数         8.3.存放指针类型数组的数组         8.4.函数指针 九、结构体和类         9.1.对象的内存布局         9.2.this指针         9.3.对象作为函数参数         9.4.对象作为返回值 十、构造函数和析构函数         10.1.构造函数的出现时机                 10.1.1.局部对象                 10.1.2堆对象                 10.1.3.参数对象                 10.4.返回对象         10.2.析构对象的出现时机                 10.2.1.局部对象                 10.2.2.堆对象 十一、虚函数         11.1.虚函数的机制                 11.1.1.默认构造函数初始化虚表指针的过程                 11.1.2.调用自身类的虚函数                 11.1.3.析构函数分析         11.2.虚函数的识别 十二、从内存角度看继承和多重继承         12.1.识别类与类之间的关系         12.2.多重继承         12.3.抽象类

一、准备工作1.1.编译环境 VS2019 Release/Debug x86 1.2.OllyDbg

常用快捷键

F2:设置断点 F3:加载一个可执行程序 F4:程序执行到光标处 F5:缩小,还原当前窗口 F7:单步步入 F8:单步步过 F9:运行程序 Ctrl+F2:重新运行程序到起始处 Ctrl+F9:执行到函数返回处,用于跳出函数实现 Alt+F9:执行到用户代码处,用于快速跳出系统函数 Ctrl+G:快速定位跳转地址 1.3.IDA

常用快捷键

空格键:反汇编窗口切换文本跟图形 a:解析成字符串的首地址 b:十六进制与二进制转换 c:解释位一条指令 d:解释为数据,每按一次转换数据长度 g:快速查找到对应地址 h:十六进制与十进制转换 k:将数据解释为栈变量 m:解释为枚举成员 n:重新命名 t:把偏移改为结构体 u:取消定义函数、代码、数据的定义 x:查看交叉引用 y:更改变量的类型 分号:添加注释 shift+F9:添加结构体 Alt+T:搜索文本 ins:插入结构体 Alt+Q:修改数据类型为结构体类型 二、基本数据类型的表现形式2.1.无符号整数

以unsigned int为例

取值范围:0~4294967295(0x00000000~0xFFFFFFFF) 小尾方式存放:低数据位存放在内存的低端,高数据位存放在内存的高端 不存在正负之分,都是正数 2.2.有符号正数

以int为例

最高位是符号位,0表示正数,1表示负数 取值范围:-2147483648~2147483648 正数区间(0x00000000~0x7FFFFFFF),负数区间(0x80000000~0xFFFFFFFF) 负数在内存中都是以补码形式存放的,可以表达位:对这个数值取反+1 2.3.浮点数类型

SSE指令集

八个寄存器:XMM0-XMM8,每个寄存器占16字节(128bit)

三、认识启动函数,找用户入口3.1.找main函数入口方法

VS2019 Release版本

有3个参数,main函数是启动函数中唯一具有3个参数的函数 找到入口代码第一次调用exit函数处,离exit最近的且有3个参数的函数通常就是main函数

找main函数入口

四、观察各种表达式的求值过程4.1.加法

release版

1234567891011#include  int main(int argc, char* argv[]) {    int n1 = argc;     int n2 = argc;         //复写传播:n2等价于引用argc, n2则被删除    n1 = n1 + 1;         //下一句n1重新赋值了,所以这句被删除了        n1 = 1 + 2;            //常量折叠:n1 = 3    n1 = n1 + n2;        //常量传播和复写传播: n1 = 3 + argc    printf("n1 = %d\n", n1);    return 0;}

ida

4.2.减法

release

1234567891011#include  int main(int argc, char* argv[]) {    int n1 = argc;    int n2 = 0;    scanf_s("%d", &n2);    n1 = n1 - 100;    n1 = n1 + 5 - n2;       //n1 = n1 -95 - n2    printf("n1 = %d \r\n", n1);    return 0;}

ida

4.3.乘法

release

123456789101112#include int main(int argc, char* argv[]) {    int n1 = argc;    int n2 = argc;     printf("n1 * 15 = %d\n", n1 * 15);       //变量乘常量 ( 常量值为非 2 的幂 )    printf("n1 * 16 = %d\n", n1 * 16);       //变量乘常量 ( 常量值为 2 的幂 )    printf("2 * 2 = %d\n", 2 * 2);           //两常量相乘    printf("n2 * 4 + 5 = %d\n", n2 * 4 + 5); //混合运算    printf("n1 * n2 = %d\n", n1 * n2);       //两变量相乘    return 0;}

ida

4.4.除法

常用指令

cdq:把eax的最高位填充到edx,如果eax ≥ 0,edx = 0,如果eax < 0,edx = 0xFFFFFFFF sar:算术右移 shr:逻辑右移 neg:将操作数取反+1 div:无符号数除法 idiv:有符号除法 mul:无符号数乘法 imul:有符号数乘法 4.4.1.除数为无符号2的幂

release

1234567#include int main(unsigned argc, char* argv[]) {     printf("a / 16 = %u", argc / 16);     return 0;}

ida

4.4.2.除数为无符号非2的幂

release

123456#include  int main(int argc, char* argv[]) {    printf("argc / 3 = %u", (unsigned)argc / 3); //变量除以常量,常量为无符号非2的幂    return 0;}

ida

4.4.3.另一种除数为无符号非2的幂

release

1234567#include int main(unsigned argc, char* argv[]) {     printf("a / 7 = %u", argc / 7);     return 0;}

ida反汇编

4.4.4.除数为有符号2的幂

release

1234567#include int main(int  argc, char* argv[]) {     printf("a / 8 = %d", argc / 8);     return 0;}

ida

 

4.4.5.除数为有符号非2的幂

release

1234567#include int main(int  argc, char* argv[]) {     printf("a / 9 = %d", argc / 9);   ////变量除以常量,常量为非2的幂     return 0;}

ida

 

4.4.6.第二种除数为有符号非2的幂

release版

12345#include int main(int argc, char* argv[]) {    printf("argc / 7 = %d", argc / 7); //变量除以常量,常量为非2的幂    return 0;}

ida

 

4.4.7.除数为有符号负2的幂

release版

1234567#include int main(int  argc, char* argv[]) {     printf("a / -4 = %d", argc / -4);     return 0;}

ida反汇编

4.4.8.除数为有符号负非2的幂

release

1234567#include int main(int  argc, char* argv[]) {     printf("a / -5 = %d", argc / -5);     return 0;}

ida

 

4.4.9.另一种除数为有符号负非2的幂

release版

123456#include  int main(int argc, char* argv[]) {    printf("argc / -7 = %d", argc / -7); //变量除以常量,常量为负非2的幂    return 0;}

ida

 

4.5.取模

release版

123456#include int main(int argc, char* argv[]) {    printf("%d", argc % 8); //变量模常量,常量为2的幂    printf("%d", argc % 9); //变量模常量,常量为非2的幂    return 0;}

ida反汇编

 

4.6.条件跳转指令表

4.7.条件表达式

第一种,相差为1

 

release

123456789#include   int main(int argc, char* argv[]) {    printf("%d\r\n",argc == 5 ? 5:6);     return 0;}

ida 第二种,相差大于1

 

release

123456789#include   int main(int argc, char* argv[]) {    printf("%d\r\n",argc == 5 ? 4:10);     return 0;}

ida 第三种变量表达式

 

release

12345678#include  int main(int argc, char* argv[]) {    int n1, n2;    scanf_s("%d %d", &n1, &n2);    printf("%d\n", argc ? n1 : n2);    return 0;}

ida 第四种表达式无优化使用分支

 

release

12345678#include  int main(int argc, char* argv[]) {    int n1, n2;    scanf_s("%d %d", &n1, &n2);    printf("%d\n", argc ? n1 : n2 + 3);    return 0;}

ida

五、流程控制语句的识别5.1.if

release

12345678#include  int main(int argc, char* argv[]) {    if (argc == 0) {        printf("argc == 0");    }    return 0;}

ida

 

总结

5.2.if else

release

1234567891011121314#include  int main(int argc, char* argv[]) {    if (argc > 0) {        printf("argc > 0");    }    else if (argc == 0) {        printf("argc == 0");    }    else {        printf("argc


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3