电子说
首先来说下 什么是hack ? hack字面意思“ 非法入侵 ”,那么在C/C++中其实就是 使用反汇编查看C/C++代码对应的汇编代码 。
那可能有人要问了,C/C++不是高级语言么,为什么还要看汇编代码?理由嘛见仁见智,
个人理解有下面几种:
既然有这么多用处,那么下面小余就来讲解下如何在我们的应用中hack。
不过在hack前我们需要了解一些汇编语言基础。
首先我们得了解汇编语言中的几个模块:1.寄存器 2.内存 3.CPU
寄存器是我们计算机中的最小存储单位,在计算机金字塔的顶端, 属于CPU的内部存储 ,主要用来存储CPU需要使用到的临时数据。
CPU访问寄存器的速度比访问内存的速度快了100倍左右。
CPU中寄存器种类包括:通用寄存器,指令地址寄存器,状态寄存器等等等等。。 这里只介绍几个比较关键的寄存器:
寄存器 | 原文 | 解释 | 说明 |
---|---|---|---|
AX | accumulator | 累加寄存器 | 通常用来执行加法,函数调用的返回值一般也放在这里面 |
CX | counter | 计数寄存器 | 通常用来作为计数器,比如for循环 |
DX | data | 数据寄存器 | 数据存取 |
BX | base | 基址寄存器 | 读写I/O端口时,edx用来存放端口号 |
SP | stack pointer | 栈指针寄存器 | 栈顶指针,指向栈的顶部 |
BP | base pointer | 基址指针寄存器 | 栈底指针,指向栈的底部,通常用ebp+偏移量的形式来定位函数存放在栈中的局部变量 |
SI | source index | 源变址寄存器 | 字符串操作时,用于存放数据源的地址 |
DI | destination index | 目标变址寄存器 | 字符串操作时,用于存放目的地址的,和esi两个经常搭配一起使用,执行字符串的复制等操作 |
这里说明几点:
eip寄存器可以说是CPU中最关键的一个寄存器了,它指向了下一条要执行的指令所存放的地址, CPU工作其实就是取出eip中的地址中的指令,然后去执行这条指令,并将下一条指令的地址赋值给eip ,这样CPU就可以依次执行完成所有的汇编代码.
如果你要问我它是怎么找到下一条指令的地址的,首先正常执行指令是+1位下一条指令地址,如果碰到一些比如if语句,函数调用等情况,就会在上一条指令中得到这个地址,并赋值给eip,这个赋值动作是CPU自动完成的,开发是不能随便更改的,这也变相的防止你搞出bug不是?
状态寄存器中记录了CPU执行过程中的一系列状态,对于32位就有32个标志位,这些标志大部分都是由CPU自行设置:
寄存器标志位 | 解释 |
---|---|
CF | 进位标志 |
PF | 奇偶标志 |
ZF | 零标志 |
SF | 符号标志 |
OF | 补码溢出标志 |
TF | 跟踪标志 |
IF | 中断标志 |
…… |
根据指令在存贮器中的地址(由指令地址计数器给出),把指令从存贮器中取出来之后,需要有一个专门用于存放指令的地方,以便对指令进行分析和执行。 这个专门存放现行指令的部件就叫做指令寄存器 。
后面会具体汇编代码会涉及到。
关于寄存器就讲这么几个吧,hack过程够用了。
这里讲解的内存一般是指高速缓存(Cache)或者主存。
计算机在运行程序时,首先将程序从磁盘读取到主存,然后CPU按规则从主存中取出指令,数据并执行指令,但是直接从主存(一般是DRAM)中读写是很慢的,所以引入了高速缓存(Cache)(使用的是SRAM)。
在程序运行前首先会试图将指令,数据从主存中读取到Cache中,然后在程序执行时直接访问Cache, 如果指令和数据可以从Cache中读取到,那么就说是“命中(hit)”,反之就是“不命中(miss)”, miss情况下需要从主存中读取指令或者数据,这样会直接影响CPU的性能,所以命中率对CPU来说至关重要。
内存在计算中又会分为:堆区,栈区,全局(静态)区,常量区,代码区等等。
这里讲解下hack中比较关键的栈区。
栈区
栈区就像一个桶一样,桶底就是栈底为高地址区,桶的顶部为低地址, 桶中放东西当然是先放桶底然后依次叠加咯,也就是平时所说的FILO先进后出的模式。
指令控制(程序的顺序控制)
操作控制(一条指令由若干操作信号实现)
时间控制(指令各个操作实施时间的定时)
数据加工(算术运算和逻辑运算)
中央处理器 CPU= 运算器 + 控制器
运算器:
ALU
累加器
暂存器
控制器
程序计数器 (PC) 、指令寄存器 (IR) 、数据缓冲器 (DR) 、地址寄存器 (AR) 、通用寄存器、状态寄存器 (PSW) 、时序发生器、指令译码器 (ID) 、总线
CPU的工作分为以下 5 个阶段:取指令阶段、指令译码阶段、执行指令阶段、访存取数和结果写回。
1.mov :传送指令,也可以单纯理解为赋值语句,这个语句在汇编中是最常用的。 格式:mov det,src
首先mov语句分以下几种情况:
首先要了解,加减法运算是会改变状态寄存器中的值的,如一个有符号数的运算高位溢出标志(OF),无符号的运算进位标志(CF)等。
格式:add OPRD1,OPRD2
功能:OPRD1 = OPRD1 + OPRD2
举例:
add eax ecx;//得到的结果为eax = eax+ecx;
格式:add OPRD1,OPRD2
功能:OPRD1 = OPRD1 + OPRD2
举例:
adc eax ecx;得到的结果为eax = eax+ecx+状态寄存器中给的进位标志CF;
格式:add OPRD
功能:OPRD = OPRD + 1
举例:
inc eax;//得到的结果为eax = eax+1;
格式:sub OPRD1,OPRD2
功能:OPRD1 = OPRD1 - OPRD2
举例:
sub eax ecx;//得到的结果为eax = eax - ecx;
格式:dec OPRD
功能:OPRD = OPRD - 1
举例:
dec eax;//得到的结果为eax = eax - 1;
格式:cmp OPRD1,OPRD2
功能:执行OPRD1 - OPRD2,但运算结果不运送到OPRD1
注:该指令通过OPRD - OPRD2影响标志位CF、ZF、SF、OF、AF、PF来判断OPRD1和OPRD2的大小关系。
通过ZF判断是否相等;如果是无符号数,通过CF可判断大小;如果是有符号数,通过SF和OF判断大小
格式:NOT OPRD
功能:把操作数OPRD取反,然后送回OPRD。
注: OPRD可以是通用寄存器,也可以是存储器操作数,此指令对标志没有影响
格式:AND OPRD1,OPRD2
功能:对两个操作数进行按位逻辑“与”运算,结果送到OPRD1中
注: 该指令执行后,CF=0,OF=0,标志PF、ZF、SF反映运算结果,AF未定义。
某个操作数与自身相与,值不变,但可以使CF置0。
格式:OR OPRD1,OPRD2
功能:对两个操作数进行按位逻辑“或”运算,结果送到OPRD1中
注: 该指令执行后,CF=0,OF=0,标志PF、ZF、SF反映运算结果,AF未定义。
某个操作数与自身相或,值不变,但可以使CF置0。
格式:XOR OPRD1,OPRD2
功能:对两个操作数进行按位逻辑“异或”运算,结果送到OPRD1中
格式:SAL OPRD,m
SHL OPRD,m
功能:把操作数OPRD左移m位,每移动一位,右边用0补足1位,移出的最高位进入标志位CF
注: 算术左移和逻辑左移进行相同的动作,为了方便提供了两个助记符。
格式:SAR OPRD,m
功能:操作数右移m位,同时每移1位,左边的符号位保持不变,移出的最低位进入标志位CF
注: 对有符号数和无符号数,算数右移1位相当于除以2
如:SAR BH,1 ;(BH)= 80H,指令执行后(BH)= C0H
格式:SHR OPRD,m
功能:操作数右移m位,同时每移1位,左边用0补足,移出的最低位进入标志位CF
注: 对无符号数,逻辑右移1位相当于除以2
如:SHR AH,1 ;(AH)= 80H,指令执行后(AH)= 40H
切记:算术移位和逻辑移位的区别:
对于左移不管是算术移位和逻辑移位,低位都补0; 对于右移的算术移位:对于有符号数,符号位不变,然后整体右移。
直接跳转到Jump指定的地址, 跳转指令也是改变当前eip的值来决定的 ,这样下次取指令会去新的eip地址下取。
格式:JMP OPRD
功能:使控制指令无条件转移到OPRD的内容给定的目标地址处。操作数OPRD可以是通用寄存器,也可以是字存储单元
例如:
jmp cx ;CX寄存器的内容送IP
jmp word ptr [1234h] ;字存储单元[1234h]的内容送IP
全部0条评论
快来发表一下你的评论吧 !