130 lines
3.8 KiB
Haskell
130 lines
3.8 KiB
Haskell
-- Sample code to demonstrate how to emulate Mips code (big endian)
|
|
|
|
import Unicorn
|
|
import Unicorn.Hook
|
|
import qualified Unicorn.CPU.Mips as Mips
|
|
|
|
import qualified Data.ByteString as BS
|
|
import Data.Word
|
|
import qualified Numeric as N (showHex)
|
|
|
|
-- Code to be emulated
|
|
--
|
|
-- ori $at, $at, 0x3456
|
|
mipsCodeEb :: BS.ByteString
|
|
mipsCodeEb = BS.pack [0x34, 0x21, 0x34, 0x56]
|
|
|
|
-- ori $at, $at, 0x3456
|
|
mipsCodeEl :: BS.ByteString
|
|
mipsCodeEl = BS.pack [0x56, 0x34, 0x21, 0x34]
|
|
|
|
-- 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)
|
|
|
|
testMipsEb :: IO ()
|
|
testMipsEb = do
|
|
putStrLn "Emulate MIPS code (big-endian)"
|
|
|
|
result <- runEmulator $ do
|
|
-- Initialize emulator in MIPS mode
|
|
uc <- open ArchMips [ModeMips32, ModeBigEndian]
|
|
|
|
-- Map 2MB memory for this emulation
|
|
memMap uc address (2 * 1024 * 1024) [ProtAll]
|
|
|
|
-- Write machine code to be emulated to memory
|
|
memWrite uc address mipsCodeEb
|
|
|
|
-- Initialise machine registers
|
|
regWrite uc Mips.Reg1 0x6789
|
|
|
|
-- 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 mipsCodeEb
|
|
start uc address (address + codeLen) Nothing Nothing
|
|
|
|
-- Return the results
|
|
r1 <- regRead uc Mips.Reg1
|
|
|
|
return r1
|
|
case result of
|
|
Right r1 -> do
|
|
-- Now print out some registers
|
|
putStrLn ">>> Emulation done. Below is the CPU context"
|
|
putStrLn $ ">>> R1 = 0x" ++ showHex r1
|
|
Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++
|
|
strerror err ++ ")"
|
|
|
|
testMipsEl :: IO ()
|
|
testMipsEl = do
|
|
putStrLn "==========================="
|
|
putStrLn "Emulate MIPS code (little-endian)"
|
|
|
|
result <- runEmulator $ do
|
|
-- Initialize emulator in MIPS mode
|
|
uc <- open ArchMips [ModeMips32, ModeLittleEndian]
|
|
|
|
-- Map 2MB memory for this emulation
|
|
memMap uc address (2 * 1024 * 1024) [ProtAll]
|
|
|
|
-- Write machine code to be emulated to memory
|
|
memWrite uc address mipsCodeEl
|
|
|
|
-- Initialize machine registers
|
|
regWrite uc Mips.Reg1 0x6789
|
|
|
|
-- 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 mipsCodeEl
|
|
start uc address (address + codeLen) Nothing Nothing
|
|
|
|
-- Return the results
|
|
r1 <- regRead uc Mips.Reg1
|
|
|
|
return r1
|
|
case result of
|
|
Right r1 -> do
|
|
-- Now print out some registers
|
|
putStrLn ">>> Emulation done. Below is the CPU context"
|
|
putStrLn $ ">>> R1 = 0x" ++ showHex r1
|
|
Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++
|
|
strerror err ++ ")"
|
|
|
|
main :: IO ()
|
|
main = do
|
|
testMipsEb
|
|
testMipsEl
|