Files
lief-project-LIEF/tests/elf/test_replace_segment.py
T
2026-03-19 17:08:49 +01:00

108 lines
3.8 KiB
Python

#!/usr/bin/env python
import os
import re
import stat
import subprocess
import sys
import pytest
from subprocess import Popen
from pathlib import Path
import lief
from utils import get_sample, has_recent_glibc, is_linux, is_x86_64, is_aarch64
is_updated_linux = is_linux() and is_x86_64() and has_recent_glibc()
is_linux_x64 = is_linux() and is_x86_64()
CWD = Path(__file__).parent
def test_simple(tmp_path: Path):
sample_path = get_sample('ELF/ELF64_x86-64_binary_ls.bin')
stub = lief.ELF.parse(CWD / "hello_lief.bin")
output = tmp_path / "ls.replace_segment"
target = lief.ELF.parse(sample_path)
if lief.ELF.Segment.TYPE.NOTE not in target:
lief.logging.err("Note not found!")
return
segment = stub.segments[0]
original_va = segment.virtual_address
segment.virtual_address = 0
segment = target.replace(segment, target[lief.ELF.Segment.TYPE.NOTE])
new_ep = (stub.header.entrypoint - original_va) + segment.virtual_address
target.header.entrypoint = new_ep
target.write(output)
if is_updated_linux:
st = os.stat(output)
os.chmod(output, st.st_mode | stat.S_IEXEC)
with Popen(output.as_posix(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as P:
stdout = P.stdout.read().decode("utf8")
lief.logging.info(stdout)
assert re.search(r'LIEF is Working', stdout) is not None
def test_gcc(tmp_path: Path):
sample_path = get_sample('ELF/ELF64_x86-64_binary_gcc.bin')
stub = lief.ELF.parse(CWD / "hello_lief.bin")
output = tmp_path / "gcc.replace_segment"
target = lief.ELF.parse(sample_path)
if lief.ELF.Segment.TYPE.NOTE not in target:
lief.logging.err("Note not found!")
return
segment = stub.segments[0]
original_va = segment.virtual_address
segment.virtual_address = 0
segment = target.replace(segment, target[lief.ELF.Segment.TYPE.NOTE])
new_ep = (stub.header.entrypoint - original_va) + segment.virtual_address
target.header.entrypoint = new_ep
target.write(output)
if is_updated_linux:
st = os.stat(output)
os.chmod(output, st.st_mode | stat.S_IEXEC)
with Popen(output.as_posix(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as P:
stdout = P.stdout.read().decode("utf8")
lief.logging.info(stdout)
assert re.search(r'LIEF is Working', stdout) is not None
@pytest.mark.skipif(not is_linux(), reason="requires Linux")
@pytest.mark.skipif(not Path('/usr/bin/ssh').is_file(), reason="missing '/usr/bin/ssh'")
def test_ssh(tmp_path: Path):
stub = None
if is_x86_64():
stub = lief.ELF.parse(CWD / "hello_lief.bin")
elif is_aarch64():
stub = lief.ELF.parse(CWD / "hello_lief_aarch64.bin")
output = tmp_path / "ssh.replace_segment"
target = lief.ELF.parse("/usr/bin/ssh")
if lief.ELF.Segment.TYPE.NOTE not in target:
lief.logging.warn("Note not found!")
return
segment = stub.segments[0]
original_va = segment.virtual_address
segment.virtual_address = 0
segment = target.replace(segment, target[lief.ELF.Segment.TYPE.NOTE])
new_ep = (stub.header.entrypoint - original_va) + segment.virtual_address
target.header.entrypoint = new_ep
target.write(output)
if is_linux() and has_recent_glibc():
st = os.stat(output)
os.chmod(output, st.st_mode | stat.S_IEXEC)
with Popen(output.as_posix(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as P:
stdout = P.stdout.read().decode("utf8")
lief.logging.info(stdout)
assert re.search(r'LIEF is Working', stdout) is not None