unicorn/bindings/haskell/samples/SampleArm.hs

134 lines
3.9 KiB
Haskell
Raw Normal View History

-- Sample code to demonstrate how to emulate ARM code
import Unicorn
import Unicorn.Hook
import qualified Unicorn.CPU.Arm as Arm
import qualified Data.ByteString as BS
import Data.Word
import qualified Numeric as N (showHex)
-- Code to be emulated
--
-- mov r0, #0x37; sub r1, r2, r3
armCode :: BS.ByteString
armCode = BS.pack [0x37, 0x00, 0xa0, 0xe3, 0x03, 0x10, 0x42, 0xe0]
-- sub sp, #0xc
thumbCode :: BS.ByteString
thumbCode = BS.pack [0x83, 0xb0]
-- Memory address where emulation starts
address :: Word64
address = 0x10000
-- Pretty-print integral as hex
showHex :: (Integral a, Show a) => a -> String
showHex =
flip N.showHex ""
-- Calculate code length
codeLength :: Num a => BS.ByteString -> a
codeLength =
fromIntegral . BS.length
hookBlock :: BlockHook ()
hookBlock _ addr size _ =
putStrLn $ ">>> Tracing basic block at 0x" ++ showHex addr ++
", block size = 0x" ++ (maybe "0" showHex size)
hookCode :: CodeHook ()
hookCode _ addr size _ =
putStrLn $ ">>> Tracing instruction at 0x" ++ showHex addr ++
", instruction size = 0x" ++ (maybe "0" showHex size)
testArm :: IO ()
testArm = do
putStrLn "Emulate ARM code"
result <- runEmulator $ do
-- Initialize emulator in ARM mode
uc <- open ArchArm [ModeArm]
-- Map 2MB memory for this emulation
memMap uc address (2 * 1024 * 1024) [ProtAll]
-- Write machine code to be emulated to memory
memWrite uc address armCode
-- Initialize machine registers
regWrite uc Arm.R0 0x1234
regWrite uc Arm.R2 0x6789
regWrite uc Arm.R3 0x3333
-- Tracing all basic blocks with customized callback
blockHookAdd uc hookBlock () 1 0
-- Tracing one instruction at address with customized callback
codeHookAdd uc hookCode () address address
-- Emulate machine code in infinite time (last param = Nothing), or
-- when finishing all the code
let codeLen = codeLength armCode
start uc address (address + codeLen) Nothing Nothing
-- Return the results
r0 <- regRead uc Arm.R0
r1 <- regRead uc Arm.R1
return (r0, r1)
case result of
Right (r0, r1) -> do
-- Now print out some registers
putStrLn ">>> Emulation done. Below is the CPU context"
putStrLn $ ">>> R0 = 0x" ++ showHex r0
putStrLn $ ">>> R1 = 0x" ++ showHex r1
Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++
strerror err ++ ")"
testThumb :: IO ()
testThumb = do
putStrLn "Emulate THUMB code"
result <- runEmulator $ do
-- Initialize emulator in ARM mode
uc <- open ArchArm [ModeThumb]
-- Map 2MB memory for this emulation
memMap uc address (2 * 1024 * 1024) [ProtAll]
-- Write machine code to be emulated to memory
memWrite uc address thumbCode
-- Initialize machine registers
regWrite uc Arm.Sp 0x1234
-- Tracing all basic blocks with customized callback
blockHookAdd uc hookBlock () 1 0
-- Tracing one instruction at address with customized callback
codeHookAdd uc hookCode () address address
-- Emulate machine code in infinite time (last param = Nothing), or
-- when finishing all the code
let codeLen = codeLength thumbCode
start uc address (address + codeLen) Nothing Nothing
-- Return the results
sp <- regRead uc Arm.Sp
return sp
case result of
Right sp -> do
-- Now print out some registers
putStrLn ">>> Emulation done. Below is the CPU context"
putStrLn $ ">>> SP = 0x" ++ showHex sp
Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++
strerror err ++ ")"
main :: IO ()
main = do
testArm
putStrLn "=========================="
testThumb