精华内容
下载资源
问答
  • zhejiang wenzhou skinshoe wet, rain flooding water will not fat. 昨天我发了一篇关于替换运行中的内核函数的文章: Linux内核如何替换内核...晚上回去有朋友在朋友圈回复了我关于 “函数开头5字节跳转” 的事...

    zhejiang wenzhou skinshoe wet, rain flooding water will not fat.


    昨天我发了一篇关于替换运行中的内核函数的文章:
    Linux内核如何替换内核函数并调用原始函数https://blog.csdn.net/dog250/article/details/84201114
    晚上回去有朋友在朋友圈回复了我关于 “函数开头5字节跳转” 的事。今天正好要确认一个与此相关的细节,就顺便又把这问题重新撸了一遍。

    其实起初我也很纳闷,以前不都是0x55开头的指令吗?怎么现在这种call self或者lea 0x0(%rsp),%rsp套路却都成了惯例。…


    关于5字节跳转,说的是下面的情况:

    0000000000000380 <ipv4_conntrack_in>:
          380:   e8 00 00 00 00          callq  385 <ipv4_conntrack_in+0x5>
          385:   55                      push   %rbp
          386:   49 8b 40 18             mov    0x18(%r8),%rax
    

    请注意函数最开头的5个字节:

    e8 00 00 00 00          callq  385 <ipv4_conntrack_in+0x5>
    

    可见,它实际上call的是紧接着它下面的地址,所以说这个5字节的call指令其实是 没有用 的!

    仔细看一下这5个字节,思考一下它到底有什么用。

    • 我们可以任意将它替换成 jmp $4字节相对偏移

    这样,代码指令流就会进入我们自己的HOOK函数里了。

    当然了,关于 “e8 00 00 00 00 callq …” 这个有很多话可以讲,比如和Link相联系的时候就比较有意思了,它可是作为一个桩指令存在。这个和HOOK无关,也不再说太多。


    让我觉得最有意思的是,昨天那位朋友提到了微软的/hotpatch编译选项,我大致看了一下:
    /hotpatch (Create Hotpatchable Image):https://docs.microsoft.com/en-us/cpp/build/reference/hotpatch-create-hotpatchable-image?view=vs-2017

    When /hotpatch is used in a compilation, the compiler ensures that first instruction of each function is at least two bytes, which is required for hot patching.

    这是一个很有意思的选项,其实编译器提供这个机制也是举手之劳吧,虽然简单,但它确实为程序员HOOK运行中的函数提供了很大的方便。

    /hotpatch的实质其实就是在函数的开头和结尾填充了一些无关紧要的指令,方便HOOK来用自己的jmp指令覆盖这个无关紧要的指令。比如下面是一个函数的开头:

    	380:	 90
    	381:	 90
    	382:	 90
    	383:	 90
    	384:	 90
    	385:  	 55                      push   %rbp
    	386:	 49 8b 40 18             mov    0x18(%r8),%rax
    	38a:	 48 89 f1                mov    %rsi,%rcx
    	38d:	 8b 57 2c                mov    0x2c(%rdi),%edx
    	390:	 be 02 00 00 00          mov    $0x2,%esi
    

    0x90代表一个nop指令,即 “什么也不做”的意思,如此一来,程序员便非常容易将类似下面的指令插入到函数开头了:

    	  380:   e9 11 22 33 44			 jmp 0x44332211
          385:   55                      push   %rbp
          386:   49 8b 40 18             mov    0x18(%r8),%rax
          38a:   48 89 f1                mov    %rsi,%rcx
          38d:   8b 57 2c                mov    0x2c(%rdi),%edx
          390:   be 02 00 00 00          mov    $0x2,%esi
    

    无需任何额外的指令保存动作。

    既然微软的编译器有这个功能可用,GCC有没有呢?看了GCC的manual,发现了一个-mhotpatch=x,y的选项,但是在x86平台不能用,还是比较不爽的。

    后来发现了在编写函数的时候,可以加上下面的属性,然后编译器就可以将其编译成带有填充的指令了:

    __attribute__ ((ms_hook_prologue))
    

    那么,简单来用一下,看看效果咯。


    由于时间并不是很多,我也没有那么多精力去应对不断的panic,所以这次准备在用户态搞。

    由于用户态可以直接使用mprotect函数更改内存的使用权限,所以就不需要那个stub函数了。今天的这个例子,原理图如下:
    在这里插入图片描述

    加上ms_hook_prologue属性修饰的函数,编译好了之后,你会在函数最开头两行找到下面的 废指令

    00000000004004ed <func>:
           4004ed:   48 8d a4 24 00 00 00    lea    0x0(%rsp),%rsp
           4004f4:   00
           4004f5:   55                      push   %rbp
    

    随意替换之就好。所以对于这个例子,上面图示里的n的值就是5.

    此外,上图中,我们的一个指令buffer不再是一个stub函数,而真的就是一块分配的内存,所以我们需要给它加上EXEC权限,不然会segment fault。这个在内核模块中是不能直接做的,因为分配带有EXEC权限的module_alloc并没有导出,所以如若想用它,则必须通过kallsyms_lookup_name的内省方式来做。

    再一个需要注意的是,由于指令buffer是在堆上分配的,在64位系统上,它的位置和函数代码的位置之差会超过4个字节界定的相对偏移,所以就不能用0xe9+4字节相对偏移来jmp了,而要通过64位绝对地址来跳转了,指令如下:

    48 b8 88 77 66 55 44 33 22 11   mov rax, 0x1122334455667788
    ff e0                           jmp rax
    

    好了,说了这么多,该上代码了:

    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/mman.h>
    
    // 保存原始函数的指针
    void (*ptr_func)(int a);
    
    // ms_hook_prologue修饰的函数,便于hook
    __attribute__ ((ms_hook_prologue))
    void func(int a)
    {
    	printf("orig %d\n", a);
    }
    
    // 自己的hook函数
    void my_func(int a)
    {
    	a += 2;
    	printf("my %d\n", a);
    	// 调用原始函数
    	ptr_func(a);
    }
    
    // 需要在func前面插入一个jmp $4字节偏移 的指令,一共5个字节
    char jump[5] = {0};
    
    int main()
    {
    	long loffset;
    	int offset;
    	char *inst_buf;
    	void *page = (void *)((unsigned long)func & ~0xfff);
    	
    	// 为func所在的页面增加可写权限
    	mprotect(page, 8, PROT_WRITE|PROT_EXEC);
    	// 这些操作和内核版本的hook一致
    	jump[0] = 0xe9;
    	offset = (int)((long)my_func - (long)func - 5);
    	(*(int*)(&jump[1])) = offset;
    	memcpy(func, jump, 5);
    
    	// 分配一个带有EXEC权限的buffer,里面将保存指令
    	inst_buf = mmap(NULL, 1024, PROT_READ|PROT_EXEC|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
    	// 拼接mov rax, 0x1122334455667788;jmp rax指令
    	inst_buf[0] = 0x48;
    	inst_buf[1] = 0xb8;
    	loffset = (long)func + 4;
    	(*(long*)(&inst_buf[2])) = loffset;
    	inst_buf[10] = 0xff;
    	inst_buf[11] = 0xe0;
    	
    	// 指定inst_buf为原始函数指针
    	ptr_func = inst_buf;
    	// 调用!!
    	func(2);
    }
    

    结果当然是先调用自己的hook函数,然后再调用原始函数咯:

    [root@localhost hotpatch]# ./a.out
    my 4
    orig 4
    

    为什么不用kprobe机制呢?kprobe的原理是 为了灵活性,使用int 3指令替换被hook的指令。 这样就可以任意编写pre/post回调函数了,但是我们也能看出来,通过int方式来hook,对效率的影响是不能忽略,特别是对于那些频繁被调用的函数,kprobe更加不可行。

    kprobe非常适合做问题排查,热点分析,但不好在生产环境跑的。

    其实,本文所描述的hotpatch原理还可以做的更好些,达到 在任意点插入自己的逻辑的目的,包括在函数的内部。 这样可以达到和kprobe相同的效果。当然,这需要对运行中的二进制指令序列做相对周密详细的分析。

    这里还有一篇关于hotpatch的文章,比我这篇好,可以看一下:
    Hotpatching a C Function on x86https://nullprogram.com/blog/2016/03/31/


    补充说明一下,朋友圈有高手最新评论,让我又知道了些新东西:

    • nop指令的实现方式有很多种,比如mov edi edi。可能很多平台并没有类似独立的0x90指令吧。不过既然有,那还是0x90纯粹些。
    • kprobe也不全部一来int 3,只有return hook的场景才依赖int 3,其它的也可以做jmp hook。
    • 线程安全,原子化操作也是生产环境必须考虑的,不然就是玩具。

    浙江温州皮鞋湿,下雨进水不会胖。

    展开全文
  • C++函数调用机制

    2017-08-28 20:04:40
    局部变量占用的内存是在程序执行过程中“动态”地建立和释放的。这种“动态”是通过栈由系统自动管理进行的。当任何一个函数调用发生时,系统都要作以下工作: ...(6)回复现场:取主调函数运行状态及返回地
    局部变量占用的内存是在程序执行过程中“动态”地建立和释放的。这种“动态”是通过栈由系统自动管理进行的。当任何一个函数调用发生时,系统都要作以下工作:
    (1)建立栈空间;
    (2)保护现场:主调函数运行状态和返回地址入栈;
    (3)为被调函数中的局部变量分配空间,完成参数传递;
    (4)执行被调函数函数体;
    (5)释放被调函数中局部变量占用的栈空间;
    (6)回复现场:取主调函数运行状态及返回地址,释放栈空间;
    (7)继续主调函数后续语句。

    函数调用过程中的内存使用:通过下面例子来看函数调用时内存的变化情况。

    void fun1(int, int);
    void fun2(float);
    int main()
    {
        int x=1;y=2;
        fun1(x, y);
        return 0;
    }
    void fun1(int a,int b)
    {
        float x=3;
        fun2(x);
    }
    void fun2(float y) 
    {
        int x;
        …
    }
    




    关于执行函数指令C++ primer plus中这样解释:

    执行到函数调用指令时,程序将在函数调用后立即存储该指令的内存地址,并将函数参数复制到堆栈(为此保留的内存块),跳到标记函数起点的内存单元,执行函数代码(也许还需要将返回值放入到寄存器中),然后跳回到地址被保存的指令处(这与阅读文章时停下来看脚注,并在阅读完脚注后返回到以前阅读的地方类似)。来回跳跃并记录跳跃位置意味着以前使用函数时,需要一定的开销。

    展开全文
  • 在Flink中提供了一种基于点检查(Check Point)机制和SnapShot的容错回复机制。这个机制的提出与应用是因为考虑到现实应用中因为追求低时延性而发生的丢包,或者是单点故障恢复等等一系列的问题。因此Flink会动态地去...

    在Flink中提供了一种基于点检查(Check Point)机制和SnapShot的容错回复机制。这个机制的提出与应用是因为考虑到现实应用中因为追求低时延性而发生的丢包,或者是单点故障恢复等等一系列的问题。因此Flink会动态地去保存各个算子和相应时间下的状态量,以备在发生故障时进行恢复。

    所谓SnapShot算法,顾名思义,可以理解为在某一个时刻对全局的算子和事件进行一次拍照以储存相应的状态量。

    贴一下我参考的文献:
    在这里插入图片描述

    在这篇文献中,提出了一种snapshot的算法:
    【ABS算法for Acyclic dataflow】
    一个中心的协调者周期性地注入stage barrier进入每一个数据源中,之后就把这些barrier广播给其下游的所有输出中。如果一个非源项的任务算子在一次接收input的时候拿到了这个barrier,那么它就会锁住这一个input,直到这个任务算子拿到了上一级的所有input,那么这个任务算子就会进行一次snapshot,然后进行解锁,于是所有的数据可以直接进入下游。
    在这里插入图片描述
    注意:只有在一个任务算子拿到了上一级的所有输入时,才会进行拍照并解锁barrier。这么做的原因是,Flink始终是一个面向于事务流的分布式处理软件,如果不使用Barrier来进行约束,就会出现这样的情况:在上游的某些数据还没有流入算子中的时候,Flink就已经拍照,如果这样去进行容错恢复,那么这个没有来得及进入算子的数据就会因为没有被及时记录下来而产生丢包。

    一个好的snapshot算法必须要保证两个特点:
    1.Termination:即能够有最终的结果(无环),由于通道(channel)和非循环执行的拓扑,可以很容易地保证。
    2.Feasibility:由于通道(channel)的先进先出机制(FIFO),也可以很容易地保证。

    【ABS算法for Acyclic dataflow】
    考虑到以上的算法并不适用于循环数据流的处理模式。提出了针对有迭代的数据处理的算法。

    由于数据一直在执行一个循环,会出现一个deadlock,最终的Termination是没有办法保证的。

    一旦一个任务算子拿到了上一级的所有input,那么这个算子就会本地记录下所有的上一级数据状态,然后解锁。在最终得到的这一级snapshot中,也包括了预先已经进入循环被染色的数据。
    在这里插入图片描述
    一个好的snapshot算法必须要保证两个特点:
    1.Termination:由于得到barrier就立即解锁释放给下一级,而不需要等待所有的input,可以保证。
    2.Feasibility:由于通道(channel)的先进先出机制(FIFO),也可以很容易地保证。

    (以前一直以为Flink的SnapShot就只是单纯地拍照储存一下数据而已…现在看来,只要是考虑到“实时性”和“分布式”的问题,相应的工作都不好做啊。)

    展开全文
  • 3.4 函数调用机制

    2016-06-12 08:54:08
    ◆ 局部变量占用的内存是在程序执行过程中“动态”地建立和释放的。这种“动态”是通过栈由系统自动管理进行的。当任何一个函数调用发生时,系统都要作以下工作: ...(6)回复现场:取主调函数运行状态及返
    ◆ 局部变量占用的内存是在程序执行过程中“动态”地建立和释放的。这种“动态”是通过栈由系统自动管理进行的。当任何一个函数调用发生时,系统都要作以下工作:
    (1)建立栈空间;
    (2)保护现场:主调函数运行状态和返回地址入栈;
    (3)为被调函数中的局部变量分配空间,完成参数传递;
    (4)执行被调函数函数体;
    (5)释放被调函数中局部变量占用的栈空间;
    (6)回复现场:取主调函数运行状态及返回地址,释放栈空间;
    (7)继续主调函数后续语句。

    ◆ 函数调用过程中的内存使用:通过下面例子来看函数调用时内存的变化情况。
    void fun1(int, int);
    void fun2(float);
    int main(){
        int x=1;y=2;
        fun1(x, y);
        return 0;
    }
    void fun1(int a,int b){
        float x=3;
        fun2(x);
    }
    void fun2(float y) {
        int x;
        …
    }
    展开全文
  • 在前一篇文章中讲解了通过入口存储过程动态调用业务过程的原理。下面来说明如何实现游戏状态的更新。 项目的源码可在CSDN资源中下载 实现原理 由于http协议是无状态的请求响应式协议,用户可以主动向服务器发起请求...
  • 图元动态感知

    2017-08-08 16:58:00
    当鼠标在AnyCAD三维控件中掠过图元上方的时候,图元会“高亮”显示,当鼠标移走的时候会回复之前的状态。在一般的窗体控件中会提供MouseEnter/MouseLeave事件。 在AnyCAD提供了图元选择消息,当图元选择的时候会被...
  • 本章节缕一缕PyTorch的动态机制与Tensorflow的静态图机制(最新版的TF也支持动态图了似乎)。 1 动态图的初步推导 计算图是用来描述运算的有向无环图 计算图有两个主要元素:结点(Node)和边(Edge); 结点表示...
  • 随着项目中easyui控件的深入使用,有些特定的场景需要从后端动态生成easyui控件到前端,easyui控件自身有套渲染机制,根据定义的class进行客户端渲染。 网上有关于这方面的资料介绍(入口),并提供了easyui渲染...
  • 此公众号会发表计算机考研(初复试信息)、夏令营等资料,方便考研人对信息的获取,节约自身查找资料的时间,回复408,可获得数据结构、操作系统、计算机网络、计算机组成原理全科资料 使用functools模块的lur_...
  • 关注Java后端技术栈”回复“面试”获取最新资料是父类或接口定义的引用变量可以指向子类或实现类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实现对象的方法,也就...
  • PHP动态网页设计与制作案例教程

    热门讨论 2012-12-12 10:53:30
    1.2 动态网站的运行机制 1.2.1 域名 1.2.2 网页 1.2.3 浏览器 1.2.4 服务器 1.3 动态网站的规划 1.3.1 确定网站的类型 1.3.2 确定网站的主题 1.3.3 确定网站的整体风格 1.3.4 确定网站的内容 1.3.5 规划...
  • 一个处理器只会执行一条线程中的指令,为了线程切换后能回复到正确的执行位置,所以每条线程都需要一个独立的计数器。各条线程之间互不影响,独立存储,属于‘线程私有’内存。  2、java虚拟机栈:描述的是JAVA...
  • 当热加工温度处于α+β两相区时,软化机制动态回复;而当热加工温度处于β单相区时,软化机制为动态再结晶。激光增材制造TC18钛合金较理想的热加工工艺参数:变形温度为830~880 ℃、应变速率为0.001~0.003 s-1和...
  • JAVA反射会降低你的程序性能吗?

    千次阅读 2019-06-25 19:49:33
    这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。from:http://www.111cn.net/jsp/Java/72057.htm早两天写了《从把三千行代码重构成15行代码谈起》这篇文章,看到评论中有一些同学的回复还是...
  • 从一个转发路由器到另一个转发罗尤其的转换对设备是透明的,网络从充当默认网关的设备故障中动态回复的功能为第一跳冗余。 当活动路由器发生故障时,冗余协议会使备用路由器转换为新的活动路由器。以...
  • 如果过期可以底下留言,或者关注我的微信公众号 《人生代码》《人生代码》《人生代码》,回复进群,加我微信,拉你进群,重要的事情说三遍。 JavaScript即将推出令人兴奋的新功能! 即使新ECMAScript 2020(ES2020)...
  • 爬虫学习day03

    2020-04-25 22:49:15
    获取代理IP地址selenium介绍测试session和cookie动态网页和静态网页session和cookiessessioncookies实战:模拟登录163小项目:模拟登录丁香园,并抓取论坛页面所有的人员基本信息与回复帖子内容 IP 介绍 为什么会...
  • 23种设计模式之观察者模式代码demo

    千次阅读 2020-12-18 16:16:58
    观察者模式主要用于在关联行为之间建立一套触发机制的场景。 懒人源码: 扫描下面二维码关注公众号: 程序员修炼宝典 ,回复:观察者模式 获取源码 java源码模拟朋友圈动态通知: public class GPer ...
  • Redis常用集群方案

    2020-11-03 11:26:18
    集群的几种实现方式 客户端分片 基于代理的分片 路由查询 客户端分片 由客户端决定key写入或者读取的节点。...客户端发送请求到一个代理,代理解析客户端的数据,将请求转发至正确的节点,然后将结果回复给客户端
  • ClassLoader类装载策略

    2007-12-26 12:16:57
    Java编程极限考验:ClassLoader类装载策略 作者:banq 发表时间:2004年07月26日 ...个人认为,Java编程中极限考验是Classloader机制的掌握和灵活运用,特别是在复杂的系统,如存在动态类装载,Reflect,EJB,AOP等...
  • CLP的强化机制主要包括两方面:一是深冷环境抑制位错的动态回复,并降低热激活能,从而促进了细化晶粒和第二相对位错的阻碍作用;二是深冷环境下试样的体积收缩效应产生的塑性变形和内应力,它们会产生显著的组织强化效果...
  • TCP协议:在三次握手连接成功后,每次通信都会有回复,这就知道了哪些数据包接受到了,哪些丢失了,通过重发的机制保证了传输的可靠性 UDP协议只是将数据包发送了过去,并没有验证的过程,所以在数据可靠性方...
  • iOS性能优化

    2021-01-31 21:28:20
    在 iOS 中有双缓存机制,有前帧缓存、后帧缓存,这样渲染的效率很高。 屏幕成像原理 我们所看到的动态的屏幕的成像其实和视频一样也是一帧一帧组成的。为了把显示器的显示过程和系统的视频控制器进行同步,显示器...
  • 2. 最新动态显示(最新帖子、最新图片、最新回复等) 3. 注册功能 4. 支持UID、Email登录 5. 指定回复功能 6. 回复删除功能 7. 支持自定义微博账号(appkey) 8. 无图浏览模式(更省流量) 9. 资讯文章列表显示默认...
  • 进程知识梳理

    2021-01-21 14:36:01
    进程是程序的一次执行过程,是一次动态的过程。 进程是系统进行资源分配的最小单位。 进程调度过程 1.通过一些机制,让当前运行的进程停止,进入操作系统逻辑。 2.保存上下文信息——进程A(当前进程)运行到什么...
  • 专辑功能,内容的评论、转发与回复功能,让信息无限传播。 3.社交互动 收藏、喜欢、好友分享的图片或商品,发现自己喜欢; 关注自己喜欢的人和动态,寻找相同兴趣爱好的朋友; 建立自己的粉丝团,让自己变成意见...
  • 专辑功能,内容的评论、转发与回复功能,让信息无限传播。 淘宝客 淘宝客接口API集成,淘宝商品条件筛选一键采集,乐享佣金; 分享推荐商品导购链接,淘宝导购,赚取佣金; 商品点评,喜欢,转发分享,形成社会...
  • 增加主题评价排行榜以及JS调用,方便会员调用数据 ... 管理员不受任何搜索限制 某些主题回帖只对发帖人、自己、管理可见 在任意版块选择性置顶,管理员可以选择版块 ...回帖时间设置倒序排列,帖子...帖子审核机制改进

空空如也

空空如也

1 2 3 4 5 6
收藏数 104
精华内容 41
关键字:

动态回复机制