{-# LANGUAGE DuplicateRecordFields #-}
module Binja.AnalysisContext
( Binja.AnalysisContext.create,
Binja.AnalysisContext.symbolAt,
Binja.AnalysisContext.callers,
Binja.AnalysisContext.extractCallDestSymbol,
Binja.AnalysisContext.close,
)
where
import Binja.BinaryView
import Binja.ControlFlowGraph
import Binja.Function
import Binja.Mlil
import Binja.Types
import Data.Map as Map
import Data.Maybe (catMaybes)
import Data.Set as Set
create ::
String ->
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'
symbols' <- Binja.BinaryView.symbols viewHandle'
strings' <- catMaybes <$> Binja.BinaryView.strings viewHandle'
pure
AnalysisContext
{ viewHandle = viewHandle',
functions = functionContexts,
symbols = symbols',
strings = strings'
}
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'})
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 ((Word64
requestAddr Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
==) (Word64 -> Bool) -> (Symbol -> Word64) -> Symbol -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Symbol -> Word64
address) [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
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
extractCallDestSymbol :: AnalysisContext -> MediumLevelILSSAInstruction -> Maybe Symbol
AnalysisContext
context MediumLevelILSSAInstruction
callInst =
case MediumLevelILSSAInstruction
callInst of
Localcall Localcall
lc ->
case Localcall
lc of
(MediumLevelILCall MediumLevelILCallRec {dest :: MediumLevelILCallRec -> MediumLevelILSSAInstruction
dest = MediumLevelILSSAInstruction
d}) -> MediumLevelILSSAInstruction -> Maybe Symbol
processDest MediumLevelILSSAInstruction
d
(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
(MediumLevelILCallUntyped MediumLevelILCallUntypedRec {dest :: MediumLevelILCallUntypedRec -> 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
callers :: AnalysisContext -> FunctionContext -> Set.Set Symbol
callers :: AnalysisContext -> FunctionContext -> Set Symbol
callers AnalysisContext
analysisContext FunctionContext
functionContext =
[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] -> [[MediumLevelILSSAInstruction]])
-> [MediumLevelILSSAInstruction] -> [[MediumLevelILSSAInstruction]]
forall a b. (a -> b) -> a -> b
$
FunctionContext -> [MediumLevelILSSAInstruction]
Binja.Types.instructions FunctionContext
functionContext
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
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