我正在尝试在64位linux进程中运行32位代码。 32位代码是完全独立的,它直接进行IA32系统调用。 如果我要在32位进程中加载此代码,它将运行得很好。
最初,我以为我可以为32位代码分配一个堆栈,切换到它,一切都可以正常工作,但这并没有那么好。 主要是因为与堆栈相关的指令(POP / PUSH / …)正在执行8字节的移位而不是4个字节。
通过googling,我了解到,我可以通过切换到段select器0x23转换到32位模式。 不幸的是,细分是我所知甚less的。
我可以用这样的东西(内联AT&T汇编)转换到32位模式:
在linux上混合syscall写与printf
我如何调用一个函数,它需要几个int整数?
有没有什么办法来分析x86程序集源代码中的“注册types”?
linux内核中的UD2 *** 作码的目的是什么?
mprotect()作为ASM系统调用的用法与第三个参数有什么不同?
movl $0x23,4(%%rsp) // segment selector 0x23 movq %0,%%rax movl %%eax,(%%rsp) // target 32-bit address to jump to lret
其中%0包含代码映射位置的32位地址。 代码开始运行,我可以看到PUSH / POP现在按照它应该的方式工作,但是它比在64位模式下运行代码时看起来无害的指令更早崩溃:
0x8fe48201 mov 0xa483c(%rbx),%ecx
其中%rbx (或者更像是%ebx因为这个代码已经是32位,GDB只是不知道)包含0x8fe48200 。 它试图读取的地址( 0x8feeca3c )是有效的和可读的(根据/proc/XXX/maps ),当我从GDB中读取它时,它包含期望值。
然而,linux在这条指令上向进程发送一个SIGSEGV ,错误地址为0 (由gdb strace或p $_siginfo._sifIElds._sigfault.si_addr报告)。 不知何故,似乎0x8feeca3c不是在32位领域的有效地址。
任何想法如何进行?
更新:我写了一个最小的例子,segfaults读取地址0,虽然地址0是不是真的被引用。 看来读取内存中的任何地址都失败了(即使读取刚执行的指令的地址!),尽pipe堆栈 *** 作正常。
#include <sys/mman.h> #include <string.h> #include <stdio.h> #include <stdint.h> // 32-bit code we're executing const unsigned char instructions[] = { 0x6a,// push 0 0x58,// popl %eax 0xe8,// call the next line to get our location in memory 0x5b,// pop %ebx // THE FolLOWING mov SEGFAulTS,but it is well within the mapped area (which has size 0x3000) // A simpler "mov (%ebx),%eax" (0x8b,0x03) would fail as well 0x8b,0x83,0x20,// mov 0x2000(%ebx),%eax 0xf4 // hlt,not reached }; int main() { voID* area; voID* stack; area = mmap(NulL,3*4096,PROT_WRITE|PROT_READ|PROT_EXEC,MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT,-1,0); memcpy(area,instructions,sizeof(instructions)); stack = mmap(NulL,4096,PROT_READ|PROT_WRITE,0); stack = (voID*) (((uint64_t) stack) + 4096 - 4); memset(((char*)area) + 2*4096,0xab,100); // Place 0xAB in the area we mov from in 32-bit instructions // Switch to 32-bit mode and jump into the code __asm__ volatile("movq %1,%%rsp;" "subq $8,%%rsp;" "movl $0x23,4(%%rsp);" "movq %0,%%rax;" "movl %%eax,(%%rsp);" "lret" :: "m"(area),"r"(stack) :); }
windows汇编语言编程
从C的议论到议会
编译器使用本地variables而不调整RSP
如何在汇编程序中打开文件并进行修改?
在libc.a中了解简单的linux系统调用
很好的问题:)
问题是, ds仍然被设置为零,在64位模式下它没有被使用。 所以,你需要重新加载,它会工作。 改变你的初始测试推/d出push $0x2b; pop %ds push $0x2b; pop %ds将做的伎俩:
const unsigned char instructions[] = { 0x6a,0x2b,// push $0x2b 0x1f,// pop %ds
我从32位程序中提取0x2b值。 我只是不知道为什么push工作。 仔细一看, ss也设置为64位模式,因此将其复制到ds以及es可能更安全。
总结以上是内存溢出为你收集整理的在Linux上以64位进程运行32位代码 – 内存访问全部内容,希望文章能够帮你解决在Linux上以64位进程运行32位代码 – 内存访问所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)