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变为函数以及指令的最后讲解的更多相关文章

  1. 32位汇编第六讲,OllyDbg逆向植物大战僵尸,快速定位阳光基址

    32位汇编第六讲,OllyDbg逆向植物大战僵尸,快速定位阳光基址 一丶基址,随机基址的理解 首先,全局变量的地址,我们都知道是固定的,是在PE文件中有保存的 但是高版本有了随机基址,那么要怎么解决这 ...

  2. x86汇编之十(使用字符串)

    x86汇编之十(使用字符串) 转自网络,出处不详 一.传送字符串 Intel提供了完整的字符串传送指令,就像是MOV指令一样. 1.MOVS指令 1)movs指令格式 把字符串从一个位内存位置传送到另 ...

  3. Java Web快速入门——全十讲

    Java Web快速入门——全十讲 这是一次培训的讲义,就是我在给学生讲的过程中记录下来的,非常完整,原来发表在Blog上,我感觉这里的学生可能更需要. 内容比较长,你可以先收藏起来,慢慢看. 第一讲 ...

  4. 32位汇编第四讲,干货分享,汇编注入的实现,以及快速定位调用API的数量(OD查看)

    32位汇编第四讲,干货分享,汇编注入的实现,以及快速定位调用API的数量(OD查看) 昨天,大家可能都看了代码了,不知道昨天有没有在汇编代码的基础上,实现注入计算器. 如果没有,今天则会讲解,不过建议 ...

  5. C语言第十讲,枚举类型简单说明

    C语言第十讲,枚举类型简单说明 一丶C语言中的枚举类型(ENUM) 在我们实际工作中,或者编写代码中.我们有的时候会用固定的值.而且不是很多. 这个时候就可以使用枚举了.如果我们使用#define显然 ...

  6. Python十讲

    第一讲:从零开始学Python 第二讲:变量和基础数据类型 第三讲:条件分支以及循环 第四讲:列表与元组 第五讲:字典 第六讲:函数 第七讲:类 第八讲:标准库 第九讲:异常 第十讲:文件处理

  7. 第十讲_图像检索 Image Retrieval

    第十讲_图像检索 Image Retrieval 刚要 主要是图像预处理和特征提取+相似度计算 相似颜色检索 算法结构 颜色特征提取:统计图片的颜色成分 颜色特征相似度计算 色差距离 发展:欧式距离- ...

  8. x64汇编第四讲,c / C++中调用x64汇编

    目录 x64汇编第四讲,c / C++中调用x64汇编 一丶简介 1.说明 二丶C/C++调用 asm64.asm函数. 1.配置asm参与生成 2.给Asm文件添加函数代码 3.C/C++调用asm ...

  9. 第十六节,使用函数封装库tf.contrib.layers

    这一节,介绍TensorFlow中的一个封装好的高级库,里面有前面讲过的很多函数的高级封装,使用这个高级库来开发程序将会提高效率. 我们改写第十三节的程序,卷积函数我们使用tf.contrib.lay ...

随机推荐

  1. Android源码博文集锦4

    Android精选源码 一款常见的自定义加载动画 android开源记账项目CoCoin Android自定义view:拖拽选择按钮 Android指纹识别 一个折线图,它提供了几个非常实用的功能 一 ...

  2. EF 直接修改数据,不再查询数据库

    public int UpData(T model, params string[] proNames) { //4.1将 对象 添加到 EF中 DbEntityEntry entry = null; ...

  3. 一个最最简易的RPC框架雏形---转载自梁飞的博客

    查阅RPC与HTTP区别的时候, 无意间发现一篇博客,内容是一个简易的RPC服务框架, 仔细一看, 不得了,博主竟然就是阿里dubbo的作者. 原文链接在此: http://javatar.iteye ...

  4. VMware workstation虚拟集群实践(1)—— 配置集群多节点互信

    一. 简述 节点互信,是集群管理的基本操作之一.节点互信是通过SSH协议的公钥密钥认证来代替密码认证来实现的.对于单点批量管理多个节点,多个节点之间相互通信来说,配置SSH单方向信任,或者互信十分必要 ...

  5. 被DDOS攻击的解决方法

    在DDOS分布式借"机"堵塞正常访问的非法攻击中,任何技术高手都成了文科生.只能用非专业的方法解决.DDOS攻击的重心是堵塞服务器,给域名解析访问造成困难,被攻击后我们可以采用以下 ...

  6. SSRF漏洞学习

    SSRF SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞.一般情况下,SSRF攻击的目标是从外网无法访问的内 ...

  7. Spring Boot整合Dubbo使用及开发笔记

    一.概述: Spring Dubbo是我开发的一个基于spring-boot和dubbo,目的是使用Spring boot的风格来使用dubbo.(即可以了解Spring boot的启动过程又可以学习 ...

  8. ReactiveSwift源码解析(十) Lifetime代码实现

    为了之后博客的进行,本篇博客我们就来聊一下ReactiveSwift框架中的Lifetime类的具体实现.从Lifetime这个名字中我们就这道,就是生命周期.在ReactiveSwift中使用Lif ...

  9. 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 ...

  10. java网络编程实现两端聊天

    网络编程的三要素: ip地址:唯一标识网络上的每一台计算机 端口号:计算机中应用的标号(代表一个应用程序),0-1024系统使用或者保留端口,有效端口0-65535(short) 通信协议:通信的规则 ...