From 30a2a1e1f1e4fb7a9a5fa74bc7906711cf0eee55 Mon Sep 17 00:00:00 2001 From: kunalsz Date: Sat, 7 Feb 2026 11:32:28 +0530 Subject: [PATCH 1/2] Add Complex Functions heuristic Signed-off-by: kunalsz --- floss/features/extract.py | 32 ++++++++++++++++++++++++++++++++ floss/features/features.py | 27 +++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/floss/features/extract.py b/floss/features/extract.py index f79bbf880..9042dca2b 100644 --- a/floss/features/extract.py +++ b/floss/features/extract.py @@ -36,6 +36,7 @@ TightFunction, KindaTightLoop, NzxorTightLoop, + ComplexFunctions, ) # security cookie checks may perform non-zeroing XORs, these are expected within a certain @@ -317,10 +318,41 @@ def extract_function_loop(f): yield Loop(comp) +def extract_function_complex_functions(f): + """ + Cyclomatic complexity + M = E - N + 2P + where: + E = edges + N = nodes (basic blocks) + P = number of connected components (usually 1) + """ + try: + cfg = viv_utils.CFG(f) + blocks = list(cfg.basic_blocks) + + num_nodes = len(blocks) + + num_edges = 0 + for bb in blocks: + succs = cfg.get_successor_basic_blocks(bb) + num_edges += len(list(succs)) + + complexity = num_edges - num_nodes + 2 + + complexity = max(1, complexity) + + yield ComplexFunctions(complexity) + + except Exception: + yield ComplexFunctions(1) + + FUNCTION_HANDLERS = ( extract_function_calls_to, extract_function_loop, extract_function_kinda_tight_loop, + extract_function_complex_functions, # extract_function_order, # TODO decoding functions are often one of the first in a program # extract_num_api_calls, # TODO decoding functions don't normally contain many (API) calls ) diff --git a/floss/features/features.py b/floss/features/features.py index 1ea341d87..48ad8661c 100644 --- a/floss/features/features.py +++ b/floss/features/features.py @@ -199,3 +199,30 @@ def __init__(self): def score(self): return 1.0 + + +class ComplexFunctions(Feature): + weight = MEDIUM + + def __init__(self,comp): + super(ComplexFunctions, self).__init__(True) + self.comp = comp + + def score(self): + complexity = self.comp + + if complexity <= 1: + return 0.0 + elif complexity <= 10: + # Simple functions + return 0.2 + elif complexity <= 20: + return 0.4 + elif complexity <= 30: + return 0.6 + elif complexity <= 50: + # Very complex + return 0.8 + else: + # Extremely complex + return 1.0 From 9fdc7b69d0dda44810d4213b622c3422d4bb5173 Mon Sep 17 00:00:00 2001 From: kunalsz Date: Sat, 7 Feb 2026 19:20:48 +0530 Subject: [PATCH 2/2] Fix ComplexFunctions class Signed-off-by: kunalsz --- floss/features/extract.py | 4 +++- floss/features/features.py | 7 +++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/floss/features/extract.py b/floss/features/extract.py index 9042dca2b..7b6cd263a 100644 --- a/floss/features/extract.py +++ b/floss/features/extract.py @@ -344,7 +344,9 @@ def extract_function_complex_functions(f): yield ComplexFunctions(complexity) - except Exception: + except Exception as e: + logger.warning("Failed to calculate complexity for function: %s", e) + # Yield default complexity of 1(a purely linear function, with no branches) on error yield ComplexFunctions(1) diff --git a/floss/features/features.py b/floss/features/features.py index 48ad8661c..0dfbec459 100644 --- a/floss/features/features.py +++ b/floss/features/features.py @@ -204,12 +204,11 @@ def score(self): class ComplexFunctions(Feature): weight = MEDIUM - def __init__(self,comp): - super(ComplexFunctions, self).__init__(True) - self.comp = comp + def __init__(self, comp): + super(ComplexFunctions, self).__init__(comp) def score(self): - complexity = self.comp + complexity = self.value if complexity <= 1: return 0.0