re基础知识(复习)

一 动态调试

1.exe与elf的区别

可执行文件指的是可以由操作系统进行加载执行的文件

可执行文件的文件格式常见有:exe 和 dll(Windows 系列)、elf(Linux 系列)

EXE(Executable)是Windows操作系统中的可执行文件格式,它是一种二进制格式,包含了程序的机器代码和相关的资源。EXE文件可以直接在Windows上运行,它通常以.exe作为文件扩展名。EXE文件可以包含多个可执行程序和库文件,它们可以通过链接器和加载器来进行连接和加载。

ELF(Executable and Linkable Format)是一种通用的可执行文件格式,主要用于UNIX和类UNIX操作系统,如Linux。ELF文件也是一种二进制格式,包含了程序的机器代码、数据和相关的元数据。ELF文件可以通过链接器和加载器来进行连接和加载,它支持动态链接和共享库的使用。

总的来说,EXE和ELF是不同操作系统中的可执行文件格式,它们在文件结构和使用方式上有一些区别。

文件结构上的区别:

  1. EXE文件通常包含一个程序的完整可执行代码,以及相关的资源和数据。它可以有多个节(section)来存储不同类型的数据。
  2. ELF文件也包含程序的可执行代码,但它使用节(section)和段(segment)的概念来组织数据。节用于存储不同类型的数据,而段用于定义内存映射的相关信息。

使用方式上的区别:

  1. EXE文件主要用于Windows操作系统,可以直接在Windows上运行。它可以通过Windows的API和资源管理器来访问和执行。
  2. ELF文件主要用于UNIX和类UNIX操作系统,如Linux。它可以通过命令行或者调用系统调用来执行。ELF文件还支持动态链接和共享库的使用,可以在运行时加载和链接所需的库。

此外,EXE和ELF还有一些其他细微的差异,比如文件头部的结构和字段的定义,以及特定操作系统的特定功能和限制。

2.IDA中F7和F8区别
F8 Step Over 表示跳到下一步
F7 Step Into 表示进入到代码

一句话:1、想要点进方法里面就按F7
2、想要跳转到下一行就按F8

3.调试sub.elf

首先将IDA的linux_server64放在虚拟机中,再在虚拟机命令行里用管理员(sudo linux_server64)打开,再在命令行运行要调试的sub.elf,在回主机打开IDA,在debugger里找到Attach,再找到remote linux debugger,输入虚拟机的ip(用ifconfig -a命令查找),确认完毕后,即可对sub.elf进行调试(包括F2下断点,F7和F8的步入和步过)

注:如果要调试安卓的文件等,要先运行android_x64_server等文件(注意版本问题),其他步骤类似同上。

二. 位运算

1.位运算概述

从现代计算机中所有的数据二进制的形式存储在设备中。即 0、1 两种状态,计算机对二进制数据进行的运算(+、-、*、/)都是叫位运算,即将符号位共同参与运算的运算。

2.位运算概览:
符号 描述 运算规则
& 两个位都为1时,结果才为1
| 两个位都为0时,结果才为0
^ 异或 两个位相同为0,相异为1
~ 取反 0变1,1变0
<< 左移 各二进位全部左移若干位,高位丢弃,低位补0
>> 右移 各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移)

注意:

逻辑运算符:位与(&),位或(|),位异或(^),位非(~)。

移位运算符:左移(<<),右移(>>),无符号右移(>>>)。

3.按位与运算符(&):

定义:参加运算的两个数据,按二进制位进行”与”运算。

运算规则:

1
0&0=0  0&1=0  1&0=0  1&1=1

总结:两位同时为1,结果才为1,否则结果为0。

例如:3&5 即 0000 0011& 0000 0101 = 0000 0001,因此 3&5 的值得1。

注意:负数按补码形式参加按位与运算。

4.与运算的用途:

1)清零

如果想将一个单元清零,即使其全部二进制位为0,只要与一个各位都为零的数值相与,结果为零。

2)取一个数的指定位

比如取数 X=1010 1110 的低4位,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行按位与运算(X&Y=0000 1110)即可得到X的指定位。

3)判断奇偶

只要根据最未位是0还是1来决定,为0就是偶数,为1就是奇数。因此可以用if ((a & 1) == 0)代替if (a % 2 == 0)来判断a是不是偶数。

5.按位或运算符(|):

定义:参加运算的两个对象,按二进制位进行”或”运算。

1
0|0=0  0|1=1  1|0=1  1|1=1

总结:参加运算的两个对象只要有一个为1,其值为1。

例如:3|5即 0000 0011| 0000 0101 = 0000 0111,因此,3|5的值得7。 

注意:负数按补码形式参加按位或运算。

6.或运算的用途:

常用来对一个数据的某些位设置为1

比如将数 X=1010 1110 的低4位设置为1,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行按位或运算(X|Y=1010 1111)即可得到。

7.异或运算符(^):

定义:参加运算的两个数据,按二进制位进行”异或”运算。

运算规则:

1
0^0=0  0^1=1  1^0=1  1^1=0

总结:参加运算的两个对象,如果两个相应位相同为0,相异为1。

8.异或运算的用途:

1)翻转指定位

比如将数 X=1010 1110 的低4位进行翻转,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行异或运算(X^Y=1010 0001)即可得到。

2)与0相异或值不变

例如:1010 1110 ^ 0000 0000 = 1010 1110

3)使一个数的最低位为零

使a的最低位为0,可以表示为:a & 1。1的值为 1111 1111 1111 1110,再按”与”运算,最低位一定为0。因为” ~”运算符的优先级比算术运算符、关系运算符、逻辑运算符和其他运算符都高。

9.异或的几条性质:
  • 1、交换律
  • 2、结合律 (a^b)^c == a^(b^c)
  • 3、对于任何数x,都有 x^x=0,x^0=x
  • 4、自反性: a^b^b=a^0=a;
10.取反运算符 (~):

定义:参加运算的一个数据,按二进制进行”取反”运算。

运算规则: 

1
2
~1=0
~0=1

总结:对一个二进制数按位取反,即将0变1,1变0。

11.左移运算符(<<):

定义:将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)。

设 a=1010 1110,a = a<< 2 将a的二进制位左移2位、右补0,即得a=1011 1000。

若左移时舍弃的高位不包含1,则每左移一位,相当于该数乘以2。

12.右移运算符(>>):

定义:将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。

例如:a=a>>2 将a的二进制位右移2位,在符号位左补0 或者 左补1得看被移数是正还是负。

操作数每右移一位,相当于该数除以2。

三、寄存器,汇编

一 通用寄存器

通用寄存器是一种用于存储和操作数据的硬件组件【一个典型CPU一般由运算器,控制器,寄存器等器件组成】。它们是计算机体系结构中的一部分,用于临时存储和处理数据。通用寄存器通常具有固定的位数大小,在一台计算机中可能会有多个通用寄存器。(例如AX,BX,CX,DX四个寄存器通常存放一般性数据,因此被称为通用寄存器。)

通用寄存器的主要功能包括:

  1. 存储数据:通用寄存器可以用来存储指令中的操作数、临时结果和其他需要在计算过程中保存的数据。
  2. 数据操作:通过通用寄存器,可以对存储在其中的数据执行各种数学和逻辑操作,如加法、减法、乘法、移位和逻辑运算等。
  3. 数据传输:通用寄存器可以用来传输数据,比如从内存中读取数据到寄存器,或将寄存器中的数据写回到内存中。

通用寄存器在计算机体系结构中起着重要的作用,因为它们提供了一个快速访问和操作数据的方式。不同的体系结构可能会有不同数量和命名方式的通用寄存器。

二 标志寄存器

标志寄存器是计算机中的一种特殊寄存器,用于存储特定的标志位或状态信息。它通常用于记录程序运行过程中的条件和结果,以便进行条件分支、循环等控制操作。

常见的标志寄存器包括:

  1. 零标志位(ZF):用于表示运算结果是否为零。
  2. 进位标志位(CF):用于表示无符号数运算过程中是否发生进位或借位。
  3. 溢出标志位(OF):用于表示有符号数运算过程中是否发生溢出。
  4. 符号标志位(SF):用于表示运算结果的符号。
  5. 奇偶标志位(PF):用于表示运算结果中 1 的个数的奇偶性。
三 基础汇编指令

基础汇编指令是用于编写汇编语言程序的基本指令集。这些指令用于执行各种操作,例如数据传输、运算、控制流程等。下面是一些常见的基础汇编指令:

1.数据传送指令:

指令 名称 示例 备注
MOV 传送指令 MOV dest, src 将数据从src移动到dest
PUSH 进栈指令 PUSH src 把源操作数src压入堆栈
POP 出栈指令 POP desc 从栈顶弹出字数据到dest

相关补充:movb传送字节;movw传送字(2Byte):movl传送双字;movq传送四字。

2.算术运算指令:

指令 名称 示例 备注
ADD 加法指令 ADD dest, src 在dest基础上加src
SUB 减法指令 SUB dest, src 在dest基础上减src

3.逻辑运算指令:

指令 名称 示例 备注
NOT 取反运算指令 NOT dest 把操作数dest按位取反
AND 与运算指令 AND dest, src 把dest和src进行与运算之后送回dest
OR 或运算指令 OR dest, src 把dest和src进行或运算之后送回dest
XOR 异或运算 XOR dest, src 把dest和src进行异或运算之后送回dest

4.转移指令:

指令 名称 示例 备注
JMP 无条件转移指令 JMP lable 无条件地转移到标号为label的位置
CALL 过程调用指令 CALL labal 直接调用label
JE 条件转移指令 JE lable zf =1 时跳转到标号为label的位置
JNE 条件转移指令 JNE lable zf=0 时跳转到标号为label的位置

5.其他:

RET指令则是将栈顶的返回地址弹出到EIP,然后按照EIP此时指示的指令地址继续执行程序。

JZ跳转 ZF=1,运算结果为0 跳转

JNZ跳转 ZF≠1,运算结果不为0时 跳转

四 栈

百度百科解释:栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

栈是一种数据结构,它按照后进先出(LIFO)的原则存储和访问数据。这意味着最后进入栈的元素首先被访问和移除。栈有两个主要操作:推入(push)将元素放入栈的顶部,弹出(pop)将顶部元素移除。

五 内存分区

在没有运行程序前,也就是说程序没有加载到内存前,可执行程序内部已经分好3段信息,分别为代码区(text)、数据区(data) 和 未初始化数据区(bss) 3 个部分(有人直接把data和bss合起来叫做静态区或全局区)

代码区

存放 CPU 执行的机器指令。

通常代码区是可共享的(即另外的执行程序可以调用它),使其可共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可。代码区通常是只读的,使其只读的原因是防止程序意外地修改了它的指t令。另外,代码区还规划了局部变量的相关信息。

全局初始化数据区/静态数据区(data段)

该区包含了在程序中明确被初始化的全局变量、已经初始化的静态变量(包括全局静态变量和t)和常量数据(如字符串常量)。

未初始化数据区(又叫 bss 区)

存入的是全局未初始化变量和未初始化静态变量。未初始化数据区的数据在程序开始执行之前被内核初始化为 0 或者空(NULL)。

总体来讲说,程序源代码被编译之后主要分成两种段:程序指令(代码区)和程序数据(数据区)。代码段属于程序指令,而数据域段和.bss段属于程序数据。