mirror of
https://github.com/cyber-defence-campus/mole
synced 2026-06-20 13:19:21 +00:00
252 redirect logs to stderr add silent mode and introduce final summary in mole headless (#254)
- Write headless log output to `stderr` - Add log level `none` to suppress log output - Write machine-readable summary to `stdout`
This commit is contained in:
+53
-3
@@ -8,7 +8,9 @@ import argparse as ap
|
||||
import binaryninja as bn
|
||||
import hashlib
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
import time
|
||||
import yaml
|
||||
|
||||
|
||||
@@ -29,7 +31,7 @@ def main() -> None:
|
||||
parser.add_argument("--config_file", help="custom configuration file to use")
|
||||
parser.add_argument(
|
||||
"--log_level",
|
||||
choices=["error", "warning", "info", "debug"],
|
||||
choices=["error", "warning", "info", "debug", "none"],
|
||||
default="debug",
|
||||
help="log level",
|
||||
)
|
||||
@@ -72,6 +74,8 @@ def main() -> None:
|
||||
"--save_bndb", help="save BN database file with analysis results"
|
||||
)
|
||||
args = vars(parser.parse_args())
|
||||
# Time before analysis
|
||||
start_time = time.time()
|
||||
# Load and analyze binary with Binary Ninja
|
||||
try:
|
||||
bv = bn.load(args["file"])
|
||||
@@ -86,9 +90,10 @@ def main() -> None:
|
||||
# Analyze binary with Mole
|
||||
try:
|
||||
# Find paths
|
||||
path_service = PathService(
|
||||
bv, log, ConfigModel(ConfigService(log, args["config_file"]).load_config())
|
||||
config_model = ConfigModel(
|
||||
ConfigService(log, args["config_file"]).load_config()
|
||||
)
|
||||
path_service = PathService(bv, log, config_model)
|
||||
path_service.find_paths(
|
||||
max_workers=args["max_workers"],
|
||||
fix_func_type=args["fix_func_type"],
|
||||
@@ -141,6 +146,51 @@ def main() -> None:
|
||||
fp = args["save_bndb"]
|
||||
fp = os.path.abspath(os.path.expanduser(os.path.expandvars(fp)))
|
||||
bv.create_database(fp)
|
||||
# Time after analysis
|
||||
end_time = time.time()
|
||||
# Calculate path statistics
|
||||
paths_stats: Dict[str, Dict[str, int]] = {}
|
||||
for path in paths:
|
||||
paths_stats[path.src_sym_name][path.snk_sym_name] = (
|
||||
paths_stats.setdefault(path.src_sym_name, {}).setdefault(
|
||||
path.snk_sym_name, 0
|
||||
)
|
||||
+ 1
|
||||
)
|
||||
sources: Dict[str, List[str]] = {}
|
||||
for lib_name in config_model.get_libraries("Sources").keys():
|
||||
src_funcs = [
|
||||
func.name
|
||||
for func in config_model.get_functions(
|
||||
lib_name=lib_name, fun_type="Sources", fun_enabled=True
|
||||
)
|
||||
]
|
||||
if src_funcs:
|
||||
sources.setdefault(lib_name, []).extend(src_funcs)
|
||||
sinks: Dict[str, List[str]] = {}
|
||||
for lib_name in config_model.get_libraries("Sinks").keys():
|
||||
snk_funcs = [
|
||||
func.name
|
||||
for func in config_model.get_functions(
|
||||
lib_name=lib_name, fun_type="Sinks", fun_enabled=True
|
||||
)
|
||||
]
|
||||
if snk_funcs:
|
||||
sinks.setdefault(lib_name, []).extend(snk_funcs)
|
||||
# Output summary of results in machine-readable format
|
||||
print(
|
||||
json.dumps(
|
||||
{
|
||||
"analysis_time_seconds": math.trunc((end_time - start_time) * 1000)
|
||||
/ 1000,
|
||||
"paths_total": len(paths),
|
||||
"paths_stats": paths_stats,
|
||||
"sources": sources,
|
||||
"sinks": sinks,
|
||||
},
|
||||
indent=2,
|
||||
)
|
||||
)
|
||||
# Close binary
|
||||
bv.file.close()
|
||||
except KeyboardInterrupt:
|
||||
|
||||
+12
-11
@@ -12,12 +12,12 @@ class Logger:
|
||||
This class implements a logger that can print messages to Binary Ninja's log and to the console.
|
||||
"""
|
||||
|
||||
_levels = ["debug", "info", "warning", "error"]
|
||||
_levels = ["debug", "info", "warning", "error", "none"]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
bv: bn.BinaryView | None = None,
|
||||
level: Literal["debug", "info", "warning", "error"] = "debug",
|
||||
level: Literal["debug", "info", "warning", "error", "none"] = "debug",
|
||||
) -> None:
|
||||
"""
|
||||
This method initializes a logger that can be used to write messages of a given level (and
|
||||
@@ -92,7 +92,7 @@ class Logger:
|
||||
on_color: str = "",
|
||||
print_raw: bool = False,
|
||||
attrs: List[str] = [],
|
||||
file=sys.stdout,
|
||||
file=sys.stderr,
|
||||
) -> None:
|
||||
"""
|
||||
This method prints the given message to the console.
|
||||
@@ -129,7 +129,7 @@ class Logger:
|
||||
text = self._tag_msg(tag, msg)
|
||||
if not self._runs_headless and not self._runs_debugger:
|
||||
self._logger.log_debug(text)
|
||||
elif self._level <= 0:
|
||||
elif self._runs_debugger or self._level <= 0:
|
||||
self._print(
|
||||
"DEBG",
|
||||
text,
|
||||
@@ -137,8 +137,9 @@ class Logger:
|
||||
on_color=on_color,
|
||||
print_raw=print_raw,
|
||||
attrs=attrs,
|
||||
file=sys.stdout,
|
||||
file=sys.stdout if self._runs_debugger else sys.stderr,
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
def info(
|
||||
@@ -156,7 +157,7 @@ class Logger:
|
||||
text = self._tag_msg(tag, msg)
|
||||
if not self._runs_headless and not self._runs_debugger:
|
||||
self._logger.log_info(text)
|
||||
elif self._level <= 1:
|
||||
elif self._runs_debugger or self._level <= 1:
|
||||
self._print(
|
||||
"INFO",
|
||||
text,
|
||||
@@ -164,7 +165,7 @@ class Logger:
|
||||
on_color=on_color,
|
||||
print_raw=print_raw,
|
||||
attrs=attrs,
|
||||
file=sys.stdout,
|
||||
file=sys.stdout if self._runs_debugger else sys.stderr,
|
||||
)
|
||||
return
|
||||
|
||||
@@ -183,7 +184,7 @@ class Logger:
|
||||
text = self._tag_msg(tag, msg)
|
||||
if not self._runs_headless and not self._runs_debugger:
|
||||
self._logger.log_warn(text)
|
||||
elif self._level <= 2:
|
||||
elif self._runs_debugger or self._level <= 2:
|
||||
self._print(
|
||||
"WARN",
|
||||
text,
|
||||
@@ -191,7 +192,7 @@ class Logger:
|
||||
on_color=on_color,
|
||||
print_raw=print_raw,
|
||||
attrs=attrs,
|
||||
file=sys.stderr,
|
||||
file=sys.stdout if self._runs_debugger else sys.stderr,
|
||||
)
|
||||
return
|
||||
|
||||
@@ -210,7 +211,7 @@ class Logger:
|
||||
text = self._tag_msg(tag, msg)
|
||||
if not self._runs_headless and not self._runs_debugger:
|
||||
self._logger.log_error(text)
|
||||
elif self._level <= 3:
|
||||
elif self._runs_debugger or self._level <= 3:
|
||||
self._print(
|
||||
"ERRO",
|
||||
text,
|
||||
@@ -218,6 +219,6 @@ class Logger:
|
||||
on_color=on_color,
|
||||
print_raw=print_raw,
|
||||
attrs=attrs,
|
||||
file=sys.stderr,
|
||||
file=sys.stdout if self._runs_debugger else sys.stderr,
|
||||
)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user