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 +86/−0
- Dewdrop/Analyze.hs +114/−0
- LICENSE +26/−0
- Setup.hs +4/−0
- dewdrop.cabal +51/−0
+ 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