MochaPayload/source/ios_kernel/source/elf_patcher.c

94 lines
3.2 KiB
C

/***************************************************************************
* Copyright (C) 2016
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
***************************************************************************/
#include "elf_abi.h"
#include "types.h"
#include "utils.h"
static Elf32_Phdr *get_section(u32 data, u32 vaddr) {
Elf32_Ehdr *ehdr = (Elf32_Ehdr *) data;
if (!IS_ELF(*ehdr) || (ehdr->e_type != ET_EXEC) || (ehdr->e_machine != EM_ARM)) {
return 0;
}
Elf32_Phdr *phdr = 0;
u32 i;
for (i = 0; i < ehdr->e_phnum; i++) {
phdr = (Elf32_Phdr *) (data + ehdr->e_phoff + ehdr->e_phentsize * i);
if ((vaddr >= phdr[0].p_vaddr) && ((i == ehdr->e_phnum) || (vaddr < phdr[1].p_vaddr))) {
break;
}
}
return phdr;
}
void section_write_bss(u32 ios_elf_start, u32 address, u32 size) {
Elf32_Phdr *phdr = get_section(ios_elf_start, address);
if (!phdr)
return;
if ((address - phdr->p_vaddr + size) > phdr->p_memsz) {
phdr->p_memsz = (address - phdr->p_vaddr + size);
}
}
void section_write(u32 ios_elf_start, u32 address, const void *data, u32 size) {
Elf32_Phdr *phdr = get_section(ios_elf_start, address);
if (!phdr)
return;
u32 *addr = (u32 *) (ios_elf_start + address - phdr->p_vaddr + phdr->p_offset);
if ((address - phdr->p_vaddr + size) > phdr->p_filesz) {
u32 additionalSize = address - phdr->p_vaddr + size - phdr->p_filesz;
Elf32_Ehdr *ehdr = (Elf32_Ehdr *) ios_elf_start;
Elf32_Phdr *tmpPhdr;
u32 i;
for (i = (ehdr->e_phnum - 1); i >= 0; i--) {
tmpPhdr = (Elf32_Phdr *) (ios_elf_start + ehdr->e_phoff + ehdr->e_phentsize * i);
if (phdr->p_offset < tmpPhdr->p_offset) {
reverse_memcpy((u8 *) ios_elf_start + tmpPhdr->p_offset + additionalSize, (u8 *) ios_elf_start + tmpPhdr->p_offset, tmpPhdr->p_filesz);
tmpPhdr->p_offset += additionalSize;
} else {
break;
}
}
phdr->p_filesz += additionalSize;
if (phdr->p_memsz < phdr->p_filesz) {
phdr->p_memsz = phdr->p_filesz;
}
}
// in most cases only a word is copied to an aligned address so do a short cut for performance
if (size == 4 && !((unsigned int) addr & 3) && !((unsigned int) data & 3)) {
*(u32 *) addr = *(u32 *) data;
} else {
kernel_memcpy(addr, data, size);
}
}