Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在数据区域中执行代码需要做什么(段保护)_C++_C_Assembly_Linux Kernel - Fatal编程技术网

C++ 在数据区域中执行代码需要做什么(段保护)

C++ 在数据区域中执行代码需要做什么(段保护),c++,c,assembly,linux-kernel,C++,C,Assembly,Linux Kernel,我在linux平台上工作,使用g++编写上述程序,将函数从代码区复制到数据区。如何更改数据段的保护以允许我执行复制的功能 代码如下: #include <stdio.h> #include <stdint.h> #include <string.h> #define Return asm volatile("pop %rbp; retq; retq; retq; retq; retq;") int64_t funcEnd=0xc35dc3c3c3c3c35d

我在linux平台上工作,使用g++编写上述程序,将函数从代码区复制到数据区。如何更改数据段的保护以允许我执行复制的功能

代码如下:

#include <stdio.h>
#include <stdint.h>
#include <string.h>

#define Return asm volatile("pop %rbp; retq; retq; retq; retq; retq;")
int64_t funcEnd=0xc35dc3c3c3c3c35d;
constexpr int maxCode=0x800;
int8_t code[maxCode];

void testCode(void){
    int a=8,b=7;
    a+=b*a;
    Return;
}

typedef void (*action)(void);

int main(int argc, char **argv)
{
    action a=&testCode;
    testCode();

    int8_t *p0=(int8_t*)a,*p=p0,*p1=p0+maxCode;
    for(;p!=p1;p++)
        if ( (*(int64_t*)p)==funcEnd ) break;

    if(p!=p1){
            p+=sizeof(int64_t);
            printf("found\n");
        memcpy(&code,(void*)a,p-(int8_t*)a);
        ((action)&code)();
    }

  printf("returning 0\n");
    return 0;

}
#包括
#包括
#包括
#定义返回asm volatile(“pop%rbp;retq;retq;retq;retq;retq;”)
int64_t funcEnd=0xC35DC3C35D;
constexpr int maxCode=0x800;
int8_t代码[maxCode];
void测试代码(void){
INTA=8,b=7;
a+=b*a;
返回;
}
类型定义无效(*行动)(无效);
int main(int argc,字符**argv)
{
动作a=&testCode;
testCode();
int8_t*p0=(int8_t*)a,*p=p0,*p1=p0+maxCode;
对于(;p!=p1;p++)
如果(*(int64_t*)p)=funcEnd)中断;
如果(p!=p1){
p+=sizeof(int64_t);
printf(“找到的”\n);
memcpy(&code,(void*)a,p-(int8_*)a);
((行动)及守则)();
}
printf(“返回0\n”);
返回0;
}

这取决于您是在静态(构建时)还是在动态(运行时)执行此操作

构建时间 您需要告诉GCC将blob放在可执行的部分中。我们使用
\uuuuuuuuuuuuuuu属性((section))
,并在创建节时指定节的属性

运行时 TL;DR:跳到我的答案的末尾,在那里我使用
mmap

尽管其他人可能会质疑为什么您希望在运行时允许这样的操作,但请记住,这正是带有JIT编译器的VM(例如Java VM、.NET CLR等)在发出本机代码时所做的

您需要更改尝试执行的内存的内存保护。我们通过
mprotect(addr,PROT\u EXEC)
来实现这一点。请注意,
addr
必须与平台的页面大小对齐。在x86上,页面大小为4K。我们用它来保证这种一致性

(两者的)示例: SELinux冲击 请注意,这会将可执行代码放在堆上,这可能有点危险。CentOS 7机器上的SELinux实际上拒绝了
mprotect
呼叫:

SELinux正在阻止/home/jreinhart/so/a.out对进程使用execheap访问。
*****插件允许执行堆(53.1置信度)建议********************
如果您不认为/home/jreinhart/so/a.out应该需要映射可写和可执行的堆内存。
然后你需要报告一个bug。这是一个潜在的危险通道。
因此,我必须临时
sudo setEnforced 0
,才能让它正常工作

但是,我不知道为什么,因为查看
/proc/[pid]/maps
,页面清楚地标记为仅可执行,而不是SELinux指出的“可写和可执行”。如果我将
memcpy
移动到
mprotect
之后,我的进程就会出错,因为我正试图写入不可写内存。所以看来SELinux有点过于热心了

改用
mmap
mprotect
ing堆的一个区域(使用
aligned\u alloc
分配)不同,使用
mmap
更简单。这也避免了SELinux的任何问题,因为我们不尝试在堆上执行

#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>   /* mmap() */

static uint8_t code[] = { 
    0xB8,0x2A,0x00,0x00,0x00,   /* mov  eax,0x2a    */
    0xC3,                       /* ret              */
};

int main(void)
{
    void *p = mmap(NULL, sizeof(code), PROT_READ|PROT_WRITE|PROT_EXEC,
            MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 
    if (p==MAP_FAILED) {
        fprintf(stderr, "mmap() failed\n");
        return 2;
    }   
    memcpy(p, code, sizeof(code));

    int (*func)(void) = p;
    printf("(dynamic) code returned %d\n", func());

    pause();
    return 0;
}

你需要<代码> McReule>代码>。我需要导入C++中用其他语言编译的函数作为数据。我在哪里找到McPuthman McEnter(它显示出来)C或C++?选择一个。我会选择
mmap
,因为在我看来,它是上述解决方案中最不“黑客”和可移植的。@tangrs我完全同意。使用
mmap
mprotect
正确管理您的页面权限是一件明智的事情。@JonathonReinhart我刚刚阅读了非常详细的评论。谢谢与此同时,我已经到达mmap并做了一些检查,但在执行时能够分配内存和复制,我得到了段错误。我会检查你的代码,必要时再回来。@JonathonReinhart它工作了,但没有在代码中使用“printf”。如果我使用对“printf”的调用,则调用的addres会被损坏,因此必须执行一些不同的操作。@user3723779请注意,
调用
指令分支到一个相对地址。也就是说,
调用
指令中的立即数告诉CPU要跳转多少字节(来自下一条指令)<代码>EIP
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>   /* mmap() */

static uint8_t code[] = { 
    0xB8,0x2A,0x00,0x00,0x00,   /* mov  eax,0x2a    */
    0xC3,                       /* ret              */
};

int main(void)
{
    void *p = mmap(NULL, sizeof(code), PROT_READ|PROT_WRITE|PROT_EXEC,
            MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 
    if (p==MAP_FAILED) {
        fprintf(stderr, "mmap() failed\n");
        return 2;
    }   
    memcpy(p, code, sizeof(code));

    int (*func)(void) = p;
    printf("(dynamic) code returned %d\n", func());

    pause();
    return 0;
}
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>   /* mmap(), mprotect() */

static uint8_t code[] = {
    0xB8,0x2A,0x00,0x00,0x00,   /* mov  eax,0x2a    */
    0xC3,                       /* ret              */
};

int main(void)
{
    const size_t len = sizeof(code);

    /* mmap a region for our code */
    void *p = mmap(NULL, len, PROT_READ|PROT_WRITE,  /* No PROT_EXEC */
            MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 
    if (p==MAP_FAILED) {
        fprintf(stderr, "mmap() failed\n");
        return 2;
    }   

    /* Copy it in (still not executable) */
    memcpy(p, code, len);

    /* Now make it execute-only */
    if (mprotect(p, len, PROT_EXEC) < 0) {
        fprintf(stderr, "mprotect failed to mark exec-only\n");
        return 2;
    } 

    /* Go! */
    int (*func)(void) = p;
    printf("(dynamic) code returned %d\n", func());

    pause();
    return 0;
}