调试程序调试到系统库函数的代码时,总会发现系统函数都是从一条MOV EDI, EDI指令开始的,紧接着这条指令下面才是标准的建立函数局部栈的代码。对系统DLL比如ntdll.dll进行反汇编,可以发现它的每个导出函数都是如此,并且每个导出函数开始处的MOV EDI, EDI上面紧接着5条NOP指令。比如在WinDbg中查看TextOutA周围的代码: 

0:000> u TextOutA-0x0a L 10 

GDI32!NtGdiTransparentBlt+0xa: 

77efc43f ff12            call    dword ptr [edx] 

77efc441 c22c00          ret     2Ch 

77efc444 90              nop 

77efc445 90              nop 

77efc446 90              nop 

77efc447 90              nop 

77efc448 90              nop 

GDI32!TextOutA: 

77efc449 8bff            mov     edi,edi 

77efc44b 55              push    ebp 

77efc44c 8bec            mov     ebp,esp 

很明显,两个字节的MOV EDI,EDI指令什么事情也不做,那么,就有两个问题:第一,为什么不直接从函数体开始而要从这条什么都不做的指令开始呢?第二,即使需要在函数一开始空出两个字节,为什么不直接使用两条NOP指令,而要使用这条MOV指令呢?在网上查阅一些资料后,得到了答案: 

对于第一个问题,答案是为了实现hot-patching技术,即运行时修改一个函数的行为。修改过程如下:把MOV EDI, EDI修改为一条短跳转指令(一条短跳转指令恰好两个字节),把MOV EDI, EDI上面的五个NOP修改为一条长跳转指令(一条长跳转指令恰好五个字节),短跳转指令跳到长跳转指令上,长跳转指令跳到修改后的函数体上。 

对于第二个问题,答案是为了提高效率。执行一条MOV指令比执行两条NOP指令花费更少的时间。 

  

下面是在网上搜索到的相关资料: 

http://blogs.msdn.com/ishai/archive/2004/06/24/165143.aspx 

在这篇日志中作者指出这是一种实现hot-patching和hot-fix的技术,而且解释了为什么不使用detours技术来实现hot-patching。此外,作者提到了具体是如何使用这种技术来实现hot-patching的,但是只是一句话带过。 

  

http://msmvps.com/blogs/kernelmustard/archive/2005/04/25/44413.aspx 

这篇文章中作者从效率和其它方面详细解释了为什么选择用这种技术来实现hot-patching以及为什么要这样实现(短跳转加长跳转而不是一次性长跳转)。 

  

http://xelf.info/knowledge/MemoryCopy.cpp 

这里给出了具体的memcpy的C语言源代码。如果在安装VC6的时候选择了安装CRT源代码,则在VC安装目录的SRC/INTEL/目录中有memcmp.asm等文件,它们就是对应的CRT函数的源代码,这些源代码中也都有详细的注释。 

  

另外,在自己的日志http://blog.csdn.net/jcwKyl/archive/2008/03/25/2217428.aspx里面,曾经对strcmp函数中的MOV
EDI, EDI指令感到困惑,其实只要看看strcmp.asm中的源代码就可以明白,那条MOV EDI, EDI完全是为了内存四字节对齐的。源代码中写的是align 4,在运行时,如果需要一个填充字节,则会填充一条NOP指令,如果需要两个字节来填充,则会填充一条MOV EDI, EDI指令,之所以不用两条NOP,是出于效率的考虑。

函数开始处的MOV EDI, EDI的作用的更多相关文章

  1. Win32API起始处的mov edi, edi与用户空间InlineHook

    在x86平台上,无论是在调试器中跟到系统DLL中时,还是反汇编某个系统DLL时,经常会发现很多API的第一条汇编指令都是mov edi, edi.根据经验来讲,C函数的汇编形式,应该是首先push e ...

  2. Delphi函数的out、var等关键字的作用,和使用场景

    问题描述 Delphi函数的out.var等关键字的作用,和使用场景 Delphi函数的out.var等关键字的作用,和使用场景,我知道var是作为传值调用,但是像out这个关键字又是什么作用呢? 解 ...

  3. [反汇编]函数开始部分利用mov ebx,esp找到返回地址(_KTRAP_FRAME结构)

    我们理解call原理,首先将返回地址压入栈中,之后执行调用. 因此,在一个函数开始部分,esp依旧是上一个栈帧的esp,此时esp指向返回地址. 这就意味着使用 mov ebx,esp,之后 [ebx ...

  4. vscode跳转到函数定义处

    需要安装对应语言的插件,帮助-欢迎使用,安装javascript, php php还需要安装php7, 到官网https://windows.php.net/download#php-7.2 下载解压 ...

  5. 一句话改变TWinControl控件的left坐标的前世今生(入口函数是SetBounds,然后调用SetWindowPos起作用,并发消息更新Delphi的left属性值)

    Delphi的重要属性,主要是Enable,  Visible, Color, left等等.这里分析left,因为TWinControl里有些覆盖函数的原因,虽然起点都是TControl.SetLe ...

  6. Python中动态编译函数compile(source, filename, mode, ......)参数filename的作用是什么?

    动态编译函数compile调用语法如下: compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1) 其中的fi ...

  7. C语言函数中的3个点 ...有什么作用

    标准库提供的一些参数的数目可以有变化的函数.例如我们很熟悉的printf,它需要有一个格式串,还应根据需要为它提供任意多个"其他参数".这种函数被称作"具有变长度参数表的 ...

  8. Windows系统调用中API的3环部分(依据分析重写ReadProcessMemory函数)

    Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html Windows系统调用中API的3环部分 一.R3环API分析的重 ...

  9. 汇编之 eax, ebx, ecx, edx, esi, edi, ebp, esp??

    一般寄存器:AX.BX.CX.DXAX:累积暂存器,BX:基底暂存器,CX:计数暂存器,DX:资料暂存器 索引暂存器:SI.DISI:来源索引暂存器,DI:目的索引暂存器 堆叠.基底暂存器:SP.BP ...

随机推荐

  1. 3.Struts2中Action类的三种写法

    一.普通的POJO类(没有继承没有实现)-基本不使用 public class DemoAction1 { public String execute(){ System.out.println(&q ...

  2. 配置Cesium编译环境

    1.安装node.js https://nodejs.org/en/ 2.配置node.js 在node.js安装目录下新建node_global.node_cache两个文件夹,并把node_glo ...

  3. Redis探索之路(七):Redis高级使用特性

    一:安全性 设置客户端连接后进行任何其他指定前需要使用的密码. 因为Redis的速度非常之快,一台比较好的服务器下,一个外部的用户可以在1s内进行15万次的密码尝试连接,这就意味着你需要指定非常强大的 ...

  4. Unity 2018 version class.jar path

    { C:\Program Files\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes }

  5. MaxCompute小文件问题优化方案

    小文件背景知识 小文件定义 分布式文件系统按块Block存放,文件大小比块大小小的文件(默认块大小为64M),叫做小文件. 如何判断存在小文件数量多的问题 查看文件数量 desc extended + ...

  6. 动态隐藏显示窗口的标题栏(同时保持窗口的sizeable性能

    今天考虑作界面的时候,想去掉窗体的标题栏,但设置 Form.BorderStyle := bsNone; 会导致窗体不可再 Sizeable (通过鼠标操作改变窗体大小),仔细翻看了相关Help也没找 ...

  7. NX二次开发-UFUN CSYS坐标系转换UF_CSYS_map_point

    1 NX9+VS2012 2 3 #include <uf.h> 4 #include <uf_curve.h> 5 #include <uf_csys.h> 6 ...

  8. 【latex】latex基础

    文档边距.间距调整 边距调整 \usepackage{geometry} %设置页边距的宏包 \geometry{left=3.0cm,right=2.5cm,top=2.5cm,bottom=2.5 ...

  9. C++源文件的后缀名问题

    VC里用cpp作后缀名, 在GCC里默认采用C.cc.cxx作为后缀名 .cpp, .h (VS file).cc, .h (GCC file)   C中: 头文件后缀名: .h 源文件后缀名: .c ...

  10. slot 的简单用法

    注:默认在父组件调用子组件时<SlotChild></SlotChild>中文字不会显示.但是在子组件加入<slot></slot>后,<Slot ...