Skip to content

Commit

Permalink
Add elf_relocations table (#20)
Browse files Browse the repository at this point in the history
* Introduce elf_relocations

A relocations table fleshed out.
Not 100% sure how I want to leverage it but the markings of the table
are there.

* Ignore object files from examples directory
* Added object relocations example
* Bumped lief and pyright
* removed redundant cast when bumped to 0.14.1 for LIEF
  • Loading branch information
fzakaria authored Feb 19, 2024
1 parent aaa6e64 commit 1ef70d5
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 10 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ sqlelf.egg-info/
dist/
result
examples/**/exe
examples/**/*.o
examples/**/*.so
venv/
temp/
Expand Down
18 changes: 18 additions & 0 deletions examples/object-relocations/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Variables
CC = gcc
CFLAGS = -Wall -g
TARGET = exe

# Default rule
all: $(TARGET)

$(TARGET): main.c sum.o
$(CC) $(CFLAGS) -o $(TARGET) main.c sum.o

sum.o: sum.c sum.h
$(CC) $(CFLAGS) -c sum.c


.PHONY: clean
clean:
rm -f $(TARGET) sum.o
11 changes: 11 additions & 0 deletions examples/object-relocations/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include <stdio.h>

#include "sum.h"

int array[4] = {1, 2, 3, 4};

int main() {
int val = sum(array, 4);
printf("Sum: %d\n", val);
return 0;
}
9 changes: 9 additions & 0 deletions examples/object-relocations/sum.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@


int sum(const int* array, int size) {
int sum = 0;
for (int i = 0; i < size; i++) {
sum += array[i];
}
return sum;
}
3 changes: 3 additions & 0 deletions examples/object-relocations/sum.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@


int sum(const int* array, int size);
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ classifiers = [
]
dependencies = [
"capstone >= 5.0.1",
"lief >=0.14.0",
"lief >=0.14.1",
"apsw >= 3.43.1.0",
"sh >= 2.0.6",
]
Expand All @@ -39,7 +39,7 @@ dev = [
"isort >= 5.12.0",
"flake8 >= 6.1.0",
"flake8-print >= 5.0.0",
"pyright >= 1.1.349",
"pyright >= 1.1.350",
"pytest >= 7.4.0",
"mypy >= 1.8.0",
"coverage[toml] >= 7.3",
Expand Down
78 changes: 70 additions & 8 deletions sqlelf/elf.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class CacheFlag(Flag):
INSTRUCTIONS = auto()
SECTIONS = auto()
SYMBOLS = auto()
RELOCATIONS = auto()
STRINGS = auto()
VERSION_REQUIREMENTS = auto()
VERSION_DEFINITIONS = auto()
Expand Down Expand Up @@ -266,13 +267,6 @@ def sections_generator() -> Iterator[dict[str, Any]]:
)


def coerce_section_name(name: str | None) -> str | None:
"""Return a section name or undefined if the name is empty."""
if name == "":
return "undefined"
return name


def register_strings_generator(
binaries: list[lief_ext.Binary], connection: apsw.Connection, cache_flags: CacheFlag
) -> None:
Expand Down Expand Up @@ -364,6 +358,10 @@ def symbols_generator() -> Iterator[dict[str, Any]]:
),
None,
)
if section_name is None or section_name == "":
section_name = lief.ELF.SYMBOL_SECTION_INDEX.from_value(
symbol.shndx
).__name__

yield {
"path": binary_name,
Expand All @@ -380,7 +378,7 @@ def symbols_generator() -> Iterator[dict[str, Any]]:
# https://www.m4b.io/elf/export/binary/analysis/2015/05/25/what-is-an-elf-export.html
"imported": symbol.imported,
"exported": symbol.exported,
"section": coerce_section_name(section_name),
"section": section_name,
"size": symbol.size,
# TODO(fzakaria): Better understand why is it auxiliary?
# this returns versions like GLIBC_2.2.5
Expand Down Expand Up @@ -425,6 +423,69 @@ def symbols_generator() -> Iterator[dict[str, Any]]:
)


def register_relocations_generator(
binaries: list[lief_ext.Binary], connection: apsw.Connection, cache_flags: CacheFlag
) -> None:
"""Create the ELF relocations virtual table."""

def relocations_generator() -> Iterator[dict[str, Any]]:
for binary in binaries:
# super important that these accessors are pulled out of the tight loop
# as they can be costly
binary_name = binary.path
for relocation in binary.relocations:
yield {
"path": binary_name,
"addend": relocation.addend,
"info": relocation.info,
# Relocations are either of type Elf64_Rela or Elf64_Rel
# the difference being whether addend is present in the struct
# https://refspecs.linuxbase.org/elf/gabi4+/ch4.reloc.html
"is_rela": relocation.is_rela,
"purpose": relocation.purpose.__name__,
"section": relocation.section.name if relocation.section else None,
"symbol": relocation.symbol.name,
"symbol_table": (
relocation.symbol_table.name
if relocation.symbol_table
else None
),
"type": relocation_type(
binary.header.machine_type, relocation.type
),
}

generator = Generator.make_generator(
[
"path",
"addend",
"info",
"is_rela",
"purpose",
"section",
"symbol",
"symbol_table",
"type",
],
relocations_generator,
)

register_generator(
connection,
generator,
"elf_relocations",
CacheFlag.RELOCATIONS,
cache_flags,
)


def relocation_type(arch: lief.ELF.ARCH, type: int) -> str:
"""Return the relocation type as a string for a given arch."""
if arch == lief.ELF.ARCH.x86_64:
return lief.ELF.RELOCATION_X86_64.from_value(type).__name__
raise RuntimeError(f"Unknown relocation type for {arch}")


def register_version_requirements(
binaries: list[lief_ext.Binary], connection: apsw.Connection, cache_flags: CacheFlag
) -> None:
Expand Down Expand Up @@ -742,6 +803,7 @@ def register_virtual_tables(
register_sections_generator,
register_strings_generator,
register_symbols_generator,
register_relocations_generator,
register_version_requirements,
register_version_definitions,
register_dwarf_dies,
Expand Down

0 comments on commit 1ef70d5

Please sign in to comment.