Files
capa/tests/test_os_detection.py
Willi Ballenthin 8726de0d65 ELF: Detect OS from Go binaries (#1987)
* elf: read segment memory size

* elf: add routine to read mapped memory

* elf: better detect OS for binaries compiled by Go

* elf: guess OS from Go source filenames

* changelog

* elf: mypy

* merge

* elf: add OS detection based on vDSO strings

* elf: document VTGrep searches

* elf: describe further technique to identify Go binaries

* elf: search for `.go.buildinfo` section via @yelhamer

* black

* elf: detect Alpine Linux ident

* elf: log interest symtab entries

* tests: add test for OS detection by Go buildinfo

* loader: handle missing viv modules

* pre-commit: run deptry before tests (which are slow)

* loader: describe removing viv symbolic switch solver

* pyproject: add PyGithub for deptry

* black
2024-06-13 13:23:47 +02:00

180 lines
9.5 KiB
Python

# -*- coding: utf-8 -*-
# Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at: [package root]/LICENSE.txt
# Unless required by applicable law or agreed to in writing, software distributed under the License
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and limitations under the License.
import io
import zlib
from pathlib import Path
from fixtures import get_data_path_by_name
import capa.features.extractors.elf
def test_elf_sh_notes():
# guess: osabi: None
# guess: ph notes: None
# guess: sh notes: OS.LINUX
# guess: linker: None
# guess: ABI versions needed: None
# guess: symtab: None
# guess: needed dependencies: None
path = get_data_path_by_name("2f7f5f")
with Path(path).open("rb") as f:
assert capa.features.extractors.elf.detect_elf_os(f) == "linux"
def test_elf_pt_notes():
# guess: osabi: None
# guess: ph notes: None
# guess: sh notes: OS.LINUX
# guess: linker: OS.LINUX
# guess: ABI versions needed: OS.LINUX
# guess: symtab: None
# guess: needed dependencies: None
path = get_data_path_by_name("7351f.elf")
with Path(path).open("rb") as f:
assert capa.features.extractors.elf.detect_elf_os(f) == "linux"
def test_elf_so_needed():
# guess: osabi: None
# guess: ph notes: None
# guess: sh notes: OS.HURD
# guess: linker: None
# guess: ABI versions needed: OS.HURD
# guess: symtab: None
# guess: needed dependencies: OS.HURD
path = get_data_path_by_name("b5f052")
with Path(path).open("rb") as f:
assert capa.features.extractors.elf.detect_elf_os(f) == "hurd"
def test_elf_abi_version_hurd():
# guess: osabi: None
# guess: ph notes: None
# guess: sh notes: OS.HURD
# guess: linker: None
# guess: ABI versions needed: OS.HURD
# guess: symtab: None
# guess: needed dependencies: None
path = get_data_path_by_name("bf7a9c")
with Path(path).open("rb") as f:
assert capa.features.extractors.elf.detect_elf_os(f) == "hurd"
def test_elf_symbol_table():
# guess: osabi: None
# guess: ph notes: None
# guess: sh notes: None
# guess: linker: None
# guess: ABI versions needed: None
# guess: symtab: OS.LINUX
# guess: needed dependencies: None
path = get_data_path_by_name("2bf18d")
with Path(path).open("rb") as f:
assert capa.features.extractors.elf.detect_elf_os(f) == "linux"
def test_elf_android_notes():
# DEBUG:capa.features.extractors.elf:guess: osabi: None
# DEBUG:capa.features.extractors.elf:guess: ph notes: OS.ANDROID
# DEBUG:capa.features.extractors.elf:guess: sh notes: None
# DEBUG:capa.features.extractors.elf:guess: linker: None
# DEBUG:capa.features.extractors.elf:guess: ABI versions needed: None
# DEBUG:capa.features.extractors.elf:guess: needed dependencies: OS.ANDROID
path = get_data_path_by_name("1038a2")
with Path(path).open("rb") as f:
assert capa.features.extractors.elf.detect_elf_os(f) == "android"
def test_elf_go_buildinfo():
path = get_data_path_by_name("3da7c")
with Path(path).open("rb") as f:
assert capa.features.extractors.elf.detect_elf_os(f) == "linux"
def test_elf_parse_capa_pyinstaller_header():
# error after misidentified large pydata section with address 0; fixed in #1454
# compressed ELF header of capa-v5.1.0-linux
# SHA256 e16974994914466647e24cdcfb6a6f8710297a4def21525e53f73c72c4b52fcf
elf_header = zlib.decompress(
b"".join(
[
b"\x78\x9C\x8D\x56\x4F\x88\x1C\xD5\x13\xAE\x1D\x35\x0A\x7A\x58\x65",
b"\xD1\xA0\x9B\xB0\x82\x11\x14\x67\x63\xD6\xCD\x26\xF1\xF0\x63\x49",
b"\xDC\xC4\xC8\x26\x98\x7F\x07\x89\xA4\xED\xE9\x7E\x6F\xA6\x99\xD7",
b"\xAF\xDB\xEE\x37\xBB\x13\x3D\xB8\x78\x8A\x28\x28\x1E\xBC\x09\x7B",
b"\xF0\xCF\x82\xA0\x41\x10\x23\xA8\x07\x89\x17\x41\x85\x88\x07\x2F",
b"\xE2\x25\xB0\x17\x51\x7E\x07\xD9\x5B\x52\xF5\xFE\xCC\x36\x71\x0A",
b"\x6C\x98\xA9\xF7\xBE\xF9\xEA\xAB\xAF\xEA\x35\x3D\xFD\xDA\xD2\xF2",
b"\xD1\xD6\xC4\x04\x84\xAB\x05\xFF\x03\xDA\x2D\xED\x59\xB4\x7B\xF7",
b"\x8D\xF1\xEF\x57\x5B\x81\xB3\x08\x07\xE1\x6E\xFC\x9E\x86\x87\x60",
b"\x07\xEE\x6F\x6F\xF2\xFC\x2A\xC4\x9E\xCF\x0A\xF1\x2E\xCF\xBB\xCD",
b"\xE7\x6D\x78\x7C\xA3\xE5\xF8\x21\x4E\x7B\x5E\x88\xC1\x21\x45\xCA",
b"\xDB\xBE\xB6\x2B\xD3\x75\xE9\x01\xB7\x0B\x11\x26\xB7\xF3\xEE\xA0",
b"\xC5\x8C\xC7\x67\x7C\x9E\x8F\xF9\x8B\x6E\x1B\x62\x33\xCF\xD6\x5B",
b"\xF3\xF8\x9A\xCF\xF3\xF1\xCA\x7E\xB7\x0D\xB1\x99\x47\xB3\xD9\xFC",
b"\xC6\xED\x37\x7F\x74\xFC\x10\xAF\xF8\x26\x36\x86\xBE\x33\x9F\x47",
b"\xE3\xA0\xBC\x2D\x9F\xB7\xE5\xF9\x21\x5A\x42\x23\x86\x79\x92\x1C",
b"\x7D\xAE\x7A\xFC\xAA\x9F\x63\x88\xCF\x78\x5E\x88\x61\x86\xCF\x5F",
b"\x37\x29\xAD\x37\xD7\xBD\xCF\x75\xEF\xD3\xC7\x27\xE8\xA0\x1A\x31",
b"\xE4\x9D\xC2\x3C\xF2\xF9\x5F\x2F\xDF\x1E\x9C\x0E\xF5\x98\xB9\xEC",
b"\xF4\xFE\x43\x0C\xE7\xBE\x57\x65\x9D\x85\xF9\xBD\x2A\x6D\xAB\x4C",
b"\x0F\x86\xED\xE1\xC1\x85\xF6\xC2\xFC\x6C\x5D\xCC\xCE\x59\x4F\x53",
b"\xFE\x9E\x3A\x76\xF2\x1C\x9C\xFD\xE5\xD9\x33\xE2\xCC\x4B\x17\x76",
b"\x7F\xFD\xD1\xD4\xE6\xE5\xA9\xE5\xF3\x4F\xFF\x7C\x82\x38\xE4\x81",
b"\xF4\x88\xD3\x9C\x35\xDD\x12\x94\x7B\xAA\x71\x6E\x30\x31\x03\x6B",
b"\x13\x93\x2D\xC2\x4E\x7B\x0F\x8F\xED\x7A\x6B\x5A\x9E\x8B\x27\x0F",
b"\xFD\xFF\xCD\x70\x5B\xFE\xEB\xD2\x28\x7A\xDF\x18\xFC\x1A\x0A\x8F",
b"\xC3\xFF\x60\xF0\x0B\xF8\x19\x87\x7F\xC7\xE8\x3F\xC7\xE0\x27\x18",
b"\x9D\x1B\x0C\x7E\x9D\xC1\xE9\xB8\xC6\xE1\x6F\x33\xF8\x97\x4C\x5F",
b"\x6D\x86\xBF\x83\xE1\x7F\xC0\xF4\xF5\x08\x83\xFF\xC9\xE8\xFF\xC5",
b"\xE8\x4B\x06\x7F\x90\xC1\xDF\x60\xF0\x1F\x18\xFC\x13\xC6\xE7\x49",
b"\x86\x7F\x88\xC1\xFF\x61\xFA\xA2\xA7\xF2\x38\xFC\x08\x83\x7F\xC5",
b"\xE0\x47\x99\xBA\x37\x18\xFC\x4E\x46\xE7\x57\xC6\xE7\xF7\x0C\xFE",
b"\x2E\xA3\x73\x96\xA9\xFB\x05\xA3\x33\xC7\xF0\x5F\x67\xF4\x7F\x67",
b"\x74\x1E\x67\xF8\x6D\x46\x9F\x9E\x17\xE1\x2F\xA5\x79\x9D\x67\xF8",
b"\x9F\x72\x3E\x19\x7C\x91\xC1\x0F\x33\xFE\x1F\x66\xF8\x2F\x33\xFC",
b"\xFB\x99\x7E\x25\x83\xBF\xCF\xE8\xEC\x66\xF0\x75\xC6\xCF\x25\x86",
b"\xFF\x2D\xC3\x7F\x87\xC1\xE9\x99\x3E\x0E\xBF\x87\xE1\xBF\xC0\xF4",
b"\x45\x7F\xEF\xE3\xF0\x0F\x19\xFC\x3D\x06\xA7\xD7\x80\x71\xF8\x01",
b"\xA6\x6E\xC6\xF0\x3F\x67\xF8\x9F\x31\xFC\x9F\x18\xFC\x51\x66\x0E",
b"\x29\x83\x6F\x31\xF8\xC7\x0C\xBE\x8B\xF1\x99\x73\xCF\x4F\x86\xBF",
b"\x93\xF1\x9F\x32\xF8\x1E\xEE\x79\x88\x75\xEF\x45\xB5\xF5\x6B\xEE",
b"\x7D\x22\xBC\x1F\x4D\x79\x7C\xE3\x16\xFC\x37\x8F\x5F\xBE\x05\x87",
b"\x28\xEA\xE6\x85\x8E\x6A\x13\x57\x26\x8A\x20\x55\x89\x2A\x6A\x81",
b"\xB1\xBE\x98\xE3\x77\x51\x0A\x8D\x41\x54\x55\x51\x41\xA6\xA5\x8A",
b"\x8D\x08\xF1\xB8\xCE\x4C\x14\x36\x4B\x3A\x45\x2D\xE4\xE9\x22\x52",
b"\x45\x12\x9B\xAC\xD0\x50\xC5\x19\x6A\xC9\xA2\xEA\xC3\x6A\x9C\x99",
b"\x32\x23\xCE\xB0\xEC\x46\x9D\xB8\x16\x3A\xCE\x05\xE4\xFD\xD4\x88",
b"\xBC\x04\x29\xD5\xA0\xEE\x41\x6D\xAA\xA4\xBC\x08\x32\xE9\xE5\x45",
b"\x0A\x95\x88\xD3\x34\xAB\xA0\x16\x86\x24\x15\x49\x91\x9F\xD5\xA4",
b"\xD6\x44\x43\xB6\x4E\x30\x39\x42\xFB\x55\x3A\x28\xA1\x74\x3E\x6D",
b"\x0B\x36\x31\xEB\xEA\x58\x39\x1E\xF2\xF3\x4E\x6D\x0A\x4C\xC6\x04",
b"\x35\xC4\x8E\x0D\x0C\x34\xBE\x66\xF5\xC9\x05\xB2\xB1\x9C\xC2\x3A",
b"\x48\x4F\x33\x0D\x5D\x61\xFD\xF6\x33\x65\x05\x4C\xD1\x07\x29\x0A",
b"\x09\xE8\xC3\x91\x2A\x85\x56\xCA\x2A\x31\x0A\x30\xDB\x76\x53\xE5",
b"\xA4\x93\x8B\x9C\x5C\x25\x4A\xC4\x15\x1A\xC2\x22\xD8\x80\xD0\x2B",
b"\x58\x56\x96\x55\xA6\x8D\x8C\x92\x5E\x9F\xCA\x14\x03\x63\xD9\xB6",
b"\x65\x3B\xF7\x28\x5A\xA9\x75\x83\x94\x8F\xAA\xE1\x48\xAD\xC3\x32",
b"\x36\x3D\x90\x46\x20\x0E\x5A\x45\x2A\xD6\x5D\x3C\x82\x02\x68\x32",
b"\x54\x1D\x7D\x53\x2D\x54\xA7\xDA\x38\x9A\xA6\x1C\x4D\xD4\x76\x2C",
b"\x86\x22\x59\x29\xDD\x64\x50\x38\x8A\x82\xB4\xA5\xC9\x0C\x7B\x2B",
b"\x40\xAE\x56\x19\x1E\xB7\xA4\x2C\xA4\x38\xA7\x96\x80\x9D\x10\xE8",
b"\xFB\xA8\x92\x1E\x55\x5A\x69\x76\x67\xCF\x64\x9B\xEE\xC6\xED\xC0",
b"\xD8\xB8\x3C\x61\x3A\x03\x69\xD3\x71\x5A\x18\xDC\xE1\xE1\xD9\x64",
b"\x9D\xC4\xDF\x90\x79\x8C\x27\x21\xDD\x0F\xB5\x29\xED\xA0\x6A\x21",
b"\xFA\x05\x84\xB6\xC8\x9D\x00\x4C\x49\x95\x7B\x4B\xC6\xE5\x2B\xB4",
b"\xDA\x47\xAB\xD2\xF4\xC8\x27\xED\x9F\xA4\x7D\x42\xAB\x05\x38\xB6",
b"\x7C\xFC\xF0\x91\x68\x6E\x76\x6E\x76\xFF\x68\x7D\x60\xB4\xDA\x37",
b"\x3F\x5A\x3E\x35\x5A\x35\x30\x5C\xC3\x4D\x95\x6E\xA4\x60",
]
)
)
assert capa.features.extractors.elf.detect_elf_os(io.BytesIO(elf_header)) == "linux"