ml_dwarf_write: write to a separate file

Don't try to write into the ELF file directly, use objcopy.

Updated README
This commit is contained in:
Théophile Bastian 2019-03-18 14:20:53 +01:00
parent 484b20c732
commit 8fa2bc5952
9 changed files with 87 additions and 31 deletions

View file

@ -3,8 +3,6 @@ open Std
let main outfile proj = let main outfile proj =
let pre_dwarf = Simplest.of_proj proj in let pre_dwarf = Simplest.of_proj proj in
Format.printf "%a" Frontend.pp_pre_dwarf_readelf pre_dwarf; Format.printf "%a" Frontend.pp_pre_dwarf_readelf pre_dwarf;
let pre_c_dwarf = PreCBinding.convert_pre_c pre_dwarf in let pre_c_dwarf = PreCBinding.convert_pre_c pre_dwarf in
let fd = open_out_bin "tmp.marshal" in let fd = open_out_bin outfile in
Marshal.to_channel fd pre_c_dwarf [] Marshal.to_channel fd pre_c_dwarf []

View file

@ -1,14 +1,15 @@
CDEFINE = CDEFINE =
CFLAGS = -Wall -Wextra -std=c11 -O2 -g $(CDEFINE) -I/home/zappa/.opam/bap/lib/ocaml CFLAGS = -Wall -Wextra -std=c11 -O2 -g $(CDEFINE) -I$(OPAM_SWITCH_PREFIX)/lib/ocaml
LIBDWARFW_DIR=../../libdwarfw/build LIBDWARFW_DIR=$(shell readlink -f ../../libdwarfw/build)
CLIBS = -L$(LIBDWARFW_DIR) -Wl,-rpath,$(LIBDWARFW_DIR) -lz -lelf -ldwarf -ldwarfw CLIBS = -L$(LIBDWARFW_DIR) -Wl,-rpath,$(LIBDWARFW_DIR) -lz -lelf -ldwarf -ldwarfw
#CLIBELF = /usr/lib/x86_64-linux-gnu/libelf.a
OCAMLCLIBS = -ccopt -L$(LIBDWARFW_DIR) -ccopt -Wl,-rpath,$(LIBDWARFW_DIR) -cclib -lz -cclib -lelf -cclib -ldwarf -cclib -ldwarfw OCAMLCLIBS = -ccopt -L$(LIBDWARFW_DIR) -ccopt -Wl,-rpath,$(LIBDWARFW_DIR) -cclib -lz -cclib -lelf -cclib -ldwarf -cclib -ldwarfw
all: test_dw.bin ml_dwarf_write.bin all: test_dw.bin ml_dwarf_write.bin
test_%.bin: test_%.o dwarf_write.o test_%.bin: test_%.o dwarf_write.o
gcc $(CFLAGS) $^ /usr/lib/x86_64-linux-gnu/libelf.a $(CLIBS) -o $@ gcc $(CFLAGS) $^ $(CLIBELF) $(CLIBS) -o $@
%.o: %.c %.o: %.c
gcc $(CFLAGS) -c $< -o $@ gcc $(CFLAGS) -c $< -o $@

View file

@ -256,8 +256,8 @@ static int write_all_fde_instructions(struct dwarfw_fde *fde,
} }
static int process_section(struct internal_state* state, static int process_section(struct internal_state* state,
struct pre_dwarf* pre_dwarf, Elf_Scn *s, FILE *f, size_t *written /*, struct pre_dwarf* pre_dwarf, Elf_Scn *s, FILE *f,
FILE *rela_f */) size_t *written /*, FILE *rela_f */)
{ {
size_t shndx = elf_ndxscn(s); size_t shndx = elf_ndxscn(s);
fprintf(stderr, "Processing section %lu\n", shndx); //D fprintf(stderr, "Processing section %lu\n", shndx); //D
@ -357,9 +357,13 @@ static int process_section(struct internal_state* state,
return 0; return 0;
} }
int write_dwarf(char* objname, struct pre_dwarf* pre_dwarf) { int write_dwarf(char* objname, char* eh_path, struct pre_dwarf* pre_dwarf) {
elf_version(EV_CURRENT); elf_version(EV_CURRENT);
FILE* out_dwarf = fopen(eh_path, "a"); // Create file
fclose(out_dwarf);
out_dwarf = fopen(eh_path, "w"); // Truncate and open for writing
int fd = open(objname, O_RDWR); int fd = open(objname, O_RDWR);
if (fd == -1) { if (fd == -1) {
fprintf(stderr, "cannot open file\n"); fprintf(stderr, "cannot open file\n");
@ -392,6 +396,7 @@ int write_dwarf(char* objname, struct pre_dwarf* pre_dwarf) {
struct internal_state state = { .elf = elf }; struct internal_state state = { .elf = elf };
/*
char *buf; char *buf;
size_t len; size_t len;
FILE *f = open_memstream(&buf, &len); FILE *f = open_memstream(&buf, &len);
@ -399,6 +404,7 @@ int write_dwarf(char* objname, struct pre_dwarf* pre_dwarf) {
fprintf(stderr, "open_memstream() failed\n"); fprintf(stderr, "open_memstream() failed\n");
return 1; return 1;
} }
*/
/* /*
char *rela_buf; char *rela_buf;
@ -426,19 +432,21 @@ int write_dwarf(char* objname, struct pre_dwarf* pre_dwarf) {
continue; continue;
} }
if (process_section(&state, pre_dwarf, s, f, &written /*, rela_f*/)) { if (process_section(&state, pre_dwarf, s, out_dwarf, &written /*, rela_f*/)) {
return 1; return 1;
} }
} }
fclose(f); // fclose(f);
/* fclose(rela_f); */ /* fclose(rela_f); */
// Create the .eh_frame section // Create the .eh_frame section
/*
Elf_Scn *scn = create_debug_frame_section(elf, ".eh_frame", buf, len); Elf_Scn *scn = create_debug_frame_section(elf, ".eh_frame", buf, len);
if (scn == NULL) { if (scn == NULL) {
fprintf(stderr, "create_debug_frame_section() failed\n"); fprintf(stderr, "create_debug_frame_section() failed\n");
return 1; return 1;
} }
*/
/* /*
// Create the .eh_frame.rela section // Create the .eh_frame.rela section
@ -451,17 +459,20 @@ int write_dwarf(char* objname, struct pre_dwarf* pre_dwarf) {
*/ */
// Write the modified ELF object // Write the modified ELF object
/*
elf_flagelf(elf, ELF_C_SET, ELF_F_DIRTY); elf_flagelf(elf, ELF_C_SET, ELF_F_DIRTY);
if (elf_update(elf, ELF_C_WRITE) < 0) { if (elf_update(elf, ELF_C_WRITE) < 0) {
fprintf(stderr, "elf_update() failed: %s\n", elf_errmsg(-1)); fprintf(stderr, "elf_update() failed: %s\n", elf_errmsg(-1));
return 1; return 1;
} }
*/
free(buf); // free(buf);
/* free(rela_buf); */ /* free(rela_buf); */
elf_end(elf); elf_end(elf);
close(fd); close(fd);
fclose(out_dwarf);
return 0; return 0;
} }

View file

@ -55,5 +55,5 @@ struct pre_dwarf {
struct pre_dwarf_fde* fdes; struct pre_dwarf_fde* fdes;
}; };
/// Writes the provided `pre_dwarf` as DWARF in the ELF file at `obj_path` /// Writes the provided `pre_dwarf` as DWARF in the file `eh_path`, for the ELF file at `obj_path`
int write_dwarf(char* obj_path, struct pre_dwarf* pre_dwarf); int write_dwarf(char* obj_path, char* eh_path, struct pre_dwarf* pre_dwarf);

View file

@ -142,9 +142,9 @@ struct pre_dwarf * convert_pre_dwarf(value oc_pre_dwarf) {
} }
// OCaml type: string -> pre_c_dwarf -> int // OCaml type: string -> pre_c_dwarf -> int
value caml_write_dwarf (value oc_obj_path, value oc_pre_dwarf) { value caml_write_dwarf (value oc_obj_path, value oc_eh_path, value oc_pre_dwarf) {
char *obj_path; char *obj_path, *eh_path;
struct pre_dwarf *pre_dwarf; struct pre_dwarf *pre_dwarf;
CAMLparam2(oc_obj_path, oc_pre_dwarf); CAMLparam2(oc_obj_path, oc_pre_dwarf);
@ -153,9 +153,11 @@ value caml_write_dwarf (value oc_obj_path, value oc_pre_dwarf) {
obj_path = String_val(oc_obj_path); obj_path = String_val(oc_obj_path);
eh_path = String_val(oc_eh_path);
pre_dwarf = convert_pre_dwarf(oc_pre_dwarf); pre_dwarf = convert_pre_dwarf(oc_pre_dwarf);
dump_pre_dwarf(*pre_dwarf); dump_pre_dwarf(*pre_dwarf);
CAMLreturn(write_dwarf(obj_path, pre_dwarf)); CAMLreturn(write_dwarf(obj_path, eh_path, pre_dwarf));
} }

View file

@ -21,27 +21,38 @@ type pre_c_pre_dwarf = {
let dump_pre_c_pre_dwarf_entry e = let dump_pre_c_pre_dwarf_entry e =
Printf.printf " %8Lx %d+%Ld \n" e.location e.cfa_offset_reg e.cfa_offset Printf.printf " %8Lx %d+%Ld \n" e.location e.cfa_offset_reg e.cfa_offset
let dump_pre_c_pre_dwarf_fde f = let dump_pre_c_pre_dwarf_fde f =
Printf.printf "%s %Lx %Lx\n" f.name f.initial_location f.end_location; Printf.printf "%s %Lx %Lx\n" f.name f.initial_location f.end_location;
for i = 0 to Array.length f.entries - 1 do for i = 0 to Array.length f.entries - 1 do
dump_pre_c_pre_dwarf_entry f.entries.(i) dump_pre_c_pre_dwarf_entry f.entries.(i)
done done
let dump_pre_c_pre_dwarf p = let dump_pre_c_pre_dwarf p =
for i = 0 to Array.length p.fdes - 1 do for i = 0 to Array.length p.fdes - 1 do
dump_pre_c_pre_dwarf_fde p.fdes.(i) dump_pre_c_pre_dwarf_fde p.fdes.(i)
done done
external write_dwarf : string -> pre_c_pre_dwarf -> int = "caml_write_dwarf"
(* use: ml_dwarf_write <marshalled_data> <executable> *) external write_dwarf : string -> string -> pre_c_pre_dwarf -> int
= "caml_write_dwarf"
(** ========== USAGE ========== **)
let use_string =
Sys.argv.(0) ^ " <marshalled_data> <executable> [<eh_file>]\n" ^
"<eh_file> defaults to `<executable>.eh_frame`\n" ;;
let _ = let _ =
if Array.length Sys.argv <= 2 then (
Format.eprintf "Error: missing argument(s). Usage:\n%s" use_string ;
exit 1
) ;
let eh_path = (if Array.length Sys.argv <= 3
then (Sys.argv.(2) ^ ".eh_frame")
else Sys.argv.(3)) in
let fd = open_in_bin Sys.argv.(1) in let fd = open_in_bin Sys.argv.(1) in
let pre_c_dwarf = ((Marshal.from_channel fd): pre_c_pre_dwarf) in let pre_c_dwarf = ((Marshal.from_channel fd): pre_c_pre_dwarf) in
dump_pre_c_pre_dwarf pre_c_dwarf; dump_pre_c_pre_dwarf pre_c_dwarf;
write_dwarf Sys.argv.(2) pre_c_dwarf write_dwarf Sys.argv.(2) eh_path pre_c_dwarf

View file

@ -13,6 +13,6 @@ int main() {
}; };
struct pre_dwarf dwarf_data = {1, &fde}; struct pre_dwarf dwarf_data = {1, &fde};
write_dwarf("test.bin", &dwarf_data); write_dwarf("test.bin", "test.bin.eh_frame", &dwarf_data);
return 0; return 0;
} }

View file

@ -10,3 +10,35 @@ examine its assembly code and, based solely on that, generate the corresponding
This tool relies on [BAP](https://github.com/BinaryAnalysisPlatform/bap), which This tool relies on [BAP](https://github.com/BinaryAnalysisPlatform/bap), which
is available through OPAM. is available through OPAM.
## Running
First, run `make` to compile and install the BAP plugin.
### Running the BAP plugin
`bap prog_to_analyze.bin -p dwarfsynth --dwarfsynth-output tmp.marshal`
### Running `ml_dwarf_write`
You can get a help text with `./ml_dwarf_write.bin`. Otherwise, you can run
```
./ml_dwarf_write.bin tmp.marshal prog_to_analyze.bin eh_frame_section`
```
### Stitching the section into a binary
```
objcopy --add-section .eh_frame=eh_frame_section prog_to_analyze.bin prog_to_analyze.eh.bin
```
## Commonly used commands
### List a binary sections
`objdump -h blah.bin`
### Strip a binary of its `eh_frame`
`objcopy --remove-section '.eh_frame' --remove-section '.eh_frame_hdr' blah.bin`

View file

@ -14,9 +14,10 @@ module Cmdline = struct
module Cnf = Self.Config module Cnf = Self.Config
let outfile = Cnf.( let outfile = Cnf.(
param (some string) "output" param (string) "output"
~doc:("The file in which the output ELF will be written. Output goes " ~doc:("The file in which the output marshalled data will be written. "
^ "to stdout by default.") ^ "Output goes to ./tmp.marshal by default.")
~default:"tmp.marshal"
) )
let () = Cnf.( let () = Cnf.(