content: import Unicorn
  import Unicorn.Hook
  import qualified Unicorn.CPU.X86 as X86
  
  import Control.Monad.Trans.Class (lift)
  import qualified Data.ByteString as BS
  import Data.Int
  import Data.List (intercalate)
  import Data.Word
  import qualified Numeric as N (showHex)
  import System.IO (hPutStrLn, stderr)
  
  syscallABI :: [X86.Register]
  syscallABI = [ X86.Rax
               , X86.Rdi
               , X86.Rsi
               , X86.Rdx
               , X86.R10
               , X86.R8
               , X86.R9
               ]
  
  vals :: [Int64]
  vals = [ 200
         , 10
         , 11
         , 12
         , 13
         , 14
         , 15
         ]
  
  ucPerror :: Error
           -> IO ()
  ucPerror err =
      hPutStrLn stderr $ "Error " ++ ": " ++ strerror err
  
  base :: Word64
  base = 0x10000
  
  -- mov rax, 100; mov rdi, 1; mov rsi, 2; mov rdx, 3; mov r10, 4; mov r8, 5; mov r9, 6; syscall
  code :: BS.ByteString
  code = BS.pack [ 0x48, 0xc7, 0xc0, 0x64, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc7
                 , 0x01, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc6, 0x02, 0x00, 0x00
                 , 0x00, 0x48, 0xc7, 0xc2, 0x03, 0x00, 0x00, 0x00, 0x49, 0xc7
                 , 0xc2, 0x04, 0x00, 0x00, 0x00, 0x49, 0xc7, 0xc0, 0x05, 0x00
                 , 0x00, 0x00, 0x49, 0xc7, 0xc1, 0x06, 0x00, 0x00, 0x00, 0x0f
                 , 0x05
                 ]
  
  -- Pretty-print integral as hex
  showHex :: (Integral a, Show a) => a -> String
  showHex i =
      N.showHex (fromIntegral i :: Word64) ""
  
  -- Write a string (with a newline character) to standard output in the emulator
  emuPutStrLn :: String -> Emulator ()
  emuPutStrLn =
      lift . putStrLn
  
  hookSyscall :: SyscallHook ()
  hookSyscall uc _ = do
      runEmulator $ do
          readVals <- regReadBatch uc syscallABI
          emuPutStrLn $ "syscall: {"
                        ++ intercalate ", " (map show readVals)
                        ++ "}"
      return ()
  
  hookCode :: CodeHook ()
  hookCode _ addr size _ = do
      putStrLn $ "HOOK_CODE: 0x" ++ showHex addr ++ ", 0x" ++
                 maybe "0" showHex size
  
  main :: IO ()
  main = do
      result <- runEmulator $ do
          uc <- open ArchX86 [Mode64]
  
          -- regWriteBatch
          emuPutStrLn "regWriteBatch {200, 10, 11, 12, 13, 14, 15}"
          regWriteBatch uc syscallABI vals
  
          readVals <- regReadBatch uc syscallABI
      
          emuPutStrLn $ "regReadBatch = {"
                        ++ intercalate ", " (map show readVals)
                        ++ "}"
  
          -- syscall
          emuPutStrLn "running syscall shellcode"
          syscallHookAdd uc hookSyscall () 1 0
          memMap uc base (0x1000) [ProtAll]
          memWrite uc base code
          let codeLen = fromIntegral $ BS.length code
          start uc base (base + codeLen) Nothing Nothing
      case result of
          Right _  -> return ()
          Left err -> ucPerror err
  