Skip to content

Commit ad709c8

Browse files
prabhucerrussell
andauthored
generic binary SBOM (#56)
* mac sbom Signed-off-by: Prabhu Subramanian <[email protected]> * windows sbom Signed-off-by: Prabhu Subramanian <[email protected]> * Reformat file based on PR comments Signed-off-by: Prabhu Subramanian <[email protected]> * Move config items to config.py, extract duplicate code into functions. (#58) Signed-off-by: Caroline Russell <[email protected]> --------- Signed-off-by: Prabhu Subramanian <[email protected]> Signed-off-by: Caroline Russell <[email protected]> Co-authored-by: Caroline Russell <[email protected]>
1 parent 503b187 commit ad709c8

File tree

8 files changed

+1749
-664
lines changed

8 files changed

+1749
-664
lines changed

blint/analysis.py

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,12 @@
1111
from pathlib import Path
1212

1313
import yaml
14-
from rich import box
1514
from rich.progress import Progress
16-
from rich.table import Table
1715
from rich.terminal_theme import MONOKAI
1816

1917
from blint.binary import parse
2018
from blint.logger import LOG, console
21-
from blint.utils import (is_fuzzable_name, print_findings_table, )
19+
from blint.utils import (create_findings_table, is_fuzzable_name, print_findings_table, )
2220
from blint.checks import (check_nx, check_pie, # noqa, pylint: disable=unused-import
2321
check_relro, check_canary, check_rpath,
2422
check_virtual_size, check_authenticode,
@@ -279,15 +277,7 @@ def print_reviews_table(reviews, files):
279277
files: A list of file names associated with the reviews.
280278
281279
"""
282-
table = Table(
283-
title="BLint Capability Review",
284-
box=box.DOUBLE_EDGE,
285-
header_style="bold magenta",
286-
show_lines=True,
287-
)
288-
table.add_column("ID")
289-
if len(files) > 1:
290-
table.add_column("Binary")
280+
table = create_findings_table(files, "BLint Capability Review")
291281
table.add_column("Capabilities")
292282
table.add_column("Evidence (Top 5)", overflow="fold")
293283
for r in reviews:
@@ -545,7 +535,7 @@ def _review_symbols_exe(self, metadata):
545535
symbols_list = [f.get("name", "") for f in
546536
metadata.get("dynamic_symbols", [])]
547537
symbols_list += [f.get("name", "") for f in
548-
metadata.get("static_symbols", [])]
538+
metadata.get("symtab_symbols", [])]
549539
LOG.debug(f"Reviewing {len(symbols_list)} symbols")
550540
if self.review_symbols_list:
551541
self.run_review_methods_symbols(
@@ -565,11 +555,11 @@ def _methods_or_exe(self, metadata):
565555
metadata.get("functions", [])]
566556
if metadata.get("magic", "").startswith("PE"):
567557
functions_list += [f.get("name", "") for f in
568-
metadata.get("static_symbols", [])]
558+
metadata.get("symtab_symbols", [])]
569559
# If there are no function but static symbols use that instead
570-
if not functions_list and metadata.get("static_symbols"):
560+
if not functions_list and metadata.get("symtab_symbols"):
571561
functions_list = [f.get("name", "") for f in
572-
metadata.get("static_symbols", [])]
562+
metadata.get("symtab_symbols", [])]
573563
LOG.debug(f"Reviewing {len(functions_list)} functions")
574564
if self.review_methods_list:
575565
self.run_review_methods_symbols(

blint/android.py

Lines changed: 24 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,24 @@
77
from blint.binary import parse, parse_dex
88
from blint.cyclonedx.spec import (
99
Component,
10-
ComponentEvidence,
11-
FieldModel,
12-
Identity,
13-
Method,
1410
Property,
1511
RefType,
1612
Scope,
17-
Technique,
1813
Type,
1914
)
2015
from blint.logger import LOG
21-
from blint.utils import check_command, find_files, unzip_unsafe
16+
from blint.utils import check_command, create_component_evidence, find_files, unzip_unsafe
2217

2318
ANDROID_HOME = os.getenv("ANDROID_HOME")
2419
APKANALYZER_CMD = os.getenv("APKANALYZER_CMD")
25-
if not APKANALYZER_CMD and ANDROID_HOME and (
20+
if (
21+
not APKANALYZER_CMD
22+
and ANDROID_HOME
23+
and (
2624
os.path.exists(os.path.join(ANDROID_HOME, "cmdline-tools", "latest", "bin", "apkanalyzer"))
25+
)
2726
):
28-
APKANALYZER_CMD = os.path.join(
29-
ANDROID_HOME, "cmdline-tools", "latest", "bin", "apkanalyzer"
30-
)
27+
APKANALYZER_CMD = os.path.join(ANDROID_HOME, "cmdline-tools", "latest", "bin", "apkanalyzer")
3128
elif check_command("apkanalyzer"):
3229
APKANALYZER_CMD = "apkanalyzer"
3330

@@ -50,7 +47,8 @@ def exec_tool(args, cwd=None, stdout=subprocess.PIPE):
5047
env=os.environ.copy(),
5148
shell=sys.platform == "win32",
5249
encoding="utf-8",
53-
check=False, )
50+
check=False,
51+
)
5452
except subprocess.SubprocessError as e:
5553
LOG.exception(e)
5654
return None
@@ -145,9 +143,7 @@ def collect_version_files_metadata(app_file, app_temp_dir):
145143
with open(vf, encoding="utf-8") as fp:
146144
version_data = fp.read().strip()
147145
if name and version_data:
148-
component = create_version_component(
149-
app_file, group, name, rel_path, version_data
150-
)
146+
component = create_version_component(app_file, group, name, rel_path, version_data)
151147
file_components.append(component)
152148
return file_components
153149

@@ -177,14 +173,11 @@ def create_version_component(app_file, group, name, rel_path, version_data):
177173
version=version_data,
178174
purl=purl,
179175
scope=Scope.required,
180-
evidence=ComponentEvidence(
181-
identity=Identity(
182-
field=FieldModel.purl, confidence=1, methods=[Method(
183-
technique=Technique.manifest_analysis, value=rel_path, confidence=1, )], )
184-
),
176+
evidence=create_component_evidence(rel_path, 1.0),
185177
properties=[
186178
Property(name="internal:srcFile", value=rel_path),
187-
Property(name="internal:appFile", value=app_file), ],
179+
Property(name="internal:appFile", value=app_file),
180+
],
188181
)
189182
component.bom_ref = RefType(purl)
190183
return component
@@ -260,7 +253,8 @@ def parse_so_file(app_file, app_temp_dir, sof):
260253
# Retrieve the version number from notes
261254
version = get_so_version(so_metadata.get("notes", []))
262255
functions = [
263-
f.get("name") for f in so_metadata.get("functions", [])
256+
f.get("name")
257+
for f in so_metadata.get("functions", [])
264258
if f.get("name") and not f.get("name").startswith("_")
265259
]
266260
purl = f"pkg:generic/{name}@{version}"
@@ -273,19 +267,11 @@ def parse_so_file(app_file, app_temp_dir, sof):
273267
version=version,
274268
purl=purl,
275269
scope=Scope.required,
276-
evidence=ComponentEvidence(
277-
identity=Identity(
278-
field=FieldModel.purl,
279-
confidence=0.5,
280-
methods=[
281-
Method(technique=Technique.binary_analysis, value=rel_path, confidence=0.5, )
282-
],
283-
)
284-
),
270+
evidence=create_component_evidence(str(rel_path), 0.5),
285271
properties=[
286272
Property(name="internal:srcFile", value=rel_path),
287273
Property(name="internal:appFile", value=app_file),
288-
Property(name="internal:functions", value=", ".join(set(functions)), ),
274+
Property(name="internal:functions", value=", ".join(set(functions))),
289275
],
290276
)
291277
component.bom_ref = RefType(purl)
@@ -331,13 +317,11 @@ def collect_dex_files_metadata(app_file, parent_component, app_temp_dir):
331317
dex_metadata = parse_dex(adex)
332318
name = os.path.basename(adex).removesuffix(".dex")
333319
rel_path = os.path.relpath(adex, app_temp_dir)
334-
group = (parent_component.group if parent_component and parent_component.group else "")
320+
group = parent_component.group if parent_component and parent_component.group else ""
335321
version = (
336-
parent_component.version if parent_component and parent_component.version else
337-
"latest")
338-
component = create_dex_component(
339-
app_file, dex_metadata, group, name, rel_path, version
322+
parent_component.version if parent_component and parent_component.version else "latest"
340323
)
324+
component = create_dex_component(app_file, dex_metadata, group, name, rel_path, version)
341325
file_components.append(component)
342326
return file_components
343327

@@ -365,19 +349,7 @@ def create_dex_component(app_file, dex_metadata, group, name, rel_path, version)
365349
version=version,
366350
purl=purl,
367351
scope=Scope.required,
368-
evidence=ComponentEvidence(
369-
identity=Identity(
370-
field=FieldModel.purl,
371-
confidence=0.2,
372-
methods=[
373-
Method(
374-
technique=Technique.binary_analysis,
375-
value=rel_path,
376-
confidence=0.2,
377-
)
378-
],
379-
)
380-
),
352+
evidence=create_component_evidence(rel_path, 0.2),
381353
properties=[
382354
Property(name="internal:srcFile", value=rel_path),
383355
Property(name="internal:appFile", value=app_file),
@@ -393,11 +365,7 @@ def create_dex_component(app_file, dex_metadata, group, name, rel_path, version)
393365
Property(
394366
name="internal:classes",
395367
value=", ".join(
396-
set(
397-
sorted(
398-
[_clean_type(c.fullname) for c in dex_metadata.get("classes")]
399-
)
400-
)
368+
set(sorted([_clean_type(c.fullname) for c in dex_metadata.get("classes")]))
401369
),
402370
),
403371
],
@@ -430,9 +398,7 @@ def collect_files_metadata(app_file, parent_component, deep_mode):
430398
file_components += collect_version_files_metadata(app_file, app_temp_dir)
431399
file_components += collect_so_files_metadata(app_file, app_temp_dir)
432400
if deep_mode:
433-
file_components += collect_dex_files_metadata(
434-
app_file, parent_component, app_temp_dir
435-
)
401+
file_components += collect_dex_files_metadata(app_file, parent_component, app_temp_dir)
436402
shutil.rmtree(app_temp_dir, ignore_errors=True)
437403
return file_components
438404

@@ -445,9 +411,7 @@ def parse_apk_summary(data):
445411
name = parts[0]
446412
version = parts[-1]
447413
purl = f"pkg:apk/{name}@{version}"
448-
component = Component(
449-
type=Type.application, name=name, version=version, purl=purl
450-
)
414+
component = Component(type=Type.application, name=name, version=version, purl=purl)
451415
component.bom_ref = RefType(purl)
452416
return component
453417
return None

0 commit comments

Comments
 (0)