{-# LANGUAGE DuplicateRecordFields #-}

-- |
-- Module      : Binja.AnalysisContext
-- Description : Central abstraction
-- License     : MIT
-- Maintainer  : hello@bloombit.dev
-- Stability   : alpha
--
-- @Binja.AnalysisContext@ extracts and lifts low level types from binary ninja into Beluga's central
-- abstraction. This is the recommended interface for most users.
--
-- [/Reasons not to use:/]
--
-- * Less data than AnalysisContext provides is required and have limited hardware.
-- * AnalysisContext is fixed to the SSA variant of Medium Level IL.
--
-- [/Reasons to use:/]
--
-- * Extracts and lifts the common types required by most program analysis in a single call.
-- * Abstracts away many low level FFI calls and types.
-- * Creates a single type that can be queried in pure functions (no further IO calls required for most analysis).
--   This lends itself to making things easier in creating parallel code.
module Binja.AnalysisContext
  ( Binja.AnalysisContext.create,
    Binja.AnalysisContext.symbolAt,
    Binja.AnalysisContext.callers,
    Binja.AnalysisContext.extractCallDestSymbol,
    Binja.AnalysisContext.summary,
    Binja.AnalysisContext.close,
  )
where

import Binja.BinaryView
import Binja.ControlFlowGraph
import Binja.FFI (c_BNGetEntryPoint, c_BNGetImageBase)
import Binja.Function
import Binja.Mlil
import Binja.Types.Core
import Binja.Utils
import Data.Map as Map
import Data.Maybe (catMaybes)
import Data.Set as Set
import Numeric (showHex)

-- |
--
-- Derive an AnalysisContext from a given filename and json-formatted binja options.
--
-- Warning: every function contains a MLIL SSA variant; otherwise this function will
-- throw an exception.
--
-- Suggested minimum settings:
--
--   * Set analysis.mode.maxFunctionSize to 0 (disables max function size)
--   * Set analysis.mode.maxFunctionAnalysisTime to 0 (disables timeouts)
--   * Set analysis.mode` to intermediate to disable HLIL generation
create ::
  -- | Filename to an executable or an existing binja database (bndb)
  String ->
  -- | Options in json format
  String ->
  IO AnalysisContext
create :: String -> String -> IO AnalysisContext
create String
filename' String
options = do
  viewHandle' <- String -> String -> IO BNBinaryViewPtr
Binja.BinaryView.load String
filename' String
options
  functions' <- Binja.BinaryView.functions viewHandle'
  functionContexts <- mapM createFunctionContext functions'
  entryFunction' <- Binja.BinaryView.entryFunction viewHandle'
  entryFunctionContext <- traverse createFunctionContext entryFunction'
  entryFunctions' <- Binja.BinaryView.entryFunctions viewHandle'
  entryFunctionContexts <- mapM createFunctionContext entryFunctions'
  symbols' <- Binja.BinaryView.symbols viewHandle'
  strings' <- catMaybes <$> Binja.BinaryView.strings viewHandle'
  imageBase' <- c_BNGetImageBase viewHandle'
  entryPoint' <- c_BNGetEntryPoint viewHandle'
  segments' <- Binja.BinaryView.segments viewHandle'
  sections' <- Binja.BinaryView.sections viewHandle'
  -- Only keep full confidence data variables
  dataVars' <- Prelude.filter (\DataVariable {typeConfidence :: DataVariable -> Word8
typeConfidence = Word8
tc} -> Word8
tc Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
255) <$> Binja.BinaryView.dataVars viewHandle'
  pure
    AnalysisContext
      { viewHandle = viewHandle',
        filename = filename',
        functions = functionContexts,
        entryFunction = entryFunctionContext,
        entryFunctions = entryFunctionContexts,
        symbols = symbols',
        strings = strings',
        imageBase = imageBase',
        entryPoint = entryPoint',
        dataVars = dataVars',
        segments = segments',
        sections = sections'
      }

createFunctionContext :: BNFunctionPtr -> IO FunctionContext
createFunctionContext :: BNFunctionPtr -> IO FunctionContext
createFunctionContext BNFunctionPtr
handle' = do
  mlilSSAHandle <- BNFunctionPtr -> IO BNMlilSSAFunctionPtr
Binja.Function.mlilSSA BNFunctionPtr
handle'
  start' <- Binja.Function.start handle'
  symbol' <- Binja.Function.symbol handle'
  auto' <- Binja.Function.auto handle'
  instructions' <- Binja.Mlil.instructionsFromFuncNoChildren mlilSSAHandle
  ssaVariables' <- Binja.Function.ssaVars mlilSSAHandle
  ssaVarContext' <- Map.fromList <$> mapM (\BNSSAVariable
l -> BNSSAVariable
-> BNMlilSSAFunctionPtr -> IO (BNSSAVariable, SSAVariableContext)
createSSAVariableContext BNSSAVariable
l BNMlilSSAFunctionPtr
mlilSSAHandle) ssaVariables'
  aliasedVars' <- Binja.Function.aliasedVars mlilSSAHandle
  parameterVars' <- Binja.Function.parameterVars mlilSSAHandle
  architecture' <- Binja.Function.architecture mlilSSAHandle
  cfg' <- Binja.ControlFlowGraph.create mlilSSAHandle
  pure
    FunctionContext
      { handle = mlilSSAHandle,
        start = start',
        symbol = symbol',
        auto = auto',
        ssaVars = ssaVarContext',
        parameterVars = parameterVars',
        aliasedVars = aliasedVars',
        instructions = instructions',
        architecture = architecture',
        cfg = cfg'
      }

createSSAVariableContext :: BNSSAVariable -> BNMlilSSAFunctionPtr -> IO (BNSSAVariable, SSAVariableContext)
createSSAVariableContext :: BNSSAVariable
-> BNMlilSSAFunctionPtr -> IO (BNSSAVariable, SSAVariableContext)
createSSAVariableContext BNSSAVariable
var' BNMlilSSAFunctionPtr
func = do
  defSite' <- BNSSAVariable
-> BNMlilSSAFunctionPtr -> IO (Maybe MediumLevelILSSAInstruction)
Binja.Mlil.defSite BNSSAVariable
var' BNMlilSSAFunctionPtr
func
  useSites' <- Binja.Mlil.useSites var' func
  pure $ (var', SSAVariableContext {defSite = defSite', useSites = useSites'})

-- | Acquire the symbol at address if one exists.
symbolAt :: AnalysisContext -> Word64 -> Maybe Symbol
symbolAt :: AnalysisContext -> Word64 -> Maybe Symbol
symbolAt AnalysisContext {symbols :: AnalysisContext -> [Symbol]
symbols = [Symbol]
syms} Word64
requestAddr =
  case (Symbol -> Bool) -> [Symbol] -> [Symbol]
forall a. (a -> Bool) -> [a] -> [a]
Prelude.filter (\Symbol {address :: Symbol -> Word64
address = Word64
addr} -> (Word64
requestAddr Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
==) Word64
addr) [Symbol]
syms of
    [] -> Maybe Symbol
forall a. Maybe a
Nothing
    [Symbol
sym] -> Symbol -> Maybe Symbol
forall a. a -> Maybe a
Just Symbol
sym
    [Symbol]
_ -> String -> Maybe Symbol
forall a. HasCallStack => String -> a
error (String -> Maybe Symbol) -> String -> Maybe Symbol
forall a b. (a -> b) -> a -> b
$ String
"Binja.AnalysisContext.symbolAt: Multiple symbols at: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Word64 -> String
forall a. Show a => a -> String
show Word64
requestAddr

-- Convert Constant instruction to symbol if possible
constantToSymbol :: AnalysisContext -> Constant -> Maybe Symbol
constantToSymbol :: AnalysisContext -> Constant -> Maybe Symbol
constantToSymbol AnalysisContext
context (MediumLevelILConstPtr (MediumLevelILConstPtrRec {constant :: MediumLevelILConstPtrRec -> Int
constant = Int
c})) = do
  AnalysisContext -> Word64 -> Maybe Symbol
Binja.AnalysisContext.symbolAt AnalysisContext
context (Word64 -> Maybe Symbol) -> Word64 -> Maybe Symbol
forall a b. (a -> b) -> a -> b
$ Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
c
constantToSymbol AnalysisContext
context (MediumLevelILImport (MediumLevelILImportRec {constant :: MediumLevelILImportRec -> Int
constant = Int
c})) = do
  AnalysisContext -> Word64 -> Maybe Symbol
Binja.AnalysisContext.symbolAt AnalysisContext
context (Word64 -> Maybe Symbol) -> Word64 -> Maybe Symbol
forall a b. (a -> b) -> a -> b
$ Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
c
constantToSymbol AnalysisContext
_ (MediumLevelILConst (MediumLevelILConstRec {constant :: MediumLevelILConstRec -> Int
constant = Int
c})) = do
  String -> Maybe Symbol
forall a. HasCallStack => String -> a
error (String -> Maybe Symbol) -> String -> Maybe Symbol
forall a b. (a -> b) -> a -> b
$ String
"Unhandled constant: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
c
constantToSymbol AnalysisContext
_ (MediumLevelILFloatConst MediumLevelILFloatConstRec {constant :: MediumLevelILFloatConstRec -> Double
constant = Double
c}) = do
  String -> Maybe Symbol
forall a. HasCallStack => String -> a
error (String -> Maybe Symbol) -> String -> Maybe Symbol
forall a b. (a -> b) -> a -> b
$ String
"Unhandled float constant: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Double -> String
forall a. Show a => a -> String
show Double
c
constantToSymbol AnalysisContext
_ (MediumLevelILConstData MediumLevelILConstDataRec {constant :: MediumLevelILConstDataRec -> BNDataBufferPtr
constant = BNDataBufferPtr
c}) = do
  String -> Maybe Symbol
forall a. HasCallStack => String -> a
error (String -> Maybe Symbol) -> String -> Maybe Symbol
forall a b. (a -> b) -> a -> b
$ String
"Unhandled constant data: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ BNDataBufferPtr -> String
forall a. Show a => a -> String
show BNDataBufferPtr
c
constantToSymbol AnalysisContext
context (MediumLevelILExternPtr MediumLevelILExternPtrRec {constant :: MediumLevelILExternPtrRec -> Int
constant = Int
c}) = do
  AnalysisContext -> Word64 -> Maybe Symbol
Binja.AnalysisContext.symbolAt AnalysisContext
context (Word64 -> Maybe Symbol) -> Word64 -> Maybe Symbol
forall a b. (a -> b) -> a -> b
$ Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
c

-- |
--  Given a call instruction attempt to recover the destination symbol (symbol that is called).
--  There are many patterns that could occur. Currently only constant destinations are supported.
--  In the future a cocktail of patterns will be supported. Further reading: <https://dl.acm.org/doi/10.1145/3622833 A Cocktail Approach to Practical Call Graph Construction>
extractCallDestSymbol :: AnalysisContext -> MediumLevelILSSAInstruction -> Maybe Symbol
extractCallDestSymbol :: AnalysisContext -> MediumLevelILSSAInstruction -> Maybe Symbol
extractCallDestSymbol AnalysisContext
context MediumLevelILSSAInstruction
callInst =
  case MediumLevelILSSAInstruction
callInst of
    Localcall Localcall
lc ->
      case Localcall
lc of
        (MediumLevelILCallSsa MediumLevelILCallSsaRec {dest :: MediumLevelILCallSsaRec -> MediumLevelILSSAInstruction
dest = MediumLevelILSSAInstruction
d}) -> MediumLevelILSSAInstruction -> Maybe Symbol
processDest MediumLevelILSSAInstruction
d
        (MediumLevelILCallUntypedSsa MediumLevelILCallUntypedSsaRec {dest :: MediumLevelILCallUntypedSsaRec -> MediumLevelILSSAInstruction
dest = MediumLevelILSSAInstruction
d}) -> MediumLevelILSSAInstruction -> Maybe Symbol
processDest MediumLevelILSSAInstruction
d
    Tailcall Tailcall
tc ->
      case Tailcall
tc of
        (MediumLevelILTailcallUntyped MediumLevelILTailcallUntypedRec {dest :: MediumLevelILTailcallUntypedRec -> MediumLevelILSSAInstruction
dest = MediumLevelILSSAInstruction
d}) -> MediumLevelILSSAInstruction -> Maybe Symbol
processDest MediumLevelILSSAInstruction
d
        (MediumLevelILTailcall MediumLevelILTailcallRec {dest :: MediumLevelILTailcallRec -> MediumLevelILSSAInstruction
dest = MediumLevelILSSAInstruction
d}) -> MediumLevelILSSAInstruction -> Maybe Symbol
processDest MediumLevelILSSAInstruction
d
        (MediumLevelILTailcallSsa MediumLevelILTailcallSsaRec {dest :: MediumLevelILTailcallSsaRec -> MediumLevelILSSAInstruction
dest = MediumLevelILSSAInstruction
d}) -> MediumLevelILSSAInstruction -> Maybe Symbol
processDest MediumLevelILSSAInstruction
d
        (MediumLevelILTailcallUntypedSsa MediumLevelILTailcallUntypedSsaRec {dest :: MediumLevelILTailcallUntypedSsaRec -> MediumLevelILSSAInstruction
dest = MediumLevelILSSAInstruction
d}) -> MediumLevelILSSAInstruction -> Maybe Symbol
processDest MediumLevelILSSAInstruction
d
    MediumLevelILSSAInstruction
_ -> String -> Maybe Symbol
forall a. HasCallStack => String -> a
error (String -> Maybe Symbol) -> String -> Maybe Symbol
forall a b. (a -> b) -> a -> b
$ String
"Binja.AnalysisContext.extractCallDestSymbol: unhandled instruction: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ MediumLevelILSSAInstruction -> String
forall a. Show a => a -> String
show MediumLevelILSSAInstruction
callInst
  where
    processDest :: MediumLevelILSSAInstruction -> Maybe Symbol
    processDest :: MediumLevelILSSAInstruction -> Maybe Symbol
processDest MediumLevelILSSAInstruction
dest' =
      case MediumLevelILSSAInstruction
dest' of
        Constant Constant
c -> AnalysisContext -> Constant -> Maybe Symbol
Binja.AnalysisContext.constantToSymbol AnalysisContext
context Constant
c
        MediumLevelILSSAInstruction
_ -> Maybe Symbol
forall a. Maybe a
Nothing

-- |
-- Given a function context iterate all instructions to:
--
--   * Find call instructions
--   * Resolve symbols which are called when possible via extractCallDestSymbol
--
-- __Assumption__: It is assumed the function context is present in the functions
-- field of AnalysisContext.
callers :: AnalysisContext -> FunctionContext -> Set.Set Symbol
callers :: AnalysisContext -> FunctionContext -> Set Symbol
callers AnalysisContext
analysisContext FunctionContext {instructions :: FunctionContext -> [MediumLevelILSSAInstruction]
instructions = [MediumLevelILSSAInstruction]
insts} =
  [Symbol] -> Set Symbol
forall a. Ord a => [a] -> Set a
Set.fromList ([Symbol] -> Set Symbol) -> [Symbol] -> Set Symbol
forall a b. (a -> b) -> a -> b
$
    [Maybe Symbol] -> [Symbol]
forall a. [Maybe a] -> [a]
catMaybes ([Maybe Symbol] -> [Symbol]) -> [Maybe Symbol] -> [Symbol]
forall a b. (a -> b) -> a -> b
$
      (MediumLevelILSSAInstruction -> Maybe Symbol)
-> [MediumLevelILSSAInstruction] -> [Maybe Symbol]
forall a b. (a -> b) -> [a] -> [b]
Prelude.map (AnalysisContext -> MediumLevelILSSAInstruction -> Maybe Symbol
Binja.AnalysisContext.extractCallDestSymbol AnalysisContext
analysisContext) ([MediumLevelILSSAInstruction] -> [Maybe Symbol])
-> [MediumLevelILSSAInstruction] -> [Maybe Symbol]
forall a b. (a -> b) -> a -> b
$
        (MediumLevelILSSAInstruction -> Bool)
-> [MediumLevelILSSAInstruction] -> [MediumLevelILSSAInstruction]
forall a. (a -> Bool) -> [a] -> [a]
Prelude.filter MediumLevelILSSAInstruction -> Bool
isCall ([MediumLevelILSSAInstruction] -> [MediumLevelILSSAInstruction])
-> [MediumLevelILSSAInstruction] -> [MediumLevelILSSAInstruction]
forall a b. (a -> b) -> a -> b
$
          [[MediumLevelILSSAInstruction]] -> [MediumLevelILSSAInstruction]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[MediumLevelILSSAInstruction]] -> [MediumLevelILSSAInstruction])
-> [[MediumLevelILSSAInstruction]] -> [MediumLevelILSSAInstruction]
forall a b. (a -> b) -> a -> b
$
            (MediumLevelILSSAInstruction -> [MediumLevelILSSAInstruction])
-> [MediumLevelILSSAInstruction] -> [[MediumLevelILSSAInstruction]]
forall a b. (a -> b) -> [a] -> [b]
Prelude.map MediumLevelILSSAInstruction -> [MediumLevelILSSAInstruction]
Binja.Mlil.children [MediumLevelILSSAInstruction]
insts
  where
    isCall :: MediumLevelILSSAInstruction -> Bool
    isCall :: MediumLevelILSSAInstruction -> Bool
isCall (Localcall Localcall
_) = Bool
True
    isCall (Tailcall Tailcall
_) = Bool
True
    isCall (Syscall Syscall
_) = Bool
True
    isCall MediumLevelILSSAInstruction
_ = Bool
False

-- |
--  Must be called once finished with an AnalysisContext to avoid handle leak.
--  Suggested pattern: <https://wiki.haskell.org/Bracket_pattern Bracket Pattern>
close :: AnalysisContext -> IO ()
close :: AnalysisContext -> IO ()
close = BNBinaryViewPtr -> IO ()
Binja.BinaryView.close (BNBinaryViewPtr -> IO ())
-> (AnalysisContext -> BNBinaryViewPtr) -> AnalysisContext -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AnalysisContext -> BNBinaryViewPtr
viewHandle

-- |
-- Returns a string summary of values contained in an analysis context
-- including basic block count, function count, etc.
summary :: AnalysisContext -> IO String
summary :: AnalysisContext -> IO String
summary AnalysisContext
analysisContext = do
  colors <- IO Colors
Binja.Utils.getColors
  let functionCount = Colors -> String -> String
magenta Colors
colors (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ Int -> String
forall a. Show a => a -> String
show (Int -> String) -> Int -> String
forall a b. (a -> b) -> a -> b
$ [FunctionContext] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([FunctionContext] -> Int) -> [FunctionContext] -> Int
forall a b. (a -> b) -> a -> b
$ AnalysisContext -> [FunctionContext]
Binja.Types.Core.functions AnalysisContext
analysisContext
      bbCount = Colors -> String -> String
magenta Colors
colors (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ Int -> String
forall a. Show a => a -> String
show (Int -> String) -> Int -> String
forall a b. (a -> b) -> a -> b
$ [Int] -> Int
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ (FunctionContext -> Int) -> [FunctionContext] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
Prelude.map ([BasicBlockMlilSSA] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([BasicBlockMlilSSA] -> Int)
-> (FunctionContext -> [BasicBlockMlilSSA])
-> FunctionContext
-> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CFGContext -> [BasicBlockMlilSSA]
blocks (CFGContext -> [BasicBlockMlilSSA])
-> (FunctionContext -> CFGContext)
-> FunctionContext
-> [BasicBlockMlilSSA]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FunctionContext -> CFGContext
cfg) ([FunctionContext] -> [Int]) -> [FunctionContext] -> [Int]
forall a b. (a -> b) -> a -> b
$ AnalysisContext -> [FunctionContext]
Binja.Types.Core.functions AnalysisContext
analysisContext
      entryFunction' =
        case AnalysisContext -> Maybe FunctionContext
Binja.Types.Core.entryFunction AnalysisContext
analysisContext of
          Maybe FunctionContext
Nothing -> Colors -> String -> String
magenta Colors
colors (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ String
"No entry function."
          Just FunctionContext
f -> String
"Entry function: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ (Colors -> String -> String
magenta Colors
colors (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ Symbol -> String
forall a. Show a => a -> String
show (Symbol -> String) -> Symbol -> String
forall a b. (a -> b) -> a -> b
$ FunctionContext -> Symbol
Binja.Types.Core.symbol FunctionContext
f)
      entryFunctions' = Colors -> String -> String
magenta Colors
colors (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ Int -> String
forall a. Show a => a -> String
show (Int -> String) -> Int -> String
forall a b. (a -> b) -> a -> b
$ [FunctionContext] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([FunctionContext] -> Int) -> [FunctionContext] -> Int
forall a b. (a -> b) -> a -> b
$ AnalysisContext -> [FunctionContext]
Binja.Types.Core.entryFunctions AnalysisContext
analysisContext
      stringCount = Colors -> String -> String
magenta Colors
colors (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ Int -> String
forall a. Show a => a -> String
show (Int -> String) -> Int -> String
forall a b. (a -> b) -> a -> b
$ [String] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([String] -> Int) -> [String] -> Int
forall a b. (a -> b) -> a -> b
$ AnalysisContext -> [String]
Binja.Types.Core.strings AnalysisContext
analysisContext
      symbolCount = Colors -> String -> String
magenta Colors
colors (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ Int -> String
forall a. Show a => a -> String
show (Int -> String) -> Int -> String
forall a b. (a -> b) -> a -> b
$ [Symbol] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Symbol] -> Int) -> [Symbol] -> Int
forall a b. (a -> b) -> a -> b
$ AnalysisContext -> [Symbol]
Binja.Types.Core.symbols AnalysisContext
analysisContext
      dataVarCount = Colors -> String -> String
magenta Colors
colors (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ Int -> String
forall a. Show a => a -> String
show (Int -> String) -> Int -> String
forall a b. (a -> b) -> a -> b
$ [DataVariable] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([DataVariable] -> Int) -> [DataVariable] -> Int
forall a b. (a -> b) -> a -> b
$ AnalysisContext -> [DataVariable]
Binja.Types.Core.dataVars AnalysisContext
analysisContext
      imageBase' = Colors -> String -> String
magenta Colors
colors (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ (String
"0x" String -> String -> String
forall a. [a] -> [a] -> [a]
++) (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ (Word64 -> String -> String) -> String -> Word64 -> String
forall a b c. (a -> b -> c) -> b -> a -> c
flip Word64 -> String -> String
forall a. Integral a => a -> String -> String
showHex String
"" (Word64 -> String) -> Word64 -> String
forall a b. (a -> b) -> a -> b
$ AnalysisContext -> Word64
Binja.Types.Core.imageBase AnalysisContext
analysisContext
      entryPoint' = Colors -> String -> String
magenta Colors
colors (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ (String
"0x" String -> String -> String
forall a. [a] -> [a] -> [a]
++) (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ (Word64 -> String -> String) -> String -> Word64 -> String
forall a b c. (a -> b -> c) -> b -> a -> c
flip Word64 -> String -> String
forall a. Integral a => a -> String -> String
showHex String
"" (Word64 -> String) -> Word64 -> String
forall a b. (a -> b) -> a -> b
$ AnalysisContext -> Word64
Binja.Types.Core.entryPoint AnalysisContext
analysisContext
      segmentCount = Colors -> String -> String
magenta Colors
colors (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ Int -> String
forall a. Show a => a -> String
show (Int -> String) -> Int -> String
forall a b. (a -> b) -> a -> b
$ [Segment] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Segment] -> Int) -> [Segment] -> Int
forall a b. (a -> b) -> a -> b
$ AnalysisContext -> [Segment]
Binja.Types.Core.segments AnalysisContext
analysisContext
      sectionCount = Colors -> String -> String
magenta Colors
colors (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ Int -> String
forall a. Show a => a -> String
show (Int -> String) -> Int -> String
forall a b. (a -> b) -> a -> b
$ [Section] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Section] -> Int) -> [Section] -> Int
forall a b. (a -> b) -> a -> b
$ AnalysisContext -> [Section]
Binja.Types.Core.sections AnalysisContext
analysisContext
  pure $
    " ["
      ++ (green colors) "+"
      ++ "] Filename: "
      ++ (magenta colors $ filename analysisContext)
      ++ "\n"
      ++ " ["
      ++ (green colors) "+"
      ++ "] Function count: "
      ++ functionCount
      ++ "\n"
      ++ " ["
      ++ (green colors) "+"
      ++ "] Mlil basic block count: "
      ++ bbCount
      ++ "\n"
      ++ " ["
      ++ (green colors) "+"
      ++ "] Entry Function: "
      ++ entryFunction'
      ++ "\n"
      ++ " ["
      ++ (green colors) "+"
      ++ "] Entry Functions count: "
      ++ entryFunctions'
      ++ "\n"
      ++ " ["
      ++ (green colors) "+"
      ++ "] String count: "
      ++ stringCount
      ++ "\n"
      ++ " ["
      ++ (green colors) "+"
      ++ "] Symbol count: "
      ++ symbolCount
      ++ "\n"
      ++ " ["
      ++ (green colors) "+"
      ++ "] Full confidence DataVariable count: "
      ++ dataVarCount
      ++ "\n"
      ++ " ["
      ++ (green colors) "+"
      ++ "] Image base address: "
      ++ imageBase'
      ++ "\n"
      ++ " ["
      ++ (green colors) "+"
      ++ "] Entry point address: "
      ++ entryPoint'
      ++ "\n"
      ++ " ["
      ++ (green colors) "+"
      ++ "] Segment count: "
      ++ segmentCount
      ++ "\n"
      ++ " ["
      ++ (green colors) "+"
      ++ "] Section count: "
      ++ sectionCount
      ++ "\n"