draugr~ single ELF file analysis tool |
| git clone https://github.com/djnnvx/draugr.git |
| log | files | refs | archive | README |
checksec_test.odin (3656B)
1 package elf 2 3 import "core:testing" 4 5 checksec_info :: proc(phdrs: []Program_Header, dyn: [][2]u64) -> ELF_Info { 6 info: ELF_Info 7 info.program_hdrs = make([dynamic]Program_Header) 8 info.section_hdrs = make([dynamic]Section_Header) 9 info.symbols = make([dynamic]Symbol) 10 info.dyn_symbols = make([dynamic]Symbol) 11 info.dyn_entries = make([dynamic]Dyn_Entry) 12 info.needed = make([dynamic]string) 13 info.relocs = make([dynamic]Reloc) 14 info.header.type = ET_DYN 15 16 for p in phdrs { 17 append(&info.program_hdrs, p) 18 } 19 for e in dyn { 20 append(&info.dyn_entries, Dyn_Entry{tag = e[0], val = e[1]}) 21 } 22 return info 23 } 24 25 @(test) 26 test_relro_needs_bind_now_for_full :: proc(t: ^testing.T) { 27 none := checksec_info({}, {}) 28 defer destroy(&none) 29 testing.expect_value(t, relro_state(&none), Relro.None) 30 31 partial := checksec_info({{type = PT_GNU_RELRO}}, {}) 32 defer destroy(&partial) 33 testing.expect_value(t, relro_state(&partial), Relro.Partial) 34 35 full := checksec_info({{type = PT_GNU_RELRO}}, {{DT_FLAGS, DF_BIND_NOW}}) 36 defer destroy(&full) 37 testing.expect_value(t, relro_state(&full), Relro.Full) 38 39 full1 := checksec_info({{type = PT_GNU_RELRO}}, {{DT_FLAGS_1, DF_1_NOW}}) 40 defer destroy(&full1) 41 testing.expect_value(t, relro_state(&full1), Relro.Full) 42 } 43 44 @(test) 45 test_nx_absent_segment_is_unknown :: proc(t: ^testing.T) { 46 unknown := checksec_info({}, {}) 47 defer destroy(&unknown) 48 testing.expect_value(t, nx_state(&unknown), Nx.Unknown) 49 50 on := checksec_info({{type = PT_GNU_STACK, flags = PF_R | PF_W}}, {}) 51 defer destroy(&on) 52 testing.expect_value(t, nx_state(&on), Nx.Enabled) 53 54 off := checksec_info({{type = PT_GNU_STACK, flags = PF_R | PF_W | PF_X}}, {}) 55 defer destroy(&off) 56 testing.expect_value(t, nx_state(&off), Nx.Disabled) 57 } 58 59 @(test) 60 test_pie_distinguishes_shared_library_from_executable :: proc(t: ^testing.T) { 61 pie := checksec_info({{type = PT_INTERP}}, {}) 62 defer destroy(&pie) 63 testing.expect_value(t, pie_state(&pie), Pie.Pie) 64 65 lib := checksec_info({}, {{DT_SONAME, 1}}) 66 defer destroy(&lib) 67 testing.expect_value(t, pie_state(&lib), Pie.Shared_Library) 68 69 spie := checksec_info({}, {{DT_FLAGS_1, DF_1_PIE}}) 70 defer destroy(&spie) 71 testing.expect_value(t, pie_state(&spie), Pie.Static_Pie) 72 73 exe := checksec_info({}, {}) 74 defer destroy(&exe) 75 exe.header.type = ET_EXEC 76 testing.expect_value(t, pie_state(&exe), Pie.None) 77 } 78 79 @(test) 80 test_rwx_and_textrel_are_flagged :: proc(t: ^testing.T) { 81 clean := checksec_info({{type = PT_LOAD, flags = PF_R | PF_X}}, {}) 82 defer destroy(&clean) 83 testing.expect(t, !has_rwx_segment(&clean), "R X segment is not RWX") 84 testing.expect(t, !has_textrel(&clean), "no DT_TEXTREL") 85 86 rwx := checksec_info({{type = PT_LOAD, flags = PF_R | PF_W | PF_X}}, {{DT_TEXTREL, 0}}) 87 defer destroy(&rwx) 88 testing.expect(t, has_rwx_segment(&rwx), "RWX PT_LOAD must be flagged") 89 testing.expect(t, has_textrel(&rwx), "DT_TEXTREL must be flagged") 90 91 flagged := checksec_info({}, {{DT_FLAGS, DF_TEXTREL}}) 92 defer destroy(&flagged) 93 testing.expect(t, has_textrel(&flagged), "DF_TEXTREL must be flagged") 94 } 95 96 @(test) 97 test_fortify_excludes_stack_canary :: proc(t: ^testing.T) { 98 info := checksec_info({}, {}) 99 defer destroy(&info) 100 101 append(&info.dyn_symbols, Symbol{name = "__stack_chk_fail"}) 102 append(&info.dyn_symbols, Symbol{name = "__memcpy_chk"}) 103 append(&info.dyn_symbols, Symbol{name = "memcpy"}) 104 append(&info.dyn_symbols, Symbol{name = "strcpy"}) 105 106 fortified, fortifiable, partial := fortify_counts(&info) 107 testing.expect_value(t, fortified, 1) 108 testing.expect_value(t, fortifiable, 2) 109 testing.expect_value(t, partial, 1) 110 111 c := checksec(&info) 112 testing.expect(t, c.canary, "__stack_chk_fail must still set the canary flag") 113 }