空の (最初のステップとして) 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;
}