diff --git a/Dewdrop.hs b/Dewdrop.hs
new file mode 100644
--- /dev/null
+++ b/Dewdrop.hs
@@ -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
diff --git a/Dewdrop/Analyze.hs b/Dewdrop/Analyze.hs
new file mode 100644
--- /dev/null
+++ b/Dewdrop/Analyze.hs
@@ -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
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -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.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,4 @@
+#! /usr/bin/runhaskell
+
+import Distribution.Simple
+main = defaultMain
diff --git a/dewdrop.cabal b/dewdrop.cabal
new file mode 100644
--- /dev/null
+++ b/dewdrop.cabal
@@ -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
