ruby-macho 0.0.9 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|