【问题标题】:osx - write and exec on allocated memory pageosx - 在分配的内存页面上写入和执行
【发布时间】:2015-09-11 08:15:09
【问题描述】:

我遇到了关于 OS X 上的内存映射的问题。

我正在使用mmap 调用来映射特定函数附近的内存区域。这个想法是稍后jmp 使用相对跳转到这个分配的内存区域。代码:

void *alloc;
if((alloc = mmap((void*)func, 12, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0)) == MAP_FAILED)
        printf("failed\n");

暂时没有问题。内存在func 附近被映射,通过避免使用MAP_FIXED 标志,内核将其放置在附近的位置。

然后我简单地用E9操作码(jmp)+相对偏移量制作一个shellcode,通过减去函数(func)地址和分配区域(alloc)地址来计算。

char jmp32[] = {
     '\xE9', '\x00', '\x00', '\x00', '\x00'
};

int *offset = malloc(4);
*offset = (int)(alloc-func);

memcpy(jmp32+1, offset, 4);

shellcode 制作精良,可以放入内存中。

vm_protect(mach_task_self(), (vm_address_t)func, 16, 0, VM_PROT_ALL); //make function area writable

memcpy(func, jmp32, sizeof(jmp32)); // place the jmp

现在,一切似乎都很好,但是当我执行程序时(显然是调用func):

(lldb) r
Process 3563 launched: './mempool' (x86_64) // don't mind the name, was using an old Xcode project
ffffffe9 //
60       //
43       // output there, as you can see, the shellcode is crafted fine!
03       //
00       //
Process 3563 stopped
* thread #1: tid = 0x15f3e, 0x0000000100035fff, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x100036000)
    frame #0: 0x0000000100035fff

所以,进一步调查:

(lldb) d -F intel -n test
mempool`test at main.c:97:
   0x100000ca0:  or     dword ptr [rax + 0x43], esp  //OR?!?
   0x100000ca3:  add    eax, dword ptr [rax]
   0x100000ca5:  sub    esp, 0x10
   0x100000ca8:  lea    rdi, qword ptr [rip + 0x2c3] ; "culo here: %p\n"
   0x100000caf:  lea    rax, qword ptr [rip - 0x16] ; test at main.c:97
   0x100000cb6:  mov    rsi, rax
   0x100000cb9:  mov    al, 0x0
   0x100000cbb:  call   0x100000ee4               ; symbol stub for: printf
   0x100000cc0:  mov    dword ptr [rbp - 0x4], eax
   0x100000cc3:  add    rsp, 0x10
   0x100000cc7:  pop    rbp
   0x100000cc8:  ret  

指令在函数的开头,但它是OR。不是JMP。更深入:

(lldb) mem read 0x100000ca0
0x100000ca0: 09 60 43 03 00 83 ec 10 48 8d 3d c3 02 00 00 48  .`C...?.H.=?...H
0x100000cb0: 8d 05 ea ff ff ff 48 89 c6 b0 00 e8 24 02 00 00  ..????H.ư.?$...

我们实际上可以看到E9,也就是JMP 操作码被破坏为09 操作码,它代表OR 指令。

我得到了各种结果,但E9 操作码总是被修改。我必须假设这是我前段时间读到的 W^X 内存保护机制,对吧?另外,你猜怎么着,删除mmap 调用中的PROT_EXEC 标志会使操作码保持原样。

我真的不知道有没有办法解决这个问题,但我认为有,因为mach_override 完全符合我的要求,而且从我在代码中看到的一点点来看,它使用内存分配在记忆中跳跃。我将进一步阅读代码,并尝试了解如何执行此操作,但我很想听到这里有人给出一个很好的解释!具体来说:

  1. 这是 W^X 功能吗?
  2. 是否有任何解决方法?
  3. 如果不是,mach_override 怎么办?

抱歉,帖子太长了,但我想清除所有内容。感谢任何可以帮助我的人!

【问题讨论】:

    标签: c macos memory


    【解决方案1】:

    所以经过几个小时的代码阅读,我解决了它。正如我所料,答案在mach_override 代码中。它使用了这段代码:

    jumpRelativeInstruction |= 0xE900000000000000LL;
    jumpRelativeInstruction |= ((uint64_t)offset & 0xffffffff) << 24;
    jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);
    

    手动制作JMP 指令,准备好放入内存中,并具有正确的字节顺序和所有内容。它完全避免了可能执行检查的内存写入函数,例如memsetmemcpy。然后,它最终使用指针解引用将其写入内存:

    *originalFunctionPtr = jumpRelativeInstruction;
    

    这会溢出到下一个函数操作码,覆盖它们。

    因此,通过调整代码,我能够将其放入我的代码中,最后将JMP 放入分配的区域!

    (lldb) r
    Process 869 launched: './mempool' (x86_64)
    alloc: 0x100035000
    func: 0x100000bf0
    hooked!
    Process 869 exited with status = 0 (0x00000000) 
    

    【讨论】:

      猜你喜欢
      • 2011-12-05
      • 2016-11-24
      • 2015-04-16
      • 2019-02-07
      • 1970-01-01
      • 1970-01-01
      • 2015-09-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多