16汇编第十讲完结Call变为函数以及指令的最后讲解
16汇编完结Call变为函数以及指令的最后讲解
学了10天的16位汇编,这一讲就结束了,这里总结一下昨天的LOOP指令的缺陷,因为lOOP指令的缺陷,所以我们都改为下面的汇编代码使用了,自己去写,其中条件是你自己写的
请看汇编代码:
do while 的汇编代码
WHILE:
mov ax,ax
cmp ax,
jl WHILE
while 的汇编代码 WHILE:
cmp ax,
jge WHILE_END
mov ax,ax
jmp WHILE
WHILE_END:
一丶Call指令(子程序)变为函数调用(重要,这个以后逆向会天天看到所以一定掌握)
首先我们明白一点,昨天我们写的只是一个单独的子程序(什么保存栈地址,开辟局部变量空间,....都没有写,只是单独的平栈),今天我们就写一个Call变为函数调用的例子,一步一步的看为什么这么做,对以后的逆向很有帮助
1.首先我们明白Call调用的几种方式
段内: 一个段中去调用,或者跳转
段间: 代码不在同一个段中,从一个段跳跃到另一个段
Call指令分为4中类型 (类似于JMP)
Call label(标号) ; 段内调用丶直接寻址
Call r16/m16 (16位寄存器,或者2字节内存) 段内调用丶间接选址
Call far ptr label; 段间调用丶直接寻址
Call far ptr mem; 段间调用丶间接寻址
昨天我们写的简单的子程序例子:
mov ax,
push ax
mov bx,
push bx
Call 标号
add sp,4
....
标号:
mov bp,sp
mov ax,[bp +2]
mov bx,[bp +4]
add ax,bx
ret
我们压入了两个参数,一个Ax,一个Bx,在Call的时候,会把下一行的地址压入到栈中,也就是 add sp,4的所在的地址
我们画一下栈
可以看出,这个就是当前的栈结构了, 我们执行代码的时候,首先 bp 和 sp是平等的了
现在 bp+2 能寻得bx, bp +4 能寻得 ax
然后ret 注意,ret只是把sp +2了,也就是弹栈弹出了返回地址,并且给IP了,现在IP就会跳转到下一条指令执行的位置
也就是(add sp,4) 现在要注意了,bx 和 ax 都还在栈中,我们没办法让栈恢复所以在外面用 add sp,4 让sp的位置(现在的位置+2了,已经在bx的位置了)变为栈底了
所以这个就是C语言的 C调用约定
如果我们想StdCall (std 调用约定,标准的调用约定) 就要用retn 这个指令了,不能是ret了,
写成 retn 4 代表先把返回地址返回出去,然后再让sp +4 个字节,相当于在函数内部就平栈了,这样外部就不用写
add sp,4了,不用自己平栈了
2.由Call 变为函数一步一步来
现在基于上面的原理我们知道如何平衡一个栈了,但是你有没有发现,为什么我们一开始要把sp 给Bp
也就是让 BP和SP一样的位置
这个是有原因的
首先C语言调用函数的时候会进行几步操作
1.保存栈底
2.申请局部变量空间
3.保存环境
4.恢复环境
5.释放局部变量空间
6.恢复栈底
7.弹栈返回
好看上面的我们可能有点不明白,下面我把整体的栈图放出来
整体的栈是这样的,这里为什么要一开始把bp和sp相等,是有原因的,我们不妨这样想,如果我们申请局部变量空间的
时候,是不是参数的偏移也要改动,这样每次都要自己计算偏移,相当麻烦,所以只能这样,
我们以后找参数就 bp + xxx (因为bp一开始就在栈底的值这一栏) 这样就能寻找到参数,你开辟多大的局部变量看空间都和我没关系,所以以后我只需要 bp-xxx 就是找到的局部变量
现在看下汇编代码的模版吧
MY_ADD: ;stdcall
push bp
mov bp, sp ;1. 保存栈底 sub sp, ;2. 申请局部变量空间这里随你便,申请的时候先抬栈,让sp高一点,但是不会影响bp
push bx ;3.保存环境 保存环境的意思就是外面的寄存器的值要保存一下,这样恢复寄存器的值 mov word ptr [bp-], 1 ;每次我只需要 bp -xxx 就知道寻找局部变量
mov word ptr [bp-],
mov ax, [bp+] ;参数1 ;每次我bp+ xxx 就知道我是找参数,所以不会冲突,打死参数的地址不会变
add ax, [bp+] ;参数2 ;xxxxxxx
pop bx ;4. 恢复环境 弹栈的时候寄存器信息先回复
mov sp, bp ;5. 释放局部变量空间 而且恢复变量控件的时候也很容易,直接把bp当前的位置给sp即可,释放空间了
pop bp ;恢复以前的栈底的值
retf ;6. 返回 ,retf下面详细讲
在这里主要是掌握bp所在的位置即可,就能明白为什么这样写了,不信的话自己写个程序,看下反汇编,大体的就是这个套路,这里讲解的是为什么这样做,不是和市面的汇编视频一样,你看到 bp -xxx 就知道他在访问局部变量就行
其实这个是错误的,我们要知其然,并知其所以然
看下栈图,掌握bp所在的位置
只要掌握bp所在的位置即可,上面的代码即可明白
3.Call指令的retf段间转移
这个我们首先要明白,在Call的时候会把Call下边一条指令的地址保存到栈中,出栈的时候要给IP,让其更改跳转,
跳转到Call下一条指令执行的位置的地方
但是现在我们是段间Call,也就是不在一个段中,这个时候栈不光会保存返回地址,还会保存当前CS段寄存器的地址
这样返回的时候 CS:IP返回,但是现在有一个问题,就是我们自己根本就平不了栈,我们把IP拿出来了,给IP,CS段寄存器根本没办法改,这样我们必须同时修改CS:IP的值才能回到以前的地方,但是现在没办法了,因为你改IP回跳,改CS会跳,必须同时改,弄不了,所以弄一个retf的指令去帮我们去做
注意retf 你也需要平栈,比如我们压入了两个参数,就要 retf 4, retf会默认把栈顶4个字节的数据取出来分别给 ip和CS段寄存器,但是剩下4个字节都是我们的参数,比如自己去释放,让SP的加4到栈底才可以
二丶中断指令
1.什么是中断指令
中断,是有一种改变程序执行顺序的方法
中断具有很多的中断类型
中断的指令有3条
1.INT i8(i8代表一个八位的立即数)
2.IRET IRET 和Call差不对,Call的ret返回的时候会把栈顶的元素弹出两个字节,这两个字节是返回地址,所以可以回到正确的地方执行指令,但是IRET明显比ret保存的东西多,其中ret我们可以手工的pop和jmp去执行,IRET也可以自己去做,但是你要完整的模拟才可以,一般还是调用IRET即可
3.INTO
2.中断指令的自我理解
其实中断指令就是调用硬件提供的API(也称为系统调用)我们前边用过很多次了
比如显示一个字符串
mov ah,09h
int 21h
其中参数是09,int 21h代表执行,还有很多
介绍下指令
INT I8: 中断的调用指令: 产生I8号中断,就是调用int代表我要调用了,其中指令是什么使我们给的,是一个八位立即数比如 09
IRET: 中断的返回指令,理解为返回,可以进行下一条指令的执行
INTO: 不常用,不讲解.
3.21h中断,到底是个啥玩意
我们每次都调用21h什么的,但是不知道他是个啥玩意
他是DOS提供给用户的,用于调用系统功能的中断(简单理解就是DOS提供的API,让用户调用),他有近百个功能让公户选择使用.包括设备管理,目录管理,和文件管理
ROM-BIOS(主板的BIOS)也是这种形式,这就是为什么程序一开机显示器就会显示字符,别忘了这个时候系统还没有启动,还没有操作系统一说
看下图:
现在操作系统也还是这样调用,操作系统的API很多,底层就依赖于这256个中断,只不过操作系统可能处理的方式更多,比如根据AH的值,调用一个函数指针,也就是一个函数的地址,这个函数地址里面又有很多封装,慢慢的操作系统API就越来越多.这些都是我们不关心的
具体的中断,可以看下第一课所有的课堂资料中的指令字典,寻找一下中断号自己去调用
比如判断按键的汇编例子
getkey: mov ah,01h ;功能号:ah←01h
int 21h ;功能调用
cmp al,’Y’ ;处理出口参数al
je yeskey ;是“Y”
cmp al,’N’
je nokey ;是“N”
jne getkey
...
yeskey: ...
nokey: ...
三丶最后的指令详解
LOCK指令 封锁总线,不让总线接受指令
这个常用与多线程的时候操作,多线程的操作中的同步对象的 自加锁就是这样实现的
比如:
lock add word ptr[bp],
当我们吧3给内存的时候,其余的程序也可能再往这里写数据,所以同步一下,这样就完成这一条指令,才可以进行下一条指令的操作
自减锁就是 把add 变为sub,交换锁就是 把指令变为 xchg lock只能同时处理一条指令,这是为防止我们把系统总线都锁死,这样操作系统就会崩溃,信息到不了,不过这个不是我们关心的
解锁是CPU自己解锁的,没有解锁指令
HLT 暂停指令
这个就比较简单的,我们电脑都有休眠功能,就是用的这个指令,让CPU功耗降低,不执行,以前是无限循环NOP指令
但是NOP也是一个指令也会有功耗,所以现在改为HLT指令了,执行了这个指令HLT不进行任何操作,当我们发送了一条指令过去之后,就会脱离暂停状态
就好比电脑挂机了,屏幕黑了,就是进入HLT了,我们点击鼠标或者键盘,发送了一条指令,接着就唤醒了
交权指令
ESC 6位立即数,reg/mem
我们都知道,以前算浮点数的时候都是CPU一个去做的,现在有了浮点处理器,也就是协处理器,专门算浮点的一个CPU
我们的CPU计算浮点数的时候,要把权力交给浮点处理器,这时候就称为交权,在这个时候CPU要等待浮点处理器返回的结果,期间一直等待
FADD FDIV 是浮点计算指令,就是我们计算指令前面加F就会计算浮点数了
浮点数有7个寄存器
ST -> st7 按照标号来的
浮点处理器的st不能和通用寄存器一样去使用,它是吧ST寄存器压入栈中,让前两个栈中的数据相加返回的
关于浮点处理,后面再说,这个不是16为汇编中使用的
WAIT 等待指令
这个就简单了,CPU交权后,就使用这个指令去等待浮点处理器返回结果
总结:
16位汇编在我的博客上都精简了,但是你想搞明白就要多花点时间,细细品味汇编的内容,掌握汇编
过几天开始32位汇编的讲解,如果觉得好,请评论一下,关注一下,加个粉丝.支持一下,谢谢
对于Call变为函数的哪里,一定要掌握,不懂的可以去看下C语言的栈内存结构,或者看下它的汇编代码,一定搞明白
这个以后逆向的时候天天看.
学习资料: 链接:http://pan.baidu.com/s/1nuPNUFf 密码:x44c
16汇编第十讲完结Call变为函数以及指令的最后讲解的更多相关文章
- 32位汇编第六讲,OllyDbg逆向植物大战僵尸,快速定位阳光基址
32位汇编第六讲,OllyDbg逆向植物大战僵尸,快速定位阳光基址 一丶基址,随机基址的理解 首先,全局变量的地址,我们都知道是固定的,是在PE文件中有保存的 但是高版本有了随机基址,那么要怎么解决这 ...
- x86汇编之十(使用字符串)
x86汇编之十(使用字符串) 转自网络,出处不详 一.传送字符串 Intel提供了完整的字符串传送指令,就像是MOV指令一样. 1.MOVS指令 1)movs指令格式 把字符串从一个位内存位置传送到另 ...
- Java Web快速入门——全十讲
Java Web快速入门——全十讲 这是一次培训的讲义,就是我在给学生讲的过程中记录下来的,非常完整,原来发表在Blog上,我感觉这里的学生可能更需要. 内容比较长,你可以先收藏起来,慢慢看. 第一讲 ...
- 32位汇编第四讲,干货分享,汇编注入的实现,以及快速定位调用API的数量(OD查看)
32位汇编第四讲,干货分享,汇编注入的实现,以及快速定位调用API的数量(OD查看) 昨天,大家可能都看了代码了,不知道昨天有没有在汇编代码的基础上,实现注入计算器. 如果没有,今天则会讲解,不过建议 ...
- C语言第十讲,枚举类型简单说明
C语言第十讲,枚举类型简单说明 一丶C语言中的枚举类型(ENUM) 在我们实际工作中,或者编写代码中.我们有的时候会用固定的值.而且不是很多. 这个时候就可以使用枚举了.如果我们使用#define显然 ...
- Python十讲
第一讲:从零开始学Python 第二讲:变量和基础数据类型 第三讲:条件分支以及循环 第四讲:列表与元组 第五讲:字典 第六讲:函数 第七讲:类 第八讲:标准库 第九讲:异常 第十讲:文件处理
- 第十讲_图像检索 Image Retrieval
第十讲_图像检索 Image Retrieval 刚要 主要是图像预处理和特征提取+相似度计算 相似颜色检索 算法结构 颜色特征提取:统计图片的颜色成分 颜色特征相似度计算 色差距离 发展:欧式距离- ...
- x64汇编第四讲,c / C++中调用x64汇编
目录 x64汇编第四讲,c / C++中调用x64汇编 一丶简介 1.说明 二丶C/C++调用 asm64.asm函数. 1.配置asm参与生成 2.给Asm文件添加函数代码 3.C/C++调用asm ...
- 第十六节,使用函数封装库tf.contrib.layers
这一节,介绍TensorFlow中的一个封装好的高级库,里面有前面讲过的很多函数的高级封装,使用这个高级库来开发程序将会提高效率. 我们改写第十三节的程序,卷积函数我们使用tf.contrib.lay ...
随机推荐
- Android源码博文集锦4
Android精选源码 一款常见的自定义加载动画 android开源记账项目CoCoin Android自定义view:拖拽选择按钮 Android指纹识别 一个折线图,它提供了几个非常实用的功能 一 ...
- EF 直接修改数据,不再查询数据库
public int UpData(T model, params string[] proNames) { //4.1将 对象 添加到 EF中 DbEntityEntry entry = null; ...
- 一个最最简易的RPC框架雏形---转载自梁飞的博客
查阅RPC与HTTP区别的时候, 无意间发现一篇博客,内容是一个简易的RPC服务框架, 仔细一看, 不得了,博主竟然就是阿里dubbo的作者. 原文链接在此: http://javatar.iteye ...
- VMware workstation虚拟集群实践(1)—— 配置集群多节点互信
一. 简述 节点互信,是集群管理的基本操作之一.节点互信是通过SSH协议的公钥密钥认证来代替密码认证来实现的.对于单点批量管理多个节点,多个节点之间相互通信来说,配置SSH单方向信任,或者互信十分必要 ...
- 被DDOS攻击的解决方法
在DDOS分布式借"机"堵塞正常访问的非法攻击中,任何技术高手都成了文科生.只能用非专业的方法解决.DDOS攻击的重心是堵塞服务器,给域名解析访问造成困难,被攻击后我们可以采用以下 ...
- SSRF漏洞学习
SSRF SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞.一般情况下,SSRF攻击的目标是从外网无法访问的内 ...
- Spring Boot整合Dubbo使用及开发笔记
一.概述: Spring Dubbo是我开发的一个基于spring-boot和dubbo,目的是使用Spring boot的风格来使用dubbo.(即可以了解Spring boot的启动过程又可以学习 ...
- ReactiveSwift源码解析(十) Lifetime代码实现
为了之后博客的进行,本篇博客我们就来聊一下ReactiveSwift框架中的Lifetime类的具体实现.从Lifetime这个名字中我们就这道,就是生命周期.在ReactiveSwift中使用Lif ...
- Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.
我用String代替了链表显示,本题的大意是每k个进行逆序处理,剩下的不够k个的就按照原顺序保留下来. public class ReverseNodes { public static void m ...
- java网络编程实现两端聊天
网络编程的三要素: ip地址:唯一标识网络上的每一台计算机 端口号:计算机中应用的标号(代表一个应用程序),0-1024系统使用或者保留端口,有效端口0-65535(short) 通信协议:通信的规则 ...