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 +3/−0
- Example.hs +32/−0
- LICENSE +22/−0
- README.md +61/−0
- RzPipe/RzPipe.hs +56/−0
- Setup.hs +2/−0
- rz-pipe.cabal +39/−0
+ 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