Add more OSX Railgun defs and better CDECL support

bug/bundler_fix
Spencer McIntyre 2017-06-21 08:59:42 -04:00
parent f7c133cdf7
commit 717f9aad12
6 changed files with 148 additions and 61 deletions

View File

@ -18,6 +18,13 @@ class DefApiConstants_osx < ApiConstants
# Slurp in a giant list of known constants.
#
def self.add_constants(const_mgr)
# https://opensource.apple.com/source/xnu/xnu-2050.18.24/bsd/sys/socket.h
const_mgr.add_const('AF_UNSPEC', 0x00000000)
const_mgr.add_const('AF_LOCAL', 0x00000001)
const_mgr.add_const('AF_UNIX', 0x00000001)
const_mgr.add_const('AF_INET', 0x00000002)
const_mgr.add_const('AF_INET6', 0x0000001e)
# https://opensource.apple.com/source/xnu/xnu-2050.18.24/bsd/sys/mman.h
const_mgr.add_const('MAP_FILE', 0x0000)
const_mgr.add_const('MAP_SHARED', 0x0001)
@ -30,12 +37,15 @@ class DefApiConstants_osx < ApiConstants
const_mgr.add_const('PROT_WRITE', 0x0002)
const_mgr.add_const('PROT_EXEC', 0x0004)
# https://opensource.apple.com/source/xnu/xnu-2050.18.24/bsd/sys/socket.h
const_mgr.add_const('AF_UNSPEC', 0x00000000)
const_mgr.add_const('AF_LOCAL', 0x00000001)
const_mgr.add_const('AF_UNIX', 0x00000001)
const_mgr.add_const('AF_INET', 0x00000002)
const_mgr.add_const('AF_INET6', 0x0000001e)
# https://opensource.apple.com/source/dyld/dyld-95.3/include/dlfcn.h
const_mgr.add_const('RTLD_LAZY', 0x0001)
const_mgr.add_const('RTLD_NOW', 0x0002)
const_mgr.add_const('RTLD_LOCAL', 0x0004)
const_mgr.add_const('RTLD_GLOBAL', 0x0008)
const_mgr.add_const('RTLD_NOLOAD', 0x0010)
const_mgr.add_const('RTLD_NODELETE', 0x0080)
const_mgr.add_const('RTLD_FIRST', 0x0100) # Mac OS X 10.5 and later
end
end

View File

@ -22,6 +22,25 @@ class Def_libc
nil,
'cdecl'
)
lib.add_function(
'dlclose',
'DWORD',
[
['LPVOID', 'handle', 'in']
],
nil,
'cdecl'
)
lib.add_function(
'dlopen',
'LPVOID',
[
['PCHAR', 'filename', 'in'],
['DWORD', 'flags', 'in']
],
nil,
'cdecl'
)
lib.add_function(
'free',
'VOID',

View File

@ -0,0 +1,54 @@
# -*- coding: binary -*-
module Rex
module Post
module Meterpreter
module Extensions
module Stdapi
module Railgun
module Def
class Def_libobjc
def self.create_dll(constant_manager, dll_path = 'libobjc.dylib')
lib = DLL.new(dll_path, constant_manager)
# https://developer.apple.com/documentation/objectivec/1418952-objc_getclass?language=objc
lib.add_function(
'objc_getClass',
'LPVOID',
[
['PCHAR', 'name', 'in']
],
nil,
'cdecl'
)
# https://developer.apple.com/documentation/objectivec/1456712-objc_msgsend?language=objc
lib.add_function(
'objc_msgSend',
'LPVOID',
[
['LPVOID', 'self', 'in'],
['LPVOID', 'op', 'in']
],
nil,
'cdecl'
)
# https://developer.apple.com/documentation/objectivec/1418557-sel_registername?language=objc
lib.add_function(
'sel_registerName',
'LPVOID',
[
['PCHAR', 'str', 'in']
],
nil,
'cdecl'
)
return lib
end
end
end; end; end; end; end; end; end

View File

@ -69,18 +69,20 @@ class DLL
# Returns a Hash containing the return value, the result of GetLastError(),
# and any +inout+ parameters.
#
# Raises an exception if +func_symbol+ is not a known function in this DLL,
# Raises an exception if +function+ is not a known function in this DLL,
# i.e., it hasn't been defined in a Def.
#
def call_function(func_symbol, args, client)
func_name = func_symbol.to_s
def call_function(function, args, client)
unless function.instance_of? DLLFunction
func_name = function.to_s
unless known_function_names.include? func_name
raise "DLL-function #{func_name} not found. Known functions: #{PP.pp(known_function_names, '')}"
unless known_function_names.include? func_name
raise "DLL-function #{func_name} not found. Known functions: #{PP.pp(known_function_names, '')}"
end
function = get_function(func_name)
end
function = get_function(func_name)
return process_function_call(function, args, client)
end

View File

@ -56,21 +56,22 @@ class MultiCaller
end
def call(functions)
request = Packet.create_request('stdapi_railgun_api_multi')
function_results = []
layouts = []
functions.each do |f|
dll_name,funcname,args = f
dll_name, function, args = f
dll_host = @parent.get_dll( dll_name )
if not dll_host
raise "DLL #{dll_name} has not been loaded"
end
function = dll_host.functions[funcname]
if not function
raise "DLL #{dll_name} function #{funcname} has not been defined"
unless function.instance_of? DLLFunction
function = dll_host.functions[function]
if not function
raise "DLL #{dll_name} function #{function} has not been defined"
end
end
raise "#{function.params.length} arguments expected. #{args.length} arguments provided." unless args.length == function.params.length
@ -96,7 +97,7 @@ class MultiCaller
end
# we care only about out-only buffers
if param_desc[2] == "out"
if param_desc[2] == 'out'
if !args[param_idx].class.kind_of? Integer
raise "error in param #{param_desc[1]}: Out-only buffers must be described by a number indicating their size in bytes "
end
@ -122,11 +123,11 @@ class MultiCaller
end
end
tmp = assemble_buffer("in", function, args)
tmp = assemble_buffer('in', function, args)
in_only_layout = tmp[0]
in_only_buffer = tmp[1]
tmp = assemble_buffer("inout", function, args)
tmp = assemble_buffer('inout', function, args)
inout_layout = tmp[0]
inout_buffer = tmp[1]
@ -146,41 +147,41 @@ class MultiCaller
#puts " processing (#{param_desc[0]}, #{param_desc[1]}, #{param_desc[2]})"
buffer = nil
# is it a pointer to a buffer on our stack
if ["PDWORD", "PWCHAR", "PCHAR", "PBLOB"].include? param_desc[0]
#puts " pointer"
if ['PDWORD', 'PWCHAR', 'PCHAR', 'PBLOB'].include? param_desc[0]
#puts ' pointer'
if args[param_idx] == nil # null pointer?
buffer = [0].pack(@native) # type: DWORD (so the dll does not rebase it)
buffer += [0].pack(@native) # value: 0
elsif param_desc[2] == "in"
elsif param_desc[2] == 'in'
buffer = [1].pack(@native)
buffer += [in_only_layout[param_desc[1]].addr].pack(@native)
elsif param_desc[2] == "out"
elsif param_desc[2] == 'out'
buffer = [2].pack(@native)
buffer += [out_only_layout[param_desc[1]].addr].pack(@native)
elsif param_desc[2] == "inout"
elsif param_desc[2] == 'inout'
buffer = [3].pack(@native)
buffer += [inout_layout[param_desc[1]].addr].pack(@native)
else
raise "unexpected direction"
raise 'unexpected direction'
end
else
#puts " not a pointer"
#puts ' not a pointer'
# it's not a pointer
buffer = [0].pack(@native)
case param_desc[0]
when "LPVOID", "HANDLE", "SIZE_T"
when 'LPVOID', 'HANDLE', 'SIZE_T'
num = param_to_number(args[param_idx])
buffer += [num].pack(@native)
when "DWORD"
when 'DWORD'
num = param_to_number(args[param_idx])
buffer += [num % 4294967296].pack(@native)
when "WORD"
when 'WORD'
num = param_to_number(args[param_idx])
buffer += [num % 65536].pack(@native)
when "BYTE"
when 'BYTE'
num = param_to_number(args[param_idx])
buffer += [num % 256].pack(@native)
when "BOOL"
when 'BOOL'
case args[param_idx]
when true
buffer += [1].pack('V')
@ -221,9 +222,9 @@ class MultiCaller
end
functions.each do |f|
dll_name,funcname,args = f
dll_host = @parent.get_dll( dll_name )
function = dll_host.functions[funcname]
dll_name, function, args = f
dll_host = @parent.get_dll(dll_name)
function = dll_host.functions[function] unless function.instance_of? DLLFunction
response = call_results.shift
inout_layout, out_only_layout = layouts.shift
@ -239,28 +240,28 @@ class MultiCaller
# The hash the function returns
return_hash = {
"GetLastError" => rec_last_error,
"ErrorMessage" => rec_err_msg
'GetLastError' => rec_last_error,
'ErrorMessage' => rec_err_msg
}
#process return value
case function.return_type
when "LPVOID", "HANDLE"
when 'LPVOID', 'HANDLE'
if( @native == 'Q<' )
return_hash["return"] = rec_return_value
return_hash['return'] = rec_return_value
else
return_hash["return"] = rec_return_value % 4294967296
return_hash['return'] = rec_return_value % 4294967296
end
when "DWORD"
return_hash["return"] = rec_return_value % 4294967296
when "WORD"
return_hash["return"] = rec_return_value % 65536
when "BYTE"
return_hash["return"] = rec_return_value % 256
when "BOOL"
return_hash["return"] = (rec_return_value != 0)
when "VOID"
return_hash["return"] = nil
when 'DWORD'
return_hash['return'] = rec_return_value % 4294967296
when 'WORD'
return_hash['return'] = rec_return_value % 65536
when 'BYTE'
return_hash['return'] = rec_return_value % 256
when 'BOOL'
return_hash['return'] = (rec_return_value != 0)
when 'VOID'
return_hash['return'] = nil
else
raise "unexpected return type: #{function.return_type}"
end
@ -275,13 +276,13 @@ class MultiCaller
#puts " #{param_name}"
buffer = rec_out_only_buffers[buffer_item.addr, buffer_item.length_in_bytes]
case buffer_item.datatype
when "PDWORD"
when 'PDWORD'
return_hash[param_name] = buffer.unpack('V')[0]
when "PCHAR"
when 'PCHAR'
return_hash[param_name] = asciiz_to_str(buffer)
when "PWCHAR"
when 'PWCHAR'
return_hash[param_name] = uniz_to_str(buffer)
when "PBLOB"
when 'PBLOB'
return_hash[param_name] = buffer
else
raise "unexpected type in out-only buffer of #{param_name}: #{buffer_item.datatype}"
@ -292,16 +293,16 @@ class MultiCaller
# process in-out buffers
#puts "processing in-out buffers:"
inout_layout.each_pair do |param_name, buffer_item|
#puts " #{param_name}"
#puts ' #{param_name}'
buffer = rec_inout_buffers[buffer_item.addr, buffer_item.length_in_bytes]
case buffer_item.datatype
when "PDWORD"
when 'PDWORD'
return_hash[param_name] = buffer.unpack('V')[0]
when "PCHAR"
when 'PCHAR'
return_hash[param_name] = asciiz_to_str(buffer)
when "PWCHAR"
when 'PWCHAR'
return_hash[param_name] = uniz_to_str(buffer)
when "PBLOB"
when 'PBLOB'
return_hash[param_name] = buffer
else
raise "unexpected type in in-out-buffer of #{param_name}: #{buffer_item.datatype}"

View File

@ -74,7 +74,8 @@ class Railgun
'libc'
].freeze,
'osx' => [
'libc'
'libc',
'libobjc'
].freeze,
'windows' => [
'kernel32',