orbital/tools/dumper/source/self_mapper.c
2018-04-03 03:13:13 +02:00

145 lines
3.6 KiB
C

/**
* (c) 2017-2018 Alexandro Sanchez Bach.
* Released under MIT license. Read LICENSE for more details.
*
* Based in previous tools and research by: m0rph3us1987.
*/
#include "self_mapper.h"
#include "self_decrypter.h"
#include "ksdk.h"
#include "blob.h"
#include "debug.h"
#include "elf32.h"
#include "elf64.h"
#define MAP_SELF 0x80000
#define PT_NID 0x61000000
#define assert(cond) if (!(cond)) { \
dprintf("%s:%d: failed.\n", __FUNCTION__, __LINE__); \
goto error; \
}
static int valid_elf_magic(const uint8_t *magic)
{
return
(magic[0] == 0x7F) &&
(magic[1] == 0x45) &&
(magic[2] == 0x4C) &&
(magic[3] == 0x46);
}
uint8_t* self_decrypt(
uint8_t *self_data, size_t self_size, int self_fd,
size_t *elf_sizep)
{
uint8_t *elf_data;
size_t ehdr_off;
Elf64_Ehdr *ehdr;
Elf64_Phdr *phdr;
uint8_t *elf_base;
uint8_t *elf_segment;
size_t elf_size;
size_t i, j, off;
// Determine actual format
ehdr_off = 0;
ehdr = (void*)&self_data[ehdr_off];
if (valid_elf_magic(ehdr->e_ident)) {
elf_data = malloc(self_size);
memcpy(elf_data, self_data, self_size);
*elf_sizep = self_size;
return elf_data;
} else {
self_header_t *self_hdr = (void*)self_data;
ehdr_off += sizeof(self_header_t);
ehdr_off += sizeof(self_entry_t) * self_hdr->num_entries;
ehdr = (void*)&self_data[ehdr_off];
elf_base = (void*)ehdr;
}
// Parse EHDR
if (!valid_elf_magic(ehdr->e_ident)) {
return NULL;
}
ehdr->e_shoff = 0;
ehdr->e_shnum = 0;
elf_size = ehdr->e_phoff + (ehdr->e_phnum * ehdr->e_phentsize) + (ehdr->e_shnum * ehdr->e_shentsize);
// Parse PHDRs
phdr = (void*)&elf_base[ehdr->e_phoff];
for (i = 0; i < ehdr->e_phnum; i++) {
if (phdr[i].p_type == PT_LOAD ||
phdr[i].p_type == PT_NID ||
phdr[i].p_type == PT_DYNAMIC)
{
elf_size = MAX(elf_size, phdr[i].p_offset + phdr[i].p_filesz);
}
}
*elf_sizep = elf_size;
elf_data = malloc(elf_size);
// Copy EHDR
for (i = 0; i < ehdr->e_ehsize; i++)
elf_data[i] = elf_base[i];
// Copy PHDRs and segments
for (i = 0; i < ehdr->e_phnum; i++) {
for (j = 0; j < ehdr->e_phentsize; j++) {
off = ehdr->e_phoff + (i * ehdr->e_phentsize) + j;
elf_data[off] = elf_base[off];
}
if (phdr[i].p_type == PT_LOAD || phdr[i].p_type == PT_NID) {
lseek(self_fd, 0, SEEK_SET);
elf_segment = mmap(NULL, phdr[i].p_filesz, PROT_READ, MAP_SHARED | MAP_SELF, self_fd, i << 32);
for (j = 0; j < phdr[i].p_filesz; j++) {
elf_data[phdr[i].p_offset + j] = elf_segment[j];
}
munmap(elf_segment, phdr[i].p_filesz);
}
}
return elf_data;
}
uint8_t* self_decrypt_fd(int fd,
size_t *elf_sizep)
{
uint8_t *elf_data = NULL;
uint8_t *self_data = NULL;
size_t self_size;
size_t off;
off = lseek(fd, 0, SEEK_END);
assert(off >= 0);
self_size = off;
off = lseek(fd, 0, SEEK_SET);
assert(off >= 0);
self_data = malloc(self_size);
assert(self_data);
off = read(fd, self_data, self_size);
assert(off == self_size);
elf_data = self_decrypt(self_data, self_size, fd, elf_sizep);
error:
free(self_data);
return elf_data;
}
uint8_t* self_decrypt_file(const char *file,
size_t *elf_sizep)
{
uint8_t *elf_data = NULL;
int fd;
fd = open(file, O_RDONLY, 0);
assert(fd >= 0);
elf_data = self_decrypt_fd(fd, elf_sizep);
close(fd);
error:
return elf_data;
}