2023-02-10 05:44:06 +02:00

345 lines
9.5 KiB
C

#include "elf.h"
struct LibAddressCollection
{
char Name[32];
__UINTPTR_TYPE__ *ElfFile;
__UINTPTR_TYPE__ *MemoryImage;
__UINTPTR_TYPE__ *ParentElfFile;
__UINTPTR_TYPE__ *ParentMemoryImage;
struct LibAddressCollection *Next;
char Valid;
};
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
static char Lock = 0;
__attribute__((naked, used, no_stack_protector)) void ELF_LAZY_RESOLVE_STUB()
{
while (Lock == 1)
;
__asm__ __volatile__("mfence\n");
Lock = 1;
__asm__ __volatile__("pop %r11\n"
"pop %r10\n"
"push %rdi\n"
"push %rsi\n"
"push %rdx\n"
"push %rcx\n"
"push %r8\n"
"push %r9\n"
"mov %r11, %rdi\n"
"mov %r10, %rsi\n"
"call ELF_LAZY_RESOLVE_MAIN\n"
"mov %rax, %r11\n"
"pop %r9\n"
"pop %r8\n"
"pop %rcx\n"
"pop %rdx\n"
"pop %rsi\n"
"pop %rdi\n"
"jmp *%r11\n");
}
long abs(long i) { return i < 0 ? -i : i; }
void swap(char *x, char *y)
{
char t = *x;
*x = *y;
*y = t;
}
char *reverse(char *Buffer, int i, int j)
{
while (i < j)
swap(&Buffer[i++], &Buffer[j--]);
return Buffer;
}
char *ltoa(long Value, char *Buffer, int Base)
{
if (Base < 2 || Base > 32)
return Buffer;
long n = abs(Value);
int i = 0;
while (n)
{
int r = n % Base;
if (r >= 10)
Buffer[i++] = 65 + (r - 10);
else
Buffer[i++] = 48 + r;
n = n / Base;
}
if (i == 0)
Buffer[i++] = '0';
if (Value < 0 && Base == 10)
Buffer[i++] = '-';
Buffer[i] = '\0';
return reverse(Buffer, 0, i - 1);
}
static inline void PutCharToKernelConsole(char c)
{
__asm__ __volatile__("syscall"
:
: "a"(1), "D"(c), "S"(0)
: "rcx", "r11", "memory");
}
void *memcpy(void *dest, const void *src, __SIZE_TYPE__ n)
{
__UINT8_TYPE__ *d = dest;
const __UINT8_TYPE__ *s = src;
while (n--)
*d++ = *s++;
return dest;
}
int strcmp(const char *l, const char *r)
{
for (; *l == *r && *l; l++, r++)
;
return *(unsigned char *)l - *(unsigned char *)r;
}
Elf64_Sym *ELFGetSymbol(__UINTPTR_TYPE__ *ElfFile, char *SymbolName)
{
struct Elf64_Dyn *_SymTab = ELFGetDynamicTag(ElfFile, DT_SYMTAB);
struct Elf64_Dyn *_StrTab = ELFGetDynamicTag(ElfFile, DT_STRTAB);
Elf64_Sym *DynSym = (Elf64_Sym *)(ElfFile + _SymTab->d_un.d_ptr);
char *DynStr = (char *)(ElfFile + _StrTab->d_un.d_ptr);
for (int i = 0; i < _SymTab->d_un.d_val; i++)
{
if (strcmp(DynStr + DynSym[i].st_name, SymbolName) == 0)
return &DynSym[i];
}
return (Elf64_Sym *)0;
}
void Print(char *String)
{
for (short i = 0; String[i] != '\0'; i++)
PutCharToKernelConsole(String[i]);
}
void PrintNL(char *String)
{
for (short i = 0; String[i] != '\0'; i++)
PutCharToKernelConsole(String[i]);
PutCharToKernelConsole('\n');
}
long RelTmpIndex = 0xdead;
void *SymbolNotFound()
{
// TODO: Print the symbol name and the library name.
// TODO: This should go to the stderr.
char Buffer[32];
Print("Symbol index ");
ltoa(RelTmpIndex, Buffer, 10);
Print(Buffer);
PrintNL(" not found");
return (void *)0xdeadbeef;
}
void (*ELF_LAZY_RESOLVE_MAIN(struct LibAddressCollection *Info, long RelIndex))()
{
RelTmpIndex = RelIndex;
if (Info)
{
struct LibAddressCollection *tmp = Info;
PrintNL("________________");
// The last entry is the null entry (Valid == false) which determines the end of the list.
while (tmp->Valid)
{
Print("-- ");
Print(tmp->Name);
PrintNL(" --");
__UINTPTR_TYPE__ BaseAddress = __UINTPTR_MAX__;
Elf64_Phdr ItrProgramHeader;
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)tmp->ElfFile)->e_phnum; i++)
{
memcpy(&ItrProgramHeader, (__UINT8_TYPE__ *)tmp->ElfFile + ((Elf64_Ehdr *)tmp->ElfFile)->e_phoff + ((Elf64_Ehdr *)tmp->ElfFile)->e_phentsize * i, sizeof(Elf64_Phdr));
BaseAddress = MIN(BaseAddress, ItrProgramHeader.p_vaddr);
}
char LibAddressBuffer[32];
ltoa(tmp->MemoryImage, LibAddressBuffer, 16);
Print("MemoryImage: 0x");
PrintNL(LibAddressBuffer);
char BaseAddressBuffer[32];
ltoa(BaseAddress, BaseAddressBuffer, 16);
Print("BaseAddress: 0x");
PrintNL(BaseAddressBuffer);
struct Elf64_Dyn *_JmpRel = ELFGetDynamicTag(tmp->ElfFile, DT_JMPREL);
struct Elf64_Dyn *_SymTab = ELFGetDynamicTag(tmp->ElfFile, DT_SYMTAB);
struct Elf64_Dyn *_StrTab = ELFGetDynamicTag(tmp->ElfFile, DT_STRTAB);
if (!_JmpRel)
{
PrintNL("No DT_JMPREL");
goto RetryNextLib;
}
else if (RelIndex >= _JmpRel->d_un.d_val / sizeof(Elf64_Rela))
{
PrintNL("RelIndex is greater than the number of relocations");
goto RetryNextLib;
}
if (!_SymTab)
{
PrintNL("No DT_SYMTAB");
goto RetryNextLib;
}
if (!_StrTab)
{
PrintNL("No DT_STRTAB");
goto RetryNextLib;
}
if (!_JmpRel && !_SymTab && !_StrTab)
goto RetryNextLib;
char JmpRel_d_ptr[32];
ltoa(_JmpRel->d_un.d_ptr, JmpRel_d_ptr, 16);
Print("JmpRel_d_ptr: 0x");
PrintNL(JmpRel_d_ptr);
char SymTab_d_ptr[32];
ltoa(_SymTab->d_un.d_ptr, SymTab_d_ptr, 16);
Print("SymTab_d_ptr: 0x");
PrintNL(SymTab_d_ptr);
char StrTab_d_ptr[32];
ltoa(_StrTab->d_un.d_ptr, StrTab_d_ptr, 16);
Print("StrTab_d_ptr: 0x");
PrintNL(StrTab_d_ptr);
Elf64_Rela *JmpRel = tmp->MemoryImage + (_JmpRel->d_un.d_ptr - BaseAddress);
Elf64_Sym *SymTab = tmp->MemoryImage + (_SymTab->d_un.d_ptr - BaseAddress);
char *DynStr = tmp->MemoryImage + (_StrTab->d_un.d_ptr - BaseAddress);
Elf64_Rela *Rel = JmpRel + RelIndex;
// Elf64_Rela *Rel = &JmpRel[RelIndex];
Elf64_Addr *GOTEntry = (Elf64_Addr *)(tmp->MemoryImage + Rel->r_offset);
int RelType = ELF64_R_TYPE(Rel->r_info);
char RelBuffer[32];
ltoa(Rel, RelBuffer, 16);
Print("Rel: 0x");
PrintNL(RelBuffer);
char LibRelInfoBuffer[32];
ltoa(Rel->r_info, LibRelInfoBuffer, 16);
Print(" Rel->r_info: 0x");
PrintNL(LibRelInfoBuffer);
char LibRelOffsetBuffer[32];
ltoa(Rel->r_offset, LibRelOffsetBuffer, 16);
Print(" Rel->r_offset: 0x");
PrintNL(LibRelOffsetBuffer);
char LibRelAddEntBuffer[32];
ltoa(Rel->r_addend, LibRelAddEntBuffer, 16);
Print(" Rel->r_addend: 0x");
PrintNL(LibRelAddEntBuffer);
char RelIndexBuffer[32];
ltoa(RelIndex, RelIndexBuffer, 16);
Print("RelIndex: 0x");
PrintNL(RelIndexBuffer);
char GotAddressBuffer[32];
ltoa(GOTEntry, GotAddressBuffer, 16);
Print("GOTEntry: 0x");
PrintNL(GotAddressBuffer);
if (GOTEntry && GOTEntry < 0x10000000)
{
char GotInsideBuffer[32];
ltoa(*GOTEntry, GotInsideBuffer, 16);
Print("*GOTEntry: 0x");
PrintNL(GotInsideBuffer);
}
switch (RelType)
{
case R_X86_64_NONE:
{
PrintNL("R_X86_64_NONE");
if (*GOTEntry == 0)
{
PrintNL("GOTEntry is 0");
break;
}
Lock = 0;
return (void (*)()) * GOTEntry;
}
case R_X86_64_JUMP_SLOT:
{
PrintNL("R_X86_64_JUMP_SLOT");
int SymIndex = ELF64_R_SYM(Rel->r_info);
Elf64_Sym *Sym = SymTab + SymIndex;
// Elf64_Sym *Sym = &SymTab[SymIndex];
if (Sym->st_name)
{
char *SymName = DynStr + Sym->st_name;
PrintNL(SymName);
Elf64_Sym *LibSym = ELFGetSymbol(tmp->ElfFile, SymName);
if (LibSym)
{
*GOTEntry = (Elf64_Addr)(tmp->MemoryImage + LibSym->st_value);
Lock = 0;
return (void (*)()) * GOTEntry;
}
}
break;
}
default:
{
char RelTypeBuffer[32];
ltoa(RelType, RelTypeBuffer, 10);
Print("RelType not supported ");
PrintNL(RelTypeBuffer);
break;
}
}
RetryNextLib:
tmp = tmp->Next;
}
}
Lock = 0;
__asm__ __volatile__("mfence\n");
return SymbolNotFound;
}