1

空の (最初のステップとして) phdr 構造体を任意の elf バイナリに挿入するプログラムをコーディングしようとするので、以下のようにコーディングします。

猫 add_phdr.c

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

static void calc_dyntables(void **ehdr_ptr, size_t bound_size)
{
    void *ptr = *ehdr_ptr;
    Elf32_Ehdr *Elf32_ptr = NULL;

    Elf32_ptr = (Elf32_Ehdr *)ptr;
    Elf32_Phdr *elf32_phdr = NULL;
    int n, found = 0;

    n = Elf32_ptr->e_phnum;
    elf32_phdr = ptr + Elf32_ptr->e_phoff;
    while (n--) {
        if (elf32_phdr->p_type == PT_DYNAMIC) {
            found = 1;
            break;
        }
        elf32_phdr++;
    }

    if (found) {
        /* printf("=== PT_DYNAMIC: offset: 0x%x, size: 0x%x\n",  */
                /* elf32_phdr->p_offset, elf32_phdr->p_filesz); */
        /* printf("sizeof(Elf32_Dyn): %d\n", sizeof(Elf32_Dyn)); */
    }
    else
        return;

    /* list all of dynamic sections */
    found = 0;
    Elf32_Dyn *dyn_entry = ptr + elf32_phdr->p_offset;
    while (dyn_entry->d_tag != DT_NULL) {
        switch (dyn_entry->d_tag) {
            case 0x6ffffef5:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case 0x6ffffff0:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case 0x6ffffffe:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case 0x0000000c:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case 0x0000000d:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case 0x00000019:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case 0x0000001a:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case 0x00000005:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case 0x00000006:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case 0x00000003:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case 0x00000017:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case 0x00000011:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            default:
                break;
        }
        /* printf("== tag: 0x%x, value: 0x%x\n", dyn_entry->d_tag, */
                /* dyn_entry->d_un.d_val); */
        dyn_entry++;
    }

}

static int write_phdr(int fd_dst, void *ptr, size_t filesize)
{
    /* ptr for Ehdr */
    Elf32_Ehdr *Elf32_ptr = NULL;
    Elf32_ptr = (Elf32_Ehdr *)ptr;

    /* ptr for Phdr */
    Elf32_Phdr *elf32_phdr = NULL;
    /* ptr for Shdr */
    Elf32_Shdr *elf32_shdr = NULL;

    int n;

    /*
     * We must find the phdr array's border, then recalcuate 
     * the offset of phdrs & shdrs which's offset beyond the
     * offset of border.
     */
    off_t old_phdr_border = Elf32_ptr->e_phoff + Elf32_ptr->e_phentsize * Elf32_ptr->e_phnum;
    printf("=== border 0x%x\n", (unsigned int) (0x8048000 + old_phdr_border));
    off_t phdr_size = Elf32_ptr->e_phentsize;

    /* recalcuate the hash table address */
    calc_dyntables(&ptr, phdr_size);
    /* pdhr */
    n = Elf32_ptr->e_phnum;
    elf32_phdr = ptr + Elf32_ptr->e_phoff;

    /* recalculate phdr offset */
    while (n-- > 0) {
        if (elf32_phdr->p_offset  >= old_phdr_border) {
            elf32_phdr->p_offset += phdr_size;
            elf32_phdr->p_vaddr += phdr_size;
            elf32_phdr->p_paddr += phdr_size;
        }
        else {
            if ((elf32_phdr->p_offset + elf32_phdr->p_filesz) >= old_phdr_border) {
                elf32_phdr->p_filesz += phdr_size;
                elf32_phdr->p_memsz += phdr_size;
            }
        }
        elf32_phdr++;
    }

    /* recalculate shdr offset */
    n = Elf32_ptr->e_shnum;
    elf32_shdr = ptr + Elf32_ptr->e_shoff;
    while (n-- > 0) {
        if (elf32_shdr->sh_offset >= old_phdr_border) {
            elf32_shdr->sh_offset += phdr_size;
            elf32_shdr->sh_addr += phdr_size;
        }
        else {
            if ((elf32_shdr->sh_offset + elf32_shdr->sh_size) >= old_phdr_border) {
                elf32_shdr->sh_size += phdr_size;
            }
        }
        elf32_shdr++;
    }

    Elf32_ptr->e_shoff += phdr_size;

    Elf32_Phdr *new_ptr = malloc(sizeof(Elf32_Phdr));
    if (new_ptr == NULL)
        return -1;

    Elf32_ptr->e_phnum += 1;

    /* recalculate the entry */
    if (Elf32_ptr->e_entry > old_phdr_border)
        Elf32_ptr->e_entry += phdr_size;


    write(fd_dst, ptr, old_phdr_border);
    memset(new_ptr, 0, sizeof(Elf32_Phdr));
    new_ptr->p_type = PT_NULL;
    new_ptr->p_offset = 0xffff;
    new_ptr->p_vaddr = 0xffff;
    new_ptr->p_paddr = 0xffff;
    new_ptr->p_filesz = 0x1111;
    new_ptr->p_memsz = 0;
    new_ptr->p_flags = PF_R;
    new_ptr->p_align = 0x4;
    write(fd_dst, new_ptr, phdr_size);
    write(fd_dst, ptr + old_phdr_border, filesize - old_phdr_border);

    free(new_ptr);

    return 0;
}

/*
 * this version of write_phdr will apend phdr to
 * the tail of file, so it wont move any sections
 * or offset, we just need change the entry address.
 */
static int write_phdr2(int fd_dst, void *ptr, size_t filesize)
{
    /* ptr for Ehdr */
    Elf32_Ehdr *Elf32_ptr = NULL;
    Elf32_ptr = (Elf32_Ehdr *)ptr;

    /* ptr for Phdr */
//    Elf32_Phdr *elf32_phdr = NULL;

    Elf32_Phdr *new_ptr = malloc(sizeof(Elf32_Phdr));
    if (new_ptr == NULL)
        return -1;

    off_t phdr_size = Elf32_ptr->e_phentsize;

    /* recalculate the entry */
//    Elf32_ptr->e_entry += phdr_size;

    write(fd_dst, ptr, filesize);

    /* append the phdr to the tail of file */
    memset(new_ptr, 0, sizeof(Elf32_Phdr));
    new_ptr->p_type = PT_NULL;
    new_ptr->p_offset = 0xffff;
    new_ptr->p_vaddr = 0xffff;
    new_ptr->p_paddr = 0xffff;
    new_ptr->p_filesz = 0;
    new_ptr->p_memsz = 0;
    new_ptr->p_flags = PF_R;
    new_ptr->p_align = 0x4;
    write(fd_dst, new_ptr, phdr_size);

    free(new_ptr);

    return 0;
}

/*
 * we'll add a new phdr to the binary file
 */
int main(int argc, char *argv[])
{
    int fd_src, fd_dst;
    //size_t len = 0;
    size_t filesize = 0;
    void *ptr = NULL;   /* ptr to binary file which mapped in memory */
    if (argc != 3) {
        printf("Usage: %s [ src bin ] [ dst bin ]...\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    /*
     * we'll calculate the file size then map to memory
     */
    fd_src = open(argv[1], O_RDONLY);

    if (fd_src < 0) {
        printf("Failed to open %s!\n", argv[1]);
        exit(EXIT_FAILURE);
    }

    fd_dst = open(argv[2], O_CREAT | O_WRONLY | O_TRUNC, 0755);

    if (fd_dst < 0) {
        printf("Failed to open %s!\n", argv[2]);
        exit(EXIT_FAILURE);
    }

    /* get file size with lseek SEEK_END */
    filesize = lseek(fd_src, 0, SEEK_END);
    if (filesize < 0) {
        perror("lseek failed!");
        close(fd_src);
        exit(EXIT_FAILURE);
    }

    ptr = mmap(0, filesize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd_src, 0);
    if (ptr < 0) {
        perror("mmap failed!");
        close(fd_src);
        exit(EXIT_FAILURE);
    }

    if (1)
    write_phdr(fd_dst, ptr, filesize);

    if (0)
    write_phdr2(fd_dst, ptr, filesize);

    /* copy the modified file to dst */
    /* do the clean work */
    munmap(ptr, filesize);
    close(fd_src);
    close(fd_dst);

    return EXIT_SUCCESS;
}

次に Makefile:

cat Makefile
CC  = $(CROSS_COMPILE)gcc
LD  = $(CROSS_COMPILE)ld
LDFLAGS = -m elf_i386
CFLAGS  = -m32 -Wall -fPIE

TARGETS = elf_parser show_addr without_libc add_phdr read_elf hello

all: $(TARGETS)

elf_parser:elf_parser.c
    $(CC) $(CFLAGS) -o $@ $<

show_addr:show_addr.c
    $(CC) $(CFLAGS) -o $@ $<

without_libc:without_libc.c
    $(CC) $(CFLAGS) -nostdlib -o $@ $<

add_phdr:add_phdr.c
    $(CC) $(CFLAGS) -o $@ $<

hello:hello.c
    $(CC) $(CFLAGS) -o $@ $<

read_elf:read_elf.o
    $(LD) $(LDFLAGS) -o $@ $<

read_elf.o:read_elf.asm
    nasm -f elf32 -o $@ $<

clean:
    rm -rf $(TARGETS)
    rm -rf *.o

OK、asm コードを含む他の多くのコードがあります。比較として read_elf.asm と hello.c をリストします: cat read_elf.asm:

    global _start
_start:
    call    main
    xor     eax, eax
    inc     eax
    xor     ebx, ebx
    int     0x80

main:
    call    funA
    ret

funA:
    call    funB
    ret
funB:
    call    funC
    ret
funC:
    push    byte 4
    pop     eax
    xor     ebx, ebx
    inc     ebx
    mov     ecx, 0x08048001
    push    byte 3
    pop     edx
    int     0x80
    ret

猫ハロー.c:

int main()
{
    return 10;
}

次に、コードをコンパイルして、add_phdr プログラムを実行しましょう。

./add_phdr read_elf test

次にテストを実行すると、うまく機能しますが、次のように hello プログラムにパッチを適用しようとすると、次のようになります。

./add_phdr hello hello_test
./hello_test

私はこれを得た:

Inconsistency detected by ld.so: dl-lookup.c: 876: _dl_setup_hash: Assertion `(bitmask_nwords & (bitmask_nwords - 1)) == 0' failed!

もう実行できませんでした!
ヒントはありますか?

アップデート:

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

static void calc_symtab(void **ehdr_ptr, size_t bound_size)
{
    void *ptr = *ehdr_ptr;
    Elf32_Shdr *shdr_ptr = NULL;
    Elf32_Ehdr *Elf32_ptr = (Elf32_Ehdr *)ptr;


    int n = Elf32_ptr->e_shnum;
    char *shstrtab = NULL;

    /*
     * first of all, let's get the shstrtab, we'll get 
     * the name of each section with it
     */
    shdr_ptr = (Elf32_Shdr *)(ptr + Elf32_ptr->e_shoff);
    while (n--) {
        if (shdr_ptr->sh_type == SHT_STRTAB) {
            shstrtab = (char *)(ptr + shdr_ptr->sh_offset);
            if (!strcmp(&shstrtab[shdr_ptr->sh_name], ".shstrtab"))
                break;
        }
        shdr_ptr++;
    }

    /* list all of sections */
    shdr_ptr = (Elf32_Shdr *)(ptr + Elf32_ptr->e_shoff);
    n = Elf32_ptr->e_shnum;
    while (n--) {
        if (shdr_ptr->sh_type == SHT_SYMTAB) {
            int n2 = (shdr_ptr->sh_size / sizeof(Elf32_Sym)); 
            Elf32_Sym *sym = (Elf32_Sym *)(ptr + shdr_ptr->sh_offset);
            while (n2--) {
                if (sym->st_value > 0)
                    sym->st_value += bound_size;
                sym++;
            }
        }
        shdr_ptr++;
    }
}

static void calc_dynsym(void **ehdr_ptr, size_t bound_size)
{
    void *ptr = *ehdr_ptr;
    Elf32_Shdr *shdr_ptr = NULL;
    Elf32_Ehdr *Elf32_ptr = (Elf32_Ehdr *)ptr;


    int n = Elf32_ptr->e_shnum;
    char *shstrtab = NULL;

    /*
     * first of all, let's get the shstrtab, we'll get 
     * the name of each section with it
     */
    shdr_ptr = (Elf32_Shdr *)(ptr + Elf32_ptr->e_shoff);
    while (n--) {
        if (shdr_ptr->sh_type == SHT_STRTAB) {
            shstrtab = (char *)(ptr + shdr_ptr->sh_offset);
            if (!strcmp(&shstrtab[shdr_ptr->sh_name], ".shstrtab"))
                break;
        }
        shdr_ptr++;
    }

    /* list all of sections */
    shdr_ptr = (Elf32_Shdr *)(ptr + Elf32_ptr->e_shoff);
    n = Elf32_ptr->e_shnum;
    while (n--) {
        if (shdr_ptr->sh_type == SHT_DYNSYM) {
            int n2 = (shdr_ptr->sh_size / sizeof(Elf32_Sym)); 
            Elf32_Sym *sym = (Elf32_Sym *)(ptr + shdr_ptr->sh_offset);
            while (n2--) {
                if (sym->st_value > 0)
                    sym->st_value += bound_size;
                sym++;
            }
        }
        shdr_ptr++;
    }
}

static void calc_relocs(void **ehdr_ptr, size_t bound_size)
{
    void *ptr = *ehdr_ptr;
    Elf32_Shdr *shdr_ptr = NULL;
    Elf32_Ehdr *Elf32_ptr = (Elf32_Ehdr *)ptr;


    int n = Elf32_ptr->e_shnum;
    char *shstrtab = NULL;

    /*
     * first of all, let's get the shstrtab, we'll get 
     * the name of each section with it
     */
    shdr_ptr = (Elf32_Shdr *)(ptr + Elf32_ptr->e_shoff);
    while (n--) {
        if (shdr_ptr->sh_type == SHT_STRTAB) {
            shstrtab = (char *)(ptr + shdr_ptr->sh_offset);
            if (!strcmp(&shstrtab[shdr_ptr->sh_name], ".shstrtab"))
                break;
        }
        shdr_ptr++;
    }

    /* list all of sections */
    shdr_ptr = (Elf32_Shdr *)(ptr + Elf32_ptr->e_shoff);
    n = Elf32_ptr->e_shnum;
    while (n--) {
        if (shdr_ptr->sh_type == SHT_REL || shdr_ptr->sh_type == SHT_RELA) {

            int n2 = (shdr_ptr->sh_size / sizeof(Elf32_Rel)); 
            Elf32_Rel *rel = (Elf32_Rel *)(ptr + shdr_ptr->sh_offset);
            while (n2--) {
                rel->r_offset += bound_size;
                rel++;
            }
        }
        shdr_ptr++;
    }
}

static void calc_dyntables(void **ehdr_ptr, size_t bound_size)
{
    void *ptr = *ehdr_ptr;
    Elf32_Ehdr *Elf32_ptr = NULL;

    Elf32_ptr = (Elf32_Ehdr *)ptr;
    Elf32_Phdr *elf32_phdr = NULL;
    int n, found = 0;

    n = Elf32_ptr->e_phnum;
    elf32_phdr = ptr + Elf32_ptr->e_phoff;
    while (n--) {
        if (elf32_phdr->p_type == PT_DYNAMIC) {
            found = 1;
            break;
        }
        elf32_phdr++;
    }

    if (found) {
        /* printf("=== PT_DYNAMIC: offset: 0x%x, size: 0x%x\n",  */
                /* elf32_phdr->p_offset, elf32_phdr->p_filesz); */
        /* printf("sizeof(Elf32_Dyn): %d\n", sizeof(Elf32_Dyn)); */
    }
    else
        return;

    /* list all of dynamic sections */
    found = 0;
    Elf32_Dyn *dyn_entry = ptr + elf32_phdr->p_offset;
    while (dyn_entry->d_tag != DT_NULL) {
        switch (dyn_entry->d_tag) {
            case DT_GNU_HASH:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case DT_VERSYM:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case DT_VERNEED:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case DT_INIT:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case DT_FINI:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case DT_INIT_ARRAY:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case DT_FINI_ARRAY:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case DT_STRTAB:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case DT_SYMTAB:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case DT_PLTGOT:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case DT_JMPREL:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            case DT_REL:
                dyn_entry->d_un.d_ptr += bound_size;
                break;
            default:
                break;
        }
        /* printf("== tag: 0x%x, value: 0x%x\n", dyn_entry->d_tag, */
                /* dyn_entry->d_un.d_val); */
        dyn_entry++;
    }

}

static int write_phdr(int fd_dst, void *ptr, size_t filesize)
{
    /* ptr for Ehdr */
    Elf32_Ehdr *Elf32_ptr = NULL;
    Elf32_ptr = (Elf32_Ehdr *)ptr;

    /* ptr for Phdr */
    Elf32_Phdr *elf32_phdr = NULL;
    /* ptr for Shdr */
    Elf32_Shdr *elf32_shdr = NULL;

    int n;

    /*
     * We must find the phdr array's border, then recalcuate 
     * the offset of phdrs & shdrs which's offset beyond the
     * offset of border.
     */
    off_t old_phdr_border = Elf32_ptr->e_phoff + Elf32_ptr->e_phentsize * Elf32_ptr->e_phnum;
    printf("=== border 0x%x\n", (unsigned int) (0x8048000 + old_phdr_border));
    off_t phdr_size = Elf32_ptr->e_phentsize;

    /* recalcuate the hash table address */
    calc_dyntables(&ptr, phdr_size);
    calc_relocs(&ptr, phdr_size);
    calc_symtab(&ptr, phdr_size);
    calc_dynsym(&ptr, phdr_size);
    /* pdhr */
    n = Elf32_ptr->e_phnum;
    elf32_phdr = ptr + Elf32_ptr->e_phoff;

    /* recalculate phdr offset */
    while (n-- > 0) {
        if (elf32_phdr->p_offset  >= old_phdr_border) {
            elf32_phdr->p_offset += phdr_size;
            elf32_phdr->p_vaddr += phdr_size;
            elf32_phdr->p_paddr += phdr_size;
        }
        else {
            if ((elf32_phdr->p_offset + elf32_phdr->p_filesz) >= old_phdr_border) {
                elf32_phdr->p_filesz += phdr_size;
                elf32_phdr->p_memsz += phdr_size;
            }
        }
        elf32_phdr++;
    }

    /* recalculate shdr offset */
    n = Elf32_ptr->e_shnum;
    elf32_shdr = ptr + Elf32_ptr->e_shoff;
    while (n-- > 0) {
        if (elf32_shdr->sh_offset >= old_phdr_border) {
            elf32_shdr->sh_offset += phdr_size;
            if (elf32_shdr->sh_addr > 0)
                elf32_shdr->sh_addr += phdr_size;
        }
        else {
            if ((elf32_shdr->sh_offset + elf32_shdr->sh_size) >= old_phdr_border) {
                elf32_shdr->sh_size += phdr_size;
            }
        }
        elf32_shdr++;
    }

    Elf32_ptr->e_shoff += phdr_size;

    Elf32_Phdr *new_ptr = malloc(sizeof(Elf32_Phdr));
    if (new_ptr == NULL)
        return -1;

    Elf32_ptr->e_phnum += 1;

    /* recalculate the entry */
    if (Elf32_ptr->e_entry >= old_phdr_border)
        Elf32_ptr->e_entry += phdr_size;


    write(fd_dst, ptr, old_phdr_border);
    memset(new_ptr, 0, sizeof(Elf32_Phdr));
    new_ptr->p_type = PT_NULL;
    new_ptr->p_offset = 0xffff;
    new_ptr->p_vaddr = 0xffff;
    new_ptr->p_paddr = 0xffff;
    new_ptr->p_filesz = 0x1111;
    new_ptr->p_memsz = 0;
    new_ptr->p_flags = PF_R;
    new_ptr->p_align = 0x4;
    write(fd_dst, new_ptr, phdr_size);
    write(fd_dst, ptr + old_phdr_border, filesize - old_phdr_border);

    free(new_ptr);

    return 0;
}

/*
 * this version of write_phdr will apend phdr to
 * the tail of file, so it wont move any sections
 * or offset, we just need change the entry address.
 */
static int write_phdr2(int fd_dst, void *ptr, size_t filesize)
{
    /* ptr for Ehdr */
    Elf32_Ehdr *Elf32_ptr = NULL;
    Elf32_ptr = (Elf32_Ehdr *)ptr;

    /* ptr for Phdr */
//    Elf32_Phdr *elf32_phdr = NULL;

    Elf32_Phdr *new_ptr = malloc(sizeof(Elf32_Phdr));
    if (new_ptr == NULL)
        return -1;

    off_t phdr_size = Elf32_ptr->e_phentsize;

    /* recalculate the entry */
//    Elf32_ptr->e_entry += phdr_size;

    write(fd_dst, ptr, filesize);

    /* append the phdr to the tail of file */
    memset(new_ptr, 0, sizeof(Elf32_Phdr));
    new_ptr->p_type = PT_NULL;
    new_ptr->p_offset = 0xffff;
    new_ptr->p_vaddr = 0xffff;
    new_ptr->p_paddr = 0xffff;
    new_ptr->p_filesz = 0;
    new_ptr->p_memsz = 0;
    new_ptr->p_flags = PF_R;
    new_ptr->p_align = 0x4;
    write(fd_dst, new_ptr, phdr_size);

    free(new_ptr);

    return 0;
}

/*
 * we'll add a new phdr to the binary file
 */
int main(int argc, char *argv[])
{
    int fd_src, fd_dst;
    //size_t len = 0;
    size_t filesize = 0;
    void *ptr = NULL;   /* ptr to binary file which mapped in memory */
    if (argc != 3) {
        printf("Usage: %s [ src bin ] [ dst bin ]...\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    /*
     * we'll calculate the file size then map to memory
     */
    fd_src = open(argv[1], O_RDONLY);

    if (fd_src < 0) {
        printf("Failed to open %s!\n", argv[1]);
        exit(EXIT_FAILURE);
    }

    fd_dst = open(argv[2], O_CREAT | O_WRONLY | O_TRUNC, 0755);

    if (fd_dst < 0) {
        printf("Failed to open %s!\n", argv[2]);
        exit(EXIT_FAILURE);
    }

    /* get file size with lseek SEEK_END */
    filesize = lseek(fd_src, 0, SEEK_END);
    if (filesize < 0) {
        perror("lseek failed!");
        close(fd_src);
        exit(EXIT_FAILURE);
    }

    ptr = mmap(0, filesize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd_src, 0);
    if (ptr < 0) {
        perror("mmap failed!");
        close(fd_src);
        exit(EXIT_FAILURE);
    }

    if (1)
    write_phdr(fd_dst, ptr, filesize);

    if (0)
    write_phdr2(fd_dst, ptr, filesize);

    /* copy the modified file to dst */
    /* do the clean work */
    munmap(ptr, filesize);
    close(fd_src);
    close(fd_dst);

    return EXIT_SUCCESS;
}
4

2 に答える 2

2

ヒントはありますか?

ELF 形式には内部に多くのポインターがあり、(プログラムのように) データを移動する場合は、これらすべてのポインターを調整して、新しい場所/オフセットを指すようにする必要があります (プログラムはこれを行いません)。

ELF は実際には、実行しようとしている種類のリンク後の処理用には設計されていません。

当面の問題は、またはセクションの古いオフセットを指しているor (または両方) が含まれてますが、ビットを移動したため、ランタイムローダーが期待する有効なハッシュテーブルが古いオフセットに含まれていないことです。そこを見つけるために。helloDT_HASHDT_GNU_HASH.hash.gnu.hash

ランニング

for exe in hello hello_test; do
  readelf -d $exe | grep HASH
  readelf -WS $exe | grep hash
done

これが事実であることを証明する必要があります。

編集

case 0x6ffffef5:
           dyn_entry->d_un.d_ptr += bound_size;
           break;

絶対にやらないでください。コードを読んだり理解したりすることができなくなります。代わりにこれを行います:

#include <elf.h>
...
  case DT_GNU_HASH:
            dyn_entry->d_un.d_ptr += bound_size;
            break;

そのようなケースが 12 件あるため、それらを記号名に戻すことは拒否します。

いずれにせよ、私の答えは次のとおりです。どこかでポインターを更新していないため結果の ELF が自己矛盾し、動的ローダーが不幸になります。

本当にこの方向に固執したい場合は、glibc デバッグ シンボルをインストールし、次のようにローダーをデバッグします。

gdb /path/to/ld-linux.so ./hello_test

これにより、更新に失敗したポインターを特定できるはずです。

于 2013-08-31T05:40:56.147 に答える
0

「readelf」を使用して新しい実行可能ファイルを見ましたか?

私自身、phdrが(すでに)ファイルの最後にあるかどうかを確認します(phoff + phentsize * phnum == file_size)。そうでない場合は、phdr テーブルのコピーをファイルの末尾に追加し、elf ヘッダーの phoff メンバーを変更するだけです。

次に、ファイルの最後に phdr セクションを追加できます (セクションを移動する必要はありません)。

元の phdr テーブルはファイルに残りますが、非アクティブになります。

于 2013-08-29T11:54:01.823 に答える