C/C++教程

《C++反汇编与逆向分析技术揭秘》--钱林松,赵海旭 著

本文主要是介绍《C++反汇编与逆向分析技术揭秘》--钱林松,赵海旭 著,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

1 熟悉工作环境和相关工具

1.1 调试工具Microsoft Visual C++6.0和OllyDBG

1.2 反汇编静态分析工具IDA

1.3 反汇编引擎的工作原理


2 基本数据类型的表现形式

2.1 整数类型

2.2 浮点数类型

2.3 字符和字符串

2.4 布尔类型

2.5 地址、指针和引用

2.6 常量


3 认识启动函数,找到用户入口

3.1 程序的真正入口

3.2 了解VC++6.0的启动函数

3.3 main函数的识别


4 观察各种表达式的求值过程

4.1 算术运算和赋值

4.2 关系运算和逻辑运算

4.3 位运算

4.4 编译器使用的优化技巧

4.5 一次算法逆向之旅


5 流程控制语句的识别

5.1 if语句

  • if语句只能判断两种情况,0和非0

  • 5-1 if语句构成

#include<stdio.h>
int main()
{
	int a=2;
	if (a==2)//注意与汇编位置对比
	{
		printf("%d",a);
	}
	return 0;
}

image-20211003092942039

image-20211003093502615

  • 使用相反的条件跳转指令

  • 表达式短路和if语句的反汇编一样,不容易区分

    总结:
    ;先执行各类影响标志位的指令
    ;其后各种条件跳转指令
    JCC xxxx
    
  • 循环结构中也会出现类似代码,分析过程还需要结合上下文

5.2 if...else...语句

  • 取相反的条件跳转指令
  • if语句条件成立执行后有个jmp指令,跳过else的代码块
  • 条件表达式与if-else的判断比较难
  • 5-3 if-else组合
#include<stdio.h>
int main()
{
	int a=2;
	if (a==2)
	{
		printf("a等于2");
	}
	else{
		printf("a不等于2");
	}
	return 0;
}

image-20211003094550882

  • 利用两个跳转(jne,jmp)来区别if块和else块的边界
总结:
;先执行影响标志位的指令
jcc ELSE_BEGIN  ;重点
IF_BEGIN:
...
IF_END:
jmp ELSE_END    ;重点
ELSE_BEGIN:
...
ELSE_END:
  • 在没有高级源码的情况下,分析者需要先定位语句块的边界,然后根据跳转目标和逻辑依赖慢慢推出高级代码

5.3 用if构成的多分支流程

#include<stdio.h>
int main()
{
	int a=2;
	if (a<0)
	{
		printf("a小于2");
	}
	else if(a==2)
	{
		printf("a等于2");
	}
	else
	{
		printf("a为其他");
	}
	return 0;
}

image-20211003101243644

image-20211003101433819

  • 每一个if语句由cmp与jcc组成,而else代码之前没有cmp判断,直接跳到最后
总结:
;会影响标志位的指令 
JCC ELSE_IF_BEGIN   //if条件不成立,跳转到下一条if_else首地址
IF_BEGIN:
...            //if条件成立执行代码块
IF_END: 
jmp END      //执行if后跳出到结束地址

ELSE_IF_BEGIN:      //else_if条件不成立,跳转到else首地址
;会影响标志位的指令
JCC ELSE_BEGIN
...             //else_if条件成立,执行代码块
ELSE_IF_END:
jmp END    //执行else_if后跳出到结束地址

ELSE_BEGIN:   //if和else_if条件都不成立,执行else代码
...
ELSE_END   //执行完就结束了,不用再跳转了
...
END:
...
  • 编译器自动优化问题,空间与效率的问题

5.4 switch的真相

  • switch是常用的多分支结构,效率上高于if else_if语句
#include<stdio.h>
int main()
{
	int nIndex = 1;
	scanf_s("%d", &nIndex);
	switch (nIndex)
	{
	case 1:
		printf("nIndex==1");
	case 2:
		printf("nIndex==2");
	case 100:
		printf("nIndex==100");
	}
	return 0;
}

image-20211003105522799

image-20211003105622944

int main()
{
000C18B0  push        ebp  
000C18B1  mov         ebp,esp  
000C18B3  sub         esp,0D4h  
000C18B9  push        ebx  
000C18BA  push        esi  
000C18BB  push        edi  
000C18BC  lea         edi,[ebp-14h]  
000C18BF  mov         ecx,5  
000C18C4  mov         eax,0CCCCCCCCh  
000C18C9  rep stos    dword ptr es:[edi]  
000C18CB  mov         eax,dword ptr [__security_cookie (0CA024h)]  
000C18D0  xor         eax,ebp  
000C18D2  mov         dword ptr [ebp-4],eax  
000C18D5  mov         ecx,offset _A43DB3BE_源@cpp (0CC003h)  
000C18DA  call        @__CheckForDebuggerJustMyCode@4 (0C1316h)  

	int nIndex = 1;
000C18DF  mov         dword ptr [nIndex],1  
	scanf_s("%d", &nIndex);
000C18E6  lea         eax,[nIndex]  
000C18E9  push        eax  
000C18EA  push        offset string "%s" (0C7B30h)  
000C18EF  call        _scanf_s (0C13C0h)  
000C18F4  add         esp,8  
	switch (nIndex)
000C18F7  mov         eax,dword ptr [nIndex]  
000C18FA  mov         dword ptr [ebp-0D4h],eax  
000C1900  cmp         dword ptr [ebp-0D4h],1  
000C1907  je          __$EncStackInitStart+61h (0C191Dh)  
000C1909  cmp         dword ptr [ebp-0D4h],2  
000C1910  je          _printf+0Ah (0C192Ah)  
000C1912  cmp         dword ptr [ebp-0D4h],64h  
000C1919  je          _printf+17h (0C1937h)  
000C191B  jmp         _printf+24h (0C1944h)  
	{
	case 1:
		printf("nIndex==1");
000C191D  push        offset string "two" (0C7B34h)  
000C1922  call        _printf (0C10CDh)  
000C1927  add         esp,4  
	case 2:
		printf("nIndex==2");
000C192A  push        offset string "nIndex==2" (0C7BE4h)  
000C192F  call        _printf (0C10CDh)  
000C1934  add         esp,4  
	case 100:
		printf("nIndex==100");
000C1937  push        offset string "nIndex==100" (0C7BF0h)  
000C193C  call        _printf (0C10CDh)  
000C1941  add         esp,4  
	}
	return 0;
000C1944  xor         eax,eax  
}
  • if...else_if会在条件跳转后紧跟语句块,switch case则将所有的条件跳转放到一起,把case语句块也放到了一起

5.5 难以构成跳转表的switch

5.6 降低判定树的高度

5.7 do/while/for的比较

5.8 编译器对循环结构的优化


6 函数的工作原理

6.1 栈帧的形参和关闭

6.2 各种调用方式的考察

6.3 使用ebp或esp寻址

6.4 函数的参数

6.5 函数的返回值

6.6 回顾


7 变量在内存中的位置和访问方式

7.1 全局变量和局部变量的区别

7.2 局部静态变量的工作方式

7.3 堆变量


8 数组和指针的寻址

8.1 数组在函数内

8.2 数组作为参数

8.3 数组作为返回值

8.4 下标寻址和指针寻址

8.5 多维数组

8.6 存放指针类型数据的数组

8.7 指向数组的指针变量

8.8 函数指针


9 结构体和类

9.1 对象的内存布局

9.2 this指针

9.3 静态数据成员

9.4 对象作为函数参数

9.5 对象作为返回值


10 关于构造函数和析构函数

10.1 构造函数的出现时机

10.2 每个对象都有默认的构造函数吗

10.3 析构函数的出现时机


11 关于虚函数

11.1 虚函数的机制

11.2 虚函数的识别


12 从内存角度看继承和多重继承

  • 父类指针指向子类对象

12.1 识别类和类之间的关系

  • 子类具备父类所有成员数据,成员函数

  • 父类声明为私有的成员,子类对象无法直接访问,但在子类对象的内存结构中,父类私有的成员数据依然存在

  • C++访问权限仅限于编译层面,不会影响对象的内存结构

  • 12-1 定义派生类和继承类

    
    

12.2 多重继承

12.3 抽象类

12.4 菱形继承


13 异常处理

13.1 异常处理的相关知识

13.2 异常类型为基本数据类型的处理流程

13.3 异常类型为对象的处理流程

13.4 识别异常处理


14 PEiD的工作原理分析

14.1 开发环境的识别

14.2 开发环境的伪造


15 “熊猫烧香”病毒逆向分析

15.1 调试环境配置

15.2 病毒程序初步分析

15.3 “熊猫烧香”启动过程分析

15.4 “熊猫烧香”的自我保护分析

15.5 “熊猫烧香”的感染过程分析


16 调试器OllyDBG的工作原理分析

16.1 INT3断点

16.2内存断点

16.3 硬件断点

16.4 异常处理机制

16.5 加载调试程序


17 反汇编代码的重建与编译

17.1 重建反汇编代码

17.2 编译重建后的反汇编代码

这篇关于《C++反汇编与逆向分析技术揭秘》--钱林松,赵海旭 著的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!