README.md
Rendering markdown...
const sizeof_Elf64_Ehdr = 64n;
const sizeof_Elf64_Phdr = 56n;
const sizeof_Elf64_Dyn = 16n;
const sizeof_Elf64_Rela = 24n;
const sizeof_Elf64_Sym = 24n;
const offsetof_phnum = 56n;
const offsetof_phoff = 32n;
const offsetof_p_type = 0n;
const offsetof_p_flags = 4n;
const offsetof_p_filesz = 32n;
const offsetof_p_vaddr = 16n;
const offsetof_d_tag = 0n;
const offsetof_d_un_d_val = 8n;
const offsetof_r_info = 8n;
const offsetof_st_name = 0n;
const offsetof_st_value = 8n;
const PT_DYNAMIC = 2n;
const DT_PLTGOT = 3n;
const DT_JMPREL = 23n;
const DT_PLTRELSZ = 2n;
const DT_SYMTAB = 6n;
const DT_STRTAB = 5n;
const DT_STRSZ = 10n;
const DT_RELAENT = 9n;
const DT_RELA = 7n;
const DT_RELASZ = 8n;
const DT_HASH = 4n
const AT_PHDR = 3n;
const AT_PHNUM = 5n;
const AT_ENTRY = 9n;
const AT_RANDOM = 25n;
const AT_PHENT = 4n;
const AT_NULL = 0n
const R_X86_64_GLOB_DAT = 6n;
const R_X86_64_JUMP_SLOT = 7n;
class Elf {
constructor(base_addr, reader) {
this.reader = reader;
this.base_addr = base_addr;
}
read(addr, len) {
let result = 0;
let offset = Number(addr - this.base_addr)
if (len == 1) {
result = this.reader.getUint8(offset)
} else if (len == 2) {
result = this.reader.getUint16(offset, true)
} else if (len == 4) {
result = this.reader.getUint32(offset, true)
} else {
result = this.reader.getBigUint64(offset, true);
}
return result;
}
elf_hash(sym_name) {
let h = 0;
let g;
let char;
for (let i = 0; i < sym_name.length; i++) {
char = Number(sym_name.charCodeAt(i))
h = (h << 4) + char;
g = h & 0xf0000000;
if (g) {
h ^= g >> 24;
}
h &= ~g;
}
return h;
}
resolve_symbol(sym_name) {
let dyn_phdr;
console.log("[+] Resolving symbolfrom ELF image at 0x" + this.base_addr.toString(16));
let phnum = this.read(this.base_addr + offsetof_phnum, 2);
let phoff = this.read(this.base_addr + offsetof_phoff, 8);
for (var i = 0n; i < phnum; i++) {
let phdr_offset = phoff + (sizeof_Elf64_Phdr * i);
let p_type = this.read(this.base_addr + phdr_offset + offsetof_p_type, 4);
if (p_type == PT_DYNAMIC) {
dyn_phdr = i;
}
}
let dyn_phdr_filesz = this.read(this.base_addr + phoff + sizeof_Elf64_Phdr * dyn_phdr + offsetof_p_filesz, 8);
let dyn_phdr_vaddr = this.read(this.base_addr + phoff + sizeof_Elf64_Phdr * dyn_phdr + offsetof_p_vaddr, 8);
for (let i = 0n; i < dyn_phdr_filesz/sizeof_Elf64_Dyn; i++) {
let dyn_offset = BigInt(dyn_phdr_vaddr + sizeof_Elf64_Dyn * i);
let d_tag = this.read(this.base_addr + dyn_offset + offsetof_d_tag, 8);
let d_val = this.read(this.base_addr + dyn_offset + offsetof_d_un_d_val, 8);
switch (d_tag) {
case DT_SYMTAB:
this.symtab = d_val;
console.log("\t[+] DT_SYMTAB found: 0x" + this.symtab.toString(16))
break;
case DT_STRTAB:
this.strtab = d_val;
console.log("\t[+] DT_STRTAB found: 0x" + this.strtab.toString(16))
break;
}
}
function lookup(sym_name) {
let i = 0n;
let sym_ptr;
let sym_str = "";
let char;
while(true) {
let sym_offset = BigInt(this.symtab + (i * sizeof_Elf64_Sym));
let st_name = this.read(sym_offset, 4);
if (st_name === 0n) {
continue
}
let sym_str_addr = this.strtab + BigInt(st_name);
while (true) {
char = this.read(sym_str_addr, 1);
if (char == 0)
break;
sym_str += String.fromCharCode(char);
sym_str_addr++;
}
i += 1n;
sym_str += String.fromCharCode(0);
if (sym_name == sym_str) {
sym_ptr = this.base_addr + this.read(sym_offset + offsetof_st_value, 8);
console.log("\t[+] " + str + " : " + ptr.toString(16))
break;
}
};
return sym_ptr;
}
return lookup(sym_name);
}
resolve_symbol_quick(sym_name) {
let dyn_phdr;
let phnum = BigInt(this.read(this.base_addr + offsetof_phnum, 2));
let phoff = BigInt(this.read(this.base_addr + offsetof_phoff, 8));
for (let i = 0n; i < phnum; i++) {
let offset = BigInt(phoff + sizeof_Elf64_Phdr * i);
let p_type = BigInt(this.read(this.base_addr + offset + offsetof_p_type, 4));
if (p_type == PT_DYNAMIC) {
dyn_phdr = i;
}
}
let dyn_phdr_filesz = BigInt(this.read(this.base_addr + phoff + sizeof_Elf64_Phdr * dyn_phdr + offsetof_p_filesz, 8));
let dyn_phdr_vaddr = BigInt(this.read(this.base_addr + phoff + sizeof_Elf64_Phdr * dyn_phdr + offsetof_p_vaddr, 8));
let strtab, symtab, dthash;
for (let i = 0n; i < dyn_phdr_filesz/sizeof_Elf64_Dyn; i++) {
let offset = BigInt(dyn_phdr_vaddr + sizeof_Elf64_Dyn * i);
let d_tag = BigInt(this.read(this.base_addr + offset + offsetof_d_tag, 8));
let d_val = BigInt(this.read(this.base_addr + offset + offsetof_d_un_d_val, 8));
switch (d_tag) {
case DT_SYMTAB:
this.symtab = d_val;
break;
case DT_STRTAB:
this.strtab = d_val;
break;
case DT_HASH:
this.dthash = d_val;
default:
break;
}
}
function lookup(name_hash, hashtab, symtab, strtab) {
let nbuckets = BigInt(this.read(hashtab + (0n * 4n), 4));
let nchains = BigInt(this.read(hashtab + (1n * 4n), 4));
let buckets = BigInt(hashtab + (2n* 4n));
let chains = BigInt(buckets + (nbuckets * 4n));
let h = BigInt(name_hash) % nbuckets;
for (let i = this.read(buckets + (h * 4n), 4); i != 0n; i = this.read(chains + (i * 4n), 4)) {
sym_offset = this.symtab + (i * sizeof_Elf64_Sym);
st_name = this.read(sym_offset + offsetof_st_name, 4);
let sym_str_addr = this.strtab + BigInt(st_name);
while (true) {
char = this.read(sym_str_addr, 1);
if (char == 0)
break;
sym_str += String.fromCharCode(char);
sym_str_addr++;
}
if (elf_hash(sym_str) == name_hash) {
return this.base_addr + this.read(sym_offset + offsetof_st_value, 4);
}
}
return 0n;
}
let sym_hash = this.elf_hash(sym_name);
return lookup(sym_hash, dthash, symtab, strtab);
}
resolve_reloc(sym_name, sym_type) {
let dyn_phdr;
console.log("[+] Resolving relocs for image at 0x"+this.base_addr.toString(16));
let phnum = this.read(this.base_addr + offsetof_phnum, 2);
let phoff = this.read(this.base_addr + offsetof_phoff, 8);
for (let i = 0n; i < phnum; i++) {
let offset = phoff + sizeof_Elf64_Phdr * i;
let p_type = this.read(this.base_addr + offset + offsetof_p_type, 4);
if (p_type == PT_DYNAMIC) {
dyn_phdr = i;
}
}
let dyn_phdr_filesz = this.read(this.base_addr + phoff + sizeof_Elf64_Phdr * dyn_phdr + offsetof_p_filesz, 8);
let dyn_phdr_vaddr = this.read(this.base_addr + phoff + sizeof_Elf64_Phdr * dyn_phdr + offsetof_p_vaddr, 8);
for (let i = 0n; i < dyn_phdr_filesz/sizeof_Elf64_Dyn; i++) {
let dyn_offset = dyn_phdr_vaddr + sizeof_Elf64_Dyn * i;
let d_tag = this.read(this.base_addr + dyn_offset + offsetof_d_tag, 8);
let d_val = this.read(this.base_addr + dyn_offset + offsetof_d_un_d_val, 8);
switch (d_tag) {
case DT_JMPREL:
this.jmprel = d_val;
break;
case DT_PLTRELSZ:
this.pltrelsz = d_val;
break;
case DT_PLTGOT:
this.pltgot = d_val;
break;
case DT_SYMTAB:
this.symtab = d_val;
break;
case DT_STRTAB:
this.strtab = d_val;
break;
case DT_STRSZ:
this.strsz = d_val;
break;
case DT_RELAENT:
this.relaent = d_val;
break;
case DT_RELA:
this.rel = d_val;
break;
case DT_RELASZ:
this.relasz = d_val;
break;
default:
break;
}
}
let centinel, size;
if (sym_type == R_X86_64_GLOB_DAT) {
centinel = this.rel;
size = this.relasz/this.relaent;
} else {
centinel = this.jmprel;
size = this.pltrelsz/this.relaent;
}
for (let i = 0n; i < size; i++) {
let rela_offset = centinel + (sizeof_Elf64_Rela * i);
let r_type = this.read(rela_offset + offsetof_r_info + 0n, 4);
let r_sym = this.read(rela_offset + offsetof_r_info + 4n, 4);
let sym_address;
if (r_type == sym_type) {
let sym_offset = this.symtab + BigInt(r_sym) * sizeof_Elf64_Sym;
if (sym_offset == 0n) {
continue;
}
let st_name = this.read(sym_offset + offsetof_st_name, 4);
if (st_name == 0n) {
continue;
}
if (sym_type == R_X86_64_GLOB_DAT) {
sym_address = this.base_addr + BigInt(this.read(sym_offset + offsetof_st_value, 4));
} else {
sym_address = this.pltgot + (i + 3n) * 8n;
}
if (st_name === 0n) {
continue
}
let sym_str_addr = this.strtab + BigInt(st_name);
let sym_str = "";
let char
while (true) {
char = this.read(sym_str_addr, 1);
if (char == 0)
break;
sym_str += String.fromCharCode(char);
sym_str_addr++;
}
if (sym_name == sym_str) {
return sym_address;
}
}
}
}
}