汇编语言:第二讲

 前言:

这学期选修了汇编语言,通过发表学习记录,希望可以帮助加深我的理解,扎实掌握汇编语言相关知识。这门课是网络安全攻防课程的基础,学校强调逆向工程方法。除此之外,我还希望可以深入学习到汇编程序的开发,落实一些编程方法,掌握一部分单片机的开发技巧。另外,本文不仅是课上的学习记录,也包含了补充和拓展。 

参考书籍:

C++反汇编与逆向分析技术揭秘(第2版)

C++反汇编与逆向分析技术揭秘(第2版)-钱林松 张延清-微信读书 (qq.com)

《汇编语言》王爽

汇编语言-王爽-微信读书 (qq.com)

《深入理解计算机系统》

深入理解计算机系统(原书第3版) -兰德尔 E.布莱恩特 等-微信读书 (qq.com)

目录

 前言:

备注:

 正文:

随堂笔记:

1.数据寄存器:

 2.地址寄存器

课堂实验:以动态方式逆向修改输出字符串

巩固拓展:(会略过部分内容并突出部分内容)

1.1使用Visual Studio

重要操作:

VS编译选项:

使用命令行编译

<1>编译32位Debug/Release程序

<2>编译64位Debug/Release程序

1.2安装GCC(略写)

1.3安装Clang

1.4调试工具OllyDbg

1.5调试工具x64dbg

1.6调试工具WinDbg

1.7反汇编静态分析工具IDA

1.加载分析文件

2.认识各种视图功能

3.查看分析结果

4.切换反汇编视图与流程视图

5.IDA名称识别

1.8反汇编引擎工作原理


备注:

 这节课课上讲解了汇编语言基本概念和寄存器相关基础,进行了动态逆向的课上实践。

 

 正文:

随堂笔记:

1.数据寄存器:

 2.地址寄存器

3. 控制寄存器

有关更深入的内容,后续会在CSAPP的回顾中整理清楚。

课堂实验:以动态方式逆向修改输出字符串

 现使用这个C程序进行实验:

#include<cstdio>
#include<cstdlib>
int main()
{
	printf("hello world!");
	system("pause");
	return 0;
}

 

巩固拓展:(会略过部分内容并突出部分内容)

C++反汇编与逆向分析技术揭秘(第2版)第一章:熟悉工作环境和相关工具

1.1使用Visual Studio

(上学期这部分已有相关训练,略写这部分内容)

重要操作:

“生成解决方案”(快捷键Ctrl+Shift+B)——编译程序

“调试”——“开始执行“(快捷键Ctrl+F5)——运行程序

32位程序在项目根目录Debug\Release目录下

64位程序在项目根目录x64/Debug/或/x64/Release目录下

”调试“——”窗口“——”反汇编“(快捷键Ctrl+Alt+D)——打开反汇编窗口

VS编译选项:

Debug:调试版:编译器默认不对生成的代码进行优化

Release:发布版:

x86:编译32位应用程序

x64:编译64位应用程序

01优化:最小文件优化

02优化:最快执行速度优化(默认)

使用命令行编译

VS也提供命令行工具编译程序,使用命令行可以很方便地编译没有VS项目文件(.sln)的程序,例如一些开源源码。

说明:

x64 Native Tools Command Prompt for VS 2022:编译64位程序命令行

x64_x86 Cross Tools Command Prompt for VS 2022:编译兼容32位程序命令行

x86 Native Tools Command Prompt for VS 2022:编译32位程序命令行

x64_x86 Cross Tools Command Prompt for Vs 2022:编译兼容64位程序命令行

Developer Command Prompt:

使用32位 x86构架的本地工具,构建32位x86架构的代码(生成32位的库)
x86 Native Tools Command Prompt:

使用32位 x86构架的本地工具,构建32位x86架构的代码(生成32位的库)
x64 Native Tools Command Prompt:

使用64位 x64构架的本地工具,构建64位x64架构的代码(生成64位的库)
x86_x64 Cross Tools Command Prompt:

使用32位 x86构架的本地工具,构建64位x64架构的代码(32位系统编译64位的库)
x64_x86 Cross Tools Command Prompt:

使用64位 x64构架的本地工具,构建32位x86架构的代码(64位系统编译32位的库)

<1>编译32位Debug/Release程序

运行命令行x86 Native Tools Command Prompt

cd <源码目录>
cl /O2 /Fe:Hello.exe Hello.cpp

/O2表示编译Release版,不写默认Debug版

/Fe指定生成可执行文件的名称

<2>编译64位Debug/Release程序

运行x64 Native Tools Command Prompt,其余操作不变。

1.2安装GCC(略写)

GCC(GNU Compiler Collection,GNU编译器套件)是由GNU开发的支持C/C++的编译器。

是以GPL许可证发行的自由软件,是一个跨平台的编译器。

在软件逆向工程中,经常会遇见使用GCC编译的应用程序。

在Windows上安装GCC可以选择安装Cygwin或者MinGW-w64

1.3安装Clang

Clang是现在一个比较流行的编译器,越来越多的软件选择使用Clang编译器编译。

Clang官网下载地址:http://releases.llvm.org/download.html

1.4调试工具OllyDbg

在软件开发过程,调试工具可以高效找出软件中存在的错误

在逆向分析领域,调试工具可以分析软件的行为

对于有源码的程序,使用Visual Studio进行调试

对于无源码的程序,使用OllyDbg等进行调试分析

操作系统提供了完整的调试接口,各类调试工具可以方便地观察和控制目标软件。

使用调试工具加载程序一边运行一边分析的过程,称为动态分析

1.加载可执行程序

2.查看API MessageBoxA各参数功能

3.定位数据

4.修改数据

5.调试程序

1.5调试工具x64dbg

OllyDbg虽然功能强大,但是并不支持64位应用程序的调试。

x64dbg是一个调试器,支持32/64位程序的调试。

1.6调试工具WinDbg

WinDbg是微软公司出品的一个支持32/64位程序调试的免费调试器,既支持有源码的调试,又支持无源码的程序调试。

不仅可以调试应用程序,还可以进行内核测试。

可以从微软的符号服务器中获取系统符号文件,使应用反汇编代码可读性更好。

1.7反汇编静态分析工具IDA

  静态分析,是相对于动态分析而言的。

在动态分析过程,调试器加载程序,并以调试模式运行起来,观察者在执行过程中观察执行流程。

但是在实际分析中,很多场合不方便运行目标,比如软件的某一模块、病毒程序等

需要直接把程序的二进制代码翻译成汇编语言,方便程序员阅读(静态分析)。这个过程称为反汇编。

OllyDbg也有反汇编功能,但它是调试工具,不适用于静态分析。

通过hello.exe文件来尝试使用以下IDA:

1.加载分析文件

IDA加载分析文件,会询问分析方式。

Portable executable for AMD64(PE)[pe64.dll]————分析文件为PE格式

Binary file———————————————————分析文件为二进制格式

现选择PE格式分析文件进行尝试。

2.认识各种视图功能

IDA View-A:分析视图窗口,用于显示分析结果。可选流程图/代码形式。

Hex View-1:二进制视图窗口,打开文件的二进制信息

Exports:分析文件中的导出函数信息窗口

Imports:分析文件中的导入函数信息窗口

Names Window:名称窗口,分析文档用到的名称

Functions Window:分析文件中的函数信息窗口

Structures:添加结构体信息窗口

Enums:添加枚举信息窗口

Local Types:Each database has a local type library embedded into it. This type library (til) is used to store types that are local to the current database. 

3.查看分析结果

图中反汇编代码,将其复制到汇编IDE中,稍加修改,就可以进行编译和链接。

IDA的数据查询非常简单,只需要双击标号,即可跟踪到该数据的定义处。

查看函数实现的方式也是如此。

如果要返回函数调用处,按Ese键即可返回。

4.切换反汇编视图与流程视图

默认视图为流程视图。

切换——在函数体内选择Text view。

切回——在函数体内选择Graph view。

5.IDA名称识别

IDA可以识别出函数MessageBoxA及各参数的信息。

IDA通过SIG文件识别已知的函数信息。利用此功能可以识别第三方提供的库函数,简化分析

制作SIG文件:……

sig文件将函数定义包含在了里面,我们引用了sig文件之后,调用函数看到的就是函数名,对代码可读性有很大提升。

1.8反汇编引擎工作原理

在x86平台下使用的汇编指令对应的二进制机器码为Intel指令集Opcode.

1.Instruction Prefixes:指令前缀

指令前缀是可选项,作为指令的补充说明信息,主要用于4种情况

A:重复指令,如REP、REPE\REPZ

B:跨段指令,如MOV DWORD PTR FS:[XXXX],0

C:将操作数从32位转为16位,如MOV AX,WORD PTR DS:[EAX]

D:将地址从16位转为32位,如MOV EAX,DWORD PTR DS:[BX+SI]

2.Opcode:指令操作码

Opcode是机器中的操作符部分,用来说明指令语句执行什么操作

比如说明某条汇编语句是MOV、JMP还是CALL。

Opcode是汇编指令语句必不可少的组成部分,解析Opcode是反汇编引擎的主要工作。

3.Mode R/M:操作数类型

Mode R/M 作用是辅助Opcode解视汇编指令助记符后面的操作数类型。

R——寄存器

M——内存单元

Mode R/M 占一字节的固定长度

第6.7位可以描述4种状态,分别用来描述第0、1、2位是寄存器还是内存单元

第3.4.5位用于指定作为变址的寄存器;

第6.7位用于指定乘数,四种状态对应——1、2、4、8

4.SIB:辅助 Mode R/M 计算地址偏移

SIB的寻址方式:基址 + 变址

第0.1.2位用于指定作为基址的寄存器,

第3.4.5位用于指定作为变址的寄存器

第6.7位用于指定乘数——1.2.4.8

5.Displacement:辅助 Mode R/M,计算地址偏移

Displacement用于辅助SIB,如MOV EAX,DWORD PTR DS:[EBX+ECX*2+3]

这条指令的“+3”是由Displacement指定的。

6.Immediate:立即数

用于解释指令语句中操作数作为一个常量值的情况。

反汇编引擎通过查表将由以上6种方案组合而成的机器指令编码解释为对应的汇编指令

从而完成机器码的转换工作

《汇编语言》王爽Chapter2——寄存器

在CPU中:

运算器进行信息处理

寄存器进行信息存储

控制器控制各种器件进行工作

内部总线连接各种器件,在它们之间进行数据的传送。

寄存器是CPU中程序员可以用指令读写的部件。

程序员通过改变寄存器中的内容来实现对CPU的控制。

 2.1 8086CPU 有14个寄存器:

AX、BX、CX、DX通常用来存放一般的数据——通用寄存器

8086CPU 的上一代CPU中的寄存器都是8位的,为了保证兼容,使原来基于上代CPU编写的程序仍可以运行,

8086CPU的AX、BX、CX、DX这4个寄存器都可分为两个可独立使用的8为寄存器来用。

AX:分为AH(低八位) AL(高八位) 

BX:分为BH(低八位) BL(高八位)

CX:分为CH (低八位)CL (高八位)

DX:分为DH(低八位) DL (高八位)

 2.2字在寄存器中的存储

8086CPU可以一次性处理两种尺寸的数据:

字节:记为Byte,一个字节由8个bit构成,可以存在8位寄存器中

字:记为word,一个字由两个字节构成,这两个字节分别称为这个字的高位字节和低位字节

2.3几条汇编指令

在写一条汇编指令或一个寄存器名称时不区分大小写。

在进行数据传输或运算时,要注意指令的两个操作对象的位数应当是一致的。

2.4物理地址:

在CPU访问内存单元时,要给出内存单元的地址。

所有的内存单元构成的存储空间是一个一维的线性空间

每一个内存单元在这个空间中都有一个唯一的地址

我们将这个唯一的地址称为物理地址。

 2.5 16位结构的CPU

我们说8086CPU的上一代CPU(8080,8085)等是8位机,

而8086是16位机,也可以说8086是16位结构的CPU

  16位结构,描述了一个CPU具有一下方面的结构特性

运算器依次最多可以处理16位的数据

寄存器的最大宽度为16位

寄存器和运算器之间的通路为16位

8086是16位的CPU,也就是说,

在8086内部,能够一次性处理、传输、暂时存储的信息的最大长度是16位的。

2.6 8086CPU给出物理地址的方法

8086CPU有20位地址总线,可以传送20位地址,达到1MB的寻址能力

8086CPU又是16位结构,在内部一次性处理、传输、暂时存储的地址为16位。

从内部结构来看:

  如果将地址从内部简单地发出,那么它只能送出16位地址,表现出的寻址能力只有64KB。

8086CPU采用一种在内部用两个16位地址合成的方法来形成一个20位的物理地址。

8086CPU相关部件的逻辑结构如图:

当8086CPU要读写内存时:

1>CPU中相关的部件提供两个16位地址,一个称为段地址,一个叫偏移地址

2>段地址和偏移地址通过内部总线送入一个称为地址加法器的部件

3>地址加法器将两个16位地址合成为一个20位的物理地址

4>地址加法器通过内部总线将20位物理地址送入输入输出的控制电路

5>输入输出控制电路将20位物理地址送上地址总线

6>20位物理地址被地址总线传送到存储器

地址加法器采用:物理地址=段地址*16+偏移地址的方式用段地址合成物理地址。

例如:8086CPU要访问123C8H的内存单元时:

2.7段地址*16+偏移地址=物理地址的本质含义

本质含义是:

  CPU在访问内存时,用一个基础地址(段地址*16)和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址。

用这种方法来计算物理地址是因为16位结构有限,为了拓展寻址能力,引入段地址和偏移地址

2.8 段的概念

“段地址”可能让人误以为内存被划分成了一个一个的段,每一个段有一个段地址。

这种认识是不正确的,会影响以后的理解和应用。

  其实,内存没有分段,段的划分来自CPU,由于8086CPU用“基础地址+偏移地址=物理地址”的方式给出内存单元的物理地址,使得我们可以用分段的方式来管理内存。

 在编程时可以根据需要,将若干地址连续的内存单元看作一个段。

用段地址*16定位段的起始地址(基础地址)

用偏移地址定位段中的内存单元

注意:

段地址*16必然是16的倍数,所以一个段的起始地址也一定是16的倍数

偏移地址位16位,16位地址的寻址能力位64KB,所以一个段长度最大为64KB

小结: 

CPU访问内存单元时,必须向内存提供内存单元的物理地址

CPU可以用不同的段地址和偏移地址形成同一个物理地址

可以根据需要,将地址连续、起始地址为16的倍数的一组内存单元定义为一个段。

2.9段寄存器

段地址在8086CPU的段寄存器中存放。8086CPU有4个段寄存器:CS、DS、SS、ES

8086CPU要访问内存时由这4个段寄存器提供内存单元的段地址。

2.10CS和IP

CS和IP是8086CPU中两个最关键的寄存器

它们指示了CPU当前要读取指令的地址。

CS为代码段寄存器,IP为指令指针寄存器

 在8086PC机中,任意时刻,设CS中内容为M,IP中内容为N

8086CPU将从内存M*16+N单元开始,读取一条指令并执行。

  即任意时刻,CPU将CS:IP指向的内容当作指令执行。

8086CPU:

8086CPU的工作过程:

1>从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器

2>IP=IP+所读取指令的长度,从而指向下一条指令

3>执行指令,转到步骤1>,重复这个过程

在8086CPU加电启动或复位后(CPU 刚开始工作时)CS和IP被设置为:

CS = FFFFH

IP  = 0000H

即在8086PC机刚启动后,CPU从内存FFFF0H单元中读取指令执行,FFFF0H单元中的指令是8086PC开机后执行的第一条指令。

 CPU将CS:IP指向的内存单元中的内容看作指令,而不是数据。

 2.11修改CS、IP 的指令

程序员可以通过改变CS:IP 中的内容来控制CPU执行目标指令。

8086CPU大部分寄存器的值,都可以用mov指令来改变,mov指令被称为传送指令。

但是,mov指令不能用于设置CS、IP的值。

原因是8086CPU没有提供这种功能。

8086CPU提供了另外的指令来改变它们的值。

能够改变CS、IP的内容的指令被统称为转移指令

2.12代码段

对于8086PC机,在编程时,可以根据需要,将一组内存单元定义为一个段。

我们可以将长度为N(N<=64KB)的一组代码,存在一组地址连续、起始地址为16的倍数的内存单元中,我们可以认为,这段内存是用来存放代码的,从而定义了一个代码段:

如何使得代码段中的指令被执行呢?将一段内存当作代码段,仅仅是我们在编程时的一种安排,CPU并不会由于这种安排,就自动地将我们定义的代码段中的指令当作指令来执行。

CPU只认被CS:IP指向的内存单元中的内容为指令。

所以,要让CPU执行我们放在代码段中的指令,必须要将CS:IP指向所定义的的代码段中的第一条指令的首地址

小结:

1>段地址在8086CPU的段寄存器中存放。当8086CPU要访问内存时,由段寄存器提供内存单元的段地址。8086有4个段寄存器,其中CS用来存放指令的段地址。

2>CS存放指令的段地址,IP存放指令的偏移地址。

3>8086CPU工作过程:

  从CS:IP指向的内存单元读取指令并放入指令缓冲器

  IP指向下一条指令

  执行指令

4>8086CPU提供转移指令修改CS、IP中的内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值