module Binja.BinaryView
( Binja.BinaryView.load,
Binja.BinaryView.close,
Binja.BinaryView.save,
Binja.BinaryView.hasFunctions,
Binja.BinaryView.hasSymbols,
Binja.BinaryView.hasDataVariables,
Binja.BinaryView.updateAnalysis,
Binja.BinaryView.updateAnalysisAndWait,
Binja.BinaryView.abortAnalysis,
Binja.BinaryView.functions,
Binja.BinaryView.functionsContaining,
Binja.BinaryView.functionsAt,
Binja.BinaryView.functionsByName,
Binja.BinaryView.symbols,
Binja.BinaryView.symbolsByName,
Binja.BinaryView.strings,
Binja.BinaryView.read,
Binja.BinaryView.symbolAt,
)
where
import Binja.FFI
import Binja.Function
import Binja.Plugin
import Binja.Symbol
import Binja.Types
import Binja.Utils
import qualified Data.ByteString as BS
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import qualified Data.Text.Encoding.Error as TEE
loadFilename ::
String ->
Bool ->
String ->
IO BNBinaryViewPtr
loadFilename :: String -> Bool -> String -> IO BNBinaryViewPtr
loadFilename String
filename Bool
updateAnalysisB String
options =
String -> (Ptr CChar -> IO BNBinaryViewPtr) -> IO BNBinaryViewPtr
forall a. String -> (Ptr CChar -> IO a) -> IO a
withCString String
filename ((Ptr CChar -> IO BNBinaryViewPtr) -> IO BNBinaryViewPtr)
-> (Ptr CChar -> IO BNBinaryViewPtr) -> IO BNBinaryViewPtr
forall a b. (a -> b) -> a -> b
$ \Ptr CChar
cFilename ->
String -> (Ptr CChar -> IO BNBinaryViewPtr) -> IO BNBinaryViewPtr
forall a. String -> (Ptr CChar -> IO a) -> IO a
withCString String
options ((Ptr CChar -> IO BNBinaryViewPtr) -> IO BNBinaryViewPtr)
-> (Ptr CChar -> IO BNBinaryViewPtr) -> IO BNBinaryViewPtr
forall a b. (a -> b) -> a -> b
$ \Ptr CChar
cOptions ->
Ptr CChar
-> CBool
-> Ptr CChar
-> BNProgressFunctionPtr
-> Ptr ()
-> IO BNBinaryViewPtr
c_BNLoadFilename
Ptr CChar
cFilename
(if Bool
updateAnalysisB then Word8 -> CBool
CBool Word8
1 else Word8 -> CBool
CBool Word8
0)
Ptr CChar
cOptions
BNProgressFunctionPtr
forall a. FunPtr a
nullFunPtr
Ptr ()
forall a. Ptr a
nullPtr
load :: String -> String -> IO BNBinaryViewPtr
load :: String -> String -> IO BNBinaryViewPtr
load String
filename String
options = do
_ <- Bool -> IO Bool
initPlugins Bool
False
viewPtr' <- loadFilename filename True options
if viewPtr' == nullPtr
then error $ "Failed to load binary view on file: " ++ filename
else pure viewPtr'
close :: BNBinaryViewPtr -> IO ()
close :: BNBinaryViewPtr -> IO ()
close BNBinaryViewPtr
view' = do
fileMetaDataPtr <- BNBinaryViewPtr -> IO BNFileMetaDataPtr
getFileForView BNBinaryViewPtr
view'
closeFile fileMetaDataPtr
hasFunctions :: BNBinaryViewPtr -> IO Bool
hasFunctions :: BNBinaryViewPtr -> IO Bool
hasFunctions = (CBool -> Bool) -> IO CBool -> IO Bool
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap CBool -> Bool
Binja.Utils.toBool (IO CBool -> IO Bool)
-> (BNBinaryViewPtr -> IO CBool) -> BNBinaryViewPtr -> IO Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BNBinaryViewPtr -> IO CBool
c_BNHasFunctions
hasSymbols :: BNBinaryViewPtr -> Bool
hasSymbols :: BNBinaryViewPtr -> Bool
hasSymbols = CBool -> Bool
Binja.Utils.toBool (CBool -> Bool)
-> (BNBinaryViewPtr -> CBool) -> BNBinaryViewPtr -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BNBinaryViewPtr -> CBool
c_BNHasSymbols
hasDataVariables :: BNBinaryViewPtr -> Bool
hasDataVariables :: BNBinaryViewPtr -> Bool
hasDataVariables = CBool -> Bool
Binja.Utils.toBool (CBool -> Bool)
-> (BNBinaryViewPtr -> CBool) -> BNBinaryViewPtr -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BNBinaryViewPtr -> CBool
c_BNHasDataVariables
save :: BNBinaryViewPtr -> String -> IO Bool
save :: BNBinaryViewPtr -> String -> IO Bool
save BNBinaryViewPtr
view String
filename =
String -> (Ptr CChar -> IO Bool) -> IO Bool
forall a. String -> (Ptr CChar -> IO a) -> IO a
withCString String
filename ((Ptr CChar -> IO Bool) -> IO Bool)
-> (Ptr CChar -> IO Bool) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \Ptr CChar
cFilename -> do
result <- BNBinaryViewPtr -> Ptr CChar -> IO CBool
c_BNSaveToFilename BNBinaryViewPtr
view Ptr CChar
cFilename
pure (Binja.Utils.toBool result)
updateAnalysis :: BNBinaryViewPtr -> IO ()
updateAnalysis :: BNBinaryViewPtr -> IO ()
updateAnalysis = BNBinaryViewPtr -> IO ()
c_BNUpdateAnalysis
updateAnalysisAndWait :: BNBinaryViewPtr -> IO ()
updateAnalysisAndWait :: BNBinaryViewPtr -> IO ()
updateAnalysisAndWait = BNBinaryViewPtr -> IO ()
c_BNUpdateAnalysisAndWait
abortAnalysis :: BNBinaryViewPtr -> IO ()
abortAnalysis :: BNBinaryViewPtr -> IO ()
abortAnalysis = BNBinaryViewPtr -> IO ()
c_BNAbortAnalysis
getFunctionList :: BNBinaryViewPtr -> IO FunctionList
getFunctionList :: BNBinaryViewPtr -> IO FunctionList
getFunctionList BNBinaryViewPtr
view =
(Ptr CSize -> IO FunctionList) -> IO FunctionList
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CSize -> IO FunctionList) -> IO FunctionList)
-> (Ptr CSize -> IO FunctionList) -> IO FunctionList
forall a b. (a -> b) -> a -> b
$ \Ptr CSize
countPtr -> do
rawPtr <- BNBinaryViewPtr -> Ptr CSize -> IO (Ptr BNFunctionPtr)
c_BNGetAnalysisFunctionList BNBinaryViewPtr
view Ptr CSize
countPtr
count' <- fromIntegral <$> peek countPtr
xs <-
if rawPtr == nullPtr || count' == 0
then pure []
else peekArray count' rawPtr
arrPtr <- newForeignPtr rawPtr (c_BNFreeFunctionList rawPtr $ fromIntegral count')
pure
FunctionList
{ flArrayPtr = arrPtr,
flCount = count',
flList = xs,
flViewPtr = view
}
functions :: BNBinaryViewPtr -> IO [BNFunctionPtr]
functions :: BNBinaryViewPtr -> IO [BNFunctionPtr]
functions = (FunctionList -> [BNFunctionPtr])
-> IO FunctionList -> IO [BNFunctionPtr]
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap FunctionList -> [BNFunctionPtr]
flList (IO FunctionList -> IO [BNFunctionPtr])
-> (BNBinaryViewPtr -> IO FunctionList)
-> BNBinaryViewPtr
-> IO [BNFunctionPtr]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BNBinaryViewPtr -> IO FunctionList
getFunctionList
functionsByName :: BNBinaryViewPtr -> String -> IO [BNFunctionPtr]
functionsByName :: BNBinaryViewPtr -> String -> IO [BNFunctionPtr]
functionsByName BNBinaryViewPtr
view String
name' = do
syms <- BNBinaryViewPtr -> String -> IO [Symbol]
symbolsByName BNBinaryViewPtr
view String
name'
let funcSyms = (Symbol -> Bool) -> [Symbol] -> [Symbol]
forall a. (a -> Bool) -> [a] -> [a]
filter Symbol -> Bool
Binja.Symbol.isFunction [Symbol]
syms
xs <- mapM (functionsAt view . address) funcSyms
pure $ concat xs
symbols :: BNBinaryViewPtr -> IO [Symbol]
symbols :: BNBinaryViewPtr -> IO [Symbol]
symbols BNBinaryViewPtr
view =
(Ptr CSize -> IO [Symbol]) -> IO [Symbol]
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CSize -> IO [Symbol]) -> IO [Symbol])
-> (Ptr CSize -> IO [Symbol]) -> IO [Symbol]
forall a b. (a -> b) -> a -> b
$ \Ptr CSize
countPtr -> do
rawPtr <- BNBinaryViewPtr
-> Ptr CSize -> BNNameSpacePtr -> IO (Ptr BNSymbolPtr)
c_BNGetSymbols BNBinaryViewPtr
view Ptr CSize
countPtr BNNameSpacePtr
forall a. Ptr a
nullPtr
count' <- fromIntegral <$> peek countPtr
xs <-
if rawPtr == nullPtr || count' == 0
then pure []
else peekArray count' rawPtr
_ <- newForeignPtr rawPtr (c_BNFreeSymbolList rawPtr $ fromIntegral count')
mapM Binja.Symbol.create xs
symbolsByName :: BNBinaryViewPtr -> String -> IO [Symbol]
symbolsByName :: BNBinaryViewPtr -> String -> IO [Symbol]
symbolsByName BNBinaryViewPtr
view String
name' = do
syms <- BNBinaryViewPtr -> IO [Symbol]
Binja.BinaryView.symbols BNBinaryViewPtr
view
pure $ filter (\Symbol
s -> Symbol -> String
name Symbol
s String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
name') syms
functionsContaining :: BNBinaryViewPtr -> Word64 -> IO [BNFunctionPtr]
functionsContaining :: BNBinaryViewPtr -> Word64 -> IO [BNFunctionPtr]
functionsContaining BNBinaryViewPtr
view Word64
addr =
(Ptr CSize -> IO [BNFunctionPtr]) -> IO [BNFunctionPtr]
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CSize -> IO [BNFunctionPtr]) -> IO [BNFunctionPtr])
-> (Ptr CSize -> IO [BNFunctionPtr]) -> IO [BNFunctionPtr]
forall a b. (a -> b) -> a -> b
$ \Ptr CSize
countPtr -> do
arrPtr <- BNBinaryViewPtr -> Word64 -> Ptr CSize -> IO (Ptr BNFunctionPtr)
c_BNGetAnalysisFunctionsContainingAddress BNBinaryViewPtr
view Word64
addr Ptr CSize
countPtr
count' <- peek countPtr
if arrPtr == nullPtr || count' == 0
then pure []
else do
refs <- peekArray (fromIntegral count') (castPtr arrPtr :: Ptr BNFunctionPtr)
c_BNFreeFunctionList arrPtr count'
pure refs
functionsAt :: BNBinaryViewPtr -> Word64 -> IO [BNFunctionPtr]
functionsAt :: BNBinaryViewPtr -> Word64 -> IO [BNFunctionPtr]
functionsAt BNBinaryViewPtr
view Word64
addr =
(Ptr CSize -> IO [BNFunctionPtr]) -> IO [BNFunctionPtr]
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CSize -> IO [BNFunctionPtr]) -> IO [BNFunctionPtr])
-> (Ptr CSize -> IO [BNFunctionPtr]) -> IO [BNFunctionPtr]
forall a b. (a -> b) -> a -> b
$ \Ptr CSize
countPtr -> do
arrPtr <- BNBinaryViewPtr -> Word64 -> Ptr CSize -> IO (Ptr BNFunctionPtr)
c_BNGetAnalysisFunctionsForAddress BNBinaryViewPtr
view Word64
addr Ptr CSize
countPtr
count' <- peek countPtr
if arrPtr == nullPtr || count' == 0
then pure []
else do
refs <- peekArray (fromIntegral count') (castPtr arrPtr :: Ptr BNFunctionPtr)
c_BNFreeFunctionList arrPtr count'
pure refs
strings :: BNBinaryViewPtr -> IO [Maybe String]
strings :: BNBinaryViewPtr -> IO [Maybe String]
strings BNBinaryViewPtr
view =
(Ptr CSize -> IO [Maybe String]) -> IO [Maybe String]
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CSize -> IO [Maybe String]) -> IO [Maybe String])
-> (Ptr CSize -> IO [Maybe String]) -> IO [Maybe String]
forall a b. (a -> b) -> a -> b
$ \Ptr CSize
countPtr -> do
arrPtr <- BNBinaryViewPtr -> Ptr CSize -> IO (Ptr BNStringRefPtr)
c_BNGetStrings BNBinaryViewPtr
view Ptr CSize
countPtr
count' <- fromIntegral <$> peek countPtr
if arrPtr == nullPtr || count' == 0
then pure []
else do
refs <- peekArray count' (castPtr arrPtr :: Ptr BNStringRef)
c_BNFreeStringReferenceList arrPtr
forM refs $ \(BNStringRef BNStringType
t Word64
s CSize
l) -> do
mbs <- BNBinaryViewPtr -> Word64 -> CSize -> IO (Maybe ByteString)
Binja.BinaryView.read BNBinaryViewPtr
view Word64
s CSize
l
pure $ fmap (T.unpack . decodeByType t) mbs
decodeByType :: BNStringType -> BS.ByteString -> T.Text
decodeByType :: BNStringType -> ByteString -> Text
decodeByType BNStringType
ty' = ByteString -> Text
go
where
go :: ByteString -> Text
go = case BNStringType
ty' of
BNStringType
AsciiString -> ByteString -> Text
TE.decodeLatin1
BNStringType
Utf8String -> OnDecodeError -> ByteString -> Text
TE.decodeUtf8With OnDecodeError
TEE.lenientDecode
BNStringType
Utf16String -> ByteString -> Text
decodeUtf16Auto
BNStringType
Utf32String -> ByteString -> Text
decodeUtf32Auto
decodeUtf16Auto :: ByteString -> Text
decodeUtf16Auto ByteString
bs
| [Word8] -> ByteString -> Bool
hasPrefix [Word8
0xFF, Word8
0xFE] ByteString
bs = OnDecodeError -> ByteString -> Text
TE.decodeUtf16LEWith OnDecodeError
TEE.lenientDecode (Int -> ByteString -> ByteString
BS.drop Int
2 ByteString
bs)
| [Word8] -> ByteString -> Bool
hasPrefix [Word8
0xFE, Word8
0xFF] ByteString
bs = OnDecodeError -> ByteString -> Text
TE.decodeUtf16BEWith OnDecodeError
TEE.lenientDecode (Int -> ByteString -> ByteString
BS.drop Int
2 ByteString
bs)
| Bool
otherwise = OnDecodeError -> ByteString -> Text
TE.decodeUtf16LEWith OnDecodeError
TEE.lenientDecode ByteString
bs
decodeUtf32Auto :: ByteString -> Text
decodeUtf32Auto ByteString
bs
| [Word8] -> ByteString -> Bool
hasPrefix [Word8
0xFF, Word8
0xFE, Word8
0x00, Word8
0x00] ByteString
bs = OnDecodeError -> ByteString -> Text
TE.decodeUtf32LEWith OnDecodeError
TEE.lenientDecode (Int -> ByteString -> ByteString
BS.drop Int
4 ByteString
bs)
| [Word8] -> ByteString -> Bool
hasPrefix [Word8
0x00, Word8
0x00, Word8
0xFE, Word8
0xFF] ByteString
bs = OnDecodeError -> ByteString -> Text
TE.decodeUtf32BEWith OnDecodeError
TEE.lenientDecode (Int -> ByteString -> ByteString
BS.drop Int
4 ByteString
bs)
| Bool
otherwise = OnDecodeError -> ByteString -> Text
TE.decodeUtf32LEWith OnDecodeError
TEE.lenientDecode ByteString
bs
hasPrefix :: [Word8] -> BS.ByteString -> Bool
hasPrefix :: [Word8] -> ByteString -> Bool
hasPrefix [Word8]
pfx ByteString
bs = [Word8] -> ByteString
BS.pack [Word8]
pfx ByteString -> ByteString -> Bool
`BS.isPrefixOf` ByteString
bs
read :: BNBinaryViewPtr -> Word64 -> CSize -> IO (Maybe BS.ByteString)
read :: BNBinaryViewPtr -> Word64 -> CSize -> IO (Maybe ByteString)
read BNBinaryViewPtr
view Word64
addr CSize
len = do
dataBuffer <- BNBinaryViewPtr -> Word64 -> CSize -> IO BNDataBufferPtr
c_BNReadViewBuffer BNBinaryViewPtr
view Word64
addr CSize
len
if dataBuffer == nullPtr
then pure Nothing
else do
dataPtr <- c_BNGetDataBufferContents dataBuffer
if dataPtr == nullPtr
then pure Nothing
else do
bs <- BS.packCStringLen (dataPtr, fromIntegral len)
c_BNFreeDataBuffer dataBuffer
pure $ Just bs
symbolAt :: BNBinaryViewPtr -> Word64 -> IO (Maybe Binja.Types.Symbol)
symbolAt :: BNBinaryViewPtr -> Word64 -> IO (Maybe Symbol)
symbolAt BNBinaryViewPtr
view Word64
addr = do
symbolPtr <- BNBinaryViewPtr -> Word64 -> BNNameSpacePtr -> IO BNSymbolPtr
c_BNGetSymbolByAddress BNBinaryViewPtr
view Word64
addr BNNameSpacePtr
forall a. Ptr a
nullPtr
if symbolPtr == nullPtr
then do
funcs <- functionsAt view addr
if length funcs > 0
then do
sym <- Binja.Function.symbol $ head funcs
pure $ Just sym
else pure Nothing
else do
sym <- Binja.Symbol.create symbolPtr
pure $ Just sym