如何从数据缓冲区执行x86命令?

Iva*_*ars 7 c++ x86 module

我的问题主要是专注于教授,并且是以"奇怪"的方式使用C++.在C++中,指向变量的指针和指向函数的指针之间没有太大区别.我们可以做一些像这样无用的事情:

char* buff     = new char[32];
void (*func)() = (void (*)())buff;
Run Code Online (Sandbox Code Playgroud)

但我们几乎创造了一个从未存在的功能,对吗?如果我们进一步用文件中的x86命令stord填充buff怎么办?操作系统永远不会知道创建了一个函数.

#include <iostream>
using namespace std;

// no stack push'ing or pop'ing, nothing to return
void func(void){cout << "Hello?";}

int main()
{
  char* x86_code = new char[6];

  x86_code[0]                 = 0x9A;          // call (far)
  *((__int32*)(x86_code + 1)) = (__int32)func; // load 32-bit address
  x86_code[5]                 = 0xC3;          // ret

  void (*x86_func)(void) = (void (*)(void))x86_code;
  x86_func();

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

调用x86_func()会产生运行时错误(违反读取位置0xFFFFFFFF).如果不是这样,操作系统如何在RAM中加载它的二进制文件或模块?非常感谢.

Iwi*_*ist 4

事实上,您可以用 x86 机器代码填充数组并尝试执行它。它被称为shellcode,设法让应用程序或库在不打算执行的情况下执行此类代码被称为“漏洞利用”。

不幸的是,这并不容易,因为现代硬件和操作系统通常会阻止您从可写区域(例如非常量字符数组)执行代码。这称为 W^X(写入或执行权限,但不能同时执行两者),但可以请求 POSIX 兼容操作系统使用该mprotect()功能禁用此类保护。这是一个有效的示例,因为它启用了对相关机器代码字节数组的读、写和执行权限:

#include <stdio.h>
#include <stdint.h>
#include <sys/mman.h>


typedef int(*FUNKY_POINTER)(void);


char shellcode[] = {
    0xb8, 0x2a, 0x00, 0x00, 0x00, //mov    $0x2a,%eax
    0xc3                          //retq
};



int main(void){
    uintptr_t pageSize        = 4096;
    uintptr_t shellcodeAddr   = (uintptr_t)shellcode;
    uintptr_t pageAlignedAddr = shellcodeAddr & ~(pageSize-1);
    FUNKY_POINTER shellcodeFn = (FUNKY_POINTER)shellcode;

    /* Magic */
    mprotect((void*)pageAlignedAddr,
             (shellcodeAddr - pageAlignedAddr) + sizeof(shellcode),
             PROT_EXEC|PROT_WRITE|PROT_READ);

    printf("The answer to the ultimate question of life, "
           "the universe and everything is %d\n",
           shellcodeFn());

    return 0;
}
Run Code Online (Sandbox Code Playgroud)