Vulnerability Development mailing list archives

Re: How to Change section attribute in ELF file


From: Shaun Clowes <shaun () securereality com au>
Date: Tue, 01 Jan 2002 14:37:37 +1100


Hi,

My program try to modified one of its sections (.plt)
loaded into the memory.  But it  got a SIGSEGV
signal.

Again, I think this is a misunderstanding about the way ELF works. On Sparc machines the PLT is directly patched (see long discussion in previous email) to redirect to the correct dynamic function, on IA32 machines the PLT is never changed since it references an entry in the GOT, only the GOT is changed to dynamically bind the function. Thus on Solaris machines the PLT is always writable but on IA32 it shouldn't ever be.


The .plt section marked READONLY CODE when I
used objdump -h myprogram, I am wondering
whether this readonly attribute can be changed or
not?

The key is that sections are used only at link time, at run time _segments_ are used to load the process image into memory and set the memory permissions. Don't use objdump, use readelf instead and check out the output of the -l option:

readelf -l /bin/ls

...

  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x08048034 0x08048034 0x000c0 0x000c0 R E 0x4
  INTERP         0x0000f4 0x080480f4 0x080480f4 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /lib/ld-linux.so.2]
  LOAD           0x000000 0x08048000 0x08048000 0x0a100 0x0a100 R E 0x1000
  LOAD           0x00a100 0x08053100 0x08053100 0x00270 0x00508 RW  0x1000
  DYNAMIC        0x00a2c8 0x080532c8 0x080532c8 0x000a8 0x000a8 RW  0x4
  NOTE           0x000108 0x08048108 0x08048108 0x00020 0x00020 R   0x4

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
02 .interp .note.ABI-tag .hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.got .rel.bss .rel.
plt .init .plt .text .fini .rodata
   03     .data .eh_frame .ctors .dtors .got .dynamic .bss
   04     .dynamic
   05     .note.ABI-tag

So we can see that the section .plt is in segment 2 which as expected has permissions R-E (or more obviously R-X).

I have tried editing it in several places in the file
but haven't success yet. Anybody done this before?

Yep, you need to modify the segment table permissions, the source for a program that does just that follows, I just quickly hacked it up so no promises as to quality.

You might find the ELF specification an interesting read in regards to all of this stuff.

Cheers,
Shaun

#include <stdio.h>
#include <elf.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>

/* Change the permissions on a segment */

int main(int argc, char *argv[]) {
   char *sInFile;
   unsigned long ulPerm = 0;
   int iSegNo, iInFd, i;
   char *pcFileAddr;
   struct stat tStatBuf;
   off_t tMapSize;
   Elf32_Ehdr *ptElfHdr;
   Elf32_Phdr *ptElfPHdr;
   char sElfMagic[] = "\x7f" "ELF";

   if (argc != 4) {
fprintf(stderr, "Usage: %s <file> <segment no> <segment permissions (e.g rwx)>\n",
              argv[0]);
      exit(1);
   }

   i = 0;
   while (argv[3][i]) {
      switch(argv[3][i]) {
         case 'x':
            ulPerm |= PF_X;
         case 'r':
            ulPerm |= PF_R;
         case 'w':
            ulPerm |= PF_W;
      }
      i++;
   }
   sInFile = argv[1];
   iSegNo = atoi(argv[2]);

   if (-1 == (iInFd = open(sInFile, O_RDWR))) {
fprintf(stderr, "Could not open %s, %d %s\n", sInFile, errno, strerror(errno));
      exit(-1);
   }

   if (fstat(iInFd, &tStatBuf)) {
fprintf(stderr, "Could not stat %s, %d %s\n", sInFile, errno, strerror(errno));
      exit(-1);
   }
   tMapSize = tStatBuf.st_size;

if (!(pcFileAddr = mmap(0, tMapSize, PROT_READ | PROT_WRITE, MAP_SHARED, iInFd, 0))) { fprintf(stderr, "Could not mmap %s, %d %s\n", sInFile, errno, strerror(errno));
      exit(-1);
   }
printf("File %s mapped at %p for %lu bytes\n", sInFile, pcFileAddr, tMapSize);

   ptElfHdr = (Elf32_Ehdr *) pcFileAddr;
   if (memcmp(&(ptElfHdr->e_ident), sElfMagic, sizeof(sElfMagic) - 1)) {
      fprintf(stderr, "File %s does not appear to be an ELF file\n", sInFile);
      exit(-1);
   }

   /* Does this file have the segment they requested?                 */
   if ((iSegNo < 0) || (iSegNo >= ptElfHdr->e_phnum)) {
      printf("Segment %d does not exist in the executable\n", iSegNo);
      exit(-1);
   }

   /* Get the segment header for the specified segment                */
   ptElfPHdr = (Elf32_Phdr *) ((char *) pcFileAddr + ptElfHdr->e_phoff +
                               (ptElfHdr->e_phentsize * iSegNo));

   /* Set the permissions as specified                                */
   ptElfPHdr->p_flags = ulPerm;

   munmap(pcFileAddr, tMapSize);
   close(iInFd);

   return(0);
}



Current thread: