package binsec

  1. Overview
  2. Docs

doc/src/binsec_kernel_loader/loader_utils.ml.html

Source file loader_utils.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
(**************************************************************************)
(*  This file is part of BINSEC.                                          *)
(*                                                                        *)
(*  Copyright (C) 2016-2026                                               *)
(*    CEA (Commissariat à l'énergie atomique et aux énergies              *)
(*         alternatives)                                                  *)
(*                                                                        *)
(*  you can redistribute it and/or modify it under the terms of the GNU   *)
(*  Lesser General Public License as published by the Free Software       *)
(*  Foundation, version 2.1.                                              *)
(*                                                                        *)
(*  It is distributed in the hope that it will be useful,                 *)
(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
(*  GNU Lesser General Public License for more details.                   *)
(*                                                                        *)
(*  See the GNU Lesser General Public License version 2.1                 *)
(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
(*                                                                        *)
(**************************************************************************)

open Basic_types.Integers

let get_byte_at img addr =
  Bitvector.value_of addr |> Virtual_address.of_bigint
  |> Loader.read_address img |> Uint8.to_int

(* { Manipulation of symbols } *)

let symbol_by_name ~name img =
  let symbols = Loader.Img.symbols img in
  try
    Some
      (Array_utils.find
         (fun sy -> String.compare (Loader.Symbol.name sy) name = 0)
         symbols)
  with Not_found -> None

let address_of_symbol symbol = Loader.Symbol.value symbol

let address_of_symbol_by_name ~name img =
  match symbol_by_name ~name img with
  | Some symbol -> Some (address_of_symbol symbol)
  | None -> None

let size_of_symbol symbol : int =
  let header = Loader.Symbol.header symbol in
  match header with
  | Loader.ELF elf -> elf.Loader_elf.Sym.size
  | Loader.PE _ -> failwith "No size for PE symbols"
  | Loader.Raw _ -> failwith "No size for Raw symbols"
  | Loader.TI83 _ -> failwith "No size for TI83 symbols"

let size_of_symbol_by_name ~name img =
  match symbol_by_name ~name img with
  | Some symbol -> Some (size_of_symbol symbol)
  | None -> None

let symbol_interval symbol =
  let start_addr = address_of_symbol symbol in
  let size = size_of_symbol symbol in
  let end_addr = Virtual_address.add_int size start_addr in
  (start_addr, end_addr)

let symbol_interval_by_name ~name img =
  match symbol_by_name ~name img with
  | Some symbol -> Some (symbol_interval symbol)
  | None -> None

let belongs_to_symbol symbol addr =
  let start_addr, end_addr = symbol_interval symbol in
  Virtual_address.compare start_addr addr <= 0
  && Virtual_address.compare end_addr addr > 0

let belongs_to_symbol_by_name ~name img addr =
  match symbol_by_name ~name img with
  | Some symbol -> belongs_to_symbol symbol addr
  | None -> raise Not_found

(* { End of Manipulation of symbols } *)

let interval section =
  let open Loader_types in
  let sec_start = (Loader.Section.pos section).virt in
  let sec_end =
    Virtual_address.add_bigint
      (Z.pred (Loader.Section.size section).virt)
      sec_start
  in
  (sec_start, sec_end)

let in_section section addr =
  let open Loader_types in
  let lo = (Loader.Section.pos section).virt
  and sz = (Loader.Section.size section).virt in
  let hi = Virtual_address.add_bigint sz lo in
  addr >= lo && addr < hi

let find_section ~p img =
  try Some (Array_utils.find p (Loader.Img.sections img))
  with Not_found -> None

let find_section_by_address ~address img =
  find_section ~p:(fun s -> in_section s address) img

let find_section_by_address_exn ~address img =
  Array_utils.find (fun s -> in_section s address) (Loader.Img.sections img)

let find_section_by_name section_name img =
  Array_utils.find
    (fun section -> section_name = Loader.Section.name section)
    (Loader.Img.sections img)

let section_slice_by_name section_name img =
  find_section_by_name section_name img |> interval

let section_slice_by_address ~address img =
  find_section_by_address_exn img ~address |> interval

let entry_point img = Loader.Img.entry img

let address_of_symbol_or_section_by_name ~name img =
  match address_of_symbol_by_name ~name img with
  | Some _ as a -> a
  | None -> (
      try
        Some
          (Loader.Section.pos (find_section_by_name name img)).Loader_types.virt
      with Not_found -> None)

let size_of_symbol_or_section_by_name ~name img =
  match size_of_symbol_by_name ~name img with
  | Some _ as s -> s
  | None -> (
      try
        Some
          (Z.to_int
             (Loader.Section.size (find_section_by_name name img))
               .Loader_types.virt)
      with Not_found -> None)

let interval_of_symbol_or_section_by_name ~name img =
  match symbol_interval_by_name ~name img with
  | Some _ as i -> i
  | None -> (
      try
        let section = find_section_by_name name img in
        let p = (Loader.Section.pos section).Loader_types.virt
        and s = (Loader.Section.size section).Loader_types.virt in
        Some (p, Virtual_address.add_bigint s p)
      with Not_found -> None)

module Binary_loc = struct
  type t = Address of Virtual_address.t | Name of string | Offset of t * int

  let name s = Name s
  let address a = Address a

  let offset n t =
    if n = 0 then t
    else
      match t with
      | Name _ as t -> Offset (t, n)
      | Offset (t, m) -> Offset (t, m + n)
      | Address a -> Address (Virtual_address.add_int n a)

  let rec pp ppf = function
    | Name s -> Format.pp_print_string ppf s
    | Offset (t, n) ->
        Format.fprintf ppf "<%a %c %d>" pp t (if n < 0 then '-' else '+') n
    | Address a -> Virtual_address.pp ppf a

  let rec of_string s =
    match s.[0] with
    | '<' ->
        let pos_end = String.rindex s '>' in
        let pos_plus = String.index s '+' in
        let base = of_string (String.sub s 1 (pos_plus - 1))
        and int_off =
          let start = pos_plus + 1 in
          let len = pos_end - start in
          int_of_string (String.sub s start len)
        in
        offset int_off base
    | '0' ->
        if s.[1] = 'x' || s.[1] = 'X' then
          Address (Virtual_address.create (int_of_string s))
        else Name s
    | _ -> Name s

  (* match int_of_string s with
   * | addr -> Address (Virtual_address.create addr)
   * | exception Failure "int_of_string" -> Name s *)

  let ( >> ) g f = match g with None -> None | Some v -> Some (f v)
  let address_from_img name img = address_of_symbol_by_name img ~name

  let to_virtual_address_from_file ~filename t =
    let rec eval = function
      | Address addr -> Some addr
      | Name name ->
          let img = Loader.load_file filename in
          address_from_img name img
      | Offset (t, n) -> eval t >> Virtual_address.add_int n
    in
    eval t

  let to_virtual_address ~img t =
    let rec loop = function
      | Address addr -> Some addr
      | Name name -> address_from_img name img
      | Offset (t, n) -> loop t >> Virtual_address.add_int n
    in
    loop t
end