当前位置: 首页 > article >正文

汇编与逆向(二)-汇编基础

一、汇编入门

(一)x86体系的CPU的工作模式

有两种基本的工作模式:实模式和保护模式。

实模式:也称为实地址模式,该模式最早被DOS,win9x所支持。可访问1M内存,可直接访问硬件,如对端口、中断等进行操作。目前CPU任然支持实模式,一是与早期CPU架构保持兼容,二是x86处理器都是从实模式引导。

保护模式:是处理器主要的工作模式,linux与windowsNT内核的系统都工作在x86的保护模式下。在保护模式下每个CPU可访问4GB的内存地址,且进程间是间隔的。

(二)寄存器

任何程序的执行,归根结底,都是存放在存储器中的指令序列执行的结果。

寄存器用来存放程序运行中的各种信息,包括操作数地址、操作数、运算的中间结果等。

寄存器(Register)是CPU内部的存储数据的存储单元。

x86寄存器中与逆向有关的寄存器有:基本寄存器、调试寄存器、控制寄存器。

基本寄存器分4类:8个通用寄存器(4个数据寄存器:EAX,EBX,ECX,EDX;4个指针变址寄存器:EDP,ESP,ESI,EDI),6个段寄存器(CS代码段,DS数据段,SS堆栈段,ES附加数据段,32位CPU中还有两个附加的段寄存器FS,GS)1个指令指针寄存器(EIP)1个标志寄存器(EFLAGS)。

注意:在32位CPU保护模式下段寄存器使用与概念完全不同于16位CPU段寄存器。在逆向工程中经常使用FS用于存储SEH、TEB、PEB等重要的操作系统数据结构。

(三)汇编指令

汇编指令由两部分组成分别为操作码与操作数,操作数可以有1,2或没有。

1.数据传递指令:MOV,XCHG(交换数据),LEA(装入有效地址指令)

2.逻辑运算指令:AND,OR,XOR,NOT

3.算术运算指令:ADD,SUB,ADC(带进位的加法指令=ADD+标志寄存器CF位的值),SBB(带借位的减法指令=SUB-标志寄存器CF位的值),INC(加1指令),DEC(减1指令)

注意:在进行算术运算时,需要注意各个指令影响标志寄存器的位。

4.堆栈操作指令

入栈与出栈指令:PUSH,POP。

ESP和EBP是两个32位的通用寄存器,分别存储栈顶与栈底的内存地址。堆栈分配的地址是由高到低。

保存/恢复指通用寄存器指令:PUSH AD,即在堆栈上压入所有的32位寄存器,顺序依次为EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI。POP AD指令以相反顺序弹出所有通用寄存器的数据

保存/恢复标志寄存器指令:PUSHFD、POPFD。在堆栈上压入或弹出32位EFLAGS标志寄存器的值。在某些特定情况下可以手动修改标准寄存器的某个标志位。比如让程序单步执行时可以设置EFLAGS的第八位TF标志位等,代码如下:

PUSHFD
POP EAX
OR EAX,100h
PUSH EAX
POPFD

通常将程序开始执行的地址称为入口点,简称EP。进行脱壳的首要任务就是找到程序的入口点。

指令指针EIP总是指向要执行的那条指令并在执行后自动执行下一条指令的地址。

5.转移指令:JMP(无条件转移),JCC指令集(JZ,JNZ,JE,JNE)等

测试指令TEST,比较指令(CMP),循环指令(LOOP),调用过程(CALL),返回指令(RET)

6.串操作指令:主要操作内存中连续区域的数据。MOVS,STOS,REP指令。

串传递指令MOVS:借助ESI寄存器与EDI寄存器,将内存源地址(ESI指向源地址)的数据送入内存的目标地址(EDI指向的目的地址)。共三个(MOVSB、MOVSW、MOVSD)默认MOVS为MOVSD。MOVS指令执行后,EDI和ESI寄存器指向的地址自动增加或减少1个单位(1字节、2字节或4字节),增加或减少受EFLAGS标志寄存器的DF标志位影响,DF位为0时增加,为1时减少。

串存储指令:STOS将AL/AX/EAX的值存储到EDI寄存器的指向的内存单元中。STOS指令执行后,EDI指向的内存地址根据DF标志位自动增加或减少1个单位。

重复前缀指令:REP根据ECX寄存器重复执行MOVS、STOS指令,每执行1次REP,ECX自动减1,直到为0结束。

(四)寻址方式

寻址即CPU要寻找最终操作数的过程,通常有以下方式:

1、立即数寻址:操作数直接放在指令中,作为指令的一部分放在代码中。

MOV ESI,00403000

MOV EDI,00403020

2、寄存器寻址:操作数放在寄存器中,在指令中指定寄存器名即可

MOV EAX,00403000

MOV ESI,EAX

3、内存中寻址:存储在内存中的数据,可以用多种方式给出,直接寻址、寄存器间接寻址、其他寻址方式

直接寻址:在指令中直接给出操作数所在的内存地址的方式。

MOV DWORD PTR [00403000],12345678

MOV EAX,DWORD PTR [00403000]

寄存器间接寻址:操作数的地址由寄存器给出,这里的地址为内存地址

MOV DWORD PTR [00403000],12345678

MOV EAX,00403000

MOV EDX,[EAX]

其他寻址方式:操作数据存储在内存中,寄存器相对寻址、变址寻址、基址变址寻址、比例因子寻址等。

[寄存器+立即数]

[寄存器+寄存器+数据宽度(1/2/4/8)]

......

二、汇编语言

汇编语言程序的语句指令外,还可以由伪操作宏指令组成。

伪操作又称伪指令,他不像机器指令那样在程序运行期间由计算机来执行,而是在汇编程序对源程序汇编期间由汇编程序处理的操作,它们可以完成如数据定义、分配存储区、指示程序结束等功能。

(一)数据定义及存储器分配伪操作

格式:[Variable] Mnemonic  Operand,...Operand  [;Comments]

1、其中变量(Variable)可有可无,它用符号地址表示,其作用与指令语句前的标号相同,但是后面不跟冒号。如果语句中有变量则汇编程序使其记以第一个字节的偏移量。

注释(Comments)可有可无

2、助记符(Mnemonic)说明所用伪操作的助记符,常用的有以下几种:

DB:定义字节,其后每个操作数都占1个字节

DW:定义字,占2字节

DD:定义双字,占4字节

DQ:定义四个字,占8字节

DT:定义十个字节,占10个字节

这些伪操作可以把其后跟的数据存入制定的存储单元,或者只分配存储空间并不存入确定的值。DW和DD伪操作可以存储偏移地址或完整的地址。

3、操作数(Operand)可以是常数,也可以是表达式(根据表达式可以求得一个常数),如下例4.1,图4.2

DATA_BYTE   DB   10,4,10H

DATA_WORD   DW   100,100H,-5

DATA_DW   DD   3*20,0FFFDH 

操作数也可以是字符串,如下例4.3

MESSAGE   DB  'HELLO'

 存储器中存储情况分别如下图4.2,图4.3,

操作数?可以保留存储空间,但不存入数据,如例4.3,图4.4

ABC   DB   0,?,?,?,0

DFF   DW  ?,52,?

操作数还可以使用复制操作符(DUP)复制某个或某些操作数

格式:repeat_count   DUP(operand,...,operand)

repeat_count指复制的次数或个数 。如例4.4,图4.5

ARRAY1   DB   2   DUP(0,1,2,?)

ARRAY2   DB   100   DUP(?)

             

(二)表达式赋值伪操作EQU

格式:Expression_name    EQU   Expression

例如:

CONSTANT    EQU   256   ;将数赋以符号名

DATA     EQU   HEIGHT+12   ;地址表达式赋以符号名

B   EQU   [BP+8]    ;变址引用赋以符号名B

P8    EQU    DS:[BP+8]    ;加段前缀的编制引用赋以符号名P8

注意:EQU语句的表达式中如果有变量或标号的表达式,则在该语句前应该先给出它们的定义!

与EQU类似=的伪操作也可以赋值,它们的区别:EQU中的表达式名是不允许重复定义的,而=伪操作则允许重复定义。如:EMP=7  ...   EMP=EMP+7

(三)段定义伪操作

存储器的物理地址是由段地址和偏移地址组合而成,汇编程勋再把源程序转换为目标文件时,必须确定标号和变量的偏移地址,并且需要把有关信息通过目标模块传递给连接程序,以便连接程序把不同的段和模块连接在一起形成一个可执行程序。

段定义伪操作格式:

segment   name    SEGMENT

      DS

      ES

      SS

(存储单元的定义、分配)

      CS

(指令)

      :

segment    name    SEGMENT

其中删节号部分,对于数据段、附加段和堆栈段来说,一般是存储单元的定义、分配等伪操作;对于代码段则是指令及伪操作。

 ASSUME只是将段分配给段寄存器,并不将段地址装入段寄存器中,故在代码段中要将段地址装入相应段寄存器,其中代码段并不需要装入地址,它由程序初始化时完成。

;title
;data_SEGMENT-->code_SEGMENT-->ASSUME-->start--->end
data_seg SEGMENT
	oper1 dw 10
	oper2 dw 100
	result dw ?
data_seg ENDS

code_seg SEGMENT
	ASSUME ds:data_seg,cs:code_seg ;分配段与段寄存器
	start:
		mov ax,data_seg
		mov ds,ax   ;向寄存器装入地址
		mov ax,oper1
		add ax,oper2
		mov result,ax
code_seg ENDS
	END start

 上述代码需用16位编译器 (emu8086),32位编译器(MASM32)无法编译:

(四)程序开始和结束伪操作

格式:NAME   module_name

          END  [label]

其中标号指示程序开始执行的的起始地址。若果多个程序模块相连接,则只有主程序要使用标号,其它子程序模块则只使用END而不必指定标号。汇编程序将在遇到END时结束汇编,而程序则将从START开始执行。

汇编源码基本结构

code         segment                                          ;定义code段

main         proc     far                                        ;main程序

                assume        cs:code,ds:data,es:extra        ;明确段和段寄存器

start:

        push        ds

        sub        ax,ax        ;AX寄存器值0

        ....

main        endp

code        ends

        end        start        

三、编译过程

源文件:ASM文件 ----->  目标文件:OBJ文件 ----> 执行文件:EXE文件

两个汇编程序:小汇编ASM和宏汇编MASM

MASM源代码文件通常由以下几个基本部分组成:指令(包括汇编指令和伪指令)、数据定义、宏定义、模块声明以及程序入口点。

(一)建立ASM文件

使用文本编辑器或RadASM编写asm文件

(二)生成obj文件

汇编程序的输入文件是ASM文件,输出可以有三个:OBJ文件、LST文件、CRF文件

(三)生成exe文件

LINK程序有两个输入文件OBJ和LIB,输出EXE文件

参考:1、《逆向分析实战(第2版)》冀云 杜林美著 人民邮电出版社 

          2、《IBM-PC汇编语言程序设计》沈美明 温冬婵著 清华大学出版社


http://www.kler.cn/a/516369.html

相关文章:

  • 多管齐下以IP地址查询精度
  • 汇编实验·分支程序设计
  • fpga学习入门 串口rs232回环
  • 放大器版图绘制全流程
  • JavaScript系列(41)--状态管理实现详解
  • GitHub Actions 使用需谨慎:深度剖析其痛点与替代方案
  • 《OpenCV》——图像透视转换
  • Android实训十 数据存储和访问
  • 重构后的deap因子挖掘,多股票截面因子轮动,直接优化年化收益率。(附python代码)
  • 使用C#对指定的MYSQL数据库进行备份以及常见问题
  • 网络安全大模型和人工智能场景及应用理解
  • Android核心组件——Activity
  • 虹科分享 | 汽车NVH小课堂之听音辨故障
  • three.js+WebGL踩坑经验合集:写在前面的话
  • ubuntu20.04安装使用direct_visual_lidar_calibration标定雷达和相机
  • 基于 Android 的校园闲置物品交易平台设计与实现
  • 深度探索 DeepSeek-R1:国产大模型的AGI雏形与创新进展
  • 【openwrt】openwrt odhcpd配置介绍
  • opengrok_使用技巧
  • JAVA:中介者模式(Mediator Pattern)的技术指南