unicorn/bindings/haskell/samples/SampleArm.hs

135 lines
3.9 KiB
Haskell

-- Sample code to demonstrate how to emulate ARM code
import Unicorn
import Unicorn.Hook
import qualified Unicorn.CPU.Arm as Arm
import Data.Bits
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 .|. 1) (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