IoT安全入门01

第一章 逆向基础

0x01 MIPS基础

1. 什么是MIPS?

1.1 什么是MIPS?

MIPS(无互锁流水线微处理器)是一种精简(RISC)指令集体系结构(ISA),起源于Stanford大学John Hennessy教授的研究成果。

image-20220802105706727

MIPS版本不同,支持的指令集不同,操作的位数也不同。MIPS可扩展项,可根据不同的需求进行扩充。

1.2 CISC&RISC

  • CISC(Complex Instruction Set Computer)复杂指令计算机。Inter的X86,AMD的K5,K6为该类型。
  • RISC(Reduced Instruction Set Computer)精简指令计算机。Acorn公司的ARM,IBM公司的PowerPC,MIPS公司的MIPS为该类型。

1.3 RISC和CISC架构

RISC(Reduced Instruction Set Computer):

  1. Less instruction and addressing modes.
  2. Only register-register operation.
  3. Load and Store instructions.
  4. High speed.
  5. Control signals are generate by external hardware circuit.
  6. Instruction is executed in one clock.

CISC(Complex Instruction Set Computer):

  1. More instuctions and addressing modes.
  2. Register to Register/ Memeory/ I/O.
  3. Load, Store and other instructions.
  4. Low speed.
  5. Control signals are generated by internal hardware circuit.

1.4 MIPS结构的基本特点

  1. 所有指令都是32位编码。
  2. 有些指令有32位供目标地址编码;有些则只有16位。因此想要加载任何一个32位值,就得用两个加载指令。16位的目标地址意味着,指令的跳转或子函数的位置必须在64K以内(上下32K)。
  3. 所有的动作原理上要求必须在1个时钟周期内完成,一个动作一个阶段
  4. 有32个通用寄存器,每个寄存器32位(32位机器)或64位(64位机器)
  5. 本身没有任何帮助运算判断的标志寄存器,要实现相应的功能时,是通过测试两个寄存器是否相等来完成的。
  6. 所有运算都是基于32位的,没有对字节和对半字的运算(MIPS里,字定义为32位,半字定义为16位)。
  7. 没有单独的栈指令,所有对栈的操作都是统一的内存访问方式。
  8. 由于MIPS固定指令长度,所以造成其编译后的二进制文件和内存占用空间比X86大。
  9. 寻址方式:只有一种内存寻址方式。就是一个基地址加一个16位的偏移地址。
  10. 内存中的数据访问必须严格对齐(至少4字节对齐)。
  11. 跳转指令只有26位目标地址,再加上2位的对齐位,可寻址28位的空间,即256M。
  12. 条件分支指令只有16位跳转地址,加上2位的对齐位,供18位寻址方式,即256K。
  13. MIPS默认不把子函数的返回地址(就是调用函数的受害指令地址)存放到栈中,而是存放在$31寄存器中。
  14. 流水线效应。由于采取了高度的流水线,结果产生了一些对程序员来说可见的效应,需要注意。最需要注意的两个效应就是分支延迟效应载入延迟效应

1.5 MIPS的大小端:MIPS,MIPSEL

eg:假如有一个4字节的数据为0x12 34 56 78(十进制:305419896,0x12为高字节,0x78为低字节),若将其存放于地址0x4000 8000中

内存地址 0x4000 8000(低地址) 0x4000 8001 0x4000 8002 0x4000 8003(高地址)
大端模式 0x12(高地址) 0x34 0x56 0x78(低地址)
小端模式 0x78(低地址) 0x56 0x34 0x12(高地址)

MIPS :big-endian的MIPS架构

MIPSEL :little-endian的MIPS架构

2. MIPS应用领域

image-20220802112837180

3. MIPS寄存器

register

在一般情况下,32位寄存器中每个寄存器的大小是32位,即4字节。

4. MIPS流水线

image-20220802113150952

  1. 取指令:将指令从指令Cache中取出,并计算下一条指令的地址
  2. 读操作数及转移:根据指令从寄存器中读出操作数,同时若为转移类指令,满足转移条件时设置PC
  3. 执行:根据指令进行计算,若为存取类指令,则计算地址
  4. 访问存储器:若为存取类指令,对进行数据Cache进行读写
  5. 写结果:将执行或存取的结果写过寄存器

0x02 MIPS汇编

1. MIPS寻址方式

  • 立即数寻址:操作数是位于指令自身中的常数

    image-20220810215841320

    OP表示指令的类型;RS、RT表示涉及到的寄存器;立即数

  • 寄存器寻址:操作数是寄存器

    image-20220810215955900

  • 基址寻址或偏移寻址:操作数在内存中,其地址是指令中基址寄存器和常数的和,如lw和sw指令

    image-20220810220100812

  • PC相对寻址:地址是PC和指令中常数的和

    image-20220810220217048

  • 伪直接寻址:跳转地址由指令中的26位字段和PC高位相连而成

    image-20220810220317897

2. MIPS指令格式

R格式指令为纯寄存器指令,所有的操作数(除移位外)均保存在寄存器中。Op字段均为0,使用funct字段区分指令

I格式指令为带立即数指令,最多使用两个寄存器,同时包括了load/store指令使用Op字段区分指令

J格式指令为长跳转指令,仅有一个立即数操作数。使用Op字段区分指令

image-20220810220724164

MIPS Opcode解析

机器指令:0xAF8020

二进制形式:0000 0000 1010 1111 1000 0000 0010 0000

解析:按照MIPS指令格式,前6bit为000000,通过查表可知该指令为R格式指令,rs处的5bit值为5(十进制),指代寄存器r5($a1),rt处的5bit值为15(十进制),指代寄存器r15($t7),rd处的5bit值为16(十进制),指代寄存器r16($s0),偏移位为0,通过funct位可以查看该指令的类型,通过查表后可得该指令类型为add。

综上,该指令可以解析为add $s0,$a1,$t7

image-20220811085153206

image-20220811085031456

3. MIPS汇编

常见运算:算术运算、移位运算、逻辑运算、跳转运算、载入指令···

3.1 ADD指令

image-20220811001203920

格式:ADD rd,rs,rt

作用:将rs和rt相加,将结果保存在rd中

例子:ADD $t0,$s1,$s2

相关指令:ADD、ADDI、ADDIU、ADDU、ADDIUPC

3.2 SLL指令

image-20220811001508732

格式:SLL rd,rt,sa

作用:将rt左移sa位,并将结果存入rd

例子:SLL $1,$2,10

相关指令:SLLV、SLT、SLTI、SLTU、SLTIU

3.3 XOR指令

image-20220811001651907

格式:XOR rd,rs,rt

作用:将rs和rt进行异或运算,将结果放入rd

例子:XOR 1,$2,$3

相关指令:XORI

3.4 MOVZ指令

image-20220811001849384

格式:MOVZ rd,rs,rt

作用:转移

例子:MOVZ R1,R2,R3

相关指令:MOVE、MOVT、MOVF、MOVN

3.5 BNE指令

image-20220811002039090

格式:BNE rs,rt,offset

作用:跳转

例子:BNE $1,$2,10

相关指令:B、BC2TL、BAL、BC、BEQ、BEQL

3.6 LW指令

image-20220811002242842

格式:LW rt,offset(base)

作用:加载

例子:LW $1,10($2)

相关代码:LW、LWC1、LWC2、LWE、LWL、LWLE

4. MIPS环境搭建

  • 操作系统:Ubuntu x64 TLS/Windows 10

  • MIPS IDE:MARS 4.5

下载地址:http://courses.missouristate.edu/kenvollmar/mars/download.htm

Qemu介绍及安装

QEMU是一套由Fabrice Bellard所编写的模拟处理器的自由软件。它与Bochs,PearPC相似,但其具有某些后两者所不具备的特性,如高速度及跨平台的特性。经由kqemu这个开源的加速器,QEMU能模拟至接近真实电脑的速度。

qemu两种模式:

  • User mode:用户模式
  • System mode:系统模式

安装方式:

Linux命令行安装:sudo apt-get install qemu

安装用户模式:sudo apt-get install qemu-user-static

MIPS交叉编译

MIPS交叉编译链接工具-gcc-mips-linux-gnu

sudo apt-get install linux-libc-dev-mips-cross

sudo apt-get install libc6-mips-cross libc6-dev-mips-cross

sudo apt-get install binutils-mips-linux-gnu gcc-mips-linux-gnu

上述三行命令安装动态链接库帮助编译程序。

sudo apt-get install g++-mips-linux-gnu

MIPS交叉编译链接工具-gcc-mipsel-linux-gnu

sudo apt-get install linux-libc-dev-mipsel-cross

sudo apt-get install libc6-mipsel-cross libc6-dev-mipsel-cross

sudo apt-get install binutils-mipsel-linux-gnu gcc-mipsel-linux-gnu

sudo apt-get install g++-mipsel-linux-gnu

5. MIPS汇编实战

MIPS IDE :MARS 4.5 见看雪课程。

QEMU示例

demo.c

1
2
3
4
5
6
7
#include<stdio.h>

int main(void)
{
printf("hello world!");
return 0;
}

动态编译:

image-20220811091214936

采用动态编译方式在qemu进行模拟时需要手动链接上动态链接库,位置在/usr/mipsel-linux-gnu/lib目录下。

image-20220811091613936

静态编译:

image-20220811091846312

0x03 ARM基础

1. 什么是ARM?

1.1 什么是ARM?

ARM架构,曾称进阶精简指令集机器(Advanced RISC Machine)更早称作Acorn RISC Machine,是一个32位精简指令集(RISC)处理器架构。

image-20220813093104678

1.2 ARM发展史

image-20220813093602740

1.3 ARM大小端

最高有效位MSB(Most Significant Bit)对应大端(Big-endian)

最低有效位LSB(Least Significant Bit)对应小端(Little-endian)

  • armel:arm eabi little endian的缩写,软件浮点
  • armhf:arm hard float的缩写,硬件浮点
  • arm64:64位的arm默认就是hf的,因此不需要hf的后缀

2. ARM应用领域

image-20220813094132481

3. ARM基础

3.1 ARM运行模式

image-20220813094246663

ARM有9种运行模式,图中为常见7种,不同模式之间可以通过特定的指令来控制切换。

3.2 ARM工作状态

image-20220813094833041

3.3 进入不同工作方式的方法

  1. 进入Thumb状态

    (1)执行BX指令,并设置操作数寄存器的状态(位[0])为1。

    (2)在Thumb状态进入异常(所有的异常都是ARM状态,当异常处理返回时自动转换Thumb指令

  2. 进入ARM状态

    (1)执行BX指令,并设置操作数寄存器的状态(位[0]为0)

    (2)进入异常时,将PC放入异常模式链接寄存器中,从异常向量地址开始执行也可进入ARM状态

3.4 ARM工作状态寄存器

image-20220813095408586

R1-R7类似于通用寄存器,R13堆栈相关,R14与函数返回相关,R15全局PC。

3.4 Thumb工作状态寄存器

image-20220813095846784

3.5 Thumb状态与ARM状态寄存器

image-20220813095932359

4. ARM流水线

  • CPU流水线,把一条指令分为多个处理阶段
  • ARM使用三级流水线,加速指令处理速度
  • ARM的三级流水分别是:取址(fetch)、译码(decode)、执行(execute)。PC指向fetch的指令

image-20220813100256681

0x04 ARM汇编

1. ARM指令集

1.1 ARM状态

image-20220813100844166

1.2 ARM指令集

image-20220813101039332

1.2.1 数据处理指令

MOV指令:它的传送指令只能是把一个寄存器的值(要能用立即数表示)赋给另一个寄存器,或者将一个常量赋给寄存器,将后边的量赋给前边的量。

格式:MOV{条件}{S} 目的寄存器,源操作数

MOV指令中,条件缺省时指令无条件执行;S选项决定指令的操作是否影响CPSR中的条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值。

1
2
3
4
5
指令示例:
MOV R1,R0 ;将寄存器R0的值传送给寄存器R1
MOV PC,R14 ;将寄存器R14的值传送到PC,常用于子程序返回
MOV R1,R0,LSL#3 ;将寄存器R0的值左移3位后传送到1(即乘8)
MOVS PC,R14 ;将寄存器R14的值传送到PC中,返回到调用代码并恢复标志位

除了MOV指令外,还有数据取反指令MVN。

指令格式:MVN{条件}{S} 目的寄存器,源操作数

MVN指令可完成从另一个寄存器、被移位的寄存器、或把一个立即数加载到目的寄存器。与MOV指令不同之处是在传送之前按位被取反了,即把一个被取反的值传送到目的寄存器中。其中S选项决定指令的操作是否影响CPSR中的条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值。

1
2
指令示例:
MVN R0,#0 ;将立即数0取反传送到寄存器R0中,完成后R0=-1(有符号数)
1.2.2 算数运算指令

加法指令:ADD

格式:ADD{条件}{S} 目的寄存器,操作数1,操作数2

ADD指令用于把两个操作数相加,并将结果存放在目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。

1
2
3
4
指令示例:
ADD R0,R1,R2 ;R0 = R1 + R2
ADD R0,R1,#256 ;R0 = R1 + 256
ADD R0,R2,R3,LSL#1 ;R0 = R2 + (R3<<1)

带进位的加法指令:ADC

格式:ADC{条件}{S} 目的寄存器,操作数1,操作数2

ADC指令用于把两个操作数相加,再加上CPSR中的C条件标志位的值,并将结果存放到目的寄存器中。它使用一个进位标志位,这样就可以做比32位大的数的加法,注意不要忘记设置S后缀来更改进位标志。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。

减法指令:SUB

格式:SUB{条件}{S} 目的寄存器,操作数1,操作数2

SUB指令用于把操作数1减去操作数2,并将结果存放到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。该指令可用于有符号数或无符号数的减法运算。

1
2
3
4
指令示例:
SUB R0,R1,R2 ;R0 = R1 - R2
SUB R0,R1,#256 ;R0 = R1 - 256
SUB R0,R2,R3,LSL#1 ;R0 = R2 - (R3<<1)

带借位减法指令:SBC

格式:SBC{条件}{S} 目的寄存器,操作数1,操作数2

SBC指令用于把操作数1减去操作数2,再减去CPSR中的c条件标志位的反码,并将结果存放到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。该指令使用进位标志位来表示借位,这样就可以做大于32位的减法,注意不要忘记设置S后缀来更改标志位。该指令可用于有符号数或无符号数的减法运算。

1
SUBS R0,R1,R2	;R0 =R1 - R2 -!c,并根据结果设置CPSR的进位标志位
1.2.3 比较指令

直接比较指令:CMP

格式:CMP{条件} 操作数1,操作数2

CMP指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行比较,同时更新CPSR中的条件标志位的值。该指令进行一次减法运算,但不存储结果,只改变条件标志位。标志位表示的是操作数1与操作数2的关系(大、小、相等),例如,当操作数1大于操作数2,则此后的有GT后缀的指令将可以执行。

1
2
3
指令示例:
CMP R1,R0 ;将寄存器R1的值与寄存器R0的值相减,并根据结果设置CPSR的标志位
CMP R1,#100 ;将寄存器R1的值与立即数100相减,并根据结果设置CPSR的标志位

位测试指令:TST

格式:TST{条件} 操作数1,操作数2

TST指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位的与运算,并根据运算结果更新CPSR中的条件标志位的值。操作数1是要测试的数据,而操作数2是一个位掩码,该指令一般用来检测是否设置了特定的位。

1
2
3
指令示例:
TST R1,#%1 ;用于测试在寄存器R1中是否设置了最低位(%表示二进制数)
TST R1,#0xffe ;将寄存器R1的值与立即数0xffe按位与,并根据结果设置CPSR的标志位

位测试指令:TEQ

格式:TEQ{条件} 操作数1,操作数2

TEQ指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位的与运算,并根据运算结果更新CPSR中的条件标志位的值。该指令通常用于比较操作数1和操作数2是否相等。

1
TEQ R1,R2	;将寄存器R1的值与寄存器R2的值按位异或,并根据结果设置CPSR的标志位
1.2.4 逻辑运算指令

逻辑与指令:AND

格式:ADD{条件}{S} 目的寄存器,操作数1,操作数2

AND指令用于在两个操作数上进行逻辑与运算,并把结果放置到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于屏蔽操作数1的某些位。

1
AND R0,R0,#3	;该指令保持R0的0,1位,其余位清零

逻辑异或指令:EOR

格式:EOR{条件}{S} 目的寄存器,操作数1,操作数2

EOR指令用于在两个操作数上进行逻辑异或运算,并把结果放置到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于反转操作数1的某些位。

1
AND R0,R0,#3	;该指令反转R0的0,1位,其余位保持不变

位清零指令:BIC

格式:BIC{条件}{S} 目的寄存器,操作数1,操作数2

BIC指令用于清楚操作数1的某些位,并把结果放置到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。操作数2位32位的掩码,如果在掩码中设置了某一位,则清除这一位。未设置的掩码位保持不变。

1
BIC R0,R0 #%1011	;该指令清楚R0中的位0、1、3,其余的位保持不变
1.2.5 转移指令

跳转指令用于实现程序流程的跳转,在ARM程序中有两种方法可以实现程序流程的跳转。

image-20220813105909396

ARM指令集中的跳转指令可以完成从当前指令向前或向后的32MB的地址空间的跳转,包括以下4条指令

image-20220813110005405

B指令

格式:B{条件} 目的地址

B指令是最简单的跳转指令。一旦遇到一个B指令,ARM处理器将立即跳转到给定的目标地址,从那里继续执行。注意存储在跳转指令中的实际值是相对于当前PC值的一个偏移量,而不是一个绝对地址,它的值由汇编器来来计算(参考寻址方式中的相对寻址)。它是24位有符号数,左移两位后有符号扩展为32位,表示的有效偏移位26位(前后32MB的地址空间)。

1
2
3
B Label	;程序无条件跳转到标号Label处执行
CMP R1,#0 ;当CPSR寄存器中的Z条件码置位时,程序跳转到标号Label处执行
BEQ Label

BL指令

格式:BL{条件} 目标地址

BL是另一个跳转指令,但跳转之前,会在寄存器R14中保存PC的当前内容,因此,可以通过R14的内容重新加载到PC中,来返回到跳转指令之后的那个指令处执行。该指令是实现子程序调用的一个基本但常用的手段。

1
BL Label	;当程序无条件跳转到标号Label处执行时,同时将当前的PC值保存到R14中

BLX指令

格式:BLX 目标地址

BLX指令从ARM指令集跳转到指令中所指定的目标地址,并将处理器的工作状态由ARM状态切换到Thumb状态,该指令同时将PC的当前内容保存到寄存器R14中。因此,当子程序使用Thumb指令集,而调用者使用ARM指令集时,可以通过BLX指令实现子程序的调用和处理器工作状态的切换。同时,子程序的返回可以通过将寄存器R14值复制到PC中来完成。

BX指令

格式:BX{条件} 目标地址

BX指令跳转到指令中所指定的目标地址,目标地址处的指令既可以是ARM指令,也可以是Thumb指令。

1.2.6 状态寄存器访问指令

MRS指令

格式:MRS{条件} 通用寄存器,程序状态寄存器(CPSR或SPSR)

MRS指令用于将程序状态寄存器的内容传送到通用寄存器中。

image-20220813191948350

MSR指令

格式:MSR{条件} 程序状态寄存器(CPSR或SPSR)_<域>,操作数

MSR指令用于将操作数的内容传送到程序状态寄存器的特定域中。其中,操作数可以为通用寄存器或立即数。<域>用于设置程序状态寄存器中需要的位,32位的程序状态寄存器可以分为4个域:

1
2
3
4
位[31:24]为条件标志位域,用f表示;
位[23:16]为状态位域,用s表示;
位[15:8]为扩展位域,用x表示;
位[7:0]为控制位域,用c表示;
1.2.7 加载/存储指令

ARM微处理器支持加载/存储指令用于寄存器和存储器之间传送数据,加载指令用于将存储器中的数据传送到寄存器,存储指令则完成相反的操作。

LDR指令

格式:LDR{条件} 目的寄存器,<存储器地址>

LDR指令用于从存储器中将一个32位的子数据传送到目的寄存器中。该指令通常用于从存储器中读取32位的字数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。

image-20220813193209606

LDRB指令

格式:LDR{条件}B 目的寄存器,<存储器地址>

LDRB指令用于从存储器中将一个8位的字节数据传送到目的寄存器中,同时将寄存器的高24位清零。该指令通常用于从存储中读取8位的字节数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。

image-20220813193508314

LDRH指令

格式:LDR{条件}B 目的寄存器,<存储器地址>

LDRH指令用于从存储器中将一个16位的半字数据传送到目的寄存器中,同时将寄存器的高16位清零。该指令通常用于从存储器中读取16位的半字数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。

image-20220813193831024

STR指令

格式:STR{条件} 源寄存器,<存储器地址>

STR指令用于从源寄存器中将一个32位的字数据传送到存储器中。该指令在程序设计中比较常用,且寻址方式灵活多样,使用方式可参考指令LDR。

image-20220813194135404

STRB指令

格式:STR{条件}B 源寄存器,<存储地址>

STRB指令用于从源寄存器中将一个8位的字节数据传送到存储器中。该字节数据为源寄存器中的低8位。

image-20220813194326534

STRH指令

格式:STR{条件}H 源寄存器,<存储器地址>

STRH指令用于从源寄存器中将一个16位的半字数据传送到存储器中。该半字数据为源寄存器中的低16位。

image-20220813194537615

批量数据加载/存储指令

ARM微处理器所支持批量数据加载/存储指令可以一次在一片连续的存储器单元和多个寄存器之间传送数据,批量加载指令用于将一片连续的存储器中的数据传送到多个寄存器,批量数据存储指令则完成相反的操作。常见的加载存储指令如下:

1
2
—LDM 批量数据加载指令
—STM 批量数据存储指令
1
2
3
【LDM(或STM)指令】
LDM(或STM)指令的格式:
LDM(或STM){条件}{状态} 基址寄存器{!},寄存器列表{^}

LDM(或STM)指令

用于从基址寄存器所指示的一片连续存储器列表所指示的多个寄存器之间传送数据,该指令的常见用途是将多个寄存器的内容入栈或出栈。其中,{类型}为以下几种情况:

image-20220813214539464

{!}为可选后缀,若选用该后缀,则当数据传送完毕之后,将最后的地址写入基址寄存器,否则基址寄存器的内容不改变。

{^}为可选后缀,当指令为LDM且寄存器列表中包含R15,选用改后缀时表示;除了正常的数据传送之外,还将SPSR复制到CPSR。同时,该后缀还表示传入或传出的是用户模式下的寄存器,而不是当前模式下的寄存器。

image-20220813215039588

1.2.8 异常产生指令

SWI指令

格式:SWI{条件} 24位的立即数

SWI指令用于产生软件中断,以便用户程序能调用操作系统的系统例程。操作系统在SWI的异常处理程序中提供相应的系统服务,指令中24位的立即数指定用户程序调用系统例程的类型,相关参数通过通用寄存器传递,当指令中24位的立即数被忽略时,用户程序调用系统例程的类型由通用寄存器R0的内容决定,同时,参数通过其他通用寄存器传递。

1
SWI 0x02	;该指令调用操作系统编号为02的系统例程。

1.3 伪代码

AREA

一个汇编程序至少要包含一个段,当程序太长时,也可以将程序分为多个代码段和数据段,因此在汇编程序的开头,一般的语句会用到AREA。

语法格式:AREA 段名 属性1,属性2,......

AREA伪指令用于定义一个代码段或数据段。其中,段名若以数字开头,则该段名需用“|”括起来,如|1_test|。属性字段表示该代码段(或数据段)的相关属性,多个属性用逗号分隔。常用的属性如下:

1
2
3
4
- CODE 属性:用于定义代码段,默认为READONLY。
- DATA 属性:用于定义数据段,默认为READWRITE。
- READONLY 属性:指定本段为只读,代码段默认为READONLY。
- READWRITE 属性:指定本段为可读可写,数据段的默认属性为READWRITE。

ALIGN

格式:ALIGN{ 表达式{ ,偏移量}}

ALIGN伪指令可通过添加填充字节的方式,使当前位置满足一定的对其方式。其中,表达式的值用于指定对齐方式,可能的取值为2的幂,如1、2、4、8、16等。若未指定表达式,则将当前位置对齐到下一个字的位置。偏移量也为一个数字表达式,若使用该字段,则当前位置的对齐方式为: 2的表达式次幂+偏移量。

image-20220813220521921

CODE16,CODE32

格式:CODE16(或CODE32)

1
2
CODE16 伪指令通知编译器,其后的指令序列为16位的Thumb指令。
CODE32 伪指令通知编译器,其后的指令序列为32为的ARM指令。

若在汇编源程序中同时包含ARM指令和Thumb指令时,可用CODE16 伪指令通知编译器其后的指令序列为16 位的Thumb指令,CODE32 伪指令通知编译器其后的指令序列为32位的ARM指令。因此,在使用ARM指令和Thumb指令混合编程的代码里,可用这两条伪指令进行切换,但注意他们只通知编译器其后指令的类型,并不能对处理器进行状态的切换。

image-20220813220825289

ENTRY

格式:ENTRY

ENTRY伪指令用于指定汇编程序的入口点。在一个完整的汇编程序中至少要有一个ENTRY(也可以有多个,当有多个ENTRY时,程序的真正入口点由链接器指定),但在一个源文件里最多只能有一个ENTRY。

image-20220813221118983

END

格式:END

END伪指令用于通知编译器已经到了源程序的结尾。

image-20220813221219259

2. ARM环境搭建

  • 操作系统: Ubuntu x64 TLS + Windows 7
  • ARM IDE: Keil uVersion(Eclipse IDE for C/C++ + ARM插件
    /ADS/realview等)
  • 交叉编译: arm-linux - gnueabi*
  • 模拟环境: qenu

交叉环境搭建

ARM交叉编译链接工具-arm-linux-gnueabi-gcc

sudo apt-get install gcc-arm-linux-gnueabi g++-arm-linux-gnueabi

ARM交叉编译链接工具-arm-linux-gnueabihf-gcc

sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf

安装Qemu

sudo apt-get install qemu

3. ARM实战

keil示例:参见看雪课程

QEMU示例

demo.c

1
2
3
4
5
6
7
#include<stdio.h>

int main(void)
{
printf("hello world!");
return 0;
}

同MIPS,动态编译如下:

image-20220813222810182

静态编译如下:

image-20220813223007112

0x05 逆向分析环境搭建

1. 逆向分析工具

1.1 虚拟环境

Vmware、VirtualBox、Qemu

image-20220813223124207

1.2 静态反编译工具

IDA Pro、Ghidra、Radare2

image-20220813223348677

Linux下常用的命令:

  • objdump
  • arm-linux-gnueabihf-objdump
  • file
  • capstone
  • ······

1.3 动态调试工具

gdb,插件:peda、pwndbg、gef

image-20220813224759473

image-20220813225001839

0x06 IDA使用详解

1. 反汇编

1.1 反汇编理论

  • 第一代语言:机器语言
  • 第二代语言:汇编语言
  • 第三代语言:引入关键字和结构,可转化为汇编语言或机器语言,如C/C++,JAVA等
  • 第四代语言:旨在实现特定目标(例如开发商业应用程序)的语言,如:SQL等
  • 第五代语言:允许程序员通过定义某些约束而不是编写算法来解决问题的编程语言,如:Prolog,Lisp等

1.2 何为反汇编?

image-20220814110654997

1.3 反编译的困难

  • 编译过程会造成损失
  • 编译属于多对多操作
  • 反编译器非常依赖于语言和库
  • 要想准确地反编译一个二进制文件,需要近乎完美的反汇编能力

1.4 为何进行反汇编

  • 分析恶意软件
  • 漏洞分析
  • 软件互操作性
  • 编译器验证(后门)
  • 显示调试信息

1.5 如何反汇编

基本的反汇编算法:

  1. 第一步:确定进行反汇编的代码区域
  2. 第二部:读取该地址(或文件偏移量)所包含的值,并执行一次表查找,将二进制操作码与它的汇编语言助记符对应起来
  3. 第三步:获取指令并解码任何所需的操作数后,需要对它的汇编语言等价形式进行格式化
  4. 第四步:逐条输出指令

线性扫描反汇编

递归下降反汇编

2. 反汇编引擎

  • ODDisassm.

  • BeaEngin.

  • udis86.

  • Capstone.

  • XDE

3. IDA

3.1 IDA

交互式反汇编器专业版( Interactive Disassembler Professional),人们常称其为IDA Pro,或简称为IDA。是目前最棒的一个静态反编译软件,为众多0day世界的成员和ShellCode安全分析人士不可缺少的利器!

3.2 IDA目录结构

  • cfg:包含各种配置文件,基本IDA配置文件ida.cfg,GUI配置文件idagui.cfg,文本模式用户界面配置文件idatui.cfg
  • idc:包含IDA内置脚本语言IDC所需要的核心文件
  • ids:包含一些符号文件
  • loaders:包含用于识别和解析PE或ELF
  • plugins:附加的插件模块
  • procs:包含处理器的模块

3.3 IDA快捷键

image-20220817100544311

image-20220817100825598

4. IDA实战

以arm编写的demo为例,使用32位IDA打开后如下:

image-20220817101927872

IDA自动化脚本实战

image-20220817103109214

python模块,文档地址:https://www.hex-rays.com/wp-content/static/products/ida/support/idapython_docs/

0x07 Ghidra使用详解

1. Ghidra

1.1 什么是Ghidra?

Ghidra是一个软件逆向工程(SRE)框架,包括一套功能齐全的高端软件分析工具,使用户能够在各种平台上分析编译后的代码,包括Windows、Mac OS和Linux。功能包括反汇编,汇编,反编译,绘图和脚本,以及数百个其他功能。Ghidra支持各种处理器指令集和可执行格式,可以在用户交互模式和自动模式下运行。用户还可以使用公开的API开发自己的Ghidra插件和脚本。

1.2 Ghidra下载地址

https://Ghidra-sre.org
https://github.com/NationalSecurityAgency/Ghidra

1.3 Ghidra安装

支持平台:

  • Windows 7/Windows 10(64位)
  • Linux(64位)
  • MacOS(10.8.3)

安装条件

  • 硬件条件:4G内存;1GB硬盘空间
  • 软件条件:Java 11+

1.4 Ghidra模式

Ghidra Server :

  • Ghidra支持多人协作完成一个逆向项目,各种研究人员在自己设备上进行相关的逆向任务,并将其修改提交到公共的存储库中,相关配置在Ghidra Server中有详尽的说明。

命令行模式:

  • 有别于传统的GUI模式,使用者可以通过命令行模式进行批量化的反编译工作。

独立的JAR包模式:

  • Ghidra允许将其中的部分文件打包为JAR包并单独运行,以便于更方便的通过命令行模式进行启动,也方便于作为单独的Java逆向工程库。使用者可以通过/support/buildGhidraJar创建单独的Ghidra. jar文件并使用

2. Ghidra实战

Ghidra安装:

https://www.zzl14.xyz/2020/08/16/ghidra%E5%AE%89%E8%A3%85/

0x08 Radare2使用详解

1. Radare2

1.1 Radare2简介

开源世界中催生出了一个新的逆向工程框架——Radare2,它拥有非常强大的功能,包括反汇编、调试、打补丁、虚拟化等等,而且可以运行在几乎所有的主流平台上(GNU/Linux、Windows、BSD、IOS、···)

1.2 Radare2安装

Install:

1
2
3
$ git clone https://github.com/radare/radare2.git
$ cd radare2
$ ./sys/install.sh

Update:

1
$ ./sys/install.sh

Remove:

1
2
$ make uninstall
$ make purge

1.3 Radare2命令行工具

image-20220817170505098

1.4 Radare2常用参数

image-20220817170742436

1.5 rabin2常用参数

image-20220817170844695

1.6 rasm2常用参数

image-20220817171107093

1.7 rahash2常用参数

image-20220817171556197

1.8 radiff2常用参数

image-20220817171641638

1.9 rafind2常用参数

image-20220817171725960

1.10 ragg2常用参数

image-20220817171802188

1.10 rarun2常用参数

image-20220817171916279

1.12 rax2常用参数

image-20220817171838753

1.13 r2交互式使用方法

image-20220817171950947

  • r2 filename 加载文件

image-20220817183743969

  • aaa分析程序中所有函数

image-20220817184145080

  • 加个问号查看帮助

image-20220817184242297

  • afl显示主函数

image-20220817184341077

  • s function跳转到想跳转的位置

image-20220817184355344

  • VV进入图形化模式(hjkl移动图像)使用p/P切换图形模式

    空格切换文本模式,文本下可以使用p切换模式,小写的vv用来粗略浏览函数信息

image-20220817184725699

  • pdf 查看当前的反汇编代码

image-20220817185144956

  • pd x 打印汇编信息x条

image-20220817185356148

  • “wa xxxx” 修改汇编指令为xxxx

image-20220817185526909

  • px表示打印16进制数,默认从当前位置开始,参数控制打印的字节数

image-20220817185641253

  • 使用-d选项进入调试模式,输入!在调试的时候可以看到历史操作记录

image-20220817185938450

  • pdc反汇编函数

image-20220817190021277

  • pdg也是反汇编函数

  • afx查看调用函数

image-20220817190122323

1.14 r2 Web GUI

r2 -c=H [filename]

默认地址为 http://localhost:9090/。

1.15 r2 Cutter GUI

cutter 是r2官方的GUI。