Skip to content

Commit a11d6b7

Browse files
authored
adds the stub resolver abi pass (#1036)
The stub resolver pass redirects on the IR level calls to stub functions to the calls to real functions if such could be identified. A function is a stub if it has the stub attribute present in the knowledge base. So far, we add only a knowledge provider for ELF stubs (that looks into the .plt section) others will be added later. The redirection algorithm establishes a one-to-one mapping between a stub and its prospective redirection. In case if a non-bijective mapping is detected (a stub has more than one implementation candidates or implementation has more than one stubs) no redirection is established.
1 parent 9619503 commit a11d6b7

16 files changed

+544
-16
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ _oasis
6767
/plugins/primus_lisp/primus_lisp_config.ml
6868
/plugins/primus_greedy/.merlin
6969
/plugins/primus_lisp/primus_lisp_config.ml
70+
/plugins/primus_systems/primus_systems_config.ml
7071
/setup.exe
7172
/tools/bap_config
7273
/lib/bap_bundle/bap_bundle_config.ml

.run_travis_tests.sh

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ if [ "$TASK" == "unit_tests" ]; then
2222
bap_powerpc_tests
2323
bap_piqi_tests
2424
bap_traces_tests
25+
bap_stub_resolver_tests
2526
fi
2627

2728
if [ "$TASK" == "veri" ]; then

lib/bap/bap.mli

+16-2
Original file line numberDiff line numberDiff line change
@@ -7806,12 +7806,26 @@ module Std : sig
78067806
that occur in jump [jmp] expressions.*)
78077807
val substitute : t -> exp -> exp -> t
78087808

7809-
(** updated jump's guard condition *)
7809+
(** [with_cond jmp c] updates jump's guard condition
7810+
7811+
@since 2.0.0 *)
78107812
val with_cond : t -> exp -> t
78117813

7812-
(** updated jump's kind *)
7814+
(** [with_kind jmp k] updates jump's kind
7815+
7816+
@since 2.0.0 *)
78137817
val with_kind : t -> jmp_kind -> t
78147818

7819+
(** [with_alt jmp d] updates jump's inter-procedural destination
7820+
7821+
@since 2.1.0 *)
7822+
val with_alt : t -> dst option -> t
7823+
7824+
(** [with_dst jmp d] updates jump's intra-procedural destination
7825+
7826+
@since 2.1.0 *)
7827+
val with_dst : t -> dst option -> t
7828+
78157829
(** [pp_slots names] prints slots that are in [names]. *)
78167830
val pp_slots : string list -> Format.formatter -> t -> unit
78177831
include Regular.S with type t := t

lib/bap_sema/bap_sema_lift.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -306,13 +306,13 @@ let program symtab =
306306
| Ok () -> tid
307307
| Error _ ->
308308
let tid = Tid.create () in
309-
Tid.set_name tid name;
310309
Hash_set.strict_add_exn tids tid;
311310
tid in
312311
Seq.iter (Symtab.to_sequence symtab) ~f:(fun (name,entry,cfg) ->
313312
let addr = Block.addr entry in
314313
let blk_tid = Tid.for_addr addr in
315314
let sub_tid = tid_for_sub name in
315+
Tid.set_addr sub_tid addr;
316316
let sub = lift_sub ~symtab ~tid:sub_tid entry cfg in
317317
Ir_program.Builder.add_sub b (Ir_sub.with_name sub name);
318318
Hashtbl.add_exn sub_of_blk ~key:blk_tid ~data:sub_tid;);

lib/bap_types/bap_ir.ml

+7-11
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ module Tid = struct
5858
KB.provide slot tid (Some name)
5959
end
6060

61-
let set_addr = set Theory.Label.addr
61+
let set_addr t w = set Theory.Label.addr t (Bap_bitvector.to_bitvec w)
6262
let set_ivec = set Theory.Label.ivec
6363

6464

@@ -316,23 +316,19 @@ end = struct
316316
let addr = Dict.find s.dict Bap_attributes.address in
317317
let name = mangle_name addr s.tid s.self.name in
318318
Tid.add_name s.tid s.self.name;
319-
Tid.add_name s.tid name;
319+
Tid.set_name s.tid name;
320320
let self = {s.self with name} in
321321
{s with self}
322322

323-
let fix_names olds news =
324-
let is_new tid name =
325-
match Array.find olds ~f:(fun s -> Tid.equal s.tid tid) with
326-
| Some s -> String.(name <> s.self.name)
327-
| None -> true in
323+
let fix_names news =
324+
let is_new sub = sub.tid <> Tid.for_name sub.self.name in
328325
let keep_name tids name tid = Map.set tids ~key:name ~data:tid in
329326
let tids = Array.fold news ~init:String.Map.empty ~f:(fun tids sub ->
330327
match Map.find tids sub.self.name with
331328
| None -> keep_name tids sub.self.name sub.tid
332329
| Some _ ->
333-
if is_new sub.tid sub.self.name then
334-
keep_name tids sub.self.name sub.tid
335-
else tids) in
330+
if is_new sub then tids
331+
else keep_name tids sub.self.name sub.tid) in
336332
if Array.length news = Map.length tids then news
337333
else
338334
Array.map news ~f:(fun sub ->
@@ -342,7 +338,7 @@ end = struct
342338

343339
let empty () = {subs = [| |] ; paths = Tid.Table.create () }
344340

345-
let update p subs = { p with subs = fix_names p.subs subs }
341+
let update p subs = { p with subs = fix_names subs }
346342

347343
let compare x y =
348344
let compare x y = [%compare:sub term array] x y in

lib/bap_types/bap_ir.mli

+3
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ module Tid : sig
5858

5959
val create : unit -> t Bap_toplevel.t
6060
val set_name : t -> string -> unit Bap_toplevel.t
61+
val set_addr : t -> word -> unit Bap_toplevel.t
6162
val name : t -> string Bap_toplevel.t
6263
val from_string : string -> tid Or_error.t
6364
val from_string_exn : string -> tid
@@ -337,6 +338,8 @@ module Ir_jmp : sig
337338
val cond : t -> exp
338339
val with_cond : t -> exp -> t
339340
val with_kind : t -> jmp_kind -> t
341+
val with_alt : t -> dst option -> t
342+
val with_dst : t -> dst option -> t
340343
val exps : t -> exp Sequence.t
341344
val map_exp : t -> f:(exp -> exp) -> t
342345
val substitute : t -> exp -> exp -> t

oasis/stub-resolver

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
Flag stub_resolver
2+
Description: Build Stub Resolver plugin
3+
Default: false
4+
5+
Library stub_resolver_library_plugin
6+
Build$: flag(everything) || flag(stub_resolver)
7+
Path: plugins/stub_resolver/
8+
BuildDepends: bap, bap-abi, bap-knowledge, bap-core-theory, core_kernel, bitvec, bitvec-order, bap-main
9+
FindlibName: bap-plugin-stub_resolver
10+
CompiledObject: best
11+
Modules: Stub_resolver
12+
InternalModules: Stub_resolver_main
13+
XMETADescription: Substitutes calls to stubs with calls to real functions
14+
XMETAExtraLines: tags="abi"
15+
16+
Library stub_resolver_tests
17+
Path: plugins/stub_resolver
18+
FindLibParent: stub_resolver_library_plugin
19+
FindlibName: tests
20+
Build$: flag(tests) && (flag(everything) || flag(stub_resolver))
21+
CompiledObject: best
22+
BuildDepends: bap, oUnit, core_kernel, ppx_jane
23+
Install: false
24+
Modules: Stub_resolver_tests
25+
26+
Executable run_stub_resolver_tests
27+
Path: plugins/stub_resolver
28+
Build$: flag(tests) && (flag(everything) || flag(stub_resolver))
29+
CompiledObject: best
30+
BuildDepends: findlib.dynload, oUnit, bap-main, bap-plugin-stub_resolver.tests
31+
Install: false
32+
MainIs: run_stub_resolver_tests.ml
33+
34+
35+
Test stub_resolver_tests
36+
TestTools: run_stub_resolver_tests
37+
Run$: flag(tests) && (flag(everything) || flag(stub_resolver))
38+
Command: $run_stub_resolver_tests

opam/opam

+5
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ install: [
117117
["ocamlfind" "remove" "bap-plugin-print"]
118118
["ocamlfind" "remove" "bap-plugin-report"]
119119
["ocamlfind" "remove" "bap-plugin-read_symbols"]
120+
["ocamlfind" "remove" "bap-plugin-stub_resolver"]
120121
["ocamlfind" "remove" "bap-plugin-x86"]
121122
["ocamlfind" "remove" "bap-traces"]
122123
["ocamlfind" "remove" "bap-taint"]
@@ -161,6 +162,7 @@ install: [
161162
["cp" "run_powerpc_tests.native" "%{bin}%/bap_powerpc_tests"]
162163
["cp" "run_piqi_tests.native" "%{bin}%/bap_piqi_tests"]
163164
["cp" "run_traces_tests.native" "%{bin}%/bap_traces_tests"]
165+
["cp" "run_stub_resolver_tests.native" "%{bin}%/bap_stub_resolver_tests"]
164166
]
165167
remove: [
166168
["ocamlfind" "remove" "bap-main"]
@@ -226,6 +228,7 @@ remove: [
226228
["ocamlfind" "remove" "bap-plugin-raw"]
227229
["ocamlfind" "remove" "bap-plugin-report"]
228230
["ocamlfind" "remove" "bap-plugin-read_symbols"]
231+
["ocamlfind" "remove" "bap-plugin-stub_resolver"]
229232
["ocamlfind" "remove" "bap-plugin-x86"]
230233
["ocamlfind" "remove" "bap-traces"]
231234
["ocamlfind" "remove" "bap-taint"]
@@ -281,6 +284,8 @@ remove: [
281284
["rm" "-f" "%{bin}%/bap_powerpc_tests"]
282285
["rm" "-f" "%{bin}%/bap_piqi_tests"]
283286
["rm" "-f" "%{bin}%/bap_traces_tests"]
287+
["rm" "-f" "%{bin}%/bap_stub_resolver_tests"]
288+
284289
]
285290
depexts: [
286291
[

plugins/primus_systems/primus_systems_config.ml

-1
This file was deleted.

plugins/stub_resolver/.merlin

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
PKG core_kernel
2+
PKG oUnit
3+
PKG bap
4+
PKG bap-abi
5+
6+
S .
7+
B ../../_build/plugins/stub_resolver
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
open Core_kernel
2+
open OUnit2
3+
open Bap_plugins.Std
4+
5+
let suite = "Stub_resolver" >::: [
6+
Stub_resolver_tests.suite;
7+
]
8+
9+
let () =
10+
match Bap_main.init () with
11+
| Error err ->
12+
Format.eprintf "Failed to initialize BAP: %a@\n%!"
13+
Bap_main.Extension.Error.pp err;
14+
exit 1;
15+
| Ok () ->
16+
run_test_tt_main suite
+142
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
open Core_kernel
2+
open Bap.Std
3+
open Bap_core_theory
4+
open Bap_knowledge
5+
6+
include Self ()
7+
8+
open KB.Syntax
9+
10+
type groups = int Tid.Map.t
11+
type names = String.Set.t Int.Map.t
12+
13+
type t = {
14+
groups : groups;
15+
names : names;
16+
next : int;
17+
stubs : Tid.Set.t;
18+
}
19+
20+
let tids = Knowledge.Domain.mapping (module Tid) "tids"
21+
~equal:Tid.equal
22+
~inspect:sexp_of_tid
23+
24+
let slot = Knowledge.Class.property
25+
Theory.Program.cls "stubs" tids
26+
~persistent:(Knowledge.Persistent.of_binable (module struct
27+
type t = tid Tid.Map.t
28+
[@@deriving bin_io]
29+
end))
30+
~public:true
31+
~desc:"The mapping from stubs to real symbols"
32+
33+
let cls = Knowledge.Slot.cls slot
34+
35+
let empty = {
36+
groups = Map.empty (module Tid);
37+
names = Map.empty (module Int);
38+
stubs = Set.empty (module Tid);
39+
next = 0;
40+
}
41+
42+
let is_stub sub =
43+
KB.collect (Value.Tag.slot Sub.stub) (Term.tid sub) >>= function
44+
| None -> KB.return false
45+
| Some () -> KB.return true
46+
47+
let aliases_of_sub s = KB.collect Theory.Label.aliases (Term.tid s)
48+
49+
let update_stubs t sub =
50+
is_stub sub >>| fun is_stub ->
51+
if is_stub
52+
then { t with stubs = Set.add t.stubs (Term.tid sub) }
53+
else t
54+
55+
let find_groups names aliases =
56+
Map.fold names ~init:[]
57+
~f:(fun ~key:group ~data:aliases' groups ->
58+
if Set.(is_empty @@ inter aliases aliases')
59+
then groups
60+
else group :: groups)
61+
62+
let unite_names t groups =
63+
List.fold groups ~init:(Set.empty (module String))
64+
~f:(fun als id ->
65+
Set.union als (Map.find_exn t.names id))
66+
67+
let pick_representative = function
68+
| [] -> assert false
69+
| groups ->
70+
List.min_elt groups ~compare:Int.compare |>
71+
Option.value_exn
72+
73+
let redirect t ~from ~to_ =
74+
Map.map t.groups ~f:(fun id ->
75+
if List.mem from id ~equal:Int.equal
76+
then to_
77+
else id)
78+
79+
let add t sub =
80+
update_stubs t sub >>= fun t ->
81+
aliases_of_sub sub >>| fun aliases ->
82+
match find_groups t.names aliases with
83+
| [] ->
84+
let groups = Map.add_exn t.groups (Term.tid sub) t.next in
85+
let names = Map.add_exn t.names t.next aliases in
86+
{ t with groups; names; next = t.next + 1 }
87+
| [id] ->
88+
let groups = Map.add_exn t.groups (Term.tid sub) id in
89+
let names = Map.update t.names id ~f:(function
90+
| None -> assert false
91+
| Some als' -> Set.union aliases als') in
92+
{ t with names; groups }
93+
| groups ->
94+
let grp = pick_representative groups in
95+
let aliases = Set.union aliases (unite_names t groups) in
96+
let names = List.fold groups ~init:t.names ~f:Map.remove in
97+
let names = Map.add_exn names grp aliases in
98+
let groups = redirect t ~from:groups ~to_:grp in
99+
{t with names; groups;}
100+
101+
let collect_by_group_id groups =
102+
Map.fold groups ~init:Int.Map.empty
103+
~f:(fun ~key:tid ~data:id xs ->
104+
Map.update xs id ~f:(function
105+
| None -> [tid]
106+
| Some tids -> tid :: tids ))
107+
108+
let unambiguous_pairs stubs xs =
109+
let is_stub tid = Set.mem stubs tid in
110+
Map.fold xs ~init:(Map.empty (module Tid))
111+
~f:(fun ~key:_group_id ~data:tids pairs ->
112+
match tids with
113+
| [x; y] ->
114+
begin
115+
match is_stub x, is_stub y with
116+
| true, false -> Map.add_exn pairs x y
117+
| false, true -> Map.add_exn pairs y x
118+
| _ -> pairs
119+
end
120+
| _ -> pairs)
121+
122+
let find_pairs t =
123+
collect_by_group_id t.groups |>
124+
unambiguous_pairs t.stubs
125+
126+
let resolve prog =
127+
Knowledge.Seq.fold ~init:empty
128+
(Term.to_sequence sub_t prog) ~f:add >>|
129+
find_pairs
130+
131+
let provide prog =
132+
Knowledge.Object.create cls >>= fun obj ->
133+
resolve prog >>= fun links ->
134+
KB.provide slot obj links >>= fun () ->
135+
KB.return obj
136+
137+
let run prog =
138+
match Knowledge.run cls (provide prog) (Toplevel.current ()) with
139+
| Ok (v,_) -> Knowledge.Value.get slot v
140+
| Error cnf ->
141+
error "%a\n" Knowledge.Conflict.pp cnf;
142+
Map.empty (module Tid)
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
open Core_kernel
2+
open Bap.Std
3+
open Bap_core_theory
4+
open Bap_knowledge
5+
6+
(** [run prog] - returns the mapping from
7+
stubs to implementations *)
8+
val run : program term -> tid Tid.Map.t

0 commit comments

Comments
 (0)