indis-macho 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +5 -0
- data/Gemfile.ci +6 -0
- data/LICENSE +674 -0
- data/README.md +6 -0
- data/Rakefile +9 -0
- data/indis-macho.gemspec +21 -0
- data/lib/indis-macho.rb +224 -0
- data/lib/indis-macho/command.rb +271 -0
- data/lib/indis-macho/symbol.rb +143 -0
- data/lib/indis-macho/version.rb +23 -0
- data/spec/fixtures/app-arm-release.o +0 -0
- data/spec/fixtures/single-object.o +0 -0
- data/spec/indis-macho/binary_format_spec.rb +7 -0
- data/spec/indis-macho/macho_spec.rb +100 -0
- data/spec/spec_helper.rb +8 -0
- metadata +103 -0
data/README.md
ADDED
data/Rakefile
ADDED
data/indis-macho.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/indis-macho/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Vladimir Pouzanov"]
|
6
|
+
gem.email = ["farcaller@gmail.com"]
|
7
|
+
gem.description = "Mach-o format processor for indis provides support for loading mach-o binaries for analysis"
|
8
|
+
gem.summary = "Mach-o format processor for indis"
|
9
|
+
gem.homepage = "http://www.indis.org/"
|
10
|
+
gem.license = "GPL-3"
|
11
|
+
|
12
|
+
gem.files = `git ls-files`.split($\)
|
13
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
14
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
|
+
gem.name = "indis-macho"
|
16
|
+
gem.require_paths = ["lib"]
|
17
|
+
gem.version = Indis::MachO::VERSION
|
18
|
+
|
19
|
+
gem.add_development_dependency 'rspec'
|
20
|
+
gem.add_runtime_dependency 'indis-core'
|
21
|
+
end
|
data/lib/indis-macho.rb
ADDED
@@ -0,0 +1,224 @@
|
|
1
|
+
##############################################################################
|
2
|
+
# Indis framework #
|
3
|
+
# Copyright (C) 2012 Vladimir "Farcaller" Pouzanov <farcaller@gmail.com> #
|
4
|
+
# #
|
5
|
+
# This program is free software: you can redistribute it and/or modify #
|
6
|
+
# it under the terms of the GNU General Public License as published by #
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or #
|
8
|
+
# (at your option) any later version. #
|
9
|
+
# #
|
10
|
+
# This program is distributed in the hope that it will be useful, #
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
13
|
+
# GNU General Public License for more details. #
|
14
|
+
# #
|
15
|
+
# You should have received a copy of the GNU General Public License #
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
17
|
+
##############################################################################
|
18
|
+
|
19
|
+
require 'indis-core/binary_format'
|
20
|
+
require 'indis-core/segment'
|
21
|
+
require 'indis-core/section'
|
22
|
+
require 'indis-core/symbol'
|
23
|
+
require 'indis-macho/version'
|
24
|
+
require 'indis-macho/command'
|
25
|
+
require 'indis-macho/symbol'
|
26
|
+
|
27
|
+
module Indis
|
28
|
+
module BinaryFormat
|
29
|
+
|
30
|
+
class MachO < Format
|
31
|
+
MH_MAGIC = 0xfeedface
|
32
|
+
|
33
|
+
CPUTYPE = {
|
34
|
+
12 => :CPU_TYPE_ARM
|
35
|
+
}
|
36
|
+
|
37
|
+
CPUSUBTYPE = {
|
38
|
+
5 => :CPU_SUBTYPE_ARM_V4T,
|
39
|
+
6 => :CPU_SUBTYPE_ARM_V6,
|
40
|
+
7 => :CPU_SUBTYPE_ARM_V5TEJ,
|
41
|
+
8 => :CPU_SUBTYPE_ARM_XSCALE,
|
42
|
+
9 => :CPU_SUBTYPE_ARM_V7
|
43
|
+
}
|
44
|
+
|
45
|
+
FILETYPE = {
|
46
|
+
0x1 => :MH_OBJECT,
|
47
|
+
0x2 => :MH_EXECUTE,
|
48
|
+
0x3 => :MH_FVMLIB,
|
49
|
+
0x4 => :MH_CORE,
|
50
|
+
0x5 => :MH_PRELOAD,
|
51
|
+
0x6 => :MH_DYLIB,
|
52
|
+
0x7 => :MH_DYLINKER,
|
53
|
+
0x8 => :MH_BUNDLE,
|
54
|
+
0x9 => :MH_DYLIB_STUB,
|
55
|
+
0xa => :MH_DSYM,
|
56
|
+
0xb => :MH_KEXT_BUNDLE
|
57
|
+
}
|
58
|
+
|
59
|
+
FLAGS = {
|
60
|
+
0x1 => :MH_NOUNDEFS,
|
61
|
+
0x2 => :MH_INCRLINK,
|
62
|
+
0x4 => :MH_DYLDLINK,
|
63
|
+
0x8 => :MH_BINDATLOAD,
|
64
|
+
0x10 => :MH_PREBOUND,
|
65
|
+
0x20 => :MH_SPLIT_SEGS,
|
66
|
+
0x40 => :MH_LAZY_INIT,
|
67
|
+
0x80 => :MH_TWOLEVEL,
|
68
|
+
0x100 => :MH_FORCE_FLAT,
|
69
|
+
0x200 => :MH_NOMULTIDEFS,
|
70
|
+
0x400 => :MH_NOFIXPREBINDING,
|
71
|
+
0x800 => :MH_PREBINDABLE,
|
72
|
+
0x1000 => :MH_ALLMODSBOUND,
|
73
|
+
0x2000 => :MH_SUBSECTIONS_VIA_SYMBOLS,
|
74
|
+
0x4000 => :MH_CANONICAL,
|
75
|
+
0x8000 => :MH_WEAK_DEFINES,
|
76
|
+
0x10000 => :MH_BINDS_TO_WEAK,
|
77
|
+
0x20000 => :MH_ALLOW_STACK_EXECUTION,
|
78
|
+
0x40000 => :MH_ROOT_SAFE,
|
79
|
+
0x80000 => :MH_SETUID_SAFE,
|
80
|
+
0x100000 => :MH_NO_REEXPORTED_DYLIBS,
|
81
|
+
0x200000 => :MH_PIE,
|
82
|
+
0x400000 => :MH_DEAD_STRIPPABLE_DYLIB,
|
83
|
+
0x800000 => :MH_HAS_TLV_DESCRIPTORS,
|
84
|
+
0x1000000 => :MH_NO_HEAP_EXECUTION,
|
85
|
+
}
|
86
|
+
|
87
|
+
attr_reader :cputype, :cpusubtype, :filetype, :commands
|
88
|
+
|
89
|
+
def self.magic
|
90
|
+
MH_MAGIC
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.name
|
94
|
+
'Mach-O'
|
95
|
+
end
|
96
|
+
|
97
|
+
def initialize(target, io)
|
98
|
+
super(target, io)
|
99
|
+
|
100
|
+
@commands = []
|
101
|
+
|
102
|
+
parse_header
|
103
|
+
parse_commands
|
104
|
+
|
105
|
+
build_segments
|
106
|
+
build_dylibs if self.flags.include? :MH_TWOLEVEL
|
107
|
+
build_symbols
|
108
|
+
end
|
109
|
+
|
110
|
+
def flags
|
111
|
+
f = []
|
112
|
+
FLAGS.each_pair do |k, v|
|
113
|
+
f << v if @flags_val & k == k
|
114
|
+
end
|
115
|
+
f
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
def validate_format
|
120
|
+
raise "Not a Mach-O" if @io.length < 4
|
121
|
+
magic = @io.read(4).unpack('V')[0]
|
122
|
+
raise "Bad magic" unless magic == MH_MAGIC
|
123
|
+
@io.seek(-4, IO::SEEK_CUR)
|
124
|
+
end
|
125
|
+
|
126
|
+
def parse_header
|
127
|
+
validate_format
|
128
|
+
|
129
|
+
@magic, @cputype, @cpusubtype, @filetype, @ncmds, @sizeofcmds, @flags_val = @io.read(7*4).unpack('VVVVVVV')
|
130
|
+
|
131
|
+
@cputype = CPUTYPE[@cputype]
|
132
|
+
raise "Unknown CPU type" unless @cputype
|
133
|
+
|
134
|
+
@cpusubtype = CPUSUBTYPE[@cpusubtype]
|
135
|
+
raise "Unknown CPU subtype" unless @cpusubtype
|
136
|
+
|
137
|
+
@filetype = FILETYPE[@filetype]
|
138
|
+
raise "Unknown file type" unless @filetype
|
139
|
+
end
|
140
|
+
|
141
|
+
def parse_commands
|
142
|
+
@ncmds.times do
|
143
|
+
cmd, size = @io.read(2*4).unpack('VV')
|
144
|
+
|
145
|
+
begin
|
146
|
+
c = Indis::MachO::Command.class_of_command(cmd).new(cmd, size, @io)
|
147
|
+
@commands << c
|
148
|
+
rescue Indis::MachO::UnknownCommandError
|
149
|
+
print "Unknown command #{cmd} size #{size}, skipping\n"
|
150
|
+
@io.read(size-8)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def build_segments
|
156
|
+
@indexed_sections = [nil]
|
157
|
+
segcommands = @commands.map{ |c| c if c.is_a?(Indis::MachO::SegmentCommand) }.compact
|
158
|
+
|
159
|
+
@target.segments = []
|
160
|
+
|
161
|
+
pos = @target.io.pos
|
162
|
+
segcommands.each do |cmd|
|
163
|
+
name = if cmd.segname.length > 0
|
164
|
+
cmd.segname
|
165
|
+
else
|
166
|
+
if cmd.sections.length > 0 && cmd.sections.first.segname.length > 0
|
167
|
+
cmd.sections.first.segname
|
168
|
+
else
|
169
|
+
name = '*NONAME*'
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
@target.io.pos = cmd.fileoff
|
174
|
+
seg = Indis::Segment.new(@target, name, cmd.vmaddr, cmd.vmsize, cmd.fileoff, @target.io.read(cmd.filesize))
|
175
|
+
@target.segments << seg
|
176
|
+
|
177
|
+
cmd.sections.each do |sec|
|
178
|
+
sec.index = @indexed_sections.length
|
179
|
+
s = Indis::Section.new(seg, sec.sectname, sec.addr, sec.size, sec.offset)
|
180
|
+
seg.sections << s
|
181
|
+
@indexed_sections << s
|
182
|
+
end
|
183
|
+
end
|
184
|
+
@target.io.pos = pos
|
185
|
+
end
|
186
|
+
|
187
|
+
def build_dylibs
|
188
|
+
@indexed_dylibs = [nil]
|
189
|
+
dylibcommands = @commands.map{ |c| c if c.is_a?(Indis::MachO::LoadDyLibCommand) }.compact
|
190
|
+
|
191
|
+
dylibcommands.each do |dy|
|
192
|
+
@indexed_dylibs << dy.name
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def build_symbols
|
197
|
+
symtabcommand = @commands.map{ |c| c if c.is_a?(Indis::MachO::SymTabCommand) }.compact
|
198
|
+
return if symtabcommand.length == 0
|
199
|
+
|
200
|
+
@target.symbols = {}
|
201
|
+
|
202
|
+
cmd = symtabcommand.first
|
203
|
+
cmd.symbols.each do |sym|
|
204
|
+
sec = if sym.sect > 0
|
205
|
+
@indexed_sections[sym.sect]
|
206
|
+
else
|
207
|
+
nil
|
208
|
+
end
|
209
|
+
|
210
|
+
dy = if self.flags.include? :MH_TWOLEVEL
|
211
|
+
l2 = sym.twolevel_library_ordinal
|
212
|
+
@indexed_dylibs[l2] if l2.is_a? Fixnum
|
213
|
+
else
|
214
|
+
nil
|
215
|
+
end
|
216
|
+
|
217
|
+
s = Indis::Symbol.new(sym.name, sec, dy, sym.value, sym)
|
218
|
+
@target.symbols[sym.name] = s
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|
224
|
+
end
|
@@ -0,0 +1,271 @@
|
|
1
|
+
##############################################################################
|
2
|
+
# Indis framework #
|
3
|
+
# Copyright (C) 2012 Vladimir "Farcaller" Pouzanov <farcaller@gmail.com> #
|
4
|
+
# #
|
5
|
+
# This program is free software: you can redistribute it and/or modify #
|
6
|
+
# it under the terms of the GNU General Public License as published by #
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or #
|
8
|
+
# (at your option) any later version. #
|
9
|
+
# #
|
10
|
+
# This program is distributed in the hope that it will be useful, #
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
13
|
+
# GNU General Public License for more details. #
|
14
|
+
# #
|
15
|
+
# You should have received a copy of the GNU General Public License #
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
17
|
+
##############################################################################
|
18
|
+
|
19
|
+
require 'indis-macho/symbol'
|
20
|
+
|
21
|
+
module Indis
|
22
|
+
module MachO
|
23
|
+
|
24
|
+
class UnknownCommandError < RuntimeError; end
|
25
|
+
|
26
|
+
class Command
|
27
|
+
LC_REQ_DYLD = 0x80000000
|
28
|
+
|
29
|
+
CMD = {
|
30
|
+
0x1 => :LC_SEGMENT,
|
31
|
+
0x2 => :LC_SYMTAB,
|
32
|
+
0x3 => :LC_SYMSEG,
|
33
|
+
0x4 => :LC_THREAD,
|
34
|
+
0x5 => :LC_UNIXTHREAD,
|
35
|
+
0x6 => :LC_LOADFVMLIB,
|
36
|
+
0x7 => :LC_IDFVMLIB,
|
37
|
+
0x8 => :LC_IDENT,
|
38
|
+
0x9 => :LC_FVMFILE,
|
39
|
+
0xa => :LC_PREPAGE,
|
40
|
+
0xb => :LC_DYSYMTAB,
|
41
|
+
0xc => :LC_LOAD_DYLIB,
|
42
|
+
0xd => :LC_ID_DYLIB,
|
43
|
+
0xe => :LC_LOAD_DYLINKER,
|
44
|
+
0xf => :LC_ID_DYLINKER,
|
45
|
+
0x10 => :LC_PREBOUND_DYLIB,
|
46
|
+
0x11 => :LC_ROUTINES,
|
47
|
+
0x12 => :LC_SUB_FRAMEWORK,
|
48
|
+
0x13 => :LC_SUB_UMBRELLA,
|
49
|
+
0x14 => :LC_SUB_CLIENT,
|
50
|
+
0x15 => :LC_SUB_LIBRARY,
|
51
|
+
0x16 => :LC_TWOLEVEL_HINTS,
|
52
|
+
0x17 => :LC_PREBIND_CKSUM,
|
53
|
+
|
54
|
+
0x18 | LC_REQ_DYLD => :LC_LOAD_WEAK_DYLIB,
|
55
|
+
0x19 => :LC_SEGMENT_64,
|
56
|
+
0x1a => :LC_ROUTINES_64,
|
57
|
+
0x1b => :LC_UUID,
|
58
|
+
0x1c | LC_REQ_DYLD => :LC_RPATH,
|
59
|
+
0x1d => :LC_CODE_SIGNATURE,
|
60
|
+
0x1e => :LC_SEGMENT_SPLIT_INFO,
|
61
|
+
0x1f | LC_REQ_DYLD => :LC_REEXPORT_DYLIB,
|
62
|
+
0x20 => :LC_LAZY_LOAD_DYLIB,
|
63
|
+
0x21 => :LC_ENCRYPTION_INFO,
|
64
|
+
0x22 => :LC_DYLD_INFO,
|
65
|
+
0x22|LC_REQ_DYLD => :LC_DYLD_INFO_ONLY,
|
66
|
+
|
67
|
+
0x23 | LC_REQ_DYLD => :LC_LOAD_UPWARD_DYLIB,
|
68
|
+
0x24 => :LC_VERSION_MIN_MACOSX,
|
69
|
+
0x25 => :LC_VERSION_MIN_IPHONEOS,
|
70
|
+
0x26 => :LC_FUNCTION_STARTS,
|
71
|
+
0x27 => :LC_DYLD_ENVIRONMENT,
|
72
|
+
}
|
73
|
+
|
74
|
+
CMD_CLASS = {
|
75
|
+
LC_SEGMENT: :SegmentCommand,
|
76
|
+
LC_DYLD_INFO_ONLY: :DyldInfoOnlyCommand,
|
77
|
+
LC_SYMTAB: :SymTabCommand,
|
78
|
+
LC_DYSYMTAB: :DySymTabCommand,
|
79
|
+
LC_LOAD_DYLINKER: :LoadDyLinkerCommand,
|
80
|
+
LC_UUID: :UUIDCommand,
|
81
|
+
LC_UNIXTHREAD: :ARMUnixThreadCommand,
|
82
|
+
LC_ENCRYPTION_INFO: :EncryptionInfoCommand,
|
83
|
+
LC_LOAD_DYLIB: :LoadDyLibCommand,
|
84
|
+
LC_CODE_SIGNATURE: :CodeSignatureCommand,
|
85
|
+
LC_VERSION_MIN_IPHONEOS: :VersionMinIPhoneOSCommand,
|
86
|
+
LC_FUNCTION_STARTS: :FunctionStartsCommand,
|
87
|
+
}
|
88
|
+
|
89
|
+
attr_reader :cmd, :length
|
90
|
+
|
91
|
+
def initialize(cmd, length, payload)
|
92
|
+
@cmd = CMD[cmd]
|
93
|
+
@length = length
|
94
|
+
raise "Unknown mach-o command" unless @cmd
|
95
|
+
|
96
|
+
process(payload)
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.class_of_command(c)
|
100
|
+
cmd = CMD[c]
|
101
|
+
raise UnknownCommandError, "Unknown mach-o command #{c.to_s(16)}" unless cmd
|
102
|
+
clsnm = CMD_CLASS[cmd]
|
103
|
+
raise "Unsupported mach-o command #{c.to_s(16)} (#{cmd})" unless clsnm
|
104
|
+
cls = Indis::MachO.const_get(clsnm)
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
def process(payload)
|
109
|
+
return unless self.class.fields
|
110
|
+
self.class.fields.each do |f|
|
111
|
+
case f[0]
|
112
|
+
when :string
|
113
|
+
s = payload.read(f[2]).strip.gsub("\0", "")
|
114
|
+
instance_variable_set("@#{f[1]}".to_sym, s)
|
115
|
+
when :uint32
|
116
|
+
instance_variable_set("@#{f[1]}".to_sym, payload.read(4).unpack('V')[0])
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.f_string(name, sz)
|
122
|
+
@fields ||= []
|
123
|
+
@fields << [:string, name, sz]
|
124
|
+
attr_reader name.to_sym
|
125
|
+
end
|
126
|
+
|
127
|
+
def self.f_uint32(*names)
|
128
|
+
@fields ||= []
|
129
|
+
names.each do |nm|
|
130
|
+
@fields << [:uint32, nm]
|
131
|
+
attr_reader nm.to_sym
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.fields
|
136
|
+
@fields
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
class SectionSubCommand < Command # LC_SEGMENT.sub
|
141
|
+
f_string :sectname, 16
|
142
|
+
f_string :segname, 16
|
143
|
+
f_uint32 :addr, :size, :offset, :align, :reloff, :nreloc, :flags, :reserved1, :reseved2
|
144
|
+
attr_accessor :index
|
145
|
+
|
146
|
+
def initialize(payload)
|
147
|
+
process(payload)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
class SegmentCommand < Command # LC_SEGMENT
|
152
|
+
f_string :segname, 16
|
153
|
+
f_uint32 :vmaddr, :vmsize, :fileoff, :filesize, :maxprot, :initprot, :nsects, :flags
|
154
|
+
attr_reader :sections
|
155
|
+
|
156
|
+
def process(payload)
|
157
|
+
super(payload)
|
158
|
+
|
159
|
+
@sections = []
|
160
|
+
@nsects.times do
|
161
|
+
s = SectionSubCommand.new(payload)
|
162
|
+
@sections << s
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
class SymTabCommand < Command # LC_SYMTAB
|
168
|
+
f_uint32 :symoff, :nsyms, :stroff, :strsize
|
169
|
+
attr_reader :symbols
|
170
|
+
|
171
|
+
def process(payload)
|
172
|
+
super(payload)
|
173
|
+
|
174
|
+
pos = payload.pos
|
175
|
+
|
176
|
+
payload.pos = @stroff
|
177
|
+
strings = payload.read(@strsize)
|
178
|
+
|
179
|
+
payload.pos = @symoff
|
180
|
+
@symbols = []
|
181
|
+
|
182
|
+
@nsyms.times do |n|
|
183
|
+
s = Indis::MachO::Symbol.new(payload, strings)
|
184
|
+
@symbols << s
|
185
|
+
end
|
186
|
+
payload.pos = pos
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
class DySymTabCommand < Command # LC_DYSYMTAB
|
191
|
+
f_uint32 :ilocalsym, :nlocalsym, :iextdefsym, :nextdefsym, :iundefsym, :nundefsym, :tocoff,
|
192
|
+
:ntoc, :modtaboff, :nmodtab, :extrefsymoff, :nextrefsyms, :indirectsymoff, :nindirectsyms,
|
193
|
+
:extreloff, :nextrel, :locreloff, :nlocrel
|
194
|
+
end
|
195
|
+
|
196
|
+
class LoadDyLinkerCommand < Command # LC_LOAD_DYLINKER
|
197
|
+
attr_reader :name
|
198
|
+
|
199
|
+
def process(payload)
|
200
|
+
super(payload)
|
201
|
+
@name = payload.read(@length-8).strip
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
class UUIDCommand < Command # LC_UUID
|
206
|
+
attr_reader :UUID
|
207
|
+
|
208
|
+
def process(payload)
|
209
|
+
super(payload)
|
210
|
+
@UUID = payload.read(16)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
class ARMUnixThreadCommand < Command # LC_UNIXTHREAD
|
215
|
+
REGISTERS = [:r0, :r1, :r2, :r3, :r4, :r5, :r6, :r7, :r8, :r9, :r10, :r11, :r12, :sp, :lr, :pc, :cpsr]
|
216
|
+
f_uint32 :flavor, :count
|
217
|
+
attr_reader :registers
|
218
|
+
|
219
|
+
def process(payload)
|
220
|
+
super(payload)
|
221
|
+
# XXX: this one parses only ARM thread state, need to get back to mach-o header to know the flavor
|
222
|
+
|
223
|
+
@registers = payload.read(4*17).unpack('V'*17)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
class EncryptionInfoCommand < Command # LC_ENCRYPTION_INFO
|
228
|
+
f_uint32 :cryptoff, :cryptsize, :cryptid
|
229
|
+
end
|
230
|
+
|
231
|
+
class LoadDyLibCommand < Command # LC_LOAD_DYLIB
|
232
|
+
attr_reader :name, :timestamp, :current_version, :compatibility_version
|
233
|
+
|
234
|
+
def process(payload)
|
235
|
+
super(payload)
|
236
|
+
|
237
|
+
ofs_to_name = payload.read(4).unpack('V')[0]
|
238
|
+
|
239
|
+
@timestamp, @current_version, @compatibility_version = payload.read(4*3).unpack('VVV')
|
240
|
+
|
241
|
+
name_sz = @length - ofs_to_name - 4*3 + 8 + 4
|
242
|
+
@name = payload.read(name_sz).strip
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
class CodeSignatureCommand < Command # LC_CODE_SIGNATURE
|
247
|
+
f_uint32 :dataoff, :datasize
|
248
|
+
end
|
249
|
+
|
250
|
+
class VersionMinIPhoneOSCommand < Command # LC_VERSION_MIN_IPHONEOS
|
251
|
+
attr_reader :version, :sdk
|
252
|
+
|
253
|
+
def process(payload)
|
254
|
+
v, s = payload.read(8).unpack('VV')
|
255
|
+
|
256
|
+
@version = "#{(v & 0xffff0000) >> 16}.#{(v & 0xff00) >> 8}.#{v & 0xff}"
|
257
|
+
@sdk = s
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
class FunctionStartsCommand < Command # LC_FUNCTION_STARTS
|
262
|
+
f_uint32 :dataoff, :datasize
|
263
|
+
end
|
264
|
+
|
265
|
+
class DyldInfoOnlyCommand < Command # LC_DYLD_INFO_ONLY
|
266
|
+
f_uint32 :rebase_off, :rebase_size, :bind_off, :bind_size, :weak_bind_off, :weak_bind_size,
|
267
|
+
:lazy_bind_off, :lazy_bind_size, :export_off, :export_size
|
268
|
+
end
|
269
|
+
|
270
|
+
end
|
271
|
+
end
|