ruby-macho 0.0.9 → 0.1.0
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 +1 -0
- data/lib/macho/exceptions.rb +17 -10
- data/lib/macho/fat_file.rb +2 -1
- data/lib/macho/headers.rb +132 -28
- data/lib/macho/load_commands.rb +313 -21
- data/lib/macho/macho_file.rb +40 -0
- data/lib/macho/sections.rb +16 -0
- data/lib/macho/structure.rb +5 -2
- data/lib/macho/utils.rb +12 -1
- metadata +1 -1
data/lib/macho/macho_file.rb
CHANGED
@@ -3,6 +3,7 @@ module MachO
|
|
3
3
|
# as well as binary executable instructions. Mach-O binaries are
|
4
4
|
# architecture specific.
|
5
5
|
# @see https://en.wikipedia.org/wiki/Mach-O
|
6
|
+
# @see MachO::FatFile
|
6
7
|
class MachOFile
|
7
8
|
# @return [MachO::MachHeader] if the Mach-O is 32-bit
|
8
9
|
# @return [MachO::MachHeader64] if the Mach-O is 64-bit
|
@@ -361,6 +362,7 @@ module MachO
|
|
361
362
|
# Write all Mach-O data to the file used to initialize the instance.
|
362
363
|
# @raise [MachOError] if the instance was created from a binary string
|
363
364
|
# @return [void]
|
365
|
+
# @note Overwrites all data in the file!
|
364
366
|
def write!
|
365
367
|
if @filename.nil?
|
366
368
|
raise MachOError.new("cannot write to a default file when initialized from a binary string")
|
@@ -371,6 +373,10 @@ module MachO
|
|
371
373
|
|
372
374
|
private
|
373
375
|
|
376
|
+
# The file's Mach-O header structure.
|
377
|
+
# @return [MachO::MachHeader] if the Mach-O is 32-bit
|
378
|
+
# @return [MachO::MachHeader64] if the Mach-O is 64-bit
|
379
|
+
# @private
|
374
380
|
def get_mach_header
|
375
381
|
magic = get_magic
|
376
382
|
cputype = get_cputype
|
@@ -388,6 +394,11 @@ module MachO
|
|
388
394
|
end
|
389
395
|
end
|
390
396
|
|
397
|
+
# The file's magic number.
|
398
|
+
# @return [Fixnum] the magic
|
399
|
+
# @raise [MachO::MagicError] if the magic is not valid Mach-O magic
|
400
|
+
# @raise [MachO::FatBinaryError] if the magic is for a Fat file
|
401
|
+
# @private
|
391
402
|
def get_magic
|
392
403
|
magic = @raw_data[0..3].unpack("N").first
|
393
404
|
|
@@ -402,6 +413,10 @@ module MachO
|
|
402
413
|
magic
|
403
414
|
end
|
404
415
|
|
416
|
+
# The file's CPU type.
|
417
|
+
# @return [Fixnum] the CPU type
|
418
|
+
# @raise [MachO::CPUTypeError] if the CPU type is unknown
|
419
|
+
# @private
|
405
420
|
def get_cputype
|
406
421
|
cputype = @raw_data[4..7].unpack("V").first
|
407
422
|
|
@@ -412,6 +427,10 @@ module MachO
|
|
412
427
|
cputype
|
413
428
|
end
|
414
429
|
|
430
|
+
# The file's CPU subtype.
|
431
|
+
# @return [Fixnum] the CPU subtype
|
432
|
+
# @raise [MachO::CPUSubtypeError] if the CPU subtype is unknown
|
433
|
+
# @private
|
415
434
|
def get_cpusubtype
|
416
435
|
cpusubtype = @raw_data[8..11].unpack("V").first
|
417
436
|
|
@@ -425,6 +444,10 @@ module MachO
|
|
425
444
|
cpusubtype
|
426
445
|
end
|
427
446
|
|
447
|
+
# The file's type.
|
448
|
+
# @return [Fixnum] the file type
|
449
|
+
# @raise [MachO::FiletypeError] if the file type is unknown
|
450
|
+
# @private
|
428
451
|
def get_filetype
|
429
452
|
filetype = @raw_data[12..15].unpack("V").first
|
430
453
|
|
@@ -435,24 +458,37 @@ module MachO
|
|
435
458
|
filetype
|
436
459
|
end
|
437
460
|
|
461
|
+
# The number of load commands in the file.
|
462
|
+
# @return [Fixnum] the number of load commands
|
463
|
+
# @private
|
438
464
|
def get_ncmds
|
439
465
|
ncmds = @raw_data[16..19].unpack("V").first
|
440
466
|
|
441
467
|
ncmds
|
442
468
|
end
|
443
469
|
|
470
|
+
# The size of all load commands, in bytes.
|
471
|
+
# return [Fixnum] the size of all load commands
|
472
|
+
# @private
|
444
473
|
def get_sizeofcmds
|
445
474
|
sizeofcmds = @raw_data[20..23].unpack("V").first
|
446
475
|
|
447
476
|
sizeofcmds
|
448
477
|
end
|
449
478
|
|
479
|
+
# The Mach-O header's flags.
|
480
|
+
# @return [Fixnum] the flags
|
481
|
+
# @private
|
450
482
|
def get_flags
|
451
483
|
flags = @raw_data[24..27].unpack("V").first
|
452
484
|
|
453
485
|
flags
|
454
486
|
end
|
455
487
|
|
488
|
+
# All load commands in the file.
|
489
|
+
# @return [Array<MachO::LoadCommand>] an array of load commands
|
490
|
+
# @raise [MachO::LoadCommandError] if an unknown load command is encountered
|
491
|
+
# @private
|
456
492
|
def get_load_commands
|
457
493
|
offset = header.bytesize
|
458
494
|
load_commands = []
|
@@ -476,6 +512,10 @@ module MachO
|
|
476
512
|
load_commands
|
477
513
|
end
|
478
514
|
|
515
|
+
# Updates the size of all load commands in the raw data.
|
516
|
+
# @param size [Fixnum] the new size, in bytes
|
517
|
+
# @return [void]
|
518
|
+
# @private
|
479
519
|
def set_sizeofcmds(size)
|
480
520
|
new_size = [size].pack("V")
|
481
521
|
@raw_data[20..23] = new_size
|
data/lib/macho/sections.rb
CHANGED
@@ -56,6 +56,7 @@ module MachO
|
|
56
56
|
SECT_ICON_HEADER = "__header"
|
57
57
|
SECT_ICON_TIFF = "__tiff"
|
58
58
|
|
59
|
+
# Represents a section of a segment for 32-bit architectures.
|
59
60
|
class Section < MachOStructure
|
60
61
|
attr_reader :sectname, :segname, :addr, :size, :offset, :align, :reloff
|
61
62
|
attr_reader :nreloc, :flags, :reserved1, :reserved2
|
@@ -63,6 +64,7 @@ module MachO
|
|
63
64
|
@format = "a16a16VVVVVVVVV"
|
64
65
|
@sizeof = 68
|
65
66
|
|
67
|
+
# @private
|
66
68
|
def initialize(sectname, segname, addr, size, offset, align, reloff,
|
67
69
|
nreloc, flags, reserved1, reserved2)
|
68
70
|
@sectname = sectname
|
@@ -78,19 +80,26 @@ module MachO
|
|
78
80
|
@reserved2 = reserved2
|
79
81
|
end
|
80
82
|
|
83
|
+
# @return [String] the section's name, with any trailing NULL characters removed
|
81
84
|
def section_name
|
82
85
|
@sectname.delete("\x00")
|
83
86
|
end
|
84
87
|
|
88
|
+
# @return [String] the parent segment's name, with any trailing NULL characters removed
|
85
89
|
def segment_name
|
86
90
|
@segname.delete("\x00")
|
87
91
|
end
|
88
92
|
|
93
|
+
# @example
|
94
|
+
# puts "this section is regular" if sect.flag?(S_REGULAR)
|
95
|
+
# @param flag [Fixnum] a section flag constant
|
96
|
+
# @return [Boolean] true if `flag` is present in the sections's flag field
|
89
97
|
def flag?(flag)
|
90
98
|
flags & flag == flag
|
91
99
|
end
|
92
100
|
end
|
93
101
|
|
102
|
+
# Represents a section of a segment for 64-bit architectures.
|
94
103
|
class Section64 < MachOStructure
|
95
104
|
attr_reader :sectname, :segname, :addr, :size, :offset, :align, :reloff
|
96
105
|
attr_reader :nreloc, :flags, :reserved1, :reserved2, :reserved3
|
@@ -98,6 +107,7 @@ module MachO
|
|
98
107
|
@format = "a16a16QQVVVVVVVV"
|
99
108
|
@sizeof = 80
|
100
109
|
|
110
|
+
# @private
|
101
111
|
def initialize(sectname, segname, addr, size, offset, align, reloff,
|
102
112
|
nreloc, flags, reserved1, reserved2, reserved3)
|
103
113
|
@sectname = sectname
|
@@ -114,14 +124,20 @@ module MachO
|
|
114
124
|
@reserved3 = reserved3
|
115
125
|
end
|
116
126
|
|
127
|
+
# @return [String] the section's name, with any trailing NULL characters removed
|
117
128
|
def section_name
|
118
129
|
@sectname.delete("\x00")
|
119
130
|
end
|
120
131
|
|
132
|
+
# @return [String] the parent segment's name, with any trailing NULL characters removed
|
121
133
|
def segment_name
|
122
134
|
@segname.delete("\x00")
|
123
135
|
end
|
124
136
|
|
137
|
+
# @example
|
138
|
+
# puts "this section is regular" if sect.flag?(S_REGULAR)
|
139
|
+
# @param flag [Fixnum] a section flag constant
|
140
|
+
# @return [Boolean] true if `flag` is present in the sections's flag field
|
125
141
|
def flag?(flag)
|
126
142
|
flags & flag == flag
|
127
143
|
end
|
data/lib/macho/structure.rb
CHANGED
@@ -1,13 +1,16 @@
|
|
1
1
|
module MachO
|
2
|
-
# general purpose pseudo-structure
|
2
|
+
# A general purpose pseudo-structure.
|
3
3
|
class MachOStructure
|
4
|
-
|
4
|
+
# Subclasses should fill these in manually.
|
5
|
+
@format = ""
|
5
6
|
@sizeof = 0
|
6
7
|
|
8
|
+
# @return [Fixnum] the size, in bytes, of the represented structure.
|
7
9
|
def self.bytesize
|
8
10
|
@sizeof
|
9
11
|
end
|
10
12
|
|
13
|
+
# @return [MachO::MachOStructure] a new MachOStructure initialized with `bin`
|
11
14
|
def self.new_from_bin(bin)
|
12
15
|
self.new(*bin.unpack(@format))
|
13
16
|
end
|
data/lib/macho/utils.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
module MachO
|
2
|
-
#
|
2
|
+
# @param value [Fixnum] the number being rounded
|
3
|
+
# @param round [Fixnum] the number being rounded with
|
4
|
+
# @return [Fixnum] the next number >= `value` such that `round` is its divisor
|
5
|
+
# @see http://www.opensource.apple.com/source/cctools/cctools-870/libstuff/rnd.c
|
3
6
|
def self.round(value, round)
|
4
7
|
round -= 1
|
5
8
|
value += round
|
@@ -7,18 +10,26 @@ module MachO
|
|
7
10
|
value
|
8
11
|
end
|
9
12
|
|
13
|
+
# @param num [Fixnum] the number being checked
|
14
|
+
# @return [Boolean] true if `num` is a valid Mach-O magic number, false otherwise
|
10
15
|
def self.magic?(num)
|
11
16
|
MH_MAGICS.has_key?(num)
|
12
17
|
end
|
13
18
|
|
19
|
+
# @param num [Fixnum] the number being checked
|
20
|
+
# @return [Boolean] true if `num` is a valid Fat magic number, false otherwise
|
14
21
|
def self.fat_magic?(num)
|
15
22
|
num == FAT_MAGIC || num == FAT_CIGAM
|
16
23
|
end
|
17
24
|
|
25
|
+
# @param num [Fixnum] the number being checked
|
26
|
+
# @return [Boolean] true if `num` is a valid 32-bit magic number, false otherwise
|
18
27
|
def self.magic32?(num)
|
19
28
|
num == MH_MAGIC || num == MH_CIGAM
|
20
29
|
end
|
21
30
|
|
31
|
+
# @param num [Fixnum] the number being checked
|
32
|
+
# @return [Boolean] true if `num` is a valid 64-bit magic number, false otherwise
|
22
33
|
def self.magic64?(num)
|
23
34
|
num == MH_MAGIC_64 || num == MH_CIGAM_64
|
24
35
|
end
|