Bochs源码分析 - 15:bochs对于call far(tss_sel)指令的实现机制

汇编语言:call、call far ptr、call word ptr、call dword ptr、call 寄存器 call指令是转移指令,CPU执行call指令,进行两步操作:(1)将当前IP或当前CS和IP压入栈中(2)转移。call 标号指令功能:将当前IP压入栈中,然后转移到标号处执行指令。call far ptr标号指令功能:将当前CS压入栈中,然后再将当前IP压入栈中,最后转移到标号处执行指令。call 16位寄存器指令功能:将当前IP压入栈中,然后转移到寄存器中指明的目的地址处执行指令。call word ptr 内存单元地址指令功能:将当前IP压入栈中,然后转移到内存中指明的目的地址处执行指令。 阅读详情

前言

        所谓“保护模式”,重点是“保护”,可保护的是什么呢?答案是:内存中的数据与代码。有几种保护手段呢?段保护与页保护。这篇文章我尝试结合intel手册来重新梳理一下intel保护模式中的段保护有关机制。

保护模式的两种保护机制

        The memory management facilities of the IA-32 architecture are divided into two parts: segmentation and paging. Segmentation provides a mechanism of isolating individual code, data, and stack modules so that multiple programs (or tasks) can run on the same processor without interfering with one another. Paging provides a mechanism for implementing a conventional demand-paged, virtual-memory system where sections of a program’s execution environment are mapped into physical memory as needed. Paging can also be used to provide isolation between multiple tasks. When operating in protected mode, some form of segmentation must be used. There is no mode bit to disable segmentation. The use of paging, however, is optional.

         上面是intel卷三 3.1节 关于“保护模式内存管理”的摘要,注意黑体和下划线部分,intel明确指出其内存管理被分成两部分,段式管理(segmentation)和页式管理(paging)。另外,段式管理是必须强制选用的,而页式管理是可选的。

        如下图,是intel说明的保护模式内存管理机制。其首先通过段保护确定具体的线性内存地址,然后通过页保护来确定对应的物理地址。其实在有关资料中很多人都注重Intel的分页机制而忽视分段机制,我猜想很可能是因为各个段的Base都为零,不容易觉察到段保护的存在,段更重要的是其权限检查机制。

 段描述符

        一个段由其段描述符所描述,其不同的段类型存在不同的段描述符,但其可以认为由三部分组成:段权限(Access),段机制(Base),段线程(Limit)。

       

        当然,因为其历史遗留问题,其实际的段描述符数据结构往往相当难看,是为了兼容有关结构体,如下图。 

         段描述符分为类,系统段描述符和代码-数据段描述符(其由S位),其中系统段描述符分为分为六类,存储在LDT或GDT表中。值得注意的是,要区分段描述符与门描述符,门描述存储在IDT表中,门描述符中存储着段选择子,通过段选择子可以从GDT/LDT表中找到段描述符。      

        

段寄存器

        CPU通过段寄存器来管理段描述符,比如我们如果调用汇编指令 "mov [0x1100],eax",其隐含着 "ds:[0x1100]",该ds就是段寄存器。

        段寄存器由两部分组成:可见部分(段选择子)+不可见部分(段描述符)。可以想一下,如果每次内存访问都需要从GDT表中查找对应的段描述符,这速度得多慢啊!!不要忘记,段描述符也在内存中哦,CPU访问自己的寄存器的速度显然比去访问内存的速度快多了!!!

        下面是段选择子的结构,这部分是可见部分,我们可以直接看到的。我们在实体机上没有办法看到不可见部分,唯一的办法就是通过段选择子的偏移从GDT表中查找。

 

代码段寄存器的加载

        现在来看《x86/x64体系探索及编程》的10.5.5.4节 - 代码段寄存器的加载。书中邓志老师是这样描述的:

代码段寄存器的加载非常复杂,这是保护模式下最为复杂的一个环节,不但涉及控制权的转移,也涉及权限的检查,以及stack的切换,某些情况下还涉及任务切换。

        文章所提及的大体内容如下,其中关于"一致代码段"和"非一致代码段"的描述之前还是不太确定,当时做过实验,可是很久了都忘记了...

EX10-1代码解读

         ex10-1就是尝试通过调用tss selector来加载段寄存器(上图加载方式的第三种),我们简单说一下汇编代码,然后主要精力放在分析bochs源码上。   

        其核心流程如下,这里值得区分far pointer的情况,当call 一个数字时,则表示使用tss段来加载cs寄存器。下面代码很简单,我们就不详述tss结构了,可以查阅手册。简单来说,获取tss_base,设置好对应值(重点tss_task_handler);然后将tss段描述符的权限修改为3(允许用户权调用);然后调用retf来返回用户代码段,之后调用call 0x50来使用tss描述符进行任务切换。

// tss段描述符在gdt表索引0x50处.
tss_sel                         equ     0x50

// 初始化tss段内容
        mov esi, tss_sel
        call get_tss_base
        mov DWORD [eax + 32], tss_task_handler          ; ���� EIP ֵΪ tss_task_handler
        mov DWORD [eax + 36], 0                         ; eflags = 0
        mov DWORD [eax + 56], KERNEL_ESP                ; esp
        mov WORD [eax + 76], KERNEL_CS                  ; cs
        mov WORD [eax + 80], KERNEL_SS                  ; ss
        mov WORD [eax + 84], KERNEL_SS                  ; ds
        mov WORD [eax + 72], KERNEL_SS                  ; es

// 修改tss的dpl权限为3,可以从三环调用过去
        mov esi, tss_sel
        call read_gdt_descriptor
        or edx, 0x6000                                  ; TSS desciptor DPL = 3
        mov esi, tss_sel
        call write_gdt_descriptor

// 使用retf指令返回三环
        push DWORD user_data32_sel | 0x3
        push esp
        push DWORD user_code32_sel | 0x3        
        push DWORD user_entry
        retf

// 直接调用tss描述符
    call tss_sel:0 --> call 0x50


tss_task_handler:
        jmp do_tss_task
tmsg1        db '---> now, switch to new Task,', 0        
tmsg2        db 'CPL:', 0
do_tss_task:
        mov esi, tmsg1
        call puts

        ....
        ....

        clts
        iret   

bochs对于call far机制的实现

        我们现在来分析bochs代码是如何处理 call tss_sel的,首先用IDA定位该代码。

        这里存在一个坑!!IDA对这部分反汇编分析不完整,定位不到,这里尝试了各种方法(反汇编,字符串搜索,硬编码搜索...)找了快一个小时才找到。说下思路,首先,定位retf指令,其跳转到用户代码时连续4个push,之后retf,特征比较明显。

        之后对该地址进行反汇编,可以看到这个 call 0x50:0h这个,此时ida还显示标红。然后我们将其硬编码写到x64windbg中看看反汇编情况,并且不支持反汇编。

         定位到0x9119这个地址,之后老方法,定位到该指令的实现代码。

        其首先进入 BX_CPU_C::CALL32_Ap(..) 这个函数,其代码实现如下,值已经在注释中给出,可以看到其调用call_far32(..)这个函数。

void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL32_Ap(bxInstruction_c *i)
{
  BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);

  Bit16u cs_raw = i->Iw2();   // 0x50
  Bit32u disp32 = i->Id();    // 0x00

  call_far32(i, cs_raw, disp32);

  BX_NEXT_TRACE(i);
}

         在call_far32(...)这个函数中,其先判断是否是保护模式,如果是则调用call_protected这个函数,我们跟进这个函数继续来进行分析。

void BX_CPU_C::call_far32(bxInstruction_c *i, Bit16u cs_raw, Bit32u disp32)
{
   
  ...

  if (protected_mode()) {
    call_protected(i, cs_raw, disp32);
  }
  else {
    ....
  }

  ....

  BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL,
                      FAR_BRANCH_PREV_CS, FAR_BRANCH_PREV_RIP,
                      BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
}

         段选择子为50,其索引为 0x50 >> 3 = 0xA,这个使用计算器快速算出。Bochs中一个selector数据结构来描述这个值,如下:

selector	0x0019f3c4 {value=0x0050 index=0x000a ti=0x00 '\0' ...}	const bx_selector_t *
		value	0x0050	unsigned short
		index	0x000a	unsigned short
		ti	0x00 '\0'	unsigned char
		rpl	0x00 '\0'	unsigned char

call_protected(..)函数部分分析

        其call_protected(..)代码关于这章主题的核心部分如下,其中删减了很多与这篇文章无关的知识。其中对于段选择子的解析最重要的是上面三个函数:parse_selector-拆解段选择子,获取上面的那个数据结构;fetch_raw_descriptor 从gdt/ldt表中获取原生的数据结构(存储在dword1,dowrd2中);parse_descriptor(...)来判断这部分函数。

        之后其通过cs_descriptor.segment判断是否是正常的代码段描述符,如果是直接调用barch_far(...),否则其会通过 gate_descirptor.type 来判断门描述符的类型,这里很明显判断出属于TSS任务门描述符。

BX_CPU_C::call_protected(bxInstruction_c *i, Bit16u cs_raw, bx_address disp)
{
   
    ...

  parse_selector(cs_raw, &cs_selector);
  fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
  parse_descriptor(dword1, dword2, &cs_descriptor);


  if (cs_descriptor.segment)   // normal segment
  {
    ....  
      // load code segment descriptor into CS cache
      // load CS with new code segment selector
      // set RPL of CS to CPL
      branch_far(&cs_selector, &cs_descriptor, disp, CPL);
      RSP = temp_rsp;
  }else{
    ....

    switch (gate_descriptor.type) {
      case BX_SYS_SEGMENT_AVAIL_286_TSS:
      case BX_SYS_SEGMENT_AVAIL_386_TSS:
        // SWITCH_TASKS _without_ nesting to TSS
        task_switch(i, &gate_selector, &gate_descriptor,
          BX_TASK_FROM_CALL, dword1, dword2);  <--- 
        return;

       ....
    }
    ...
  }
}

parse_selector(cs_raw, &cs_selector)函数分析

        该函数内容如下,其代码很短,但可以说实现的相当漂亮,使用 > 以及 '&' 运算。说实话之前搞Windows内核也写过类似程序来解析selector,但写的看起来贼难看,也不好记,要学习这种写法。

void parse_selector(Bit16u raw_selector, bx_selector_t *selector)
{
  selector->value = raw_selector;
  selector->index = raw_selector >> 3;
  selector->ti    = (raw_selector >> 2) & 0x01;
  selector->rpl   = raw_selector & 0x03;
}

fetch_raw_descriptor(...)函数分析

        这部分其实一点也不复杂,其通过offset = BX_CPU_THIS_PTR gdtr.base + index*8 来计算出其段描述符所在地址offset;然后调用system_read_qword(offset) 该函数来从内存地址中读取,这个函数我们之后在分页中还会重点分析,现在就不多说了。

        另外可以看到其GET32L与GET32H这两个宏,这种写法是非常值得我们学习的,以后在编写代码时要多多借鉴。

void BX_CPU_C::fetch_raw_descriptor(const bx_selector_t *selector,
                        Bit32u *dword1, Bit32u *dword2, unsigned exception_no)
{
  Bit32u index = selector->index;
  bx_address offset;
  Bit64u raw_descriptor;

  if (selector->ti == 0) { /* GDT */
    if ((index*8 + 7) > BX_CPU_THIS_PTR gdtr.limit) {
      BX_ERROR(("fetch_raw_descriptor: GDT: index (%x) %x > limit (%x)",
         index*8 + 7, index, BX_CPU_THIS_PTR gdtr.limit));
      exception(exception_no, selector->value & 0xfffc);
    }
    offset = BX_CPU_THIS_PTR gdtr.base + index*8;
  }
  else { /* LDT */
      // .... 
  }

  raw_descriptor = system_read_qword(offset);

  *dword1 = GET32L(raw_descriptor);
  *dword2 = GET32H(raw_descriptor);
}

#define GET32L(val64) ((Bit32u)(((Bit64u)(val64)) & 0xFFFFFFFF))
#define GET32H(val64) ((Bit32u)(((Bit64u)(val64)) >> 32))

parse_descriptor(...)函数解析

       这个函数就真正解析描述符了,自己之前也写过类似的,但写的很难看,杂乱无章。一定要来学习这种写法,之后写的话可以参考这份代码。

void parse_descriptor(Bit32u dword1, Bit32u dword2, bx_descriptor_t *temp)
{

  if (temp->segment) { /* data/code segment descriptors */
        ...
        ...
        ...
  }
  else { // system & gate segment descriptors
    switch (temp->type) {
      case BX_286_CALL_GATE:
      case BX_286_INTERRUPT_GATE:
      case BX_286_TRAP_GATE:
         ...
        break;

      case BX_386_CALL_GATE:
      case BX_386_INTERRUPT_GATE:
      case BX_386_TRAP_GATE:
        // param count only used for call gate
        ...
        break;

      case BX_TASK_GATE:
        temp->u.taskgate.tss_selector = dword1 >> 16;
        temp->valid = 1;
        break;

      case BX_SYS_SEGMENT_LDT:
      case BX_SYS_SEGMENT_AVAIL_286_TSS:
      case BX_SYS_SEGMENT_BUSY_286_TSS:
      case BX_SYS_SEGMENT_AVAIL_386_TSS:
      case BX_SYS_SEGMENT_BUSY_386_TSS:
        ...
        break;

      default: // reserved
        temp->valid    = 0;
        break;
    }
  }
}

  task_switch(...)函数分析

        bochs中这部分代码多大800多行,就不详细分析这部分了,感兴趣可以自行解读。其核心代码如下图,其从tss_base地址中读出新的。赋值,然后调用task_switch_load_selector(..)加载段选择子,调用完之后就可以返回

  newEIP    = system_read_dword(Bit32u(nbase32 + 0x20));
  ....

    
  BX_CPU_THIS_PTR prev_rip = EIP = newEIP;

  EAX = newEAX;
  ECX = newECX;
  EDX = newEDX;
  ....

  task_switch_load_selector(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS],
      &ds_selector, raw_ds_selector, cs_selector.rpl);

 总结

        TSS切换在真正的操作系统中并不常用,我记得在Windows中只使用TSS来保存ESP0, EBP0,当进入内核时用来切换进内核栈,这不常用。但是我们在分析这个过程中知道了bochs如何解析加载存储段寄存器的(上面讲的三个函数)以及对于call_far指令大体的解析流程。

         上面是我们这次分析的大体流程,这并不复杂。其中标星的函数之后我们还要重点来分析的函数。下一步我们尝试来分析 retf 与 iret指令的区别,之后继续来阅读《x86/x64体系探索及编程》。

        

PMOS过压保护电路设计与仿真优化策略 本文深入探讨PMOS过压保护电路(OVP)的设计与仿真优化策略,详细解析PMOS管选型、稳压管特性及三极管配置等关键要素。通过Proteus仿真案例揭示典型设计误区,并提供响应速度提升、抗干扰设计等进阶优化方案,助力工程师实现高可靠性的电源保护系统设计。 阅读详情

相关推荐

OpenCV 开闭运算

开运算和闭运算是将腐蚀和膨胀按照一定的次序进行处理。 但这两者并不是可逆的,即先开后闭并不能得到原来的图像。 开运算 开运算是先腐蚀后膨胀,其作用是:分离物体,消除小区域。特点:消除噪点,去除小的干扰块,而不影响原来的图像。 闭运算 闭运算与开运算相反,是先膨胀后腐蚀,作用是消除/“闭合”物体里面的孔洞,特点:可以填充闭合区域。 cv.morphologyEx(img, op, kernel) img: 要处理的图像 op: 处理方式:若进行开运算,则设为cv.MORPH_OPEN,若进行闭

꧁༺ʚvv༒catɞ༻꧂的博客 949

(4) [保护模式]调用门

不一样的call ==> call far call far 使用 调用门 进行提权,观察寄存器和堆栈的变化 使用带参数的调用门,并观察堆栈变化 关键字: 调用门 带参数的调用门

qq_50332504的博客 1454

AS5600磁编码器选型与安装避坑指南:磁铁形状、间隙距离到底怎么选?(附实测数据)

本文详细解析了AS5600磁编码器的选型与安装要点,包括磁铁形状、间隙距离等关键参数的选择,并附有实测数据支持。特别针对Arduino和I2C接口的应用场景,提供了硬件选型和机械安装的实用指南,帮助开发者避免常见陷阱,提升系统精度和稳定性。

weixin_27038245的博客 287

王爽老师汇编语言第四版第十章CALL和RET指令——小白笔记

从这一章开始,开始以小节为单位视频课本结合看,之前都是看完一章视频后再看课本,当然有不足,那就是不知道视频讲的啥,从这一章开始,以每一小节为单位,并且,小节也是结合看,并没有先后之分,希望这样的学习效率更高些。第十章讲的是call和ret 指令,他们修改IP或同时修改IP和CS。经常共同实现子程序设计。

小白垃圾笔记2 813

反激开关电源变压器设计实战:从理论到绕制的完整流程解析

本文详细解析了反激开关电源变压器的完整设计流程,从核心理论到实战绕制。文章以24W电源为例,手把手讲解如何根据输入输出电压、功率和频率等关键参数,计算匝比、峰值电流、电感量,并完成磁芯选择、匝数确定、气隙计算及线径选取。重点阐述了CCM模式下的设计要点与绕制工艺,旨在帮助工程师设计出稳定高效的反激变压器,避免常见陷阱。

weixin_29305313的博客 683

论文阅读—Square Attack: a query-efficient black-box adversarial attack via random search

论文阅读—Square Attack: a query-efficient black-box adversarial attack via random search 发表位置 ECCV 2020 摘要 作者提出了一种基于得分的黑盒Square attack,该模型不依赖于模型的局部梯度信息,因此可以绕过梯度隐藏防御攻击。Square Attack是一种随机搜索方法,它在随机位置选择局部的方形更新,使得每次迭代时扰动近似位于可行集的边界。 背景 当涉及到对安全至关重要的机器学习应用时,对抗性的例子尤其值得

yayayamaomaoya的博客 2492

call指令和ret指令

call标号类似"jmp near ptr 标号”,对应的机器指令中为相对于当前IP的。指令“call far ptr 标号”实现的是段间转移!CPU执行“call far ptr标号”时的操作。,**而不是转移的目的地址,**实现段内转移。CPU执行call指令,进行两步操作∶。"call far ptr标号”相当于。(IP)=标号所在的偏移地址。jmp far ptr 标号。(CS)=标号所在的段地址。字面意思:调用子程序。

picktheshy的博客 508

PCL 中实现平面模型分割【2026最新版】

RANSAC分割平面。博客长期更新,最近一次更新时间为:2026年5月4日。

点云侠的博客 38万+

2019/02/12-16位模式下的Call指令调用

在80x86中有两种指令可以改变程序执行流程,一种是jmp还有一种就是callcall指令由四种调用:两种近调用和两种远调用(1)相对进调用 (2)直接绝对近调用 (3)间接绝对远调用 (4)直接绝对远调用复制代码#######################################...

weixin_33910385的博客 998

智算中心建设项目初步设计方案

本项目面向区级政府、智算中心及文旅从业者,聚焦某区智算中心一期建设,响应数字经济与智慧城市建设政策,推动文旅产业升级。遵循统筹规划、数据驱动原则,目标打造智慧文旅样板。建设内容涵盖云网数据底座(以租代建)、数据中台(全生命周期管理)、智慧文旅平台(含“一机游”电商)及气象监测等配套,采用前后端架构与低代码开发,强化三级等保与纵深防御,实现安全可控。方案融合多类资源目录,提供从设计到运营的完整技术支撑,助力区域智算与文旅深度融合。

cdfunlove的博客 111

MySQL 高可用与集群技术深度解析

高可用性(High Availability,HA)是指系统在较长时间内持续提供服务的能力,通常以系统正常运行时间占总时间的百分比(如 “99.99% 可用性”)来衡量。对于数据库系统而言,高可用性目标是通过冗余设计、故障自动检测与恢复、负载均衡等技术手段,最大限度地减少因硬件故障、软件错误、网络问题等导致的服务中断,确保数据的高可靠性和业务的连续性。

加入“Super Entity”,与全能开发团队共探AI智能体与数字人项目,开启前沿技术之旅。 1501

call、ret、retf 指令详解

call、ret、retf指令详解本文讲解针对NASM编译器,8086处理器的call、ret、retf 指令。对于其他编译器和保护模式下的80x86,指令用法类似,可以作为参考。

车子(chezi) 2万+

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Call far ptr指令执行时,依次压入堆栈内容

该指令执行时,依次会向堆栈压入:标志寄存器,CS和IP 为什么要压入标志寄存器? call指令虽然不涉及标志寄存器。但是call指令的本质,它是一条跳转指令,目的是跳到子程序去执行,而子程序是可以改变标志的。 因此需要把标志寄存器也压入堆栈。 ...

Artorias的博客 2612

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

汇编语言 第十章-Call 和 Ret 指令

retf指令用栈中的数据,修改CS和IP的内容,从而实现远转移;CPU执行retf指令时,进行下面两步操作:也就是说,他将栈顶的数据当做cs和ippop IPpop CS案例分析stack endsint 21hstart:mov ss,axmov sp,16mov ax,0push cspush axmov bx,0retfend start这里也是一样,将cs,0分别推进栈顶,然后调用retf指令,分别赋值给cs和ip,最后执行程序结束指令。

2302_80490510的博客 1395

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

汇编语言--call 指令

call指令经常跟ret指令配合使用,因此CPU执行call指令,进行两步操作: 将当前的 IP 或 CS和IP 压入栈中; 转移(jmp)。 call指令不能实现短转移,除此之外,call指令实现转移的方法和 jmp 指令的原理相同。 call 标号(近转移) CPU执行此种格式的call指令时,相当于进行 push IP jmp near ptr 标号 call far ptr 标号(段间转移)...

2万+

call指令和ret指令【笔记+详解】

call指令是一个流程转移指令,就是让程序执行的顺序发生短暂的改变,去执行别处地址上的指令,遇到ret指令后再回到原来的地方继续往下顺序执行,本质和jmp大同小异,区别是在jmp基础上增加了程序回到原来跳转处的功能......

一只喜欢code的fox 2万+

【汇编要笑着学】第一个程序 | bochs使用 | mov指令 | 运算指令add和sub

这是因为bios会自动从硬盘的第一个扇区(一个扇区512字节)载入引导程序。我们首先使用nasm来编译这段汇编。没事,我们数一数,可以发现不多不少,这个程序刚好512字节。准确的说是0x7c000,因为这里的真实地址要偏移四位。这样bios就知道这是一个没有问题的扇区,不然就会。这段代码会点英文应该就看得出作用,具体的我就不讲了。我也不知道,这个是intel工程师们写死的。不爽的自己去找intel的工程师,别找我。我们打开一下看看这个编译好的二进制文件。这一切都得益于上面这行代码。我们先来运行这段代码。

m0_73552311的博客 1125

操作系统原理与实践1

文章目录1、熟悉实验环境实验环境的工作模式编译内核运行调试(1)汇编级调试(2)C 语言级调试文件交换2、操作系统的引导3、系统调用4、进程运行轨迹的跟踪与统计5、基于内核栈切换的进程切换6、信号量的实现和应用7、地址映射与共享8、终端设备的控制9、proc文件系统的实现 1、熟悉实验环境 1、Bochs 是一个免费且开放源代码的 IA-32(x86)架构 PC 机模拟器。 因为 Bochs 的是模拟器,其原理决定了它的运行效率会低于虚拟机。 但是,Bochs 有虚拟机无可比拟的调试操作系统的能力 2、

weixin_42715287的博客 887

09-长调用与短调用

要点回顾: 我们通过JMP FAR可以实现段间的跳转,如果要实现跨段的调用就必须要 学习CALL FAR,也就是长调用. CALL FAR 比JMP FAR要复杂,JMP并不影响堆栈,但CALL指令会影响. 1、短调用 指令格式:CALL 立即数/寄存器/内存 发生改变的寄存器:ESP EIP 2、长调用(跨段不提权) 指令格式:CALL CS:EIP(EIP是废弃的) 发生改变的寄存器:ESP EIP CS 3、长调用(跨段并提权) 指令格式:CALL CS:EIP(EIP是废弃的)

啊哈的博客 898

call 指令调用方式

这篇文章中,我们介绍了 call 指令的几种调用方式,举出具体代码示例说明其使用方式,并查看了相应机器码。然后通过反汇编或者直接查看机器码的方式,进一步验证了原理与实际指令布局的契合。原文链接:https://www.jianshu.com/p/55726f7e355a。

zxf347085420的博客 2768

【2021.03.19】长调用与短调用

要点回顾 通过前文知道JMP FAR可以实现段间跳转,如果要实现跨段的调用就必须要学习CALL FAR,也就是长调用。 CALL FAR 比 JMP FAR 要复杂,JMP并不影响堆栈,而CALL指令会影响。 短调用 指令格式:CALL 立即数/寄存器/内存 发生改变的寄存器:ESP、EIP 长调用(跨段不提权) 指令格式:CALL CS:EIP(EIP是废弃的) 并不使用后面的EIP,EIP是被废弃的。 主要是CS段寄存器中的段选择子,通过段选择子去查询GDT表找一个段描述符,且该段

oalken的博客 1118

中断门、陷阱门、任务段、任务门

中断门描述符 中断门概述 1.系统调用 Windows没有使用调用门,但是使用了中断门。 Windows很多3环API最终都要使用0环的代码,是使用中断门实现的这种功能。 注意:老的CPU是用的中断门而最新的CPU是使用的快速调用。 2.调试 在像OD这种调试工具中按F12下的断点就是将BYTE内容变为0xCC指令位int3这是中断门效果。 中断门和调用门的区别 中断门和调用门很相似他们最大的区别是查表的不同, 调用门是使用的GDT表而中断门使用的是IDT表。 IDT表概述 IDT全名中断描述符表,

网络安全相关文章分享 5426

7.跨段跳转,短调用和长调用堆栈图

一、回顾 上一节,我们学习了 JMP FAR 实现段间跳转,该指令修改了 CS 和 EIP。本节我们学习长调用 CALL FAR,该指令除了修改 CS和EIP,还会修改堆栈。 二、CALL 堆栈图 学习长调用之前,不妨先回顾一下短调用CALL的堆栈图: 三、长调用 CALL FAR 和 RETF 一般是成对的,RETF 的执行流程(权限控制)和 CALL FAR 是一样的 CALL FAR 不提权 3环跳转到另一个3环代码段,不会切换堆栈。 CALL FAR 提权 从3环跳转到0环,此

qq_35129925的博客 367

(7) [保护模式]任务段 (TSS)

TR寄存器 任务段描述符 TSS 文中有call far 和 jmp far使用TSS段描述符,调用后如何return。 写得很简陋,仅供参考

qq_50332504的博客 3136

4.4 call far ptr和retf指令,本质是栈、goto指令

CPU执行call指令时,进行两部操作。CPU执行retf指令时,相当于进行。CPU执行ret指令时,相当于进行。

2203_75300307的博客 561
上一篇: Bochs源码分析 - 14:bochs关于实地址模式下IVT表的管理
下一篇: Bochs源码分析 - 16:conforming与non-conforming代码段区别以及Bochs代码的实现
WriteAnything_
博客等级 码龄5年 66粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值