Ein Beispiel für ELF Relocation kann ich dir geben:
Es ist noch zu beachten, das man damit den Kernel sehr leicht mit korrupten ELF Files manipulieren kann, da mein Code weitgehend nicht überprüft ob die Werte der ELF File gültig sind. Falls du den Code in deinem OS benutzt solltest du also überprüfen ob die Pointer auf gültige Stellen in der ELF File zeigen.
Es sind ausserdem grundlegende libc Funktionen nötig um den Code auszuführen. ( strcmp(), memcpy() usw. )
Ausserdem sind vieleicht meine Structs nicht so sehr leicht zu verstehen, da die Namen nicht alle selbstdokumentierend sind ^^;; und der Code ist nicht sehr gut dokumentiert.
typedef unsigned long u32;
typedef unsigned short u16;
typedef unsigned char u8;
typedef long s32;
typedef short s16;
#define ELF386_SEC_SYMTABLE 2
#define ELF386_R_32 1
#define ELF386_R_PC32 2
#define ELF386_R_SYMBOL(z) ( (z) >> 8 )
#define ELF386_R_TYPE(z) ( (unsigned char)(z) )
#define ELF386_ST_BINDING(z) ( (z) >> 4 )
#define ELF386_ST_TYPE(z) ( (z) & 0xF )
#define ELF386_MAGINDEX_0 0
#define ELF386_MAGINDEX_1 1
#define ELF386_MAGINDEX_2 2
#define ELF386_MAGINDEX_3 3
#define ELF386_MAG_0 0x7F
#define ELF386_MAG_1 'E'
#define ELF386_MAG_2 'L'
#define ELF386_MAG_3 'F'
typedef struct {
u8 elfMagic[16];
u16 elfType;
u16 elfMachine;
u32 elfVersion;
u32 elfEntry;
u32 elfProgramOffset;
u32 elfSectionOffset;
u32 elfFlags;
u16 elfHeaderSize;
u16 elfProgramSize;
u16 elfProgramCount;
u16 elfSectionSize;
u16 elfSectionCount;
u16 elfStringSection;
} __attribute__ ((packed)) elf386Header;
typedef struct {
u32 sectionName;
u32 sectionType;
u32 sectionFlags;
u32 sectionAddress;
u32 sectionOffset;
u32 sectionSize;
u32 sectionLink;
u32 sectionInfo;
u32 sectionAlign;
u32 sectionEntrySize;
} __attribute__ ((packed)) elf386Section;
typedef struct {
u32 symbolName;
u32 symbolValue;
u32 symbolSize;
u8 symbolInfo;
u8 symbolOther;
u16 symbolSection;
} __attribute__ ((packed)) elf386Symbol;
typedef struct {
u32 relocOffset;
u32 relocInfo;
s32 relocAdded;
} __attribute__ ((packed)) elf386Relocation;
typedef struct {
u32 programType;
u32 programOffset;
u32 programVirtualAddress;
u32 programPhysicalAddress;
u32 programFileSize;
u32 programSize;
u32 programFlags;
u32 programAlign;
} __attribute__ ((packed)) elf386ProgramHeader;
void *elf386LoadModule( char *image, unsigned long size );
int elf386Relocate( char *image );
int elf386DoRelocation( char *image, elf386Section *section, elf386Relocation *relocation );
unsigned long elf386GetSymbol( char *image, unsigned long symbolTable, unsigned long symbolID );
void *elf386GetSymbolOffset( char *image, char *name );
// in memory.h steht die Funktion allocateSystemMemory(), die benutzt wird um die Module zu laden.
#include "../memory.h"
#include "string.h"
void *elf386LoadModule( char* image, unsigned long size ) {
elf386Header *header = (elf386Header *)image;
elf386Section *section;
if ((header->elfMagic[ELF386_MAGINDEX_0] != ELF386_MAG_0) ||
(header->elfMagic[ELF386_MAGINDEX_1] != ELF386_MAG_1) ||
(header->elfMagic[ELF386_MAGINDEX_2] != ELF386_MAG_2) ||
(header->elfMagic[ELF386_MAGINDEX_3] != ELF386_MAG_3)) {
return -1;
}
unsigned long bssSize;
// loop trough the sections and look for the bss section
unsigned long i;
for( i = 0; i < header->elfSectionCount; i++ ) {
section = (elf386Section *)( image + header->elfSectionOffset + header->elfSectionSize * i );
if( section->sectionType != 8 )
continue;
bssSize = section->sectionSize;
break;
}
// allocate memory for the module
void *module = (void *)allocateSystemMemory( size + bssSize );
// copy the image into memory
memcpy( module, image, size );
// zero the bss section
memset( module + size, 0, bssSize );
// setup the bss section
section->sectionOffset = (u32)module + size;
return module;
}
int elf386Relocate( char *image ) {
unsigned long i;
unsigned long j;
elf386Section *section;
elf386Header *header = (elf386Header *)image;
elf386Relocation *relocation;
if ((header->elfMagic[ELF386_MAGINDEX_0] != ELF386_MAG_0) ||
(header->elfMagic[ELF386_MAGINDEX_1] != ELF386_MAG_1) ||
(header->elfMagic[ELF386_MAGINDEX_2] != ELF386_MAG_2) ||
(header->elfMagic[ELF386_MAGINDEX_3] != ELF386_MAG_3)) {
return -1;
}
unsigned long relocSize;
// now we loop trough the sections and look for relocation infos
for( i = 0; i < header->elfSectionCount; i++ ) {
section = (elf386Section *)( image + header->elfSectionOffset + header->elfSectionSize * i );
if( section->sectionType == 4 ) {
relocSize = 12;
}else if( section->sectionType == 9 ) {
relocSize = 8;
}else{
continue;
}
// the section contains relocation infos
for( j = 0; j < section->sectionSize / relocSize; j++ ) {
relocation = (elf386Relocation *)( image + section->sectionOffset + relocSize * j );
// do the relocation
elf386DoRelocation( image, section, relocation );
}
}
}
int elf386DoRelocation( char *image, elf386Section *section, elf386Relocation *relocation ) {
elf386Header *header = (elf386Header *)image;
elf386Section *targetSection = (elf386Section *)(image + header->elfSectionOffset + header->elfSectionSize * section->sectionInfo);
unsigned long *relocationOffset = (unsigned long *)( image + targetSection->sectionOffset + relocation->relocOffset );
unsigned long symbol = elf386GetSymbol( image, section->sectionLink, ELF386_R_SYMBOL( relocation->relocInfo ) );
switch( ELF386_R_TYPE( relocation->relocInfo ) ) {
case ELF386_R_32 :
*relocationOffset = *relocationOffset + symbol;
break;
case ELF386_R_PC32 :
*relocationOffset = *relocationOffset + symbol - (unsigned long)relocationOffset;
break;
}
}
unsigned long elf386GetSymbol( char *image, unsigned long symbolTable, unsigned long symbolID ) {
elf386Header *header = (elf386Header *)image;
elf386Section *table = (elf386Section *)( image + header->elfSectionOffset + header->elfSectionSize * symbolTable );
elf386Symbol *symbol = (elf386Symbol *)( image + table->sectionOffset ) + symbolID;
elf386Section *section;
if( symbol->symbolSection == 0 ) {
// external symbol
section = (elf386Section *)( image + header->elfSectionOffset + header->elfSectionSize * table->sectionLink );
return lookupExternalSymbols( (char *)( image + section->sectionOffset + symbol->symbolName ) );
}else{
// internal symbol
section = (elf386Section *)( image + header->elfSectionOffset + header->elfSectionSize * symbol->symbolSection );
return (unsigned long)( image + section->sectionOffset + symbol->symbolValue );
}
}
void *elf386GetSymbolOffset( char *image, char *name ) {
elf386Header *header = (elf386Header *)image;
elf386Section *section;
elf386Section *strings;
elf386Symbol *symbol;
elf386Section *symbolSection;
if ((header->elfMagic[ELF386_MAGINDEX_0] != ELF386_MAG_0) ||
(header->elfMagic[ELF386_MAGINDEX_1] != ELF386_MAG_1) ||
(header->elfMagic[ELF386_MAGINDEX_2] != ELF386_MAG_2) ||
(header->elfMagic[ELF386_MAGINDEX_3] != ELF386_MAG_3)) {
return 0;
}
// loop trough the sections and look for the text section
unsigned long i;
unsigned long j;
for( i = 0; i < header->elfSectionCount; i++ ) {
section = (elf386Section *)( image + header->elfSectionOffset + header->elfSectionSize * i );
if( section->sectionType == ELF386_SEC_SYMTABLE ) {
strings = (elf386Section *)( image + header->elfSectionOffset + header->elfSectionSize * section->sectionLink );
for( j = 0; j < section->sectionSize / sizeof( elf386Symbol ); j++ ) {
symbol = (elf386Symbol *)( image + section->sectionOffset ) + j;
if( strcmp( image + strings->sectionOffset + symbol->symbolName, name ) == 0 ) {
symbolSection = (elf386Section *)( image + header->elfSectionOffset + header->elfSectionSize * symbol->symbolSection );
return image + symbolSection->sectionOffset + symbol->symbolValue;
}
}
}
}
return 0;
}
Die Funktion allocateSystemMemory() allocated Speicher und mappet ihn in alle Prozesse.
elf386LoadModule() läd ein Modul, das dann noch mit elf386Relocate() relocated werden muss. Die Funktionen elf386DoRelocation() und elf386GetSymbol() sind Hilffunktionen für elf386Relocate. elf386DoRelocation() führt das eigentliche relocaten durch, ersetzt also die Offsets innerhalb der ELF File durch die richtigen Werte. elf386GetSymbol() liefert das Offset eines Symbols, das für den Relocation Vorgang benötigt wird.
elf386GetSymbolOffset() wird benutzt, um z.b. das Offset der main() Funktion zu erhalten.
lookupExternalSymbols( char *name ) kann etwa so aussehen:
void *lookupExternalSymbols( char *name ) {
if( strcmp( name, "printf" ) == 0 ) {
return (void *)printf;
}
}
Ein Beispielcode wie du den Code oben benutzen kannst findest du hier.
Dieser Code führt ein von GRUB geladenes Modul aus.
Die Variable module zeigt auf ein Modul der multibootinfo Struktur.
argc und argv sind Variablen, in denen die Parameter des Modules stehen.
void *kmod = elf386LoadModule( module->mod_start, module->mod_end - module->mod_start );
elf386Relocate( kmod );
void (*entry)( int, char ** ) = elf386GetSymbolOffset( kmod, "main" );
entry( argc, argv );
Das sollte dann die main Funktion mit den Argumenten argc und argv ausführen.
Zu beachten ist noch, das unter Windows standardmässig den Funktionen ein _ vorgestellt wird, du solltest unter Windows also
void (*entry)( int, char ** ) = elf386GetSymbolOffset( kmod, "_main" ); benutzen.