您是否可以输入x64 32位“长兼容性子模式"?在内核模式之外? [英] Can you enter x64 32-bit "long compatibility sub-mode" outside of kernel mode?

查看:117
本文介绍了您是否可以输入x64 32位“长兼容性子模式"?在内核模式之外?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这可能与完全相同 ,是否可以通过模式切换在64位进程中执行32位代码?,但是这个问题是一年前的,并且只有一个答案,没有给出任何源代码.我希望得到更详细的答案.

This might be an exact duplicate of Is it possible to execute 32-bit code in 64-bit process by doing mode-switching?, but that question is from a year ago and only has one answer that doesn't give any source code. I'm hoping for more detailed answers.

我正在运行64位Linux(如果需要的话,请使用Ubuntu 12.04).这是一些分配页面的代码,将一些64位代码写入其中,然后执行该代码.

I'm running 64-bit Linux (Ubuntu 12.04, if it matters). Here's some code that allocates a page, writes some 64-bit code into it, and executes that code.

#include <assert.h>
#include <malloc.h>
#include <stdio.h>
#include <sys/mman.h>  // mprotect
#include <unistd.h>  // sysconf

unsigned char test_function[] = { 0xC3 };  // RET
int main()
{
    int pagesize = sysconf(_SC_PAGE_SIZE);
    unsigned char *buffer = memalign(pagesize, pagesize);
    void (*func)() = (void (*)())buffer;

    memcpy(buffer, test_function, sizeof test_function);

    // func();  // will segfault 
    mprotect(buffer, pagesize, PROT_EXEC);
    func();  // works fine
}

现在,纯粹出于娱乐目的,我想做同样的事情,但是buffer包含任意32位(ia32)代码而不是64位代码. 此页面表示您可以执行32通过将CS段描述符的位设置为LMA=1, L=0, D=1,进入长兼容性子模式",从而在64位处理器上执行位代码.我愿意将我的32位代码包装在执行此设置的序言/结尾中.

Now, purely for entertainment value, I'd like to do the same thing but with buffer containing arbitrary 32-bit (ia32) code, instead of 64-bit code. This page implies that you can execute 32-bit code on a 64-bit processor by entering "long compatibility sub-mode", by setting the bits of the CS segment descriptor as LMA=1, L=0, D=1. I am willing to wrap my 32-bit code in a prologue/epilogue that performs this setup.

但是可以我可以在Linux上的用户模式下进行此设置吗? (也将接受BSD/达尔文的答案.)这就是我开始对这些概念感到迷惑的地方.我认为解决方案包括向GDT添加新的段描述符(或者是LDT?),然后通过lcall指令切换到该段.但是可以在用户模式下完成所有操作吗?

But can I do this setup, in Linux, in usermode? (BSD/Darwin answers will also be accepted.) This is where I start to get really hazy on the concepts. I think the solution involves adding a new segment descriptor to the GDT (or is it the LDT?), and then switching to that segment via an lcall instruction. But can all that be done in usermode?

这里是一个示例函数,当在兼容性子模式下成功运行时,应返回4,而在长模式下运行时应返回8.我的目标是使指令指针采用此代码路径,并与%rax=4相对,而不会陷入内核模式(或仅通过记录的系统调用来这样做).

Here's a sample function that should return 4 when successfully run in compatibility sub-mode, and 8 when run in long mode. My goal is to get the instruction pointer to take this codepath and come out the other side with %rax=4, without ever dropping into kernel mode (or doing so only via documented system calls).

unsigned char behave_differently_depending_on_processor_mode[] = {
    0x89, 0xE0,  // movl %esp, %eax
    0x56,        // push %{e,r}si
    0x29, 0xE0,  // subl %esp, %eax
    0x5E,        // pop %{e,r}si
    0xC3         // ret
};

推荐答案

是的,可以.使用完全支持的接口甚至可以实现.使用Modify_ldt将32位代码段安装到LDT中,然后设置指向您的32位代码的远指针,然后使用AT& T表示法中的ljumpl *(%eax)间接跳转到它.

Yes, you can. It's even doable using fully supported interfaces. Use modify_ldt to install a 32-bit code segment into the LDT, then set up a far pointer to your 32-bit code, then do an indirect jump to it using ljumpl *(%eax) in AT&T notation.

尽管如此,您将面临各种困难.您的堆栈指针的高位可能会被破坏.如果您确实想运行真实代码,则可能需要一个数据段.而且您还需要跳远一步才能回到64位模式.

You'll face all kinds of snafus, though. The high bits of your stack pointer are likely to get destroyed. You probably need a data segment if you actually want to run real code. And you'll need to do another far jump to get back to 64-bit mode.

一个完全可行的示例在我的test_vsyscall.cc中的="nofollow noreferrer"> linux-clock-tests . (在任何已发布的内核上都有点中断:int cc将会崩溃.您应该将其更改为其他更巧妙的名称,例如"nop".请查看intcc32.

A fully worked-out example is in my linux-clock-tests in test_vsyscall.cc. (It's a little broken on any released kernel: int cc will crash. You should change that to something else more clever, like "nop". Look in intcc32.

这篇关于您是否可以输入x64 32位“长兼容性子模式"?在内核模式之外?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆