packages feed

rz-pipe (empty) → 0.1.0

raw patch · 7 files changed

+215/−0 lines, 7 filesdep +HTTPdep +aesondep +basesetup-changed

Dependencies added: HTTP, aeson, base, bytestring, process, rz-pipe, utf8-string

Files

+ CHANGELOG.md view
@@ -0,0 +1,3 @@+## Version 0.1.0++* Initial Release
+ Example.hs view
@@ -0,0 +1,32 @@++{-# LANGUAGE DeriveGeneric, DeriveAnyClass #-}++import RzPipe+import GHC.Generics+import Data.Aeson as JSON+import Data.Word++data Flag = Flag+    { name :: String+    , size :: Word64+    , offset :: Word64 }+    deriving (Show, Generic, JSON.FromJSON)++showMainFunction :: RzContext -> IO ()+showMainFunction ctx = do+    cmd ctx "s main"+    putStrLn =<< cmd ctx "pD `fl $$`"++showFlags :: RzContext -> IO ()+showFlags ctx = print =<< (cmdj ctx "fj" :: IO (Maybe [Flag]))++main :: IO ()+main = do+    -- Spawn a new rizin instance and open the /bin/ls binary in it+    ctx <- open $ Just "/bin/ls"+    -- Pick up pipes from parent rizin process+    -- ctx <- open Nothing+    -- Connect to rizin via HTTP (e.g. if "rizin -qc=h /bin/ls" is running)+    -- ctx <- open $ Just "http://127.0.0.1:9090"+    showMainFunction ctx+    showFlags ctx
+ LICENSE view
@@ -0,0 +1,22 @@+The MIT License (MIT)++Copyright (c) 2020 rizinorg++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.+
+ README.md view
@@ -0,0 +1,61 @@+# rz-pipe for Haskell++rz-pipe is a scripting interface for the Rizin Reverse Engineering+Framework that builds upon Rizin's command interface as a simple+point of interaction.++It can be used by launching a Rizin instance from Haskell or+connecting to an existing one using pipes or HTTP.++## Usage++The API revolves around the `RzContext` type, which represents+a connection to a running Rizin instance. The `open` function+will establish such a connection in `IO` based on its argument:++```haskell+do+  -- Spawn a new rizin instance and open the /bin/ls binary in it+  localCtx <- open $ Just "/bin/ls"+  -- Pick up pipes from parent rizin process+  parentCtx <- open Nothing+  -- Connect to rizin via HTTP (e.g. if "rizin -qc=h /bin/ls" is running)+  httpCtx <- open $ Just "http://127.0.0.1:9090"+```++Once a context has been opened, the `cmd` function can be used+to run commands and return the result as a string in `IO`:++```haskell+putStrLn =<< cmd ctx "pd 3"+-- prints e.g.+--   0x00005b20      endbr64+--   0x00005b24      xor   ebp, ebp+--   0x00005b26      mov   r9, rdx+```++For scripting, it is highly recommended to use rizin commands returning+json, commonly prefixed with `j`. To conveniently parse the results with+[aeson](https://hackage.haskell.org/package/aeson), the `cmdj` can be+used, which is polymorphic in its return type and can produce any object+in the `Data.Aeson.FromJSON` type class:++```haskell+{-# LANGUAGE DeriveGeneric, DeriveAnyClass #-}++import RzPipe+import GHC.Generics+import Data.Aeson as JSON+import Data.Word++data Flag = Flag+    { name :: String+    , size :: Word64+    , offset :: Word64 }+    deriving (Show, Generic, JSON.FromJSON)++showFlags :: RzContext -> IO ()+showFlags ctx = print =<< (cmdj ctx "fj" :: IO (Maybe [Flag]))+-- prints e.g.+-- Just [Flag {name = "section.", size = 0, offset = 0},Flag {name = "section..comment", size = 76, offset = 0},Flag {name = "section..shstrtab", size = 247, offset = 0},Flag {name = "segment.LOAD0", size = 13584, offset = 0},Flag {name = "segment.GNU_STACK", size = 0, offset = 0},Flag {name = "segment.ehdr", size = 64, offset = 0} ...+```
+ RzPipe/RzPipe.hs view
@@ -0,0 +1,56 @@+module RzPipe (RzContext(), open, cmd, cmdj) where+import Data.Char+import Data.Word+import Network.HTTP+import System.IO+import System.Process+import System.Environment (getEnv)+import GHC.IO.Handle.FD+import System.Posix.Internals (FD)+import qualified Data.Aeson as JSON+import qualified Data.ByteString.Lazy as B+import qualified Data.ByteString.Lazy.UTF8 as U++withPipes p = p { std_in = CreatePipe, std_out = CreatePipe, std_err = CreatePipe }++createProcess' args = fmap f $ createProcess (withPipes args) where+    f (Just i, Just o, Just e, h) = (i, o, e, h)+    f _ = error "createProcess': Failed to open pipes to the subprocess."++lHTakeWhile :: (Word8 -> Bool) -> Handle -> IO B.ByteString+lHTakeWhile p h = do+    c <- fmap B.head $ B.hGet h 1+    if p c+        then fmap (c `B.cons`) $ lHTakeWhile p h+        else return B.empty++data RzContext = HttpCtx String+               | PipeCtx Handle Handle++open :: Maybe String -> IO RzContext+open (Just url@('h':'t':'t':'p':_)) = return $ HttpCtx (url ++ "/cmd/")+open (Just filename) = do+    (hIn, hOut, _, _) <- createProcess' $ proc "rizin" ["-q0", filename]+    lHTakeWhile (/= 0) hOut -- drop the inital null that rizin emits+    return $ PipeCtx hIn hOut+open Nothing = do+    hIn <- fdToHandle =<< (read::(String -> FD)) <$> getEnv "RZ_PIPE_OUT"+    hOut <- fdToHandle =<< (read::(String -> FD)) <$> getEnv "RZ_PIPE_IN"+    return $ PipeCtx hIn hOut++cmdHttp :: String -> String -> IO String+cmdHttp url cmd = getResponseBody =<< simpleHTTP (getRequest (url ++ urlEncode cmd))++cmdPipe :: Handle -> Handle -> String -> IO B.ByteString+cmdPipe hIn hOut cmd = hPutStrLn hIn cmd >> hFlush hIn >> lHTakeWhile (/= 0) hOut++cmdB :: RzContext -> String -> IO B.ByteString+cmdB (HttpCtx url) cmd = U.fromString <$> cmdHttp url cmd+cmdB (PipeCtx hIn hOut) cmd = cmdPipe hIn hOut cmd++cmd :: RzContext -> String -> IO String+cmd (HttpCtx url) cmd = cmdHttp url cmd+cmd (PipeCtx hIn hOut) cmd = U.toString <$> cmdPipe hIn hOut cmd++cmdj :: JSON.FromJSON a => RzContext -> String -> IO (Maybe a)+cmdj = (fmap JSON.decode .) . cmdB
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ rz-pipe.cabal view
@@ -0,0 +1,39 @@+cabal-version:       >=1.10++name:                rz-pipe+version:             0.1.0+synopsis:            Pipe interface for Rizin+category:            Reverse Engineering, Security+license:             MIT+license-file:        LICENSE+author:              rizinorg+maintainer:          Florian Märkl <rizin@metallic.software>+build-type:          Simple+description:+    rz-pipe is a scripting interface for the Rizin Reverse Engineering+    Framework that builds upon Rizin's command interface as a simple+    point of interaction.+    .+    It can be used by launching a Rizin instance from Haskell or+    connecting to an existing one using pipes or HTTP.++extra-source-files:+    README.md CHANGELOG.md++library+  exposed-modules:     RzPipe+  hs-source-dirs:      RzPipe+  build-depends:       base >=4.12 && <5,+                       HTTP        >= 4000.3.15 && < 4000.4,+                       bytestring  >= 0.10.12 && < 0.11,+                       utf8-string >= 1.0.2 && < 1.1,+                       aeson       >= 1.5.5 && < 1.6,+                       process     >= 1.6.9 && < 1.7+  default-language:    Haskell2010++executable example+  main-is:             Example.hs+  build-depends:       base >=4.12 && <5,+                       rz-pipe,+                       aeson+  default-language:    Haskell2010