draugr.git


draugr

~ single ELF file analysis tool
git clone https://github.com/djnnvx/draugr.git
log | files | refs | archive | README

json.odin (4943B)

      1 package elf
      2 
      3 import "core:encoding/json"
      4 import "core:fmt"
      5 
      6 Json_Symbol :: struct {
      7 	name  : string,
      8 	value : u64,
      9 	size  : u64,
     10 	bind  : string,
     11 	type  : string,
     12 	shndx : u16,
     13 }
     14 
     15 Json_Section :: struct {
     16 	index  : int,
     17 	name   : string,
     18 	type   : string,
     19 	addr   : u64,
     20 	offset : u64,
     21 	size   : u64,
     22 	flags  : u64,
     23 }
     24 
     25 Json_Segment :: struct {
     26 	type   : string,
     27 	flags  : string,
     28 	offset : u64,
     29 	vaddr  : u64,
     30 	paddr  : u64,
     31 	filesz : u64,
     32 	memsz  : u64,
     33 	align  : u64,
     34 }
     35 
     36 Json_Dyn :: struct {
     37 	tag   : string,
     38 	value : u64,
     39 	name  : string,
     40 }
     41 
     42 Json_Reloc :: struct {
     43 	offset : u64,
     44 	type   : string,
     45 	addend : i64,
     46 	symbol : string,
     47 	source : string,
     48 }
     49 
     50 Json_Checksec :: struct {
     51 	relro       : string,
     52 	nx          : string,
     53 	pie         : string,
     54 	canary      : bool,
     55 	textrel     : bool,
     56 	rwx_segment : bool,
     57 	rpath       : string,
     58 	runpath     : string,
     59 	stripped    : bool,
     60 	fortified   : int,
     61 	fortifiable : int,
     62 	partial     : int,
     63 }
     64 
     65 Json_Dump :: struct {
     66 	class           : int,
     67 	endian          : string,
     68 	type            : string,
     69 	machine         : string,
     70 	entry           : u64,
     71 	flags           : u32,
     72 	pie             : bool,
     73 	is_dynamic      : bool,
     74 	interp_offset   : u64,
     75 	soname          : string,
     76 	rpath           : string,
     77 	runpath         : string,
     78 	needed          : []string,
     79 	segments        : []Json_Segment,
     80 	sections        : []Json_Section,
     81 	dynamic_entries : []Json_Dyn,
     82 	symbols         : []Json_Symbol,
     83 	dyn_symbols     : []Json_Symbol,
     84 	relocations     : []Json_Reloc,
     85 	got             : map[string]u64,
     86 	checksec        : Json_Checksec,
     87 }
     88 
     89 build_json_dump :: proc(info: ^ELF_Info, allocator := context.allocator) -> Json_Dump {
     90 	segments := make([]Json_Segment, len(info.program_hdrs), allocator)
     91 	for ph, i in info.program_hdrs {
     92 		segments[i] = Json_Segment{
     93 			type   = segment_type_str(ph.type),
     94 			flags  = flags_to_str(ph.flags),
     95 			offset = ph.offset,
     96 			vaddr  = ph.vaddr,
     97 			paddr  = ph.paddr,
     98 			filesz = ph.filesz,
     99 			memsz  = ph.memsz,
    100 			align  = ph.align,
    101 		}
    102 	}
    103 
    104 	sections := make([]Json_Section, len(info.section_hdrs), allocator)
    105 	for shdr, i in info.section_hdrs {
    106 		sections[i] = Json_Section{
    107 			index  = i,
    108 			name   = get_section_name(info, shdr),
    109 			type   = section_type_str(shdr.type),
    110 			addr   = shdr.addr,
    111 			offset = shdr.offset,
    112 			size   = shdr.size,
    113 			flags  = shdr.flags,
    114 		}
    115 	}
    116 
    117 	dyn := make([]Json_Dyn, len(info.dyn_entries), allocator)
    118 	for e, i in info.dyn_entries {
    119 		dyn[i] = Json_Dyn{tag = dyn_tag_str(e.tag), value = e.val, name = dyn_string(info, e)}
    120 	}
    121 
    122 	relocs := make([]Json_Reloc, len(info.relocs), allocator)
    123 	got := make(map[string]u64, allocator)
    124 	for r, i in info.relocs {
    125 		relocs[i] = Json_Reloc{
    126 			offset = r.offset,
    127 			type   = reloc_type_str(info.header.machine, r.type),
    128 			addend = r.addend,
    129 			symbol = r.sym_name,
    130 			source = r.source,
    131 		}
    132 		if is_jump_slot(info.header.machine, r.type) && r.sym_name != "" {
    133 			got[r.sym_name] = r.offset
    134 		}
    135 	}
    136 
    137 	c := checksec(info)
    138 
    139 	return Json_Dump{
    140 		class           = 64 if info.is_64bit else 32,
    141 		endian          = "little" if info.header.data == ELF_DATA_LSB else "big",
    142 		type            = type_to_str(info.header.type),
    143 		machine         = machine_to_str(info.header.machine),
    144 		entry           = info.header.entry,
    145 		flags           = info.header.flags,
    146 		pie             = info.is_pie,
    147 		is_dynamic      = info.is_dynamic,
    148 		interp_offset   = info.interp_offset,
    149 		soname          = info.soname,
    150 		rpath           = info.rpath,
    151 		runpath         = info.runpath,
    152 		needed          = info.needed[:],
    153 		segments        = segments,
    154 		sections        = sections,
    155 		dynamic_entries = dyn,
    156 		symbols         = to_json_symbols(info.symbols[:], allocator),
    157 		dyn_symbols     = to_json_symbols(info.dyn_symbols[:], allocator),
    158 		relocations     = relocs,
    159 		got             = got,
    160 		checksec        = Json_Checksec{
    161 			relro       = relro_str(c.relro),
    162 			nx          = nx_str(c.nx),
    163 			pie         = pie_str(c.pie),
    164 			canary      = c.canary,
    165 			textrel     = c.textrel,
    166 			rwx_segment = c.rwx_segment,
    167 			rpath       = c.rpath,
    168 			runpath     = c.runpath,
    169 			stripped    = c.stripped,
    170 			fortified   = c.fortified,
    171 			fortifiable = c.fortifiable,
    172 			partial     = c.partial,
    173 		},
    174 	}
    175 }
    176 
    177 to_json_symbols :: proc(syms: []Symbol, allocator := context.allocator) -> []Json_Symbol {
    178 	out := make([]Json_Symbol, len(syms), allocator)
    179 	for sym, i in syms {
    180 		out[i] = Json_Symbol{
    181 			name  = sym.name,
    182 			value = sym.value,
    183 			size  = sym.size,
    184 			bind  = symbol_bind_str(sym.bind),
    185 			type  = symbol_type_str(sym.type),
    186 			shndx = sym.shndx,
    187 		}
    188 	}
    189 	return out
    190 }
    191 
    192 print_json :: proc(info: ^ELF_Info) -> string {
    193 	defer free_all(context.temp_allocator)
    194 
    195 	dump := build_json_dump(info, context.temp_allocator)
    196 	data, err := json.marshal(dump, {pretty = true, use_spaces = true}, context.temp_allocator)
    197 	if err != nil {
    198 		return fmt.tprintf("json marshal failed: %v", err)
    199 	}
    200 
    201 	fmt.println(string(data))
    202 	return ""
    203 }