Skip to content

Commit 96ab02c

Browse files
authored
improves the main function discovery heurisitics (#1336)
The problem was not in heuristic per se, but cyclic dependency between the abi pass that discovers __libc_start_main, main, abi passes, and api passes. Ideally, we should reimplement our ABI/API infrastructure using the Knowledge Base, which was originally designed to handle such dependencies, but it will take much more time than we currently have. Therefore, right now we discover `__libc_start_main` in the ABI pass, to be sure that we have types applied to it (which we need as we will use them later to get the storage for the first argument). And we delay the `main` function discovery after the api pass. After we find main we also want types to be applied. Unfortunately, we can't can call the api pass again (which is responsible for that), but we known the prototype of main, so we don't really need to parse the C headers anymore and can manually apply the prototype and translate it to the arg terms. Now the main function discovery works perfectly for the programs that use glibc runtime, so yeah we can finally execute `/bin/true` and `/bin/false` :) ``` $bap /bin/false --run --primus-print-obs=call-return | grep main (call-return (main 0 0x40000008 1)) $ bap /bin/true --run --primus-print-obs=call-return | grep main (call-return (main 0 0x40000008 0)) ```
1 parent 784ebe2 commit 96ab02c

File tree

3 files changed

+91
-24
lines changed

3 files changed

+91
-24
lines changed

oasis/glibc-runtime

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Library glibc_runtime_plugin
77
Path: plugins/glibc_runtime
88
FindlibName: bap-plugin-glibc_runtime
99
CompiledObject: best
10-
BuildDepends: core_kernel, bap-main, bap, bap-abi, bap-c, ogre
10+
BuildDepends: core_kernel, bap-main, bap, bap-abi, bap-c, ogre, bap-core-theory
1111
InternalModules: Glibc_runtime_main
1212
XMETADescription: detects main and libc_start_main functions
1313
XMETAExtraLines: tags="abi, pass"

plugins/abi/abi_main.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ let () = Config.manpage [
1212
`P "$(b,bap-plugin-x86)(1), $(b,bap-plugin-arm)(1), $(b,bap-abi)(3)"
1313
]
1414

15-
let () = Config.when_ready (fun _ -> Project.register_pass ~autorun:true Bap_abi.pass)
15+
let () = Config.when_ready (fun _ ->
16+
Project.register_pass ~autorun:true Bap_abi.pass)

plugins/glibc_runtime/glibc_runtime_main.ml

Lines changed: 88 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ functions (and adds the latter if it is absent).
55
"
66
open Core_kernel
77
open Bap_main
8+
open Bap_core_theory
89
open Bap.Std
910
open Bap_c.Std
1011

@@ -95,20 +96,27 @@ let detect_main_address prog =
9596
| _ -> None
9697

9798

98-
let reinsert_args_for_new_name sub name =
99-
let sub = Term.filter arg_t sub ~f:(fun _ -> false) in
100-
let sub = Term.del_attr sub C.proto in
101-
Sub.with_name sub name
99+
let reinsert_args_for_new_name ?(abi=ident) sub name =
100+
List.fold ~init:sub ~f:(|>) [
101+
Term.filter arg_t ~f:(fun _ -> false);
102+
(fun sub -> Term.del_attr sub C.proto);
103+
(fun sub -> Sub.with_name sub name);
104+
abi
105+
]
102106

103-
let rename_main prog = match detect_main_address prog with
107+
let rename_main abi prog = match detect_main_address prog with
104108
| None -> prog
105-
| Some addr ->
106-
Term.map sub_t prog ~f:(fun sub ->
107-
match Term.get_attr sub address with
108-
| Some a when Addr.equal addr a ->
109-
reinsert_args_for_new_name sub "main"
110-
| _ -> sub)
111-
109+
| Some addr -> Term.map sub_t prog ~f:(fun sub ->
110+
match Term.get_attr sub address with
111+
| Some a when Addr.equal addr a ->
112+
reinsert_args_for_new_name ~abi sub "main"
113+
| _ -> sub)
114+
115+
let find_abi_processor proj =
116+
let (let*) = Option.(>>=) in
117+
let* name = Project.get proj Bap_abi.name in
118+
let* proc = C.Abi.get_processor name in
119+
Some proc
112120

113121
let rename_libc_start_main prog =
114122
if is_sub_absent prog "__libc_start_main"
@@ -122,17 +130,75 @@ let rename_libc_start_main prog =
122130
reinsert_args_for_new_name sub "__libc_start_main"
123131
else prog
124132

125-
let fix_glibc_runtime prog =
126-
rename_libc_start_main prog |>
127-
rename_main
133+
module Main = struct
134+
let cv = C.Type.Qualifier.{
135+
const = false;
136+
volatile = false;
137+
restrict = ();
138+
}
139+
140+
let cvr = C.Type.Qualifier.{
141+
const = false;
142+
volatile = false;
143+
restrict = false;
144+
}
145+
146+
let basic t = `Basic C.Type.Spec.{t; attrs=[]; qualifier=cv}
147+
let ptr t = `Pointer C.Type.Spec.{t; attrs=[]; qualifier=cvr}
148+
149+
let proto : C.Type.proto = C.Type.Proto.{
150+
variadic = false;
151+
return = basic `sint;
152+
args = [
153+
"argc", basic `sint;
154+
"argv", ptr (ptr (basic `char));
155+
];
156+
}
157+
158+
let var t (data : C.Data.t) name =
159+
match data with
160+
| Imm (sz,_) -> Var.create name (Type.Imm (Size.in_bits sz))
161+
| Ptr _ ->
162+
Var.create name (Type.Imm (Theory.Target.code_addr_size t))
163+
| _ -> assert false
164+
165+
let arg intent t (data,exp) name =
166+
Arg.create ~intent (var t data name) exp
167+
168+
let abi proj main =
169+
let t = Project.target proj in
170+
match find_abi_processor proj with
171+
| None -> main
172+
| Some {C.Abi.insert_args} ->
173+
match insert_args main [] proto with
174+
| Some {C.Abi.return=Some ret; params=[argc; argv]} ->
175+
List.fold ~init:main ~f:(Term.append arg_t)[
176+
arg In t argc "main_argc";
177+
arg Both t argv "main_argv";
178+
arg Out t ret "main_result";
179+
]
180+
| _ -> main
181+
end
182+
183+
let fix_main proj =
184+
let abi = Main.abi proj in
185+
Project.map_program proj ~f:(rename_main abi)
186+
187+
let is_enabled ctxt proj =
188+
Extension.Configuration.get ctxt enable || is_glibc proj
189+
190+
let recover_main ctxt proj =
191+
if is_enabled ctxt proj &&
192+
is_sub_absent (Project.program proj) "main"
193+
then fix_main proj
194+
else proj
128195

129-
let main ctxt proj =
130-
if Extension.Configuration.get ctxt enable ||
131-
is_glibc proj
132-
then
133-
Project.map_program proj ~f:fix_glibc_runtime
196+
let discover_libc_start_main ctxt proj =
197+
if is_enabled ctxt proj
198+
then Project.map_program proj ~f:rename_libc_start_main
134199
else proj
135200

136-
let () = Extension.declare ~doc ~provides:["abi"] @@ fun ctxt ->
137-
Bap_abi.register_pass (main ctxt);
201+
let () = Extension.declare ~doc ~provides:["abi"; "api"] @@ fun ctxt ->
202+
Bap_abi.register_pass (discover_libc_start_main ctxt);
203+
Project.register_pass ~autorun:true ~deps:["api"] (recover_main ctxt);
138204
Ok ()

0 commit comments

Comments
 (0)