159 lines
5.4 KiB
C
159 lines
5.4 KiB
C
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include "fixups.h"
|
|
#include "fixups_type.h"
|
|
|
|
struct ImportTable GetImportsTable(uint8_t* header_ptr) {
|
|
struct dyld_chained_fixups_header* header = (struct dyld_chained_fixups_header*)header_ptr;
|
|
|
|
char* symbols_table = (char*)(header_ptr + header->symbols_offset);
|
|
struct dyld_chained_import* imports_table = (struct dyld_chained_import*)(header_ptr + header->imports_offset);
|
|
|
|
struct ImportTable table = {
|
|
(uint64_t)symbols_table,
|
|
(uint64_t)imports_table,
|
|
header->imports_count,
|
|
};
|
|
return table;
|
|
}
|
|
|
|
struct ImportSymbol GetImportsAt(struct ImportTable* table, int i) {
|
|
struct dyld_chained_import* imports_table = (struct dyld_chained_import*)table->imports_table;
|
|
struct dyld_chained_import import = imports_table[i];
|
|
char* name = (char*)table->symbols_table + import.name_offset;
|
|
struct ImportSymbol symbol = {
|
|
import.lib_ordinal,
|
|
name,
|
|
};
|
|
// printf("imports[%d]: (%d)%s\n", i, import.lib_ordinal, name);
|
|
return symbol;
|
|
}
|
|
|
|
int GetSegmentFixAt(uint8_t* buffer, uint32_t i, struct SegmentFix* fix) {
|
|
struct dyld_chained_fixups_header* header = (struct dyld_chained_fixups_header*)buffer;
|
|
struct dyld_chained_starts_in_image* segment = (struct dyld_chained_starts_in_image*)(buffer + header->starts_offset);
|
|
|
|
if (fix == 0) {
|
|
return 1;
|
|
}
|
|
if (i >= segment->seg_count) {
|
|
return 2;
|
|
}
|
|
|
|
// printf("segment %d\n", i);
|
|
uint32_t offset = segment->seg_info_offset[i];
|
|
if (offset == 0) {
|
|
return 3;
|
|
}
|
|
|
|
struct dyld_chained_starts_in_segment* chain_header = (struct dyld_chained_starts_in_segment*)((char*)segment + offset);
|
|
|
|
// printf("segment_offset=0x%llx\n", chain_header->segment_offset);
|
|
// printf("page count=0x%x\n", chain_header->page_count);
|
|
fix->segment = (uint64_t)(chain_header->segment_offset);
|
|
fix->format = chain_header->pointer_format;
|
|
fix->page_count = chain_header->page_count;
|
|
fix->pages = chain_header->page_start;
|
|
fix->page_size = chain_header->page_size;
|
|
return 0;
|
|
}
|
|
|
|
inline int isBind(uint64_t value) {
|
|
struct dyld_chained_ptr_64_bind* b = (struct dyld_chained_ptr_64_bind*)&value;
|
|
return b->bind;
|
|
}
|
|
|
|
int ParseFixValue(int format, uint64_t value, int* bind, uint64_t* ret1, uint64_t* ret2) {
|
|
switch (format) {
|
|
case DYLD_CHAINED_PTR_64:
|
|
case DYLD_CHAINED_PTR_64_OFFSET: {
|
|
if (isBind(value)) {
|
|
struct dyld_chained_ptr_64_bind* b = (struct dyld_chained_ptr_64_bind*)&value;
|
|
// printf("is bind\n");
|
|
// printf(" ordinal=%d", b->ordinal);
|
|
// printf(" addend=0x%x", b->addend);
|
|
// printf(" next=0x%x\n", b->next);
|
|
*ret1 = b->ordinal;
|
|
*ret2 = b->addend;
|
|
*bind = 1;
|
|
return b->next;
|
|
} else {
|
|
struct dyld_chained_ptr_64_rebase* b = (struct dyld_chained_ptr_64_rebase*)&value;
|
|
// printf("is rebase\n");
|
|
// printf(" target=0x%llx", b->target);
|
|
// printf(" high8=0x%x", b->high8);
|
|
// printf(" next=0x%x\n", b->next);
|
|
*ret1 = b->target;
|
|
*ret2 = b->high8;
|
|
*bind = 0;
|
|
return b->next;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
uint64_t MakeRebaseFixupOpcode(int next, uint64_t target, uint64_t high8) {
|
|
uint64_t value;
|
|
struct dyld_chained_ptr_64_rebase* b = (struct dyld_chained_ptr_64_rebase*)&value;
|
|
b->bind = 0;
|
|
b->next = next;
|
|
b->target = target;
|
|
b->high8 = high8;
|
|
return value;
|
|
}
|
|
|
|
uint64_t MakeBindFixupOpcodeFromRebase(uint64_t rebaseOpcode, uint32_t ordinal) {
|
|
printf("fix bind value\n");
|
|
uint64_t ret;
|
|
struct dyld_chained_ptr_64_bind* b = (struct dyld_chained_ptr_64_bind*)&ret;
|
|
b->next = ((struct dyld_chained_ptr_64_rebase*)&rebaseOpcode)->next;
|
|
b->bind = 1;
|
|
b->ordinal = ordinal;
|
|
b->addend = 0;
|
|
b->reserved = 0;
|
|
return ret;
|
|
}
|
|
|
|
uint32_t MakeImportTableEntry(uint32_t lib_ordinal, uint32_t name_offset) {
|
|
printf("append import table\n");
|
|
uint32_t ret;
|
|
struct dyld_chained_import* import = (struct dyld_chained_import*)&ret;
|
|
import->lib_ordinal = lib_ordinal;
|
|
import->name_offset = name_offset;
|
|
import->weak_import = 0;
|
|
return ret;
|
|
}
|
|
|
|
void ParseFixUps(uint8_t* buffer) {
|
|
struct dyld_chained_fixups_header* header = (struct dyld_chained_fixups_header*)buffer;
|
|
printf("starts=0x%x\n", header->starts_offset);
|
|
printf("imports start=0x%x\n", header->imports_offset);
|
|
printf("symbols start=0x%x\n", header->symbols_offset);
|
|
printf("imports count=0x%x\n", header->imports_count);
|
|
printf("imports format=0x%x\n", header->imports_format);
|
|
printf("symbols format=0x%x\n", header->symbols_format);
|
|
|
|
char* symbols_table = (char*)(buffer + header->symbols_offset);
|
|
struct dyld_chained_import* imports_table = (struct dyld_chained_import*)(buffer + header->imports_offset);
|
|
for (int i = 0; i < header->imports_count; i++) {
|
|
struct dyld_chained_import import = imports_table[i];
|
|
char* name = symbols_table + import.name_offset;
|
|
printf("(%d)%s\n", import.lib_ordinal, name);
|
|
}
|
|
|
|
struct dyld_chained_starts_in_image* segment = (struct dyld_chained_starts_in_image*)(buffer + header->starts_offset);
|
|
|
|
for (int i = 0; i < segment->seg_count; i++) {
|
|
printf("segment %d\n", i);
|
|
uint32_t offset = segment->seg_info_offset[i];
|
|
if (offset == 0) continue;
|
|
struct dyld_chained_starts_in_segment* chain_header = (struct dyld_chained_starts_in_segment*)((char*)segment + offset);
|
|
|
|
printf("segment_offset=0x%llx\n", chain_header->segment_offset);
|
|
printf("page count=0x%x\n", chain_header->page_count);
|
|
}
|
|
}
|