packages feed

dewdrop (empty) → 0.1

raw patch · 5 files changed

+281/−0 lines, 5 filesdep +basedep +bytestringdep +containerssetup-changed

Dependencies added: base, bytestring, containers, elf, hdis86, syb

Files

+ Dewdrop.hs view
@@ -0,0 +1,86 @@+{- | Print ROP gadgets having some desired property.++This module provides the quickest way to get started:++> $ cat find.hs+>+> import Dewdrop+> main = dewdrop (any (usesRegister RBP))+>+> $ runhaskell find.hs /bin/ls+> 00402e56:+>   pop %rbp+>   ret+>+> 0040afe7:+>   shl %cl, -0x15(%rbp)+>   rep ret+>+> ...++If you need more control, see "Dewdrop.Analyze".++-}++module Dewdrop+    ( -- * Finding gadgets+      dewdrop++      -- * Helpers for selecting gadgets+    , usesRegister, usesSegment, opcode++      -- * Re-export of disassembler+      --+      -- | The types and functions of @Hdis86@+      -- are re-exported for convenience.+    , module Hdis86+    ) where++import Dewdrop.Analyze++import System.Environment+import Control.Monad+import Control.Applicative+import Control.Exception ( throwIO, ErrorCall(..) )++import Data.Typeable ( Typeable )+import Data.Data     ( Data )++import qualified Data.ByteString as B+import qualified Generics.SYB    as G++import Data.Elf+import Hdis86++-- | Opens the ELF binary file passed as the first command-line+-- argument, and prints all ROP gadgets satisfying the specified+-- property.+dewdrop :: ([Metadata] -> Bool) -> IO ()+dewdrop wanted = do+    args@(~(elf_file:_)) <- getArgs+    when (null args) $ do+        progname <- getProgName+        throwIO $ ErrorCall ("Usage: " ++ progname ++ " ELF-FILE")+    elf <- parseElf <$> B.readFile elf_file+    mapM_ print . filter (\g@(Gadget xs) -> valid g && wanted xs) . gadgets $ elf++hasSub :: (Typeable a, Eq a, Data b) => a -> b -> Bool+hasSub x = not . null . G.listify (== x)++-- | Does this instruction use a given register?+--+-- This only includes registers explicitly mentioned in disassembly,+-- and not e.g. the @rsi@ / @rdi@ operands of @movsd@.+usesRegister :: GPR -> Metadata -> Bool+usesRegister = hasSub++-- | Does this instruction mention a given segment register?+--+-- This only includes explicit overrides, and loads/stores of+-- segment registers.+usesSegment :: Segment -> Metadata -> Bool+usesSegment = hasSub++-- | Get the @'Opcode'@ directly from an instruction-with-metadata.+opcode :: Metadata -> Opcode+opcode = inOpcode . mdInst
+ Dewdrop/Analyze.hs view
@@ -0,0 +1,114 @@+{-# LANGUAGE+    DeriveDataTypeable #-}++-- | Analyze the ROP gadgets in an ELF binary.+--+-- Use this module if you need more control, or integration with a larger+-- program. The module "Dewdrop" provides a simpler way to put together a+-- standalone gadget finder.+module Dewdrop.Analyze+    ( -- * Finding gadgets+      Gadget(..)+    , gadgets, valid++      -- * Configuring the gadget finder+    , Config(..), defaultConfig+    , gadgetsWith+    ) where++import Text.Printf++import Data.Typeable ( Typeable )+import Data.Data     ( Data )++import qualified Data.ByteString as B+import qualified Data.Set        as S++import Data.Elf+import Hdis86 hiding ( Config(..) )+import qualified Hdis86 as H++-- | A sequence of instructions, each with metadata.+--+-- The @'Show'@ instance produces assembly code with labeled offsets,+-- so you can @'print'@ these directly.+newtype Gadget = Gadget [Metadata]+    deriving (Eq, Ord, Typeable, Data)++instance Show Gadget where+    show (Gadget []) = "<empty Gadget>"+    show (Gadget g@(g1:_)) = printf fmt addr ++ unlines asm where+        addr = mdOffset g1+        fmt | addr > 0xffffffff = "%016x:\n"+            | otherwise         = "%08x:\n"+        asm = map (("  "++) . mdAssembly) g++-- | Configuration of the gadget finder.+data Config = Config+    { cfgSyntax  :: Syntax  -- ^ Assembly syntax for display+    , cfgVendor  :: Vendor  -- ^ CPU vendor; affects decoding of a+                            --   few instructions+    , cfgMaxSize :: Int     -- ^ Maximum size of a gadget, in bytes+    } deriving (Eq, Ord, Read, Show, Typeable, Data)++-- | Default configuration of the gadget finder.+defaultConfig :: Config+defaultConfig = Config SyntaxATT Intel 20++-- | Find possible gadgets, using a custom configuration.+gadgetsWith :: Config -> Elf -> [Gadget]+gadgetsWith cfg elf = map Gadget $ concatMap scanSect exec where+    hcfg = intel32 {+          H.cfgSyntax  = cfgSyntax cfg+        , H.cfgVendor  = cfgVendor cfg+        , H.cfgCPUMode = case elfClass elf of+            ELFCLASS32 -> Mode32+            ELFCLASS64 -> Mode64+        }++    exec = filter ((SHF_EXECINSTR `elem`) . elfSectionFlags) $ elfSections elf++    scanSect sect = do+        let bytes = elfSectionData sect+            idxes = flip B.elemIndices bytes+        index <- idxes 0xC3 ++ map (+2) (idxes 0xC2)+        let hd = B.take (index + 1) bytes+        subseq <- B.tails $ B.drop (B.length hd - cfgMaxSize cfg) hd+        let addr =   elfSectionAddr sect+                   + fromIntegral index + 1+                   - fromIntegral (B.length subseq)+        return $ disassembleMetadata (hcfg { H.cfgOrigin = addr }) subseq++-- | Find possible gadgets.+--+-- You can filter these further using @'valid'@ or other tests.+gadgets :: Elf -> [Gadget]+gadgets = gadgetsWith defaultConfig++-- | Rejects gadgets which are probably not useful for return-oriented+-- programming.  This includes gadgets containing invalid or privileged+-- instructions.+valid :: Gadget -> Bool+valid = \(Gadget g) -> all ($ g) [(>1) . length, opcodesOk] where+    -- scoped outside the lambda, to share evaluation between calls+    badOpcodes = S.fromList [+        -- privileged or exception-raising+          Iinvalid+        , Iin,  Iinsb,  Iinsw,  Iinsd+        , Iout, Ioutsb, Ioutsw, Ioutsd+        , Iiretw, Iiretd, Iiretq+        , Isysexit, Isysret+        , Ihlt, Icli, Isti, Illdt, Ilgdt, Ilidt, Iltr+        , Ivmcall, Ivmresume, Ivmxon, Ivmxoff+        -- , Ivmlaunch, Ivmread, Ivmwrite,  -- not in udis86?+        , Ivmptrld, Ivmptrst, Ivmclear+        , Imonitor, Imwait, Ilmsw, Iinvlpg, Iswapgs+        , Iclts, Iinvd, Iwbinvd+        , Irdmsr, Iwrmsr++        -- return before end+        , Iret,  Iretf ]++    opcodesOk g = case reverse $ map (inOpcode . mdInst) g of+        (Iret : xs) -> all (`S.notMember` badOpcodes) xs+        _ -> False
+ LICENSE view
@@ -0,0 +1,26 @@+Copyright (c) 2011 Nelson Elhage, Keegan McAllister+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:+1. Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.+2. Redistributions in binary form must reproduce the above copyright+   notice, this list of conditions and the following disclaimer in the+   documentation and/or other materials provided with the distribution.+3. The name of the author may be used to endorse or promote products+   derived from this software without specific prior written+   permission.++THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,4 @@+#! /usr/bin/runhaskell++import Distribution.Simple+main = defaultMain
+ dewdrop.cabal view
@@ -0,0 +1,51 @@+name:                dewdrop+version:             0.1+license:             BSD3+license-file:        LICENSE+synopsis:            Find gadgets for return-oriented programming on x86+category:            Reverse Engineering, Security+author:              Nelson Elhage <nelhage@nelhage.com>, Keegan McAllister <mcallister.keegan@gmail.com>+maintainer:          Keegan McAllister <mcallister.keegan@gmail.com>+homepage:            https://github.com/kmcallister/dewdrop+build-type:          Simple+cabal-version:       >=1.6+description:+    Traditional buffer-overflow attacks work by filling a data buffer with+    exploit code and then redirecting execution to that buffer.  As a+    countermeasure, modern operating systems will forbid (by default) the+    execution of writable memory regions.+    .+    Return-oriented programming [1] is an alternative exploitation strategy+    that works around this restriction.  The exploit payload is built by+    chaining together short code sequences (\"gadgets\") which are already+    present in the exploited program, and thus are allowed to be executed.+    .+    dewdrop is a Haskell library for finding useful gadgets in 32- and 64-bit+    x86 ELF binaries.  You can describe the desired gadget properties with a+    Haskell function, and use the @Dewdrop@ module to make a customized+    gadget-finder program.  Or you can import @Dewdrop.Analyze@ and integrate+    this functionality into a larger program.+    .+    \[1\] Shacham, Hovav. /The Geometry of Innocent Flesh on the Bone:/+    /Return-into-libc without Function Calls (on the x86)/. CCS 2007,+    pages 552-561.++library+  exposed-modules:+      Dewdrop+    , Dewdrop.Analyze+  ghc-options:       -Wall+  build-depends:+      base       >= 3 && < 5+    , containers >= 0.3+    , bytestring >= 0.9+    , hdis86     >= 0.2+    , elf        >= 0.2+    , syb        >= 0.1++  other-extensions:+      DeriveDataTypeable++source-repository head+    type:     git+    location: git://github.com/kmcallister/dewdrop.git