Skip to content

Commit 717f9aa

Browse files
committed
Add more OSX Railgun defs and better CDECL support
1 parent f7c133c commit 717f9aa

File tree

6 files changed

+148
-61
lines changed

6 files changed

+148
-61
lines changed

lib/rex/post/meterpreter/extensions/stdapi/railgun/def/osx/api_constants.rb

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ class DefApiConstants_osx < ApiConstants
1818
# Slurp in a giant list of known constants.
1919
#
2020
def self.add_constants(const_mgr)
21+
# https://opensource.apple.com/source/xnu/xnu-2050.18.24/bsd/sys/socket.h
22+
const_mgr.add_const('AF_UNSPEC', 0x00000000)
23+
const_mgr.add_const('AF_LOCAL', 0x00000001)
24+
const_mgr.add_const('AF_UNIX', 0x00000001)
25+
const_mgr.add_const('AF_INET', 0x00000002)
26+
const_mgr.add_const('AF_INET6', 0x0000001e)
27+
2128
# https://opensource.apple.com/source/xnu/xnu-2050.18.24/bsd/sys/mman.h
2229
const_mgr.add_const('MAP_FILE', 0x0000)
2330
const_mgr.add_const('MAP_SHARED', 0x0001)
@@ -30,12 +37,15 @@ def self.add_constants(const_mgr)
3037
const_mgr.add_const('PROT_WRITE', 0x0002)
3138
const_mgr.add_const('PROT_EXEC', 0x0004)
3239

33-
# https://opensource.apple.com/source/xnu/xnu-2050.18.24/bsd/sys/socket.h
34-
const_mgr.add_const('AF_UNSPEC', 0x00000000)
35-
const_mgr.add_const('AF_LOCAL', 0x00000001)
36-
const_mgr.add_const('AF_UNIX', 0x00000001)
37-
const_mgr.add_const('AF_INET', 0x00000002)
38-
const_mgr.add_const('AF_INET6', 0x0000001e)
40+
# https://opensource.apple.com/source/dyld/dyld-95.3/include/dlfcn.h
41+
const_mgr.add_const('RTLD_LAZY', 0x0001)
42+
const_mgr.add_const('RTLD_NOW', 0x0002)
43+
const_mgr.add_const('RTLD_LOCAL', 0x0004)
44+
const_mgr.add_const('RTLD_GLOBAL', 0x0008)
45+
const_mgr.add_const('RTLD_NOLOAD', 0x0010)
46+
const_mgr.add_const('RTLD_NODELETE', 0x0080)
47+
const_mgr.add_const('RTLD_FIRST', 0x0100) # Mac OS X 10.5 and later
48+
3949
end
4050
end
4151

lib/rex/post/meterpreter/extensions/stdapi/railgun/def/osx/def_libc.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,25 @@ def self.create_dll(constant_manager, dll_path = 'libc.dylib')
2222
nil,
2323
'cdecl'
2424
)
25+
lib.add_function(
26+
'dlclose',
27+
'DWORD',
28+
[
29+
['LPVOID', 'handle', 'in']
30+
],
31+
nil,
32+
'cdecl'
33+
)
34+
lib.add_function(
35+
'dlopen',
36+
'LPVOID',
37+
[
38+
['PCHAR', 'filename', 'in'],
39+
['DWORD', 'flags', 'in']
40+
],
41+
nil,
42+
'cdecl'
43+
)
2544
lib.add_function(
2645
'free',
2746
'VOID',
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# -*- coding: binary -*-
2+
module Rex
3+
module Post
4+
module Meterpreter
5+
module Extensions
6+
module Stdapi
7+
module Railgun
8+
module Def
9+
10+
class Def_libobjc
11+
12+
def self.create_dll(constant_manager, dll_path = 'libobjc.dylib')
13+
lib = DLL.new(dll_path, constant_manager)
14+
15+
# https://developer.apple.com/documentation/objectivec/1418952-objc_getclass?language=objc
16+
lib.add_function(
17+
'objc_getClass',
18+
'LPVOID',
19+
[
20+
['PCHAR', 'name', 'in']
21+
],
22+
nil,
23+
'cdecl'
24+
)
25+
26+
# https://developer.apple.com/documentation/objectivec/1456712-objc_msgsend?language=objc
27+
lib.add_function(
28+
'objc_msgSend',
29+
'LPVOID',
30+
[
31+
['LPVOID', 'self', 'in'],
32+
['LPVOID', 'op', 'in']
33+
],
34+
nil,
35+
'cdecl'
36+
)
37+
38+
# https://developer.apple.com/documentation/objectivec/1418557-sel_registername?language=objc
39+
lib.add_function(
40+
'sel_registerName',
41+
'LPVOID',
42+
[
43+
['PCHAR', 'str', 'in']
44+
],
45+
nil,
46+
'cdecl'
47+
)
48+
49+
return lib
50+
end
51+
52+
end
53+
54+
end; end; end; end; end; end; end

lib/rex/post/meterpreter/extensions/stdapi/railgun/dll.rb

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,19 @@ def get_function(name)
6969
# Returns a Hash containing the return value, the result of GetLastError(),
7070
# and any +inout+ parameters.
7171
#
72-
# Raises an exception if +func_symbol+ is not a known function in this DLL,
72+
# Raises an exception if +function+ is not a known function in this DLL,
7373
# i.e., it hasn't been defined in a Def.
7474
#
75-
def call_function(func_symbol, args, client)
76-
func_name = func_symbol.to_s
75+
def call_function(function, args, client)
76+
unless function.instance_of? DLLFunction
77+
func_name = function.to_s
7778

78-
unless known_function_names.include? func_name
79-
raise "DLL-function #{func_name} not found. Known functions: #{PP.pp(known_function_names, '')}"
80-
end
79+
unless known_function_names.include? func_name
80+
raise "DLL-function #{func_name} not found. Known functions: #{PP.pp(known_function_names, '')}"
81+
end
8182

82-
function = get_function(func_name)
83+
function = get_function(func_name)
84+
end
8385

8486
return process_function_call(function, args, client)
8587
end

lib/rex/post/meterpreter/extensions/stdapi/railgun/multicall.rb

Lines changed: 48 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -56,21 +56,22 @@ def initialize(client, parent, consts_mgr)
5656
end
5757

5858
def call(functions)
59-
6059
request = Packet.create_request('stdapi_railgun_api_multi')
6160
function_results = []
6261
layouts = []
6362
functions.each do |f|
64-
dll_name,funcname,args = f
63+
dll_name, function, args = f
6564
dll_host = @parent.get_dll( dll_name )
6665

6766
if not dll_host
6867
raise "DLL #{dll_name} has not been loaded"
6968
end
7069

71-
function = dll_host.functions[funcname]
72-
if not function
73-
raise "DLL #{dll_name} function #{funcname} has not been defined"
70+
unless function.instance_of? DLLFunction
71+
function = dll_host.functions[function]
72+
if not function
73+
raise "DLL #{dll_name} function #{function} has not been defined"
74+
end
7475
end
7576

7677
raise "#{function.params.length} arguments expected. #{args.length} arguments provided." unless args.length == function.params.length
@@ -96,7 +97,7 @@ def call(functions)
9697
end
9798

9899
# we care only about out-only buffers
99-
if param_desc[2] == "out"
100+
if param_desc[2] == 'out'
100101
if !args[param_idx].class.kind_of? Integer
101102
raise "error in param #{param_desc[1]}: Out-only buffers must be described by a number indicating their size in bytes "
102103
end
@@ -122,11 +123,11 @@ def call(functions)
122123
end
123124
end
124125

125-
tmp = assemble_buffer("in", function, args)
126+
tmp = assemble_buffer('in', function, args)
126127
in_only_layout = tmp[0]
127128
in_only_buffer = tmp[1]
128129

129-
tmp = assemble_buffer("inout", function, args)
130+
tmp = assemble_buffer('inout', function, args)
130131
inout_layout = tmp[0]
131132
inout_buffer = tmp[1]
132133

@@ -146,41 +147,41 @@ def call(functions)
146147
#puts " processing (#{param_desc[0]}, #{param_desc[1]}, #{param_desc[2]})"
147148
buffer = nil
148149
# is it a pointer to a buffer on our stack
149-
if ["PDWORD", "PWCHAR", "PCHAR", "PBLOB"].include? param_desc[0]
150-
#puts " pointer"
150+
if ['PDWORD', 'PWCHAR', 'PCHAR', 'PBLOB'].include? param_desc[0]
151+
#puts ' pointer'
151152
if args[param_idx] == nil # null pointer?
152153
buffer = [0].pack(@native) # type: DWORD (so the dll does not rebase it)
153154
buffer += [0].pack(@native) # value: 0
154-
elsif param_desc[2] == "in"
155+
elsif param_desc[2] == 'in'
155156
buffer = [1].pack(@native)
156157
buffer += [in_only_layout[param_desc[1]].addr].pack(@native)
157-
elsif param_desc[2] == "out"
158+
elsif param_desc[2] == 'out'
158159
buffer = [2].pack(@native)
159160
buffer += [out_only_layout[param_desc[1]].addr].pack(@native)
160-
elsif param_desc[2] == "inout"
161+
elsif param_desc[2] == 'inout'
161162
buffer = [3].pack(@native)
162163
buffer += [inout_layout[param_desc[1]].addr].pack(@native)
163164
else
164-
raise "unexpected direction"
165+
raise 'unexpected direction'
165166
end
166167
else
167-
#puts " not a pointer"
168+
#puts ' not a pointer'
168169
# it's not a pointer
169170
buffer = [0].pack(@native)
170171
case param_desc[0]
171-
when "LPVOID", "HANDLE", "SIZE_T"
172+
when 'LPVOID', 'HANDLE', 'SIZE_T'
172173
num = param_to_number(args[param_idx])
173174
buffer += [num].pack(@native)
174-
when "DWORD"
175+
when 'DWORD'
175176
num = param_to_number(args[param_idx])
176177
buffer += [num % 4294967296].pack(@native)
177-
when "WORD"
178+
when 'WORD'
178179
num = param_to_number(args[param_idx])
179180
buffer += [num % 65536].pack(@native)
180-
when "BYTE"
181+
when 'BYTE'
181182
num = param_to_number(args[param_idx])
182183
buffer += [num % 256].pack(@native)
183-
when "BOOL"
184+
when 'BOOL'
184185
case args[param_idx]
185186
when true
186187
buffer += [1].pack('V')
@@ -221,9 +222,9 @@ def call(functions)
221222
end
222223

223224
functions.each do |f|
224-
dll_name,funcname,args = f
225-
dll_host = @parent.get_dll( dll_name )
226-
function = dll_host.functions[funcname]
225+
dll_name, function, args = f
226+
dll_host = @parent.get_dll(dll_name)
227+
function = dll_host.functions[function] unless function.instance_of? DLLFunction
227228
response = call_results.shift
228229
inout_layout, out_only_layout = layouts.shift
229230

@@ -239,28 +240,28 @@ def call(functions)
239240

240241
# The hash the function returns
241242
return_hash = {
242-
"GetLastError" => rec_last_error,
243-
"ErrorMessage" => rec_err_msg
243+
'GetLastError' => rec_last_error,
244+
'ErrorMessage' => rec_err_msg
244245
}
245246

246247
#process return value
247248
case function.return_type
248-
when "LPVOID", "HANDLE"
249+
when 'LPVOID', 'HANDLE'
249250
if( @native == 'Q<' )
250-
return_hash["return"] = rec_return_value
251+
return_hash['return'] = rec_return_value
251252
else
252-
return_hash["return"] = rec_return_value % 4294967296
253+
return_hash['return'] = rec_return_value % 4294967296
253254
end
254-
when "DWORD"
255-
return_hash["return"] = rec_return_value % 4294967296
256-
when "WORD"
257-
return_hash["return"] = rec_return_value % 65536
258-
when "BYTE"
259-
return_hash["return"] = rec_return_value % 256
260-
when "BOOL"
261-
return_hash["return"] = (rec_return_value != 0)
262-
when "VOID"
263-
return_hash["return"] = nil
255+
when 'DWORD'
256+
return_hash['return'] = rec_return_value % 4294967296
257+
when 'WORD'
258+
return_hash['return'] = rec_return_value % 65536
259+
when 'BYTE'
260+
return_hash['return'] = rec_return_value % 256
261+
when 'BOOL'
262+
return_hash['return'] = (rec_return_value != 0)
263+
when 'VOID'
264+
return_hash['return'] = nil
264265
else
265266
raise "unexpected return type: #{function.return_type}"
266267
end
@@ -275,13 +276,13 @@ def call(functions)
275276
#puts " #{param_name}"
276277
buffer = rec_out_only_buffers[buffer_item.addr, buffer_item.length_in_bytes]
277278
case buffer_item.datatype
278-
when "PDWORD"
279+
when 'PDWORD'
279280
return_hash[param_name] = buffer.unpack('V')[0]
280-
when "PCHAR"
281+
when 'PCHAR'
281282
return_hash[param_name] = asciiz_to_str(buffer)
282-
when "PWCHAR"
283+
when 'PWCHAR'
283284
return_hash[param_name] = uniz_to_str(buffer)
284-
when "PBLOB"
285+
when 'PBLOB'
285286
return_hash[param_name] = buffer
286287
else
287288
raise "unexpected type in out-only buffer of #{param_name}: #{buffer_item.datatype}"
@@ -292,16 +293,16 @@ def call(functions)
292293
# process in-out buffers
293294
#puts "processing in-out buffers:"
294295
inout_layout.each_pair do |param_name, buffer_item|
295-
#puts " #{param_name}"
296+
#puts ' #{param_name}'
296297
buffer = rec_inout_buffers[buffer_item.addr, buffer_item.length_in_bytes]
297298
case buffer_item.datatype
298-
when "PDWORD"
299+
when 'PDWORD'
299300
return_hash[param_name] = buffer.unpack('V')[0]
300-
when "PCHAR"
301+
when 'PCHAR'
301302
return_hash[param_name] = asciiz_to_str(buffer)
302-
when "PWCHAR"
303+
when 'PWCHAR'
303304
return_hash[param_name] = uniz_to_str(buffer)
304-
when "PBLOB"
305+
when 'PBLOB'
305306
return_hash[param_name] = buffer
306307
else
307308
raise "unexpected type in in-out-buffer of #{param_name}: #{buffer_item.datatype}"

lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ class Railgun
7474
'libc'
7575
].freeze,
7676
'osx' => [
77-
'libc'
77+
'libc',
78+
'libobjc'
7879
].freeze,
7980
'windows' => [
8081
'kernel32',

0 commit comments

Comments
 (0)