Skip to content

Commit d2a18af

Browse files
authored
adds integration with ida 7 (#893)
* ida 7 integartion * refactored a little * Ida 7 launches only in terminal version * work on error messages * refactoring * typo fix
1 parent 2812d5a commit d2a18af

File tree

9 files changed

+234
-81
lines changed

9 files changed

+234
-81
lines changed

oasis/ida

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,6 @@ Library bap_ida_plugin
2020
CompiledObject: best
2121
BuildDepends: bap, bap-ida
2222
Modules: Ida_main
23-
InternalModules: Bap_ida_config, Bap_ida_service, Bap_ida_check
23+
InternalModules: Bap_ida_config, Bap_ida_service, Bap_ida_info
2424
XMETADescription: use ida to provide rooter, symbolizer and reconstructor
2525
XMETAExtraLines: tags="ida, rooter, brancher, symbolizer, reconstructor"

plugins/ida/.merlin

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ REC
44

55
B ../../_build/lib/bap_ida
66
B ../../_build/plugins/ida
7-
S.
7+
S .

plugins/ida/bap_ida_check.ml

Lines changed: 0 additions & 26 deletions
This file was deleted.

plugins/ida/bap_ida_check.mli

Lines changed: 0 additions & 5 deletions
This file was deleted.

plugins/ida/bap_ida_info.ml

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
open Core_kernel
2+
open Bap.Std
3+
include Self()
4+
5+
type version = Vold | Vnew [@@deriving sexp]
6+
type old_kind = [ `idal | `idal64 | `idaq | `idaq64 ] [@@deriving sexp, enumerate]
7+
type new_kind = [ `idat | `idat64 | `ida | `ida64 ] [@@deriving sexp, enumerate]
8+
type ida_kind = [ old_kind | new_kind ] [@@deriving sexp]
9+
10+
type ida = {
11+
headless : ida_kind;
12+
graphical : ida_kind;
13+
headless64 : ida_kind;
14+
graphical64 : ida_kind;
15+
version : version;
16+
} [@@deriving sexp]
17+
18+
type t = {
19+
path : string;
20+
ida : ida;
21+
is_headless : bool;
22+
}
23+
24+
type mode = [ `m32 | `m64 ]
25+
26+
type failure =
27+
| Ida_not_exists
28+
| Non_dir_path
29+
| File_not_found of string
30+
| Unexpected_kind
31+
| Headless_win32
32+
| Ida_python_missed
33+
34+
let (/) = Filename.concat
35+
36+
let string_of_kind k = Sexp.to_string (sexp_of_ida_kind k)
37+
38+
let code_of_failure = function
39+
| Ida_not_exists -> 0
40+
| Non_dir_path -> 1
41+
| File_not_found _ -> 2
42+
| Unexpected_kind -> 3
43+
| Headless_win32 -> 4
44+
| Ida_python_missed-> 5
45+
46+
let string_of_failure = function
47+
| Ida_not_exists -> "IDA path does not exists"
48+
| Non_dir_path -> "IDA path is not a directory"
49+
| File_not_found k -> k ^ " must exist"
50+
| Unexpected_kind -> "can't infer IDA version. Check IDA installation"
51+
| Headless_win32 -> "can't use headless on windows"
52+
| Ida_python_missed -> "bap-ida-python is not installed"
53+
54+
module Check = struct
55+
56+
type error = (unit, failure) Result.t
57+
58+
let require = Result.ok_if_true
59+
60+
let require_path path = require (Sys.file_exists path)
61+
let require_dir path = require (Sys.is_directory path) ~error:Non_dir_path
62+
63+
let require_ida path =
64+
let open Result in
65+
require_path path ~error:Ida_not_exists >>= fun () ->
66+
require_dir path
67+
68+
let require_ida_python path =
69+
require_path ~error:Ida_python_missed
70+
(path / "plugins" / "plugin_loader_bap.py")
71+
72+
let require_kind path k =
73+
let file = path / string_of_kind k in
74+
require_path ~error:(File_not_found file) file
75+
76+
let run {path; ida} =
77+
let require_kind = require_kind path in
78+
Result.all_ignore [
79+
require_ida path;
80+
require_ida_python path;
81+
require_kind ida.graphical;
82+
require_kind ida.graphical64;
83+
require_kind ida.headless;
84+
require_kind ida.headless64; ]
85+
86+
let check_integrity ida =
87+
let files = [ida.graphical; ida.headless;
88+
ida.graphical64; ida.headless64;] in
89+
let is_of kinds = List.mem (kinds :> ida_kind list) ~equal:(=) in
90+
let check version = List.for_all files ~f:(is_of version) in
91+
let expected = match ida.headless with
92+
| `idal -> (all_of_old_kind :> ida_kind list)
93+
| _ -> (all_of_new_kind :> ida_kind list) in
94+
let checked = check expected in
95+
require checked ~error:Unexpected_kind
96+
97+
let check_headless is_headless =
98+
require (is_headless ==> not Sys.win32) ~error:Headless_win32
99+
100+
end
101+
102+
let check ida =
103+
match Check.run ida with
104+
| Ok () as ok -> ok
105+
| Error fail ->
106+
Or_error.errorf "IDA check failed with error code %d"
107+
(code_of_failure fail)
108+
109+
let exists_kind path kind =
110+
Sys.file_exists (path / string_of_kind kind)
111+
112+
let create_ida path =
113+
let find_kind ~is_headless mode =
114+
let kinds = match mode with
115+
| `m32 when is_headless -> [`idal; `idat]
116+
| `m64 when is_headless -> [`idal64; `idat64]
117+
| `m32 -> [`idaq; `ida]
118+
| `m64 -> [`idaq64; `ida64] in
119+
List.find ~f:(exists_kind path) kinds |>
120+
function
121+
| Some k -> Ok k
122+
| None ->
123+
let kinds = List.map ~f:string_of_kind kinds in
124+
let files = String.concat ~sep:"/" kinds in
125+
Error (File_not_found files) in
126+
let version_of_headless = function
127+
| `idal -> Vold
128+
| _ -> Vnew in
129+
Result.(
130+
find_kind ~is_headless:true `m32 >>= fun headless ->
131+
find_kind ~is_headless:false `m32 >>= fun graphical ->
132+
find_kind ~is_headless:true `m64 >>= fun headless64 ->
133+
find_kind ~is_headless:false `m64 >>= fun graphical64 ->
134+
let version = version_of_headless headless in
135+
Ok { headless; graphical; headless64; graphical64; version })
136+
137+
let create' path is_headless =
138+
let open Check in
139+
Result.(
140+
require_ida path >>= fun () ->
141+
require_ida_python path >>= fun () ->
142+
check_headless is_headless >>= fun () ->
143+
create_ida path >>= fun ida ->
144+
check_integrity ida >>= fun () ->
145+
Ok {ida; path; is_headless})
146+
147+
let create path is_headless =
148+
match create' path is_headless with
149+
| Ok r -> Ok r
150+
| Error fail ->
151+
warning "%s" (string_of_failure fail);
152+
Or_error.errorf "IDA detection failed with error code %d" (code_of_failure fail)
153+
154+
(* Note, we always launch headless ida in case of IDA Pro 7 *)
155+
let ida32 info = match info.ida.version with
156+
| Vnew -> info.ida.headless
157+
| Vold ->
158+
if info.is_headless then info.ida.headless
159+
else info.ida.graphical
160+
161+
let ida64 info = match info.ida.version with
162+
| Vnew -> info.ida.headless64
163+
| Vold ->
164+
if info.is_headless then info.ida.headless64
165+
else info.ida.graphical64
166+
167+
let ida_of_suffix info filename =
168+
let ext = FilePath.replace_extension in
169+
let exists suf = Sys.file_exists (ext filename suf) in
170+
if exists "i64" then Some (ida64 info)
171+
else if exists "idb" then Some (ida32 info)
172+
else None
173+
174+
let ida_of_mode info = function
175+
| `m32 -> ida32 info
176+
| `m64 -> ida64 info
177+
178+
let find_ida info mode target =
179+
let kind = match mode with
180+
| Some mode -> ida_of_mode info mode
181+
| None ->
182+
match ida_of_suffix info target with
183+
| Some ida -> ida
184+
| None -> ida64 info in
185+
let s = Sexp.to_string (sexp_of_ida_kind kind) in
186+
let ida = Filename.concat info.path s in
187+
Filename.quote ida
188+
189+
let is_headless t = t.is_headless
190+
let path t = t.path
191+
192+
let require_ncurses t =
193+
Sys.os_type = "Unix" && t.is_headless && t.ida.version = Vold

plugins/ida/bap_ida_info.mli

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
open Core_kernel
2+
3+
type mode = [ `m32 | `m64 ]
4+
5+
type t
6+
7+
(** [create path is_headless] *)
8+
val create : string -> bool -> t Or_error.t
9+
10+
(** [find_ida info mode target] - returns a full path
11+
to ida executable depending on [mode] and [target] name *)
12+
val find_ida : t -> mode option -> string -> string
13+
14+
val is_headless : t -> bool
15+
16+
val check : t -> unit Or_error.t
17+
18+
(** [require_ncurses ida] returns true if [ida] need ncureses lib to operate*)
19+
val require_ncurses : t -> bool

plugins/ida/bap_ida_service.ml

Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ open Bap.Std
44

55
include Self ()
66

7-
type ida_kind = [ `idal | `idal64 | `idaq | `idaq64 ] [@@deriving sexp]
7+
module Info = Bap_ida_info
88

99
type ida = {
1010
ida : string;
@@ -16,8 +16,7 @@ type ida = {
1616

1717
module Ida_config = struct
1818
type t = {
19-
ida_path : string;
20-
ida_kind : ida_kind option;
19+
ida_info : Info.t;
2120
curses : string option;
2221
debug : int;
2322
}
@@ -28,21 +27,7 @@ type 'a command = 'a Command.t
2827

2928
let ext = FilePath.replace_extension
3029

31-
let ida_of_suffix filename =
32-
let exists suf = Sys.file_exists (ext filename suf) in
33-
if exists "i64" then Some `idaq64
34-
else if exists "idb" then Some `idaq
35-
else None
36-
37-
let find_ida target path kind =
38-
let kind = match kind with
39-
| Some kind -> kind
40-
| None -> match ida_of_suffix target with
41-
| Some ida -> ida
42-
| None -> `idaq64 in
43-
let s = Sexp.to_string (sexp_of_ida_kind kind) in
44-
let ida = Filename.concat path s in
45-
Filename.quote ida
30+
let (/) = Filename.concat
4631

4732
let run cmd =
4833
let inp = Unix.open_process_in cmd in
@@ -111,18 +96,18 @@ let run (t:ida) cmd =
11196
try cmd (); cleanup ()
11297
with exn -> cleanup (); raise exn
11398

114-
let check_path path = match Bap_ida_check.check_path path with
99+
let check_path info = match Info.check info with
115100
| Ok () -> ()
116101
| Error e ->
117102
eprintf "failed to check ida path: %s." (Error.to_string_hum e);
118103
exit 1
119104

120-
let create {Ida_config.ida_path; ida_kind; debug; curses} target =
105+
let create {Ida_config.ida_info; debug; curses} target mode =
121106
if not (Sys.file_exists target)
122107
then invalid_argf "Can't find target executable" ();
123108
let exe = Filename.temp_file "bap_" "_ida" in
124109
FileUtil.cp [target] exe;
125-
let ida = find_ida target ida_path ida_kind in
110+
let ida = Info.find_ida ida_info mode target in
126111
let idb = idb ida in
127112
let self = {
128113
ida;
@@ -136,7 +121,7 @@ let create {Ida_config.ida_path; ida_kind; debug; curses} target =
136121
if Sys.file_exists (asm target) then
137122
FileUtil.cp [asm target] (asm exe);
138123
) else (
139-
check_path ida_path;
124+
check_path ida_info;
140125
run self @@ shell "%s -A -B %s" self.ida self.exe;
141126
);
142127
self
@@ -174,19 +159,18 @@ let find_curses () =
174159
| [_;path] -> Some (String.strip path)
175160
| _ -> None) |> List.filter ~f:Sys.file_exists |> List.hd
176161

177-
let register ida_path ida_kind is_headless : unit =
178-
let curses = if Sys.os_type = "Unix" && is_headless
179-
then find_curses () else None in
162+
let register ida_info mode : unit =
163+
let curses = if Info.require_ncurses ida_info then find_curses ()
164+
else None in
180165
let debug =
181166
try Int.of_string (Sys.getenv "BAP_IDA_DEBUG") with _exn -> 0 in
182167
let config = {
183-
Ida_config.ida_path;
184-
ida_kind;
168+
Ida_config.ida_info;
185169
curses;
186170
debug
187171
} in
188172
let create (target:string) : Service.t =
189-
let self = create config target in
173+
let self = create config target mode in
190174
let exec cmd = exec self cmd in
191175
let close () = close self in
192176
Service.{ exec; close } in

plugins/ida/bap_ida_service.mli

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
type ida_kind = [`idal | `idal64 | `idaq | `idaq64]
21

3-
(** [register ida_path ida_kind is_headless] registers the IDA service with
2+
(** [register ida_info ida_mode] registers the IDA service with
43
Bap_ida library *)
5-
val register : string -> ida_kind option -> bool -> unit
4+
val register : Bap_ida_info.t -> Bap_ida_info.mode option -> unit

0 commit comments

Comments
 (0)