Memory 如何写入加载到RAM内存中的共享库代码段?

Memory 如何写入加载到RAM内存中的共享库代码段?,memory,c,mmap,Memory,C,Mmap,我想让您询问为什么我不能在MIPS CPU平台(LG TV)上的Linux 2.6.28.9的RAM内存中写入加载的共享库代码段。我能读字节,但不能写任何东西。在下面的示例源代码(在gcc中交叉编译)中,当调用write()函数时,我得到了错误22:Invalid argument(EINVAL) // this app tries to replace 4 bytes in code segment memory of loaded shared library #include <s

我想让您询问为什么我不能在MIPS CPU平台(LG TV)上的Linux 2.6.28.9的RAM内存中写入加载的共享库代码段。我能读字节,但不能写任何东西。在下面的示例源代码(在gcc中交叉编译)中,当调用write()函数时,我得到了错误22:Invalid argument(EINVAL)

// this app tries to replace 4 bytes in code segment memory of loaded shared library

#include <stdio.h>  // printf
#include <stdlib.h> // off_t
#include <dlfcn.h>  // dlopen, dlclose
#include <fcntl.h>  // open, O_RDWR
#include <unistd.h> // lseek, close, read
#include <errno.h>  // errno
#include <string.h> // strerror
#include <sys/mman.h>   // mprotect, PROT_READ, PROT_WRITE, PROT_EXEC

#define BYTES_TO_REPLACE    4

int main (int argc, char *argv[])
{
   int fd, pid;
   unsigned *handle;
   unsigned long pagesize;
   off_t fun_addr, pa_fun_addr;
   unsigned char buf[BYTES_TO_REPLACE];
   char s[100];

   // initialize
   pagesize = sysconf(_SC_PAGESIZE);    // memory page size from system
   pid = getpid();          // PID of current process

   // open shared library file, OK
   handle = dlopen("/path_to_library_files/shared_library.so", RTLD_LAZY | RTLD_GLOBAL);

   // get function address, OK
   fun_addr = (off_t)dlsym(handle, "function_name_in_lib");

   // open memory device (pseudo-file), OK
   sprintf(s, "/proc/%d/mem", pid); // memory space of our process (/proc/self/mem)
   //strcpy(s, "/dev/mem");     // in that case when reading from memory ==> ERROR 14: Bad address
   fd = open(s, O_RDWR);        // open for reading and writing

   // go to starting address of the library function loaded earlier, OK
   lseek(fd, fun_addr, SEEK_SET);

   // read from memory, OK
   read(fd, buf, BYTES_TO_REPLACE);
   printf("old replaced bytes = [%02X %02X %02X %02X]\n", buf[0], buf[1], buf[2], buf[3]);

   // move back, OK
   lseek(fd, fun_addr, SEEK_SET);

   // unprotect memory page - no error, but does not help
   pa_fun_addr = (fun_addr / pagesize) * pagesize;  // page-aligned address
   mprotect((void *)pa_fun_addr, pagesize, PROT_READ | PROT_WRITE | PROT_EXEC);

   // write new data to memory: ERROR 22: Invalid argument
   buf[0] = 0x08; buf[1] = 0x00; buf[2] = 0xE0; buf[3] = 0x03;  // replacing 4-byte command: jr $ra (MIPS CPU)
   if (write(fd, buf, BYTES_TO_REPLACE) != BYTES_TO_REPLACE) printf("ERROR %d: %s!\n", errno, strerror(errno));

   // close memory device and shared library
   close(fd);
   dlclose(handle);
   return 0;
}
//此应用程序尝试替换加载的共享库的代码段内存中的4个字节
#包括//printf
#包括//off\t
#包括//dlopen、dlclose
#包括//open,O_RDWR
#包括//lseek、关闭、读取
#包括//errno
#包括//strerror
#包括//保护、保护读取、保护写入、保护执行
#定义字节\u以\u替换4
int main(int argc,char*argv[])
{
int-fd,pid;
无符号*句柄;
无符号长页面大小;
开玩笑的地址,开玩笑的地址;
无符号字符buf[字节到替换];
chars[100];
//初始化
pagesize=sysconf(_SC_pagesize);//来自系统的内存页大小
pid=getpid();//当前进程的pid
//打开共享库文件,确定吗
handle=dlopen(“/path_to_library_files/shared_library.so”,RTLD_LAZY | RTLD_GLOBAL);
//获取函数地址,好吗
fun_addr=(off_t)dlsym(句柄,“函数名在库中”);
//打开内存设备(伪文件),正常
sprintf(s,“/proc/%d/mem”,pid);//进程的内存空间(/proc/self/mem)
//strcpy(“/dev/mem”);//在这种情况下,从内存读取==>错误14:地址错误
fd=open(s,ordwr);//为读写打开
//转到前面加载的库函数的起始地址,确定吗
lseek(fd、fun\u addr、SEEK\u SET);
//从内存中读取,好吗
读取(fd、buf、字节到替换);
printf(“旧替换字节=[%02X%02X%02X%02X]\n”,buf[0],buf[1],buf[2],buf[3]);
//往后退,好吗
lseek(fd、fun\u addr、SEEK\u SET);
//取消保护内存页-无错误,但没有帮助
pa_fun_addr=(fun_addr/pagesize)*pagesize;//页面对齐地址
mprotect((void*)pau-fun-addr、pagesize、PROT-READ、PROT-WRITE、PROT-EXEC);
//将新数据写入内存:错误22:参数无效
buf[0]=0x08;buf[1]=0x00;buf[2]=0xE0;buf[3]=0x03;//替换4字节命令:jr$ra(MIPS CPU)
if(写入(fd,buf,BYTES_TO_REPLACE)!=BYTES_TO_REPLACE)printf(“错误%d:%s!\n”,errno,strerror(errno));
//关闭内存设备和共享库
关闭(fd);
dlclose(手柄);
返回0;
}

这是因为内存中的进程代码在默认情况下没有写入权限。要查看进程内存的权限,请使用
pmap

例如,下面的共享库最多只有
rx
权限:

sudo pmap 5869                                                                                                                    
5869:   vim supervisor_meeting-2017-05-22.txt
000055b391f62000   2604K r-x-- vim
000055b3923ed000     56K r---- vim
000055b3923fb000    100K rw--- vim
000055b392414000     60K rw---   [ anon ]
000055b393377000   2868K rw---   [ anon ]
00007fc59ef5a000     40K r-x-- libnss_files-2.24.so
00007fc59ef64000   2048K ----- libnss_files-2.24.so
00007fc59f164000      4K r---- libnss_files-2.24.so
00007fc59f165000      4K rw--- libnss_files-2.24.so
00007fc59f166000     24K rw---   [ anon ]

<..snip..>
sudo pmap 5869
5869:vim主管会议-2017-05-22.txt
000055b391f62000 2604K r-x--vim
000055b3923ed000 56K r----vim
000055b3923fb000 100K rw---vim
000055b392414000 60K rw---[anon]
000055b393377000 2868K rw---[anon]
00007fc59ef5a000 40K r-x——libnss_文件-2.24.so
00007fc59ef64000 2048K-----libnss_文件-2.24.so
00007fc59f164000 4K r----libnss_文件-2.24.so
00007fc59f165000 4K rw---libnss_文件-2.24.so
00007fc59f166000 24K rw---[anon]
我知道您正试图使用mprotect来更改这一点,但您也没有检查
mprotect()
调用的返回值,这可能是由于某种原因而失败的

另外,作为旁白-
write()
不能保证写入所有给定的字节,并且在返回时不写入或部分写入字节也在其设计范围内-我建议您也更改代码以反映这一点