安全笔记:逆向|windows逆向工程和8086汇编语言

    xiaoxiao2023-09-24  179

    目录

    基础知识

    代码分析

    逆向分析法

    修改应用程序文件或进程内存内容方法

    入口点

    修改地址方法

    区分代码为部分的方法

    快速查找制定代码

    两个反调试方法

    函数调用约定

    字符串

    字符串编码

    修改字符串方法

    内存

    内存分区

    字节序

    ​

    PE文件

    格式

    地址映射

    PE头

    节区头

    工具

    8086汇编语言


    基础知识

    汇编语言依赖于CPU,每个产品用的CPU种类不同,则汇编语言也有略微差异

    代码分析

    汇编文件(主)

    十六进制文件(辅)

    逆向分析法

    静态分析——分析源码

    动态分析——调试分析

    推荐方法:先静态分析再动态分析

    修改应用程序文件或进程内存内容方法

    打补丁——Patch

    破解——Crack

    入口点

    调试器停止的地方即为PE文件执行的起始地址

    修改地址方法

    call [地址]

    jmp [地址]

    区分代码为部分的方法

    goto命令

    设置断点

    注释

    标签

    快速查找制定代码

    代码执行法

    字符串检索法

    API检索法

    两个反调试方法

    压缩器——修改文件结构、压缩后文件仍为可执行文件

    保护器——压缩、反调试、反模拟、反转储

    函数调用约定

    函数执行完毕,ESP需要回滚(用户执行)


    字符串

    字符串编码

    字符的编码方式不同,占据位数不同,调试代码要注意

    Unicode码中字符长度不够后需要填充NULL

    修改字符串方法

    直接修改字符串缓冲区(新字符串长度大于原有字符串,覆盖可能损坏字符串后面的数据)

    在其他内存区域生成新字符串并传递给消息函数(注意地址,地址并不是按照规定载入内存,其按一定规律,即其要按一定文件偏移,否则程序出错)。


    内存

    内存分区

    应用程序被加载到内存有最小内存分配大小,若不够则要填充NULL(一般为1000)

    字节序

    多字节数据在计算机内存中存放的字节顺序(小端序和大端序)

    采用大端序存储数据时,内存地址低位存储数据的高位,内存地址的高位存储数据的低位。例如:Unix CPU/网络协议。

    采用小端序存储数据时,内存地址低位存储数据的低位,内存地址的高位存储数据的高位。例如:Intel x86 CPU。


    PE文件

    格式

    PE头:DOS头到节区头

    PE体:PE头其下的节区

    文件中使用偏移,内存中使用VA(虚拟地址)来表示位置。

    文件分为.text(代码)、.data(数据)、.rsrc(资源)节,其分别保存

    PE头与各节区的尾部存在一个区域,称为NULL填充(不够最小基本单位则填充NULL)

    地址映射

    VA:虚拟内存的绝对地址,RVA:相对虚拟地址,ImageBase:基准地址

    ImageBase+RVA=VA

    32位Windows OS中,各进程分配有4GB的虚拟内存,VA范围为00000000~FFFFFFFF。

    PE头

    PE头由许多结构体组成(40字节),PE头的最前面添加了一个IMAGE_DOS_HEADER结构,用来扩展已有的DOS EXE头。

    IMAGE_DOS_HEADER分为e_magic(DOS签名)、e_lfanew(指示NT头的偏移)。

    所有PE文件在开始部分(e_magic)都有DOS签名(“MZ”)。

    e_lfanew指向NT头所在位置(NT头:IMAGE_NT_HEADERS)。

    DOS存根在DOS头下方,是个可选项,且大小不固定,其由代码和数据混合而成。

    NT头结构分为签名、文件头、可选头三部分。

    节区头


    工具

    Hex Editor:二进制->十六进制

    OllyDbg:汇编逆向工具


    8086汇编语言

    ​​​​字:16bit  字节:8bit

    通用寄存器:ax、bx、cx、dx(16位)

    高位寄存器:ah、bh、ch、dh(高8位)

    低位寄存器:al、bl、cl、dl(低8位)

    从CS:IP的内存单元地址中读取指令,执行该指令,之后IP=IP+所读取指令的长度。(CS:IP永远指向当前指令的下一条指令)

    CS:段地址寄存器

    IP:偏移地址

    物理地址=段地址×16+偏移地址

    jmp 段地址:偏移地址 修改CS、IP寄存器

    jmp 寄存器 仅修改IP寄存器

    ds寄存器

    ds 段地址

    […] 表示一个内存单元的偏移地址

    DS:[…]表示的是内存(保存数据的位置)

    数据保存方向:从低地址向高地址保存,数据的高位保存在高地址,数据的低位保存在低地址。

    入栈操作:push

    出栈操作:pop

    SS:SP指向栈顶元素(操作者只能修改SP,一个段最大范围为0~FFFFH,最大容量为64KB)

    入栈,栈顶从高地址向低地址移动 SP=SP-2

    出栈,栈顶从低地址向高地址移动 SP=SP+2

    栈空间由程序声明,CPU没有控制栈空间的概念,意味着栈溢出时可以覆盖其它内存单元数据。

    内存信息:①内存单元地址②内存单元长度

    [寄存器] 表示一个内存单元,其偏移地址位于寄存器中

    loop使用方法:

    s:

    代码段

    loop s

    汇编源程序中,数据不能以字母开头(前面补0来解决这一问题)

    debug和源程序区别:

    debug: mov al,[0]

    源程序: mov al,ds:[0]

    循环方法:

    mov cx,10 #cx为循环计数器

    s:

    代码段

    inc bx

    loop s

    mov ax,ds:[bx] 相当于 mov ax,[bx]

    mov ax,ss:[bx] 段地址寄存器为ss

    若不体现:前面的寄存器,默认为ds

    寻找到安全的内存空间(其中没有重要数据,不必担心覆盖导致数据丢失)

    查看内存空间,找到全为0的连续空间,即为安全空间

    DOS系统:0:200~0:2FF一般是安全空间

    操作系统:合法通过操作系统取得的安全都为安全空间

    源程序的伪指令需要经过编译器编译,由编译器执行

    伪指令举例:

    assume cs:code

    code segment

    start(程序入口)

    代码段

    code ends

    end start(程序结束)

    dw define word 定义字型数据

    dw [数据]  从当前的CS:IP处开始存储数据

    dw 0,…,0  声明内存空间,将其用作栈(清空一个数据空间)

    编写代码时应注意用多个段存放数据、代码和栈。

    si和di和bx功能相近,但不能分成两个8位寄存器使用。

    多层循环时,需要通过对cx数据进行保存,恢复来进行。

    需要暂存数据的时候,我们都应该使用栈。

    没有寄存器名存在情况,用word ptr/byte ptr指明内存单元的大小。

    call 实现CS、IP入栈,转移地址执行命令

    内中断

    外中断

     

    最新回复(0)