diff --git a/rainbow/loaders/__init__.py b/rainbow/loaders/__init__.py
index cd7a2dd..80240d9 100644
--- a/rainbow/loaders/__init__.py
+++ b/rainbow/loaders/__init__.py
@@ -19,17 +19,17 @@
import os
from typing import Optional
-from .elfloader import elfloader
+from .cleloader import cleloader
from .hexloader import hexloader
-from .peloader import peloader
-LOADERS = {".hex": hexloader, ".elf": elfloader, ".so": elfloader, ".exe": peloader}
+LOADERS = {".hex": hexloader, ".elf": cleloader, ".so": cleloader, ".exe": cleloader}
def load_selector(filename, rainbow_instance, typ=None, *args, **kwargs) -> Optional[int]:
- if typ is None:
- ext = os.path.splitext(filename)[1]
- loader = LOADERS[ext]
- else:
- loader = LOADERS[typ]
+ """Select the appropriate loader.
+
+ Default to CLE loader if unknown as it has the most chance of succeeding.
+ """
+ typ = typ if typ is not None else os.path.splitext(filename)[1]
+ loader = LOADERS.get(typ, cleloader)
return loader(filename, rainbow_instance, *args, **kwargs)
diff --git a/rainbow/loaders/cleloader.py b/rainbow/loaders/cleloader.py
new file mode 100644
index 0000000..b3c1467
--- /dev/null
+++ b/rainbow/loaders/cleloader.py
@@ -0,0 +1,45 @@
+# This file is part of rainbow
+#
+# rainbow is free software: 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see .
+#
+#
+# Copyright 2022 A Iooss, ANSSI
+
+import cle
+
+
+def cleloader(path: str, emu, ld_path=(), verbose=False) -> None:
+ """Load binary using CLE
+
+ It will try to load their associated libraries and resolves imports.
+ """
+ if verbose:
+ print(f"[+] Opening {path}")
+ ld = cle.Loader(path, except_missing_libs=True, ld_path=ld_path)
+
+ # Map memory
+ if verbose:
+ for obj in ld.all_objects:
+ print(f"[ ] Mapping at 0x{obj.min_addr:08X}: {obj.binary_basename}")
+ emu.map_space(ld.min_addr, ld.max_addr, verbose=verbose)
+ for start_addr, backer in ld.memory.backers():
+ emu.emu.mem_write(start_addr, bytes(backer))
+
+ # Load symbols
+ func_symbols = [s for s in ld.symbols if s.is_function]
+ if verbose:
+ print(f"[+] Loading {len(func_symbols)} functions symbol")
+ for symbol in func_symbols:
+ emu.functions[symbol.name] = symbol.rebased_addr
+ emu.function_names.update({symbol.rebased_addr: symbol.name})
diff --git a/rainbow/loaders/elfloader.py b/rainbow/loaders/elfloader.py
deleted file mode 100644
index bcefd74..0000000
--- a/rainbow/loaders/elfloader.py
+++ /dev/null
@@ -1,106 +0,0 @@
-# This file is part of rainbow
-#
-# rainbow is free software: 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, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program 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.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program. If not, see .
-#
-#
-# Copyright 2019 Victor Servant, Ledger SAS
-
-import lief
-
-
-def elfloader(elf_file, emu, map_virtual_segments=False, verbose=False) -> int:
- """Load an .elf file into emu's memory using LIEF
-
- If `map_virtual_segments` is True, then segments such as `.bss` will be
- mapped even if their physical size are zero.
- """
- elffile = lief.parse(elf_file)
- if verbose:
- print(f"[x] Loading ELF segments...")
-
- if len(list(elffile.segments)) > 0:
- for segment in elffile.segments:
- # Only consider LOAD segments
- if segment.type != lief.ELF.SEGMENT_TYPES.LOAD:
- continue
-
- if map_virtual_segments:
- emu.map_space(
- segment.virtual_address,
- segment.virtual_address + segment.virtual_size,
- verbose=verbose,
- )
- emu.emu.mem_write(segment.virtual_address, bytes(segment.content))
- else:
- emu.map_space(
- segment.physical_address,
- segment.physical_address + segment.physical_size,
- verbose=verbose,
- )
- emu.emu.mem_write(segment.physical_address, bytes(segment.content))
- else:
- # if there are no segments, still attempt to map .text area
- section = elffile.get_section(".text")
- emu.map_space(
- section.virtual_address,
- section.virtual_address + section.size,
- verbose=verbose,
- )
- emu.emu.mem_write(section.virtual_address, bytes(section.content))
-
- # Handle relocations
- for r in elffile.relocations:
- if r.symbol.is_function:
- if r.symbol.value == 0:
- rsv = r.address
- else:
- rsv = r.symbol.value
- emu.functions[r.symbol.name] = rsv
- if verbose:
- print(f"Relocating {r.symbol.name} at {r.address:x} to {rsv:x}")
- emu[r.address] = rsv
-
- # lief > 0.10
- try:
- for f in elffile.exported_functions:
- tmpn = f.name
- c = 0
- while tmpn in emu.functions:
- c += 1
- tmpn = f.name + str(c)
- emu.functions[tmpn] = f.address
- except:
- pass
-
- # TODO: when the ELF has relocated functions exported, LIEF fails on get_function_address
- for i in elffile.symbols:
- if i.type == lief.ELF.SYMBOL_TYPES.FUNC:
- try:
- tmpn = i.name
- addr = i.value
- if tmpn in emu.functions.keys():
- if emu.functions[tmpn] != addr:
- c = 0
- while tmpn in emu.functions.keys():
- c += 1
- tmpn = i.name + str(c)
- emu.functions[tmpn] = addr
- else:
- emu.functions[tmpn] = addr
- except Exception as exc:
- if verbose:
- print(exc)
-
- emu.function_names = {emu.functions[x]: x for x in emu.functions.keys()}
- return elffile.entrypoint
diff --git a/rainbow/loaders/peloader.py b/rainbow/loaders/peloader.py
deleted file mode 100644
index 7b6f670..0000000
--- a/rainbow/loaders/peloader.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# This file is part of rainbow
-#
-# rainbow is free software: 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, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program 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.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program. If not, see .
-#
-#
-# Copyright 2019 Victor Servant, Ledger SAS
-
-import lief
-
-
-def peloader(exe_file, emu, verbose=False) -> int:
- """Load a .exe file into emu's memory using LIEF"""
- pefile = lief.parse(exe_file)
- if verbose:
- print(f"[x] Loading .exe ...")
-
- imagebase = pefile.optional_header.imagebase
- for section in pefile.sections:
- if verbose:
- print(f"[=] Writing {section.name}")
- emu.map_space(
- imagebase + section.virtual_address,
- imagebase + section.virtual_address + section.size,
- verbose=verbose,
- )
- emu.emu.mem_write(imagebase + section.virtual_address, bytes(section.content))
-
- emu.functions = {}
-
- # Handle relocations
- for r in pefile.relocations:
- if r.symbol.is_function:
- if r.symbol.value == 0:
- rsv = r.address - (r.address & 1)
- else:
- rsv = r.symbol.value - (r.symbol.value & 1)
- emu.functions[r.symbol.name] = rsv
- if verbose:
- print(f"Relocating {r.symbol.name} at {r.address:x} to {rsv:x}")
- emu[r.address] = rsv
-
- emu.function_names = {emu.functions[x]: x for x in emu.functions.keys()}
- return pefile.entrypoint
diff --git a/setup.py b/setup.py
index d050aad..940c676 100644
--- a/setup.py
+++ b/setup.py
@@ -43,7 +43,7 @@
install_requires=[
"unicorn>=2.0.1",
"capstone>=4.0.0",
- "lief>=0.10.0",
+ "cle>=9.2",
"intelhex",
"pygments",
"numpy",