Re: How to Change section attribute in ELF file

From: Shaun Clowes (shaunat_private)
Date: Mon Dec 31 2001 - 19:37:37 PST

  • Next message: NETKOJI: "Re: Clicktilluwin DLDER Trojan"

    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);
    }
    



    This archive was generated by hypermail 2b30 : Mon Dec 31 2001 - 19:41:38 PST