2021-09-04 第五周CTF学习记录

逆向工程步骤及常用工具

软件逆向步骤

1.研究保护方法,去除保护功能
2.反汇编目标软件,定位功能函数
3.分析汇编代码
4.修改汇编代码或还原高级源代码
在这里插入图片描述

逆向常用工具

OLLYDBG(OD)

是一个动态追踪工具,是目前最为流行的调试解密工具。同时支持插件扩展功能,是目前最强大的调试工具

Windbg

Windows平台下,强大的用户态和内核态调试工具,是微软免费调试器集合中的GUI的调试器。轻量级,但调试功能强大,另有一个用途是用来分析缓存数据

IDA Pro

交互式反汇编器专业版(Interactive Disassembler Professional)可以方便地分析软件的函数、结构体

PEID

是一款著名的查壳工具,几乎可以侦测出所有的壳,数量超过470种PE文档的加壳类型和签名

C32asm

一款反汇编程序,具有反汇编模式和十六进制编辑模式,能跟踪exe文件的端点,也可直接修改软件内部代码

常见汇编指令

汇编语言种类

关于汇编语言的种类,可以说有多少种不同内核的CPU,就有多少种汇编语言。
和C语言不同,汇编语言更多的针对特定CPU内核,因此,不同内核的CPU,必须有对应的汇编语言编译器将汇编语言别写的程序编译成对应CPU的机器语言代码,CPU才能正确识别和执行这些代码。
不同架构的CPU指令并不相同,如×86,powerpc,arm各有各的指令系统;甚至同一种架构的CPU有几套指令集。
编译器厂商最有名的两家:MASM和GNUASM。前者是微软的,只支持x86,用在DOS/Windows平台中;后者是开源产品,主要用在Linux中,基本上支持大部分的CPU架构。
不同的汇编程序有不同的汇编语言编程规定
目前支持Intel8086/8088系列微机,常用的汇编程序有ASM、MASM、TASM、OPTASM

寄存器

寄存器从理解上来说和内存类似,只不过寄存器位于CPU内部,而内存位于CPU外部
而对于一个汇编程序员来说,CPU中主要可以使用的也就是寄存器而已,汇编程序员可以使用指令来读写CPU中的寄存器,从而可以实现对于CPU的控制,当然,不同的CPU,寄存器的个数和结构都是不一样的。
8086CPU中寄存器总共为14个,且均为16位。
即AX,BX,CX,DX,SP,BP,SI,DI,IP,FLAG,CS,DS,SS,ES共14个。
而这14个寄存器按照一定方式又分为了通用寄存器,控制寄存器和段寄存器。

通用寄存器

AX(Accumulator):累加寄存器,也称之为累加器
BX(Base):基地址寄存器
CX(Count):计数器寄存器
DX(Data):数据寄存器

指针寄存器

SP(Stack Pointer):堆栈指针寄存器
BP(Base Pointer):基指针寄存器

变址寄存器

SI(Source Index):源变址寄存器
DI(Destination Index):目的变址寄存器

控制寄存器

IP(Instruction Pointer):指令指针寄存器
FLAG:标志寄存器

段寄存器

CS(Code Segment):代码段寄存器
DS(Data Segment):数据段寄存器
SS(Stack Segment):堆栈段寄存器
ES(Extra Segment):附加段寄存器
FS(Flag Segment):标志段寄存器

堆栈

堆栈是两种数据结构
堆栈都是一种数据项按序排列的数据结构,只能在一端(称为栈顶(top))
对数据项进行插入和删除。在单片机应用中,堆栈是个特殊的存储区,主要功能是暂时存放数据和地址,通常用来保护断点和现场。
堆,队列优先,先进先出(FIFO-first in first out)
栈,先进后出(FILO-First-In/Last-Out)
堆栈中的物体具有一个特性:最后一个放入堆栈中的物体总是被最先拿出来,这个特性通常称为后进先出(LIFO)队列。
堆栈中定义了一些操作。两个最重要的是PUSH和POP。
PUSH操作在堆栈的顶部加入一个元素。
POP操作相反,在堆栈顶部移去一个元素,并将堆栈的大小减一。

堆栈操作示例:
PUSH:

在这里插入图片描述
POP:

在这里插入图片描述

指令和程序设计语言

指令:是CPU根据人的意图来执行某种操作的命令。
程序设计语言:是实现人机交换信息的基本工具,分为机器语言、汇编语言和高级语言。
机器语言:用二进制编码表示每条指令,是计算机能直接识别和执行的语言。
汇编语言:是用助记符、符号和数字等来表示指令的程序设计语言。它与机器语言指令是一一对应的。

指令表现形式

二进制:10100010
十六进制:74 0AH
助记符:ADD A,#08H

汇编指令格式

由编程语言编写的源程序是由许多语句(也可称为汇编指令)组成的。
每个语句由1-4个部分组成,其格式是:
[标识符] 指令助记符 [操作数] [;注解]
其中用方括号括起来的部分,可以有也可以没有。
每个部分之间用空格(至少一个)分开,一行最多可有132个字符。
例如:
RET;无操作数
COUNT : INCCX;一个操作数
MOV CX,DI ;两个操作数
ADD AX,[BP+4] ;第二个操作数为表达式

主要汇编指令

数据传送类指令

MOV / XCHG、PUSH / POP、LEA

算数运算类指令

ADD / ADC / INC、SUB / SBB / DEC / CMP / NEG、MUL / IMUL、DIV / IDIV

位操作类指令

AND / OR / XOR / NOT / TEST

控制转移类指令

JMP / Jcc / LOOP、CALL / RET、INTn

处理机控制类指令

NOP

8086指令系统概述

Intel 8086指令系统共有117条基本指令
可分为六个功能组:
①数据传送类指令
②算术运算类指令
③位操作类指令
④串操作类指令
⑤控制转移类指令
⑥处理机控制类指令

一、数据传送类指令

数据传送是计算机中最基本、最重要的一种操作
传送指令也是最常使用的一类指令
传送指令把数据从一个位置传送到另一个位置
除标志寄存器传送指令外,均不影响标志位
重点掌握
-MOV XCHG
-PUSH POP
-LEA

1.传送指令MOV

把一个字节或字的操作数从源地址传送至目的地址
示例:
mov al,4:al←4,字节传送
move cx,0ffh:cx←00ffh,字传送
mov si,200h:si←0200h,字传送
move byte ptr [si],0ah;byte ptr属性修饰符,说明是操作数为字节
move word ptr [si+2],0bh;word ptr 说明是字操作

2.交换指令XCHG

把两个地方的数据进行互换
寄存器与寄存器之间对换数据
寄存器与存储器之间对换数据
不能在存储器与存储器之间对换数据
示例:
mov ax,1234h;ax=1234h
mov bx,5678h;bx=5678h
xchg ax,bx;ax=5678h,bx=1234h
xchg ah,al;ax=7856h

3.进栈指令PUSH

在这里插入图片描述

4.出栈指令POP

在这里插入图片描述

二、算术运算类指令

掌握:ADD / ADC / INC、SUB / SBB / DEC / NEG / CMP
熟悉:MUL / IMUL、DIV / IDIV
理解:CBW / CWD、DAA / DAS、AAA / AAS / AAM / AAD

1.加法指令ADD

功能:ADD指令将源与目的操作数相加,结果送到目的操作数
对状态标志的影响:ADD指令按状态标志的定义相应设置状态标志
示例:
mov al,0fbh;al=0fbh
add al,07h;al=02h
mov word ptr [200h],4652h;[200h]=4652h
mov bx,1feh;bx=1feh
add al,bl;al=00h
add word ptr [bx+2],0f0fh;[200h]=3742h

2.带进位加法指令ADC

ADC指令将源与目的操作数相加,再加上进位CF标志,结果送到目的操作数
ADC指令按状态标志的定义相应设置状态标志
ADC指令主要和ADD配合,实现多精度加法运算
示例:
mov ax,4652h;ax=4652h
add ax,0f0fh;ax=3742h,CF=1
mov dx,0234h;dx=0234h
adc dx,0f0fh;dx=f325h,CF=0;
DX.AX
=0234 4652H
+F0F0 F0F0H
=F325 3742H

3.增量指令INC(increment)

INC指令对操作数加1(增量)
INC指令不影响进位CF标志,按定义设置其他状态标志

4.减法指令SUB

SUB指令将目的操作数减去源操作数,结果送到目的操作数
SUB指令按照定义相应设置状态标志
示例:
mov al,0fbh;al=0fbh
sub al,07h;al=0f4h,CF=0
mov word ptr [200h],4652h;[200h]=4652h
mov bx,1feh;bx=1feh
sub al,bl;al=0f6h
sub word ptr [bx+2],0f0fh;[200h]=5562h,CF=1

5.带借位减法指令SBB

SBB指令将目的操作数减去源操作数,再减去借位CF(进位),结果送到目的操作数
SBB指令按照定义相应设置状态标志
SBB指令主要与SUB配合,实现多精度减法运算
示例:
mov ax,4652h;ax=4652h
sub ax,0f0f0h;ax=5562h,CF=1
mov dx,0234h;dx=0234h
sbb dx,0f0f0h;dx=1143h,CF=1
DX.AX
=0234 4652H
-F0F0 F0F0H
=1143 5562H

6.减量指令DEC

DEC指令对操作数-1
DEC指令不影响进位CF标志,按定义设置其他状态标志
注:
INC指令和DEC指令都是单操作数指令,主要用于对计数器和地址指针的调整

7.求补指令NEG(negative)

NEG指令对操作数执行求补运算:用零减去操作数,然后结果返回操作数
求补运算也可以表达成:将操作数按位取反后加1
NEG指令对标志的影响与用零作减法的SUB指令一样

8.比较指令CMP

CMP指令将目的操作数减去源操作数,按照定义相应设置状态标志
CMP指令执行的功能与SUB指令,但结果不回送目的操作数
示例:
cmp al,100;al-100
jb below;al<100,跳转到below执行
sub al,100;al≥100,al←al-100
inc ah;ah←ah+1
(判断al和100的关系后,执行below)
below:……

三、位操作类指令

位操作类指令以二进制位为基本单位进行数据的操作
这是一类常用的指令,功能简单、都应该掌握
注意这些指令对标志位的影响
1、逻辑运算指令
AND OR XOR NOT TEST
与、或、异或、非、测试
2、移位指令
SHL SHR SAL SAR
逻辑左移、逻辑右移、算术左移、算术右移
3、循环移位指令
ROL ROR RCL RCR
左循环移位、右循环移位、带进位左循环移位、带进位右循环移位

1.逻辑运算指令AND

功能:对两个操作数执行逻辑与运算,结果送到目的操作数
对标志的影响:AND指令设置CF=OF=0,根据结果设置SF、ZF和PF状态,而对AF未定义。
注意:所有双操作数逻辑指令均设置CF=OF=0,根据结果设置SF、ZF和PF状态,而对AF未定义
示例:
MOV AX,FF00H
MOV BX,F0F0H
AND AX,BX
AX=F000H
将AX和BX中的内容对其后,只有上下都是1结果才是1

2.逻辑运算指令OR

功能:对两个操作数执行逻辑或运算,结果送到目的操作数
对标志的影响:OR指令双操作数,设置CF=OF=0,根据结果设置SF、ZF、PF状态,而对AF未定义
示例:
MOV AX,FF00H
MOV BX,F0F0H
OR AX,BX
AX=FFF0H
将AX和BX中的内容对齐后,只要上下有一个是1结果就是1

3.逻辑运算指令XOR

功能:对两个操作数执行逻辑异或运算,结果送到目的操作数
对标志的影响:XOR指令双操作数,设置CF=OF=0,根据结果设置SF、ZF、PF状态,而对AF未定义
示例:
MOV AX,FF00H
MOV BX,F0F0H
XOR AX,BX
AX=0FF0H
只有相异或的两位不相同,结果才是1,否则结果为0。可记为同0异1

4.逻辑运算指令NOT

功能:对一个操作数执行逻辑非运算
NOT指令是一个但操作数指令
NOT指令不影响标志位
示例:
MOV AX,FF00H
NOT AX
AX=00FFH

四、控制转移类指令

控制转移类指令用于实现分支、循环、过程等程序结构,是仅次于传送指令的常用指令
重点掌握:
JMP / Jcc / LOOP CALL / RET
INT n / IRET 常用系统功能调用
一般了解:LOOPZ / LOOPNZ INTO

1.无条件转移指令JMP

JMP label:程序转向label标号指定的地址(标号要在程序其他位置标出)
只要执行JMP,不需要任何条件,就使程序转到指定的目标地址处,从目标地址处开始执行指令
操作数label是要转移到的目标地址,也叫目的地址、转移地址

转移的原理:
1.程序的执行地址,是由段寄存器CS和指令指针IP共同确定的,即当前指令的地址为CS:IP
2.程序的跳转是通过修改CS和IP的值来实现的

2.条件转移指令Jcc

指定的条件cc如果成立,程序转移到由标号label指定的目标地址去执行指令;条件不成立,则程序将顺序执行下一条指令
操作数label是短转移标号,要跳转的地址必须距当前IP地址一128~+127个单元的范围之内
Jcc指令不影响标志,但要利用标志。根据利用的标志不同,16条指令分成3种情况:
1.判断单个标志位状态
2.比较无符号数高低
3.比较有符号数大小

转移条件cc:单个标志状态

JZ / JE ZF=1 Jump if Zero/Equal
JNZ / JNE ZF=0 Jump if Not Zero/Not Equal
JS SF=1 Jump if Sign
JNS SF=0 Jump if Not Sign
JP / JPE PF=1 Jump if Parity/Parity Even
JNP / JPO PF=0 Jump if Not Parity/Parity Odd
JO OF=1 Jump if Overflow
JNO OF=0 Jump if Not Overflow
JC CF=1 Jump if Carry
JNC CF=0 Jump if Not Carry
JB / JNAE CF=1 低于或不高于等于
JNB / JAE CF=0 不低于或高于等于
JBE / JNA CF=1或ZF=1 低于等于或不高于
JNBE / JA CF=0且ZF=0 不低于等于或高于
JL / JNGE SF≠OF 小于或不大于等于
JNL / JGE SF=OF 不小于或大于等于
JLE / JNG ZF#OF或ZF=1 小于等于或不大于
JNLE / JG SF=OF且ZF=0 不小于等于或大于

判断单个标志位状态

这组指令单独判断5个状态标志之一
(1)JZ/JE和JNZ/JNE:利用零标志ZF,判断结果是否为零(或相等)
(2)JS和JNS:利用符号标志SF,判断结果是正是负
(3)J0和JNO:利用溢出标志OF,判断结果是否产生溢出
(4)JP/JPE和JNP/JPO:利用奇偶标志PF,判断结果中“1”的个数是偶是奇
(5)JC/JB/JNAE和JNC/JNB/JAE:利用进位标志CF,判断结果是否进位或借位

比较无符号数高低

无符号数的大小用高(Above)低(Below)表示
利用CF确定高低、利用ZF标志确定相等(Equal)
两数的高低分成4种关系:
(1)低于(不高于等于):JB(JNAE)
(2)不低于(高于等于):JNB(JAE)
(3)低于等于(不高于):JBE(JNA)
(4)不低于等于(高于):JNBE(JA)

比较有符号数大小

有符号数的大(Greater)小(Less)需要组合OF、SF标志,并利用ZF标志确定相等(Equal)两数的大小分成4种关系:
(1)小于(不大于等于):JL(JNGE)
(2)不小于(大于等于):JL(JGE)
(3)小于等于(不大于):JLE(JNG)
(4)不小于等于(大于):JLE(JG)

3.循环指令LOOP

功能:循环指令是一种特殊的转移指令。当满足某条件时,反复执行一系列操作,直到不满足为止
格式:
常见:LOOP label;CX←CX-1,;CX≠0,循环到标号label
其他:JCXZ label;CX=0,转移到标号label
LOOP label;CX←CX-1;CX≠0且ZF=1,循环到标号label
LOOPNZ label;CX←CX-1;CX≠0且ZF=0,循环到标号label

循环指令的执行过程

循环指令利用CX寄存器作为计数器
执行过程:
mov cx,100;准备工作,设置要循环的次数
label_one:
xxx
xxx
loop label_one
(1)无条件执行CX←CX-1
(2)判断CX
如果是0,往下执行
如果不是0,返回到label_one执行

4.子程序指令

子程序是完成特定功能的一段程序
当主程序(调用程序)需要执行这个功能时,采用CALL调用指令转移到该子程序的起始处执行
当运行完子程序功能后,采用RET返回指令回到主程序继续执行

为什么编写子程序

子程序通常是与主程序分开完成特定功能的一段程序。程序中有时要反复的实现相同的功能只不过参数不同而已。把仅参数不同功能重复的程序编写成为子程序。当主程序需要执行这个功能时,就可以调用该子程序,执行完成后再返回主程序。
子程序具有如下优点:
(1)结构清晰,维护方便
(2)有利于程序员的分工合作
(3)有利于压缩程序空间

子程序调用指令

CALL指令分成4种类型(类似JMP)
典型形式:
CALL label;段内调用、相对寻址
其它形式:
CALL r16/m16;段内调用、间接寻址
CALL far ptr label;段间调用、直接寻址
CALL far ptr mem;段间调用、间接寻址

5.中断指令

中断(Interrupt)是又一种改变程序执行顺序的方法
在程序运行时,遇到某些需要紧急处理的情况,如,停电、数据的实时接收、溢出等。
处理器暂停主程序的执行,转去执行中断处理程序。
8086中断系统有256个中断,每一个中断用唯一的一个中断向量号标识。分别为0号中断、1号中断…
中断分类:
(1)内部中断(2)外部中断

中断指令INT

INT i8
例如:INT21H产生系统功能调用中断
;中断调用指令:产生i8号中断(内部中断)
IRET
;中断返回指令:实现中断返回
其它:
INTO
;溢出中断指令:
;若溢出标志0F=1,产生4号中断;否则顺序执行

五、处理机控制类指令

对CPU状态进行控制的指令
NOP CS:SS:DS:ES:
LOCK HLT ESC WAIT

1.空操作指令NOP

NOP
不执行任何操作,但占用一个字节存储单元,空耗一个指令执行周期
NOP常用于程序调试
在需要预留指令空间时用NOP填充
■代码空间多余时也可以用NOP填充
■还可以用NOP实现软件延时
事实上,NOP和XCHGAX,AX的指令代码一样,都是90H

2.段超越前缀指令

在允许段超越的存储器操作数之前,使用段超越前缀指令,将采用指定的段寄存器寻址操作数
CS:;使用代码段的数据
SS:;使用堆栈段的数据
DS:;使用数据段的数据
ES:;使用附加段的数据

六、伪指令

■ 伪指令
没有对应的机器码的指令,最终不被CPU所执行。
■ 谁来执行伪指令呢?
伪指令是由编译器来执行的指令,编译器根据伪指令来进行相关的编译工作。
■ segment和ends是一对成对使用的伪指令,这是在写可被编译器编译的汇编程序时,必须要用到的一对伪指令。
■ segment和ends的功能是定义一个段,segment说明一个段开始,ends说明一个段结束。
■ 一个段必须有一个名称来标识,使用格式为:
段名 segment
段名ends
例如:
data segment
……
data ends

■ 一个汇编程序是由多个段组成的,这些段被用来存放代码、数据或当作栈空间来使用。
■ 一个有意义的汇编程序中至少要有一个段,这个段用来存放代码。
■ End是一个汇编程序的结束标记,编译器在编译汇编程序的过程中,如果碰到了伪指令end,就结束对源程序的编译
■ 如果程序写完了,要在结尾处加上伪指令end。否则,编译器在编译程序时,无法知道程序在何处结束。
__注意:__不要搞混了end和ends。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值