ruby-macho 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/macho.rb +3 -14
- data/lib/macho/fat_file.rb +58 -0
- data/lib/macho/load_commands.rb +107 -250
- data/lib/macho/macho_file.rb +49 -12
- data/lib/macho/open.rb +16 -0
- data/lib/macho/sections.rb +73 -7
- data/lib/macho/tools.rb +30 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 16240f8ca67e156531a460441d739de7d63fbe9e
|
4
|
+
data.tar.gz: 9a4baa19c7d468ea968a1d0eac8f12941053fcf4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cbf7d99140e66376e18dfae8efc2e0b1d9d921e4f5ba3813a6cf09f478ec5a6de2a777b6b4b582afcf8427a005d3807c6b72f13862b4d7c0d30c476a8711d547
|
7
|
+
data.tar.gz: f2a8064e9246c8b1d5f671edc830a902023f754458a2cc6a4abed62dde247e698d1b955eff5c9e91f8951e66fe6d095fd6677f8a9a7e45f0c34acb435f2b2ed5
|
data/lib/macho.rb
CHANGED
@@ -4,24 +4,13 @@ require "#{File.dirname(__FILE__)}/macho/load_commands"
|
|
4
4
|
require "#{File.dirname(__FILE__)}/macho/sections"
|
5
5
|
require "#{File.dirname(__FILE__)}/macho/macho_file"
|
6
6
|
require "#{File.dirname(__FILE__)}/macho/fat_file"
|
7
|
+
require "#{File.dirname(__FILE__)}/macho/open"
|
7
8
|
require "#{File.dirname(__FILE__)}/macho/exceptions"
|
8
9
|
require "#{File.dirname(__FILE__)}/macho/utils"
|
9
10
|
require "#{File.dirname(__FILE__)}/macho/tools"
|
10
11
|
|
11
12
|
# The primary namespace for ruby-macho.
|
12
13
|
module MachO
|
13
|
-
#
|
14
|
-
|
15
|
-
# @return [MachO::MachOFile] if the file is a Mach-O
|
16
|
-
# @return [MachO::FatFile] if the file is a Fat file
|
17
|
-
def self.open(filename)
|
18
|
-
# open file and test magic instead of using exceptions for control?
|
19
|
-
begin
|
20
|
-
file = MachOFile.new(filename)
|
21
|
-
rescue FatBinaryError
|
22
|
-
file = FatFile.new(filename)
|
23
|
-
end
|
24
|
-
|
25
|
-
file
|
26
|
-
end
|
14
|
+
# release version
|
15
|
+
VERSION = "0.1.8".freeze
|
27
16
|
end
|
data/lib/macho/fat_file.rb
CHANGED
@@ -32,6 +32,64 @@ module MachO
|
|
32
32
|
@raw_data
|
33
33
|
end
|
34
34
|
|
35
|
+
# @return [Boolean] true if the Mach-O is of type `MH_OBJECT`, false otherwise
|
36
|
+
def object?
|
37
|
+
machos.first.object?
|
38
|
+
end
|
39
|
+
|
40
|
+
# @return [Boolean] true if the Mach-O is of type `MH_EXECUTE`, false otherwise
|
41
|
+
def executable?
|
42
|
+
machos.first.executable?
|
43
|
+
end
|
44
|
+
|
45
|
+
# @return [Boolean] true if the Mach-O is of type `MH_FVMLIB`, false otherwise
|
46
|
+
def fvmlib?
|
47
|
+
machos.first.fvmlib?
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return [Boolean] true if the Mach-O is of type `MH_CORE`, false otherwise
|
51
|
+
def core?
|
52
|
+
machos.first.core?
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [Boolean] true if the Mach-O is of type `MH_PRELOAD`, false otherwise
|
56
|
+
def preload?
|
57
|
+
machos.first.preload?
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [Boolean] true if the Mach-O is of type `MH_DYLIB`, false otherwise
|
61
|
+
def dylib?
|
62
|
+
machos.first.dylib?
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [Boolean] true if the Mach-O is of type `MH_DYLINKER`, false otherwise
|
66
|
+
def dylinker?
|
67
|
+
machos.first.dylinker?
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [Boolean] true if the Mach-O is of type `MH_BUNDLE`, false otherwise
|
71
|
+
def bundle?
|
72
|
+
machos.first.bundle?
|
73
|
+
end
|
74
|
+
|
75
|
+
# @return [Boolean] true if the Mach-O is of type `MH_DSYM`, false otherwise
|
76
|
+
def dsym?
|
77
|
+
machos.first.dsym?
|
78
|
+
end
|
79
|
+
|
80
|
+
# @return [Boolean] true if the Mach-O is of type `MH_KEXT_BUNDLE`, false otherwise
|
81
|
+
def kext?
|
82
|
+
machos.first.kext?
|
83
|
+
end
|
84
|
+
|
85
|
+
def magic
|
86
|
+
header.magic
|
87
|
+
end
|
88
|
+
|
89
|
+
def magic_string
|
90
|
+
MH_MAGICS[magic]
|
91
|
+
end
|
92
|
+
|
35
93
|
# The file's type. Assumed to be the same for every Mach-O within.
|
36
94
|
# @return [String] the filetype
|
37
95
|
def filetype
|
data/lib/macho/load_commands.rb
CHANGED
@@ -3,247 +3,107 @@ module MachO
|
|
3
3
|
# LC_REQ_DYLD to be recognized by the dynamic linder (dyld)
|
4
4
|
LC_REQ_DYLD = 0x80000000
|
5
5
|
|
6
|
-
# segment of this file to be mapped
|
7
|
-
LC_SEGMENT = 0x1
|
8
|
-
|
9
|
-
# link-edit stab symbol table info
|
10
|
-
LC_SYMTAB = 0x2
|
11
|
-
|
12
|
-
# link-edit gdb symbol table info (obsolete)
|
13
|
-
LC_SYMSEG = 0x3
|
14
|
-
|
15
|
-
# thread
|
16
|
-
LC_THREAD = 0x4
|
17
|
-
|
18
|
-
# unix thread (includes a stack)
|
19
|
-
LC_UNIXTHREAD = 0x5
|
20
|
-
|
21
|
-
# load a specified fixed VM shared library
|
22
|
-
LC_LOADFVMLIB = 0x6
|
23
|
-
|
24
|
-
# fixed VM shared library identification
|
25
|
-
LC_IDFVMLIB = 0x7
|
26
|
-
|
27
|
-
# object identification info (obsolete)
|
28
|
-
LC_IDENT = 0x8
|
29
|
-
|
30
|
-
# fixed VM file inclusion (internal use)
|
31
|
-
LC_FVMFILE = 0x9
|
32
|
-
|
33
|
-
# prepage command (internal use)
|
34
|
-
LC_PREPAGE = 0xa
|
35
|
-
|
36
|
-
# dynamic link-edit symbol table info
|
37
|
-
LC_DYSYMTAB = 0xb
|
38
|
-
|
39
|
-
# load a dynamically linked shared library
|
40
|
-
LC_LOAD_DYLIB = 0xc
|
41
|
-
|
42
|
-
# dynamically linked shared lib ident
|
43
|
-
LC_ID_DYLIB = 0xd
|
44
|
-
|
45
|
-
# load a dynamic linker
|
46
|
-
LC_LOAD_DYLINKER = 0xe
|
47
|
-
|
48
|
-
# dynamic linker identification
|
49
|
-
LC_ID_DYLINKER = 0xf
|
50
|
-
|
51
|
-
# modules prebound for a dynamically linked shared library
|
52
|
-
LC_PREBOUND_DYLIB = 0x10
|
53
|
-
|
54
|
-
# image routines
|
55
|
-
LC_ROUTINES = 0x11
|
56
|
-
|
57
|
-
# sub framework
|
58
|
-
LC_SUB_FRAMEWORK = 0x12
|
59
|
-
|
60
|
-
# sub umbrella
|
61
|
-
LC_SUB_UMBRELLA = 0x13
|
62
|
-
|
63
|
-
# sub umbrella
|
64
|
-
LC_SUB_CLIENT = 0x14
|
65
|
-
|
66
|
-
# sub umbrella
|
67
|
-
LC_SUB_LIBRARY = 0x15
|
68
|
-
|
69
|
-
# two-level namespace lookup hints
|
70
|
-
LC_TWOLEVEL_HINTS = 0x16
|
71
|
-
|
72
|
-
# prebind checksum
|
73
|
-
LC_PREBIND_CKSUM = 0x17
|
74
|
-
|
75
|
-
# load a dynamically linked shared library that is allowed to be missing (all symbols are weak imported).
|
76
|
-
LC_LOAD_WEAK_DYLIB = (0x18 | LC_REQ_DYLD)
|
77
|
-
|
78
|
-
# 64-bit segment of this file to be mapped
|
79
|
-
LC_SEGMENT_64 = 0x19
|
80
|
-
|
81
|
-
# 64-bit image routines
|
82
|
-
LC_ROUTINES_64 = 0x1a
|
83
|
-
|
84
|
-
# the uuid
|
85
|
-
LC_UUID = 0x1b
|
86
|
-
|
87
|
-
# runpath additions
|
88
|
-
LC_RPATH = (0x1c | LC_REQ_DYLD)
|
89
|
-
|
90
|
-
# local of code signature
|
91
|
-
LC_CODE_SIGNATURE = 0x1d
|
92
|
-
|
93
|
-
# local of info to split segments
|
94
|
-
LC_SEGMENT_SPLIT_INFO = 0x1e
|
95
|
-
|
96
|
-
# load and re-export dylib
|
97
|
-
LC_REEXPORT_DYLIB = (0x1f | LC_REQ_DYLD)
|
98
|
-
|
99
|
-
# delay load of dylib until first use
|
100
|
-
LC_LAZY_LOAD_DYLIB = 0x20
|
101
|
-
|
102
|
-
# encrypted segment information
|
103
|
-
LC_ENCRYPTION_INFO = 0x21
|
104
|
-
|
105
|
-
# compressed dyld information
|
106
|
-
LC_DYLD_INFO = 0x22
|
107
|
-
|
108
|
-
# compressed dyld information only
|
109
|
-
LC_DYLD_INFO_ONLY = (0x22 | LC_REQ_DYLD)
|
110
|
-
|
111
|
-
# load upward dylib
|
112
|
-
LC_LOAD_UPWARD_DYLIB = (0x23 | LC_REQ_DYLD)
|
113
|
-
|
114
|
-
# build for MacOSX min OS version
|
115
|
-
LC_VERSION_MIN_MACOSX = 0x24
|
116
|
-
|
117
|
-
# build for iPhoneOS min OS version
|
118
|
-
LC_VERSION_MIN_IPHONEOS = 0x25
|
119
|
-
|
120
|
-
# compressed table of function start addresses
|
121
|
-
LC_FUNCTION_STARTS = 0x26
|
122
|
-
|
123
|
-
# string for dyld to treat like environment variable
|
124
|
-
LC_DYLD_ENVIRONMENT = 0x27
|
125
|
-
|
126
|
-
# replacement for LC_UNIXTHREAD
|
127
|
-
LC_MAIN = (0x28 | LC_REQ_DYLD)
|
128
|
-
|
129
|
-
# table of non-instructions in __text
|
130
|
-
LC_DATA_IN_CODE = 0x29
|
131
|
-
|
132
|
-
# source version used to build binary
|
133
|
-
LC_SOURCE_VERSION = 0x2a
|
134
|
-
|
135
|
-
# Code signing DRs copied from linked dylibs
|
136
|
-
LC_DYLIB_CODE_SIGN_DRS = 0x2b
|
137
|
-
|
138
|
-
# 64-bit encrypted segment information
|
139
|
-
LC_ENCRYPTION_INFO_64 = 0x2c
|
140
|
-
|
141
|
-
# linker options in MH_OBJECT files
|
142
|
-
LC_LINKER_OPTION = 0x2d
|
143
|
-
|
144
|
-
# linker options in MH_OBJECT files
|
145
|
-
LC_LINKER_OPTIMIZATION_HINT = 0x2e
|
146
|
-
|
147
6
|
# association of load commands to string representations
|
7
|
+
# @api private
|
148
8
|
LOAD_COMMANDS = {
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
9
|
+
0x1 => :LC_SEGMENT,
|
10
|
+
0x2 => :LC_SYMTAB,
|
11
|
+
0x3 => :LC_SYMSEG,
|
12
|
+
0x4 => :LC_THREAD,
|
13
|
+
0x5 => :LC_UNIXTHREAD,
|
14
|
+
0x6 => :LC_LOADFVMLIB,
|
15
|
+
0x7 => :LC_IDFVMLIB,
|
16
|
+
0x8 => :LC_IDENT,
|
17
|
+
0x9 => :LC_FVMFILE,
|
18
|
+
0xa => :LC_PREPAGE,
|
19
|
+
0xb => :LC_DYSYMTAB,
|
20
|
+
0xc => :LC_LOAD_DYLIB,
|
21
|
+
0xd => :LC_ID_DYLIB,
|
22
|
+
0xe => :LC_LOAD_DYLINKER,
|
23
|
+
0xf => :LC_ID_DYLINKER,
|
24
|
+
0x10 => :LC_PREBOUND_DYLIB,
|
25
|
+
0x11 => :LC_ROUTINES,
|
26
|
+
0x12 => :LC_SUB_FRAMEWORK,
|
27
|
+
0x13 => :LC_SUB_UMBRELLA,
|
28
|
+
0x14 => :LC_SUB_CLIENT,
|
29
|
+
0x15 => :LC_SUB_LIBRARY,
|
30
|
+
0x16 => :LC_TWOLEVEL_HINTS,
|
31
|
+
0x17 => :LC_PREBIND_CKSUM,
|
32
|
+
(0x18 | LC_REQ_DYLD) => :LC_LOAD_WEAK_DYLIB,
|
33
|
+
0x19 => :LC_SEGMENT_64,
|
34
|
+
0x1a => :LC_ROUTINES_64,
|
35
|
+
0x1b => :LC_UUID,
|
36
|
+
(0x1c | LC_REQ_DYLD) => :LC_RPATH,
|
37
|
+
0x1d => :LC_CODE_SIGNATURE,
|
38
|
+
0x1e => :LC_SEGMENT_SPLIT_INFO,
|
39
|
+
(0x1f | LC_REQ_DYLD) => :LC_REEXPORT_DYLIB,
|
40
|
+
0x20 => :LC_LAZY_LOAD_DYLIB,
|
41
|
+
0x21 => :LC_ENCRYPTION_INFO,
|
42
|
+
0x22 => :LC_DYLD_INFO,
|
43
|
+
(0x22 | LC_REQ_DYLD) => :LC_DYLD_INFO_ONLY,
|
44
|
+
(0x23 | LC_REQ_DYLD) => :LC_LOAD_UPWARD_DYLIB,
|
45
|
+
0x24 => :LC_VERSION_MIN_MACOSX,
|
46
|
+
0x25 => :LC_VERSION_MIN_IPHONEOS,
|
47
|
+
0x26 => :LC_FUNCTION_STARTS,
|
48
|
+
0x27 => :LC_DYLD_ENVIRONMENT,
|
49
|
+
(0x28 | LC_REQ_DYLD) => :LC_MAIN,
|
50
|
+
0x29 => :LC_DATA_IN_CODE,
|
51
|
+
0x2a => :LC_SOURCE_VERSION,
|
52
|
+
0x2b => :LC_DYLIB_CODE_SIGN_DRS,
|
53
|
+
0x2c => :LC_ENCRYPTION_INFO_64,
|
54
|
+
0x2d => :LC_LINKER_OPTION,
|
55
|
+
0x2e => :LC_LINKER_OPTIMIZATION_HINT
|
196
56
|
}
|
197
57
|
|
198
58
|
# association of load commands to string representations of class names
|
199
59
|
LC_STRUCTURES = {
|
200
|
-
LC_SEGMENT => "SegmentCommand",
|
201
|
-
LC_SYMTAB => "SymtabCommand",
|
202
|
-
LC_SYMSEG => "LoadCommand", # obsolete
|
203
|
-
LC_THREAD => "ThreadCommand",
|
204
|
-
LC_UNIXTHREAD => "ThreadCommand",
|
205
|
-
LC_LOADFVMLIB => "LoadCommand", # obsolete
|
206
|
-
LC_IDFVMLIB => "LoadCommand", # obsolete
|
207
|
-
LC_IDENT => "LoadCommand", # obsolete
|
208
|
-
LC_FVMFILE => "LoadCommand", # reserved for internal use only
|
209
|
-
LC_PREPAGE => "LoadCommand", # reserved for internal use only
|
210
|
-
LC_DYSYMTAB => "DysymtabCommand",
|
211
|
-
LC_LOAD_DYLIB => "DylibCommand",
|
212
|
-
LC_ID_DYLIB => "DylibCommand",
|
213
|
-
LC_LOAD_DYLINKER => "DylinkerCommand",
|
214
|
-
LC_ID_DYLINKER => "DylinkerCommand",
|
215
|
-
LC_PREBOUND_DYLIB => "PreboundDylibCommand",
|
216
|
-
LC_ROUTINES => "RoutinesCommand",
|
217
|
-
LC_SUB_FRAMEWORK => "SubFrameworkCommand",
|
218
|
-
LC_SUB_UMBRELLA => "SubUmbrellaCommand",
|
219
|
-
LC_SUB_CLIENT => "SubClientCommand",
|
220
|
-
LC_SUB_LIBRARY => "SubLibraryCommand",
|
221
|
-
LC_TWOLEVEL_HINTS => "TwolevelHintsCommand",
|
222
|
-
LC_PREBIND_CKSUM => "PrebindCksumCommand",
|
223
|
-
LC_LOAD_WEAK_DYLIB => "DylibCommand",
|
224
|
-
LC_SEGMENT_64 => "SegmentCommand64",
|
225
|
-
LC_ROUTINES_64 => "RoutinesCommand64",
|
226
|
-
LC_UUID => "UUIDCommand",
|
227
|
-
LC_RPATH => "RpathCommand",
|
228
|
-
LC_CODE_SIGNATURE => "LinkeditDataCommand",
|
229
|
-
LC_SEGMENT_SPLIT_INFO => "LinkeditDataCommand",
|
230
|
-
LC_REEXPORT_DYLIB => "DylibCommand",
|
231
|
-
LC_LAZY_LOAD_DYLIB => "LoadCommand", # undoc, maybe DylibCommand?
|
232
|
-
LC_ENCRYPTION_INFO => "EncryptionInfoCommand",
|
233
|
-
LC_DYLD_INFO => "DyldInfoCommand",
|
234
|
-
LC_DYLD_INFO_ONLY => "DyldInfoCommand",
|
235
|
-
LC_LOAD_UPWARD_DYLIB => "LoadCommand", # undoc, maybe DylibCommand?
|
236
|
-
LC_VERSION_MIN_MACOSX => "VersionMinCommand",
|
237
|
-
LC_VERSION_MIN_IPHONEOS => "VersionMinCommand",
|
238
|
-
LC_FUNCTION_STARTS => "LinkeditDataCommand",
|
239
|
-
LC_DYLD_ENVIRONMENT => "DylinkerCommand",
|
240
|
-
LC_MAIN => "EntryPointCommand",
|
241
|
-
LC_DATA_IN_CODE => "LinkeditDataCommand",
|
242
|
-
LC_SOURCE_VERSION => "SourceVersionCommand",
|
243
|
-
LC_DYLIB_CODE_SIGN_DRS => "LinkeditDataCommand",
|
244
|
-
LC_ENCRYPTION_INFO_64 => "EncryptionInfoCommand64",
|
245
|
-
LC_LINKER_OPTION => "LinkerOptionCommand",
|
246
|
-
LC_LINKER_OPTIMIZATION_HINT => "LinkeditDataCommand"
|
60
|
+
:LC_SEGMENT => "SegmentCommand",
|
61
|
+
:LC_SYMTAB => "SymtabCommand",
|
62
|
+
:LC_SYMSEG => "LoadCommand", # obsolete
|
63
|
+
:LC_THREAD => "ThreadCommand",
|
64
|
+
:LC_UNIXTHREAD => "ThreadCommand",
|
65
|
+
:LC_LOADFVMLIB => "LoadCommand", # obsolete
|
66
|
+
:LC_IDFVMLIB => "LoadCommand", # obsolete
|
67
|
+
:LC_IDENT => "LoadCommand", # obsolete
|
68
|
+
:LC_FVMFILE => "LoadCommand", # reserved for internal use only
|
69
|
+
:LC_PREPAGE => "LoadCommand", # reserved for internal use only
|
70
|
+
:LC_DYSYMTAB => "DysymtabCommand",
|
71
|
+
:LC_LOAD_DYLIB => "DylibCommand",
|
72
|
+
:LC_ID_DYLIB => "DylibCommand",
|
73
|
+
:LC_LOAD_DYLINKER => "DylinkerCommand",
|
74
|
+
:LC_ID_DYLINKER => "DylinkerCommand",
|
75
|
+
:LC_PREBOUND_DYLIB => "PreboundDylibCommand",
|
76
|
+
:LC_ROUTINES => "RoutinesCommand",
|
77
|
+
:LC_SUB_FRAMEWORK => "SubFrameworkCommand",
|
78
|
+
:LC_SUB_UMBRELLA => "SubUmbrellaCommand",
|
79
|
+
:LC_SUB_CLIENT => "SubClientCommand",
|
80
|
+
:LC_SUB_LIBRARY => "SubLibraryCommand",
|
81
|
+
:LC_TWOLEVEL_HINTS => "TwolevelHintsCommand",
|
82
|
+
:LC_PREBIND_CKSUM => "PrebindCksumCommand",
|
83
|
+
:LC_LOAD_WEAK_DYLIB => "DylibCommand",
|
84
|
+
:LC_SEGMENT_64 => "SegmentCommand64",
|
85
|
+
:LC_ROUTINES_64 => "RoutinesCommand64",
|
86
|
+
:LC_UUID => "UUIDCommand",
|
87
|
+
:LC_RPATH => "RpathCommand",
|
88
|
+
:LC_CODE_SIGNATURE => "LinkeditDataCommand",
|
89
|
+
:LC_SEGMENT_SPLIT_INFO => "LinkeditDataCommand",
|
90
|
+
:LC_REEXPORT_DYLIB => "DylibCommand",
|
91
|
+
:LC_LAZY_LOAD_DYLIB => "LoadCommand", # undoc, maybe DylibCommand?
|
92
|
+
:LC_ENCRYPTION_INFO => "EncryptionInfoCommand",
|
93
|
+
:LC_DYLD_INFO => "DyldInfoCommand",
|
94
|
+
:LC_DYLD_INFO_ONLY => "DyldInfoCommand",
|
95
|
+
:LC_LOAD_UPWARD_DYLIB => "LoadCommand", # undoc, maybe DylibCommand?
|
96
|
+
:LC_VERSION_MIN_MACOSX => "VersionMinCommand",
|
97
|
+
:LC_VERSION_MIN_IPHONEOS => "VersionMinCommand",
|
98
|
+
:LC_FUNCTION_STARTS => "LinkeditDataCommand",
|
99
|
+
:LC_DYLD_ENVIRONMENT => "DylinkerCommand",
|
100
|
+
:LC_MAIN => "EntryPointCommand",
|
101
|
+
:LC_DATA_IN_CODE => "LinkeditDataCommand",
|
102
|
+
:LC_SOURCE_VERSION => "SourceVersionCommand",
|
103
|
+
:LC_DYLIB_CODE_SIGN_DRS => "LinkeditDataCommand",
|
104
|
+
:LC_ENCRYPTION_INFO_64 => "EncryptionInfoCommand64",
|
105
|
+
:LC_LINKER_OPTION => "LinkerOptionCommand",
|
106
|
+
:LC_LINKER_OPTIMIZATION_HINT => "LinkeditDataCommand"
|
247
107
|
}
|
248
108
|
|
249
109
|
# pagezero segment name
|
@@ -319,9 +179,16 @@ module MachO
|
|
319
179
|
@cmdsize = cmdsize
|
320
180
|
end
|
321
181
|
|
182
|
+
# @return [Symbol] a symbol representation of the load command's identifying number
|
183
|
+
def type
|
184
|
+
LOAD_COMMANDS[cmd]
|
185
|
+
end
|
186
|
+
|
187
|
+
alias :to_sym :type
|
188
|
+
|
322
189
|
# @return [String] a string representation of the load command's identifying number
|
323
190
|
def to_s
|
324
|
-
|
191
|
+
type.to_s
|
325
192
|
end
|
326
193
|
|
327
194
|
# Represents a Load Command string. A rough analogue to the lc_str
|
@@ -382,7 +249,7 @@ module MachO
|
|
382
249
|
# A load command indicating that part of this file is to be mapped into
|
383
250
|
# the task's address space. Corresponds to LC_SEGMENT.
|
384
251
|
class SegmentCommand < LoadCommand
|
385
|
-
# @return [String] the name of the segment
|
252
|
+
# @return [String] the name of the segment
|
386
253
|
attr_reader :segname
|
387
254
|
|
388
255
|
# @return [Fixnum] the memory address of the segment
|
@@ -416,7 +283,7 @@ module MachO
|
|
416
283
|
def initialize(raw_data, offset, cmd, cmdsize, segname, vmaddr, vmsize, fileoff,
|
417
284
|
filesize, maxprot, initprot, nsects, flags)
|
418
285
|
super(raw_data, offset, cmd, cmdsize)
|
419
|
-
@segname = segname
|
286
|
+
@segname = segname.delete("\x00")
|
420
287
|
@vmaddr = vmaddr
|
421
288
|
@vmsize = vmsize
|
422
289
|
@fileoff = fileoff
|
@@ -426,17 +293,12 @@ module MachO
|
|
426
293
|
@nsects = nsects
|
427
294
|
@flags = flags
|
428
295
|
end
|
429
|
-
|
430
|
-
# @return [String] the segment's name, with any trailing NULL characters removed
|
431
|
-
def segment_name
|
432
|
-
@segname.delete("\x00")
|
433
|
-
end
|
434
296
|
end
|
435
297
|
|
436
298
|
# A load command indicating that part of this file is to be mapped into
|
437
299
|
# the task's address space. Corresponds to LC_SEGMENT_64.
|
438
300
|
class SegmentCommand64 < LoadCommand
|
439
|
-
# @return [String] the name of the segment
|
301
|
+
# @return [String] the name of the segment
|
440
302
|
attr_reader :segname
|
441
303
|
|
442
304
|
# @return [Fixnum] the memory address of the segment
|
@@ -470,7 +332,7 @@ module MachO
|
|
470
332
|
def initialize(raw_data, offset, cmd, cmdsize, segname, vmaddr, vmsize, fileoff,
|
471
333
|
filesize, maxprot, initprot, nsects, flags)
|
472
334
|
super(raw_data, offset, cmd, cmdsize)
|
473
|
-
@segname = segname
|
335
|
+
@segname = segname.delete("\x00")
|
474
336
|
@vmaddr = vmaddr
|
475
337
|
@vmsize = vmsize
|
476
338
|
@fileoff = fileoff
|
@@ -480,11 +342,6 @@ module MachO
|
|
480
342
|
@nsects = nsects
|
481
343
|
@flags = flags
|
482
344
|
end
|
483
|
-
|
484
|
-
# @return [String] the segment's name, with any trailing NULL characters removed
|
485
|
-
def segment_name
|
486
|
-
@segname.delete("\x00")
|
487
|
-
end
|
488
345
|
end
|
489
346
|
|
490
347
|
# A load command representing some aspect of shared libraries, depending
|
data/lib/macho/macho_file.rb
CHANGED
@@ -58,21 +58,56 @@ module MachO
|
|
58
58
|
MachO.magic64?(header.magic)
|
59
59
|
end
|
60
60
|
|
61
|
+
# @return [Boolean] true if the Mach-O is of type `MH_OBJECT`, false otherwise
|
62
|
+
def object?
|
63
|
+
header.filetype == MH_OBJECT
|
64
|
+
end
|
65
|
+
|
61
66
|
# @return [Boolean] true if the Mach-O is of type `MH_EXECUTE`, false otherwise
|
62
67
|
def executable?
|
63
68
|
header.filetype == MH_EXECUTE
|
64
69
|
end
|
65
70
|
|
71
|
+
# @return [Boolean] true if the Mach-O is of type `MH_FVMLIB`, false otherwise
|
72
|
+
def fvmlib?
|
73
|
+
header.filetype == MH_FVMLIB
|
74
|
+
end
|
75
|
+
|
76
|
+
# @return [Boolean] true if the Mach-O is of type `MH_CORE`, false otherwise
|
77
|
+
def core?
|
78
|
+
header.filetype == MH_CORE
|
79
|
+
end
|
80
|
+
|
81
|
+
# @return [Boolean] true if the Mach-O is of type `MH_PRELOAD`, false otherwise
|
82
|
+
def preload?
|
83
|
+
header.filetype == MH_PRELOAD
|
84
|
+
end
|
85
|
+
|
66
86
|
# @return [Boolean] true if the Mach-O is of type `MH_DYLIB`, false otherwise
|
67
87
|
def dylib?
|
68
88
|
header.filetype == MH_DYLIB
|
69
89
|
end
|
70
90
|
|
91
|
+
# @return [Boolean] true if the Mach-O is of type `MH_DYLINKER`, false otherwise
|
92
|
+
def dylinker?
|
93
|
+
header.filetype == MH_DYLINKER
|
94
|
+
end
|
95
|
+
|
71
96
|
# @return [Boolean] true if the Mach-O is of type `MH_BUNDLE`, false otherwise
|
72
97
|
def bundle?
|
73
98
|
header.filetype == MH_BUNDLE
|
74
99
|
end
|
75
100
|
|
101
|
+
# @return [Boolean] true if the Mach-O is of type `MH_DSYM`, false otherwise
|
102
|
+
def dsym?
|
103
|
+
header.filetype == MH_DSYM
|
104
|
+
end
|
105
|
+
|
106
|
+
# @return [Boolean] true if the Mach-O is of type `MH_KEXT_BUNDLE`, false otherwise
|
107
|
+
def kext?
|
108
|
+
header.filetype == MH_KEXT_BUNDLE
|
109
|
+
end
|
110
|
+
|
76
111
|
# @return [Fixnum] the Mach-O's magic number
|
77
112
|
def magic
|
78
113
|
header.magic
|
@@ -80,7 +115,7 @@ module MachO
|
|
80
115
|
|
81
116
|
# @return [String] a string representation of the Mach-O's magic number
|
82
117
|
def magic_string
|
83
|
-
MH_MAGICS[
|
118
|
+
MH_MAGICS[magic]
|
84
119
|
end
|
85
120
|
|
86
121
|
# @return [String] a string representation of the Mach-O's filetype
|
@@ -116,10 +151,11 @@ module MachO
|
|
116
151
|
# All load commands of a given name.
|
117
152
|
# @example
|
118
153
|
# file.command("LC_LOAD_DYLIB")
|
119
|
-
# file[
|
154
|
+
# file[:LC_LOAD_DYLIB]
|
155
|
+
# @param [String, Symbol] name the load command ID
|
120
156
|
# @return [Array<MachO::LoadCommand>] an array of LoadCommands corresponding to `name`
|
121
157
|
def command(name)
|
122
|
-
load_commands.select { |lc| lc.
|
158
|
+
load_commands.select { |lc| lc.type == name.to_sym }
|
123
159
|
end
|
124
160
|
|
125
161
|
alias :[] :command
|
@@ -129,9 +165,9 @@ module MachO
|
|
129
165
|
# @return [Array<MachO::SegmentCommand64>] if the Mach-O is 64-bit
|
130
166
|
def segments
|
131
167
|
if magic32?
|
132
|
-
command(
|
168
|
+
command(:LC_SEGMENT)
|
133
169
|
else
|
134
|
-
command(
|
170
|
+
command(:LC_SEGMENT_64)
|
135
171
|
end
|
136
172
|
end
|
137
173
|
|
@@ -144,7 +180,7 @@ module MachO
|
|
144
180
|
return nil
|
145
181
|
end
|
146
182
|
|
147
|
-
dylib_id_cmd = command(
|
183
|
+
dylib_id_cmd = command(:LC_ID_DYLIB).first
|
148
184
|
|
149
185
|
dylib_id_cmd.name.to_s
|
150
186
|
end
|
@@ -164,7 +200,7 @@ module MachO
|
|
164
200
|
return nil
|
165
201
|
end
|
166
202
|
|
167
|
-
dylib_cmd = command(
|
203
|
+
dylib_cmd = command(:LC_ID_DYLIB).first
|
168
204
|
old_id = dylib_id
|
169
205
|
|
170
206
|
set_name_in_dylib(dylib_cmd, old_id, new_id)
|
@@ -173,7 +209,7 @@ module MachO
|
|
173
209
|
# All shared libraries linked to the Mach-O.
|
174
210
|
# @return [Array<String>] an array of all shared libraries
|
175
211
|
def linked_dylibs
|
176
|
-
command(
|
212
|
+
command(:LC_LOAD_DYLIB).map(&:name).map(&:to_s)
|
177
213
|
end
|
178
214
|
|
179
215
|
# Changes the shared library `old_name` to `new_name`
|
@@ -184,7 +220,7 @@ module MachO
|
|
184
220
|
# @return [void]
|
185
221
|
# @raise [MachO::DylibUnknownError] if no shared library has the old name
|
186
222
|
def change_install_name(old_name, new_name)
|
187
|
-
dylib_cmd = command(
|
223
|
+
dylib_cmd = command(:LC_LOAD_DYLIB).find { |d| d.name.to_s == old_name }
|
188
224
|
raise DylibUnknownError.new(old_name) if dylib_cmd.nil?
|
189
225
|
|
190
226
|
set_name_in_dylib(dylib_cmd, old_name, new_name)
|
@@ -256,7 +292,7 @@ module MachO
|
|
256
292
|
ncmds = get_ncmds
|
257
293
|
sizeofcmds = get_sizeofcmds
|
258
294
|
flags = get_flags
|
259
|
-
|
295
|
+
|
260
296
|
if MachO.magic32?(magic)
|
261
297
|
MachHeader.new(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags)
|
262
298
|
else
|
@@ -347,12 +383,13 @@ module MachO
|
|
347
383
|
|
348
384
|
header.ncmds.times do
|
349
385
|
cmd = @raw_data.slice(offset, 4).unpack("V").first
|
386
|
+
cmd_sym = LOAD_COMMANDS[cmd]
|
350
387
|
|
351
|
-
raise LoadCommandError.new(cmd)
|
388
|
+
raise LoadCommandError.new(cmd) if cmd_sym.nil?
|
352
389
|
|
353
390
|
# why do I do this? i don't like declaring constants below
|
354
391
|
# classes, and i need them to resolve...
|
355
|
-
klass = MachO.const_get "#{LC_STRUCTURES[
|
392
|
+
klass = MachO.const_get "#{LC_STRUCTURES[cmd_sym]}"
|
356
393
|
command = klass.new_from_bin(@raw_data, offset, @raw_data.slice(offset, klass.bytesize))
|
357
394
|
|
358
395
|
load_commands << command
|
data/lib/macho/open.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module MachO
|
2
|
+
# Opens the given filename as a MachOFile or FatFile, depending on its magic.
|
3
|
+
# @param filename [String] the file being opened
|
4
|
+
# @return [MachO::MachOFile] if the file is a Mach-O
|
5
|
+
# @return [MachO::FatFile] if the file is a Fat file
|
6
|
+
def self.open(filename)
|
7
|
+
# open file and test magic instead of using exceptions for control?
|
8
|
+
begin
|
9
|
+
file = MachOFile.new(filename)
|
10
|
+
rescue FatBinaryError
|
11
|
+
file = FatFile.new(filename)
|
12
|
+
end
|
13
|
+
|
14
|
+
file
|
15
|
+
end
|
16
|
+
end
|
data/lib/macho/sections.rb
CHANGED
@@ -1,44 +1,110 @@
|
|
1
1
|
module MachO
|
2
|
-
#
|
3
|
-
SECTION_TYPE = 0x000000ff
|
4
|
-
SECTION_ATTRIBUTES = 0xffffff00 # attributes mask
|
5
|
-
SECTION_ATTRIBUTES_USR = 0xff000000 # user settable attributes mask
|
6
|
-
SECTION_ATTRIBUTES_SYS = 0x00ffff00 # system settable attributes mask
|
2
|
+
# type mask
|
3
|
+
SECTION_TYPE = 0x000000ff
|
7
4
|
|
8
|
-
#
|
5
|
+
# attributes mask
|
6
|
+
SECTION_ATTRIBUTES = 0xffffff00
|
7
|
+
|
8
|
+
# user settable attributes mask
|
9
|
+
SECTION_ATTRIBUTES_USR = 0xff000000
|
10
|
+
|
11
|
+
# system settable attributes mask
|
12
|
+
SECTION_ATTRIBUTES_SYS = 0x00ffff00
|
13
|
+
|
14
|
+
# a regular section
|
9
15
|
S_REGULAR = 0x0
|
16
|
+
|
17
|
+
# a zero fill on demand section
|
10
18
|
S_ZEROFILL = 0x1
|
19
|
+
|
20
|
+
# a section with only literal C strings
|
11
21
|
S_CSTRING_LITERALS = 0x2
|
22
|
+
|
23
|
+
# a section with only 4 byte literals
|
12
24
|
S_4BYTE_LITERALS = 0x3
|
25
|
+
|
26
|
+
# a section with only 8 byte literals
|
13
27
|
S_8BYTE_LITERALS = 0x4
|
28
|
+
|
29
|
+
# a section with only pointers to literals
|
14
30
|
S_LITERAL_POINTERS = 0x5
|
31
|
+
|
32
|
+
# a section with only non-lazy symbol pointers
|
15
33
|
S_NON_LAZY_SYMBOL_POINTERS = 0x6
|
34
|
+
|
35
|
+
# a section with only lazy symbol pointers
|
16
36
|
S_LAZY_SYMBOL_POINTERS = 0x7
|
37
|
+
|
38
|
+
# a section with only symbol stubs (byte size of stub in reserved2 field)
|
17
39
|
S_SYMBOL_STUBS = 0x8
|
40
|
+
|
41
|
+
# a section with only function pointers for initialization
|
18
42
|
S_MOD_INIT_FUNC_POINTERS = 0x9
|
43
|
+
|
44
|
+
# a section with only function pointers for termination
|
19
45
|
S_MOD_TERM_FUNC_POINTERS = 0xa
|
46
|
+
|
47
|
+
# a section with only symbols that are to be coalesced
|
20
48
|
S_COALESCED = 0xb
|
49
|
+
|
50
|
+
# a zero fill on demand section that can be larger than 4GB
|
21
51
|
S_GB_ZEROFILE = 0xc
|
52
|
+
|
53
|
+
# a section with only pairs of function pointers for interposing
|
22
54
|
S_INTERPOSING = 0xd
|
55
|
+
|
56
|
+
# a section with only 16 byte literals
|
23
57
|
S_16BYTE_LITERALS = 0xe
|
58
|
+
|
59
|
+
# a section containing DTrace Object Format
|
24
60
|
S_DTRACE_DOF = 0xf
|
61
|
+
|
62
|
+
# a section with only lazy symbol pointers to lazy loaded dylibs
|
25
63
|
S_LAZY_DYLIB_SYMBOL_POINTERS = 0x10
|
64
|
+
|
65
|
+
# a template of initial values for thread local variables
|
26
66
|
S_THREAD_LOCAL_REGULAR = 0x11
|
67
|
+
|
68
|
+
# a template of initial values for thread local variables
|
27
69
|
S_THREAD_LOCAL_ZEROFILL = 0x12
|
70
|
+
|
71
|
+
# thread local variable descriptors
|
28
72
|
S_THREAD_LOCAL_VARIABLES = 0x13
|
73
|
+
|
74
|
+
# pointers to thread local variable descriptors
|
29
75
|
S_THREAD_LOCAL_VARIABLE_POINTERS = 0x14
|
76
|
+
|
77
|
+
# functions to call to initialize thread local variable values
|
30
78
|
S_THREAD_LOCAL_INIT_FUNCTION_POINTERS = 0x15
|
31
79
|
|
32
|
-
# section
|
80
|
+
# a section with only true machine instructions
|
33
81
|
S_ATTR_PURE_INSTRUCTIONS = 0x80000000
|
82
|
+
|
83
|
+
# a section with coalesced symbols that are not to be in a ranlib table of contents
|
34
84
|
S_ATTR_NO_TOC = 0x40000000
|
85
|
+
|
86
|
+
# static symbols in this section can be stripped in files with the MH_DYLDLINK flag
|
35
87
|
S_ATTR_STRIP_STATIC_SYMS = 0x20000000
|
88
|
+
|
89
|
+
# no dead stripping
|
36
90
|
S_ATTR_NO_DEAD_STRIP = 0x10000000
|
91
|
+
|
92
|
+
# blocks are live if they reference live blocks
|
37
93
|
S_ATTR_LIVE_SUPPORT = 0x08000000
|
94
|
+
|
95
|
+
# used with i386 code stubs written on by dyld
|
38
96
|
S_ATTR_SELF_MODIFYING_CODE = 0x04000000
|
97
|
+
|
98
|
+
# a debug section
|
39
99
|
S_ATTR_DEBUG = 0x02000000
|
100
|
+
|
101
|
+
# a section containing some machine instructions
|
40
102
|
S_ATTR_SOME_INSTRUCTIONS = 0x00000400
|
103
|
+
|
104
|
+
# a section containing external relocation entries
|
41
105
|
S_ATTR_EXT_RELOC = 0x00000200
|
106
|
+
|
107
|
+
# a section containing local relocation entries
|
42
108
|
S_ATTR_LOC_RELOC = 0x00000100
|
43
109
|
|
44
110
|
# currently known section names
|
data/lib/macho/tools.rb
CHANGED
@@ -13,6 +13,7 @@ module MachO
|
|
13
13
|
# @param filename [String] the Mach-O or Fat binary being modified
|
14
14
|
# @param new_id [String] the new dylib ID for the binary
|
15
15
|
# @return [void]
|
16
|
+
# @todo unstub for fat files
|
16
17
|
def self.change_dylib_id(filename, new_id)
|
17
18
|
file = MachO.open(filename)
|
18
19
|
|
@@ -29,6 +30,7 @@ module MachO
|
|
29
30
|
# @param old_name [String] the old shared library name
|
30
31
|
# @param new_name [String] the new shared library name
|
31
32
|
# @return [void]
|
33
|
+
# @todo unstub for fat files
|
32
34
|
def self.change_install_name(filename, old_name, new_name)
|
33
35
|
file = MachO.open(filename)
|
34
36
|
|
@@ -38,5 +40,33 @@ module MachO
|
|
38
40
|
raise MachOError.new("changing install names for fat binaries is incomplete")
|
39
41
|
end
|
40
42
|
end
|
43
|
+
|
44
|
+
# Changes a runtime path in a Mach-O or Fat binary, overwriting the source file.
|
45
|
+
# @param filename [String] the Mach-O or Fat binary being modified
|
46
|
+
# @param old_path [String] the old runtime path
|
47
|
+
# @param new_path [String] the new runtime path
|
48
|
+
# @return [void]
|
49
|
+
# @todo unstub
|
50
|
+
def self.change_rpath(filename, old_path, new_path)
|
51
|
+
raise "stub"
|
52
|
+
end
|
53
|
+
|
54
|
+
# Add a runtime path to a Mach-O or Fat binary, overwriting the source file.
|
55
|
+
# @param filename [String] the Mach-O or Fat binary being modified
|
56
|
+
# @param new_path [String] the new runtime path
|
57
|
+
# @return [void]
|
58
|
+
# @todo unstub
|
59
|
+
def self.add_rpath(filename, new_path)
|
60
|
+
raise "stub"
|
61
|
+
end
|
62
|
+
|
63
|
+
# Delete a runtime path from a Mach-O or Fat binary, overwriting the source file.
|
64
|
+
# @param filename [String] the Mach-O or Fat binary being modified
|
65
|
+
# @param old_path [String] the old runtime path
|
66
|
+
# @return [void]
|
67
|
+
# @todo unstub
|
68
|
+
def self.delete_rpath(filename, old_path)
|
69
|
+
raise "stub"
|
70
|
+
end
|
41
71
|
end
|
42
72
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-macho
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- William Woodruff
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-11-04 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A library for viewing and manipulating Mach-O files in Ruby.
|
14
14
|
email: william@tuffbizz.com
|
@@ -25,6 +25,7 @@ files:
|
|
25
25
|
- lib/macho/headers.rb
|
26
26
|
- lib/macho/load_commands.rb
|
27
27
|
- lib/macho/macho_file.rb
|
28
|
+
- lib/macho/open.rb
|
28
29
|
- lib/macho/sections.rb
|
29
30
|
- lib/macho/structure.rb
|
30
31
|
- lib/macho/tools.rb
|