Skip to content

Commit

Permalink
rectifies x86 primus loader
Browse files Browse the repository at this point in the history
The problem arises when we deal with libraries: even if a callee is
in the same library, a call will be done through a plt entry first, meaning that
we won't visit the target subroutine.

Our solution is based on the function name: we would better to call the
function itself, but not the corresponding plt entry, so since a
function and a plt entry has the same name, then any call to a plt entry
we substitute to a call to the function.

Also, this PR fixes SP in the `primus-x86-loader` (again).

The history.

PR BinaryAnalysisPlatform#993 introduced a proper initialization of PLT entries, but
unfortunately, introduced a bug as well.

Briefly, we didn't want primus to dive deep into PLT entries because
anyway, we would fail with unresolved call exception, but to that moment
a SP would be changed several times.
The solution was to raise an unresolved call exception as soon as
possible, right after a primus machine entered an entry and restore SP
by `unresolved-call` observation.
Unfortunately, the implementation was wrong: we linked an unresolved
call handler to the address of a jump in a plt entry, so actually we
just call a handler instead, and no actual unresolved call happens, no
observation made, and no steps to restore SP taken.

This PR fixes it and now we just unlink all the addresses of plt
entries, so we get a fair unresolved call exception.
  • Loading branch information
gitoleg committed Jan 22, 2020
1 parent b40689e commit 3cfbbc5
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 11 deletions.
2 changes: 2 additions & 0 deletions plugins/api/api/c/gnu.h
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
int __libc_start_main(int (*main) (int, char **, char **), int, char **, void *auxv);

void __stack_chk_fail(void) __attribute__((noreturn));
73 changes: 63 additions & 10 deletions plugins/primus_x86/primus_x86_loader.ml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,6 @@ let is_section name v =
| Some x -> String.(x = name)
| _ -> false

module Make_unresolved(Machine : Primus.Machine.S) = struct
module Linker = Primus.Linker.Make(Machine)

let exec =
Linker.exec (`symbol Primus.Linker.unresolved_handler)
end

module Plt_jumps(Machine : Primus.Machine.S) = struct
module Linker = Primus.Linker.Make(Machine)
open Machine.Syntax
Expand All @@ -40,8 +33,7 @@ module Plt_jumps(Machine : Primus.Machine.S) = struct
Seq.exists memory ~f:(fun mem -> Memory.contains mem a))

let unlink addrs =
Machine.List.iter addrs ~f:(fun addr ->
Linker.link ~addr (module Make_unresolved))
Machine.List.iter addrs ~f:(fun addr -> Linker.unlink (`addr addr))

let unresolve =
load_table >>=
Expand All @@ -50,6 +42,65 @@ module Plt_jumps(Machine : Primus.Machine.S) = struct

end

module Link_plt(Machine : Primus.Machine.S) = struct
open Machine.Syntax

let section_memory sec_name =
Machine.get () >>| fun proj ->
Memmap.filter (Project.memory proj) ~f:(is_section sec_name) |>
Memmap.to_sequence |>
Seq.map ~f:fst

let is_a_plt_stub mem sub =
match Term.get_attr sub address with
| None -> false
| Some addr -> Seq.exists mem ~f:(fun m -> Memory.contains m addr)

let relink plt prog =
let normalize_name x =
match String.split ~on:'@' x with
| name :: _ -> name
| _ -> x in
let add m sub =
Map.set m (normalize_name @@ Sub.name sub) (Term.tid sub) in
let subs = Term.to_sequence sub_t prog in
let stubs, subs =
Seq.fold ~init:(Map.empty (module String), Map.empty (module String)) subs
~f:(fun (stubs, subs) sub ->
if is_a_plt_stub plt sub
then add stubs sub, subs
else stubs, add subs sub) in
let twins =
Map.fold stubs ~init:(Map.empty (module Tid))
~f:(fun ~key:name ~data:tid twins ->
match Map.find subs name with
| None -> twins
| Some tid' -> Map.set twins tid tid') in
(object
inherit Term.mapper

method! map_jmp jmp =
match Jmp.kind jmp with
| Goto _ | Int _ | Ret _ -> jmp
| Call c ->
match Call.target c with
| Indirect _ -> jmp
| Direct tid ->
match Map.find twins tid with
| None -> jmp
| Some tid' ->
Jmp.with_kind jmp (Call (Call.with_target c (Direct tid')))
end)#run prog

let init () =
section_memory ".plt" >>= fun plt ->
Machine.get () >>= fun proj ->
Machine.put @@
Project.with_program proj
(relink plt (Project.program proj))
end


module Component(Machine : Primus.Machine.S) = struct
open Machine.Syntax
module Env = Primus.Env.Make(Machine)
Expand All @@ -72,7 +123,9 @@ module Component(Machine : Primus.Machine.S) = struct
| Unk | Mem _ -> Machine.return ()
| Imm width ->
Value.of_int ~width addend >>= fun addend ->
Primus.Linker.Trace.lisp_call_return >>> correct_sp sp addend
Machine.sequence [
Primus.Linker.Trace.lisp_call_return >>> correct_sp sp addend;
Primus.Linker.unresolved >>> correct_sp sp addend ]

let init () =
Machine.get () >>= fun proj ->
Expand Down
3 changes: 2 additions & 1 deletion plugins/primus_x86/primus_x86_main.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ open Bap_primus.Std
include Self()

let init _ =
Primus.Machine.add_component (module Primus_x86_loader.Component);;
Primus.Machine.add_component (module Primus_x86_loader.Component);
Primus.Machine.add_component (module Primus_x86_loader.Link_plt);;

Config.manpage [
`S "DESCRIPTION";
Expand Down

0 comments on commit 3cfbbc5

Please sign in to comment.