近及远的JMP(Near and Far JMPs)

2019-08-16 21:32发布

我在做Linux的组装和我的理解就是有一个平面内存模式。 我感到困惑的是近及远的JMP。

NEAR是在同一个网段,而FAR是另一部分。 从我的理解有在Linux虚拟内存无段? 另外我们怎么知道,如果我的程序代码在多段布局?

Answer 1:

它一直不是很长的时间段了。 在保护模式下的x86正确的说法是选择。

话虽如此,近跳,远之间的区别在于,前者保持相同的代码选择cs而后者(通常)改变它。

在平面内存模式,在前一种情况下几乎总是它是如何做。

可以有一个操作系统,其中平面内存模式是由多个选择服务,但我看不到一个有用的使用情况吧,这不是Linux下正常工作,至少在x86的方式。



Answer 2:

NEAR是在同一个网段,而FAR是另一部分。

一种近跳跳转到当前代码段(由指向内的一个位置cs )。 一种远跳通常用于不同的代码段内跳转到一个位置,但是它可以在当前段内跳转到一个位置,以及,如果在远地址的段选择与所述值一致cs

从我的理解有在Linux虚拟内存无段?

我也不会惊讶地发现,使用某种分段存储器的Linux到CPU中。 所以,我会说这要看情况。 你不太可能看到在x86平台上的Linux使用段,虽然。 但同样,你或其他人可以做一个小的Linux运行在实模式和使用段。

另外我们怎么知道,如果我的程序代码在多段布局?

您检查CPU和OS。 当然,如果你编写可移植的C代码,这应该是不关心你的。



Answer 3:

从我的理解有在Linux虚拟内存无段?

这是不够准确。 有与由指向的位置线程特定数据 %fs的基础上 ,但不存在适合于远跳段。

另外我们怎么知道,如果我的程序代码在多段布局?

如果你的目标平台是Linux,你已经知道事实并非如此。 (我会感到惊讶,如果任何现代操作系统仍然采用分段的方式,这使得jump far意义)。



Answer 4:

在现代主流操作系统,如Linux使用平面内存模式使分割大多是已经过时了,(幸好)你需要担心的不是。

之前的页表支持NX位来标记页面为不可执行,有关于使用部分限制,以避免重写存储器(尤其是栈)的执行,使得缓冲区溢出攻击的不仅仅是返回到的shellcode的缓冲区更难一些工作。 如Exec的盾(LWN文章)从2003年。

我忘了这是如何实际工作,我认为这是大多只是设置在CS段限制受排斥的堆栈,不使用远JMP一个新的段描述符的每个代码块(主要可执行+每个动态库)。

不过幸运的是现代的x86可以使用与NX位现代页表(PAE或x86-64的),这意味着用户空间可有正常的单页读取和写入权限(与执行权限设置相同的方式mmapmprotect ,并ELF元数据的程序等堆栈中的初始部分,R / W数据,并且文本+只读数据)。 或者非Linux,其等效系统调用,当然还有元数据。

但是,如果操作系统是Linux和在保护模式+平面内存模式已经在运行,那么我们永远都需要远的JMP?

不,你永远不要需要一个far jmp在Linux用户空间或内核模式,这将是一个糟糕的主意,使一个。

你可能会倾向于使用远jmp ptr16:32编码直接跳转到一个绝对地址(用新的CS值是硬编码为相同的CS值的Linux已知使用32位用户空间) 。 但是,这比正常慢附近有很多jmp rel32 ,它可以从任何其他的32位地址到达任何32位地址。 (直接跳转附近是仅适用于相对位移,而不是绝对的目标,你需要一个近跳转到一个绝对地址间接跳转,如果你不知道自己的地址来计算的相对位移)。

这不是在64位模式下,即使一个选项,那里没有jmp far 80-bit immediate ptr16:64编码,只读存储器间接。 所以,你会用mov rax, imm64 / jmp rax像一个正常的人,如果跳转目标是太远了rel32编码。


在Linux所有用户空间进程使用相同的32位或64位CS段选择(与当前特权级别CPL = 3 =环3用户模式),和内核使用的不同的一个(CPL = 0 = 0环内核模式)。

CS对现代操作系统的x86的唯一目的是选择32与64位模式( .L在GDT条目位),和权限级别。

你只能通过中断/异常和类似的指示用户和内核CS之间切换intsysentersyscall进入内核模式,和iret恢复cs:eipcs:rip从内核栈,或sysexit (32位内核)或sysret从系统调用优化返回用户空间。 摆在首位(与进入保护模式后jmp far ),内核不会jmp far改变CS。


除非你想做傻不稳定,电脑花样像在开始为64位的过程转变为32位模式,我们有理由零到jmp far Linux下

可能的,但我不知道它实际上是稳定的。 例如,内核可能还记得,你的过程应该是64位,并在64位模式下的中断返回。 (即异步集CS中的硬编码USER32_CS不变的,而不是恢复旧值。)IIRC,它不这样的syscall使用返回路径sysret ,看看如果你使用32位的int 0x80的Linux的ABI中,会发生什么64位代码?

你想这样做呢? 你不可以。 有从不同的是用汇编任何工具链这样做零支持BITS 32BITS 64指令,基本为零的利益,和崩溃(你的过程,而不是机器)的大的风险。 任何你可以做手写ASM在32位模式下,你可以在64位模式下使用与分配的32位指针事情做的很好mmap(MAP_32BIT)或使用X32 ABI。

我想也许对原核2(其中,CMP / JCC宏融合仅工作在32位模式下),有可能是一个PERF的优点到运行在32位模式下的循环,并仅使用64位模式用于接触大量的存储器,但基本上转换成本管道齐平,从而它通常更便宜刚刚展开,而不是切换到32位模式并返回到64,用于特定的长时间运行循环位。



Answer 5:

远近控制转移指令主要是控制传输协议通常情况下,我们看到的节目由线从上按顺序执行线下有时有必要从一个位置控制权转移到其他近 - 如果你想控制转移到当前代码段则称为NEAR(帧内段)如果控件的当前代码段则称为FAR跳FAR因为控制是使所述当前代码段都CS(代码段以外外部传递内的存储器位置)和IP(指令指针)已进行更新,以新的价值观



文章来源: Near and Far JMPs