ruby-macho 0.1.2 → 0.1.3
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/fat_file.rb +12 -16
- data/lib/macho/load_commands.rb +125 -97
- data/lib/macho/macho_file.rb +18 -23
- data/lib/macho/sections.rb +69 -6
- data/lib/macho/structure.rb +1 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 18e0719447412b4c6fea5f4ca08f5f0e316e34c1
|
4
|
+
data.tar.gz: e42a6a11cc91a374693cd13d6d5ff8b07d5dec9c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a77b43c73461ed816155a184230f27cb4a8130117f41c9f209033eb89cc09c1581849eb58b5fec55a58a7e8d444e1c0da16576fda19463b9d7c7843b0f21082
|
7
|
+
data.tar.gz: 80ac6b3e2c76001e7a61076b7a6cfc72be034f418636d1ac195ee7f24144749ad4453ec67b3d0382e325a9f99fe88e0618db92696d7881051d93f01a2ef1b8d6
|
data/lib/macho/fat_file.rb
CHANGED
@@ -15,10 +15,9 @@ module MachO
|
|
15
15
|
|
16
16
|
# Creates a new FatFile from the given filename.
|
17
17
|
# @param filename [String] the fat file to load from
|
18
|
-
# @raise [
|
19
|
-
# @raise [MachO::MachOBinaryError] if the file is not a fat binary.
|
18
|
+
# @raise [ArgumentError] if the given filename does not exist
|
20
19
|
def initialize(filename)
|
21
|
-
raise ArgumentError.new("
|
20
|
+
raise ArgumentError.new("#{filetype}: no such file") unless File.exist?(filename)
|
22
21
|
|
23
22
|
@filename = filename
|
24
23
|
@raw_data = open(@filename, "rb") { |f| f.read }
|
@@ -33,29 +32,26 @@ module MachO
|
|
33
32
|
@raw_data
|
34
33
|
end
|
35
34
|
|
35
|
+
# The file's type. Assumed to be the same for every Mach-O within.
|
36
|
+
# @return [String] the filetype
|
37
|
+
def filetype
|
38
|
+
machos.first.filetype
|
39
|
+
end
|
40
|
+
|
36
41
|
# The file's dylib ID. If the file is not a dylib, returns `nil`.
|
37
42
|
# @example
|
38
43
|
# file.dylib_id # => 'libBar.dylib'
|
39
|
-
# @return [String] the file's dylib ID
|
44
|
+
# @return [String, nil] the file's dylib ID
|
40
45
|
def dylib_id
|
41
|
-
|
42
|
-
return nil
|
43
|
-
end
|
44
|
-
|
45
|
-
ids = machos.map(&:dylib_id)
|
46
|
-
|
47
|
-
# this should never be the case, but let's be defensive
|
48
|
-
if !ids.uniq!.size == 1
|
49
|
-
return nil
|
50
|
-
end
|
51
|
-
|
52
|
-
ids.first
|
46
|
+
machos.first.dylib_id
|
53
47
|
end
|
54
48
|
|
55
49
|
# Changes the file's dylib ID to `new_id`. If the file is not a dylib, does nothing.
|
56
50
|
# @example
|
57
51
|
# file.dylib_id = 'libFoo.dylib'
|
58
52
|
# @param new_id [String] the new dylib ID
|
53
|
+
# @return [void]
|
54
|
+
# @raise [ArgumentError] if `new_id` is not a String
|
59
55
|
def dylib_id=(new_id)
|
60
56
|
if !new_id.is_a?(String)
|
61
57
|
raise ArgumentError.new("argument must be a String")
|
data/lib/macho/load_commands.rb
CHANGED
@@ -303,16 +303,17 @@ module MachO
|
|
303
303
|
# @param offset [Fixnum] the offset to initialize with
|
304
304
|
# @param bin [String] the binary string to initialize with
|
305
305
|
# @return [MachO::LoadCommand] the new load command
|
306
|
-
# @private
|
307
|
-
def self.new_from_bin(offset, bin)
|
308
|
-
self.new(offset, *bin.unpack(@format))
|
306
|
+
# @api private
|
307
|
+
def self.new_from_bin(raw_data, offset, bin)
|
308
|
+
self.new(raw_data, offset, *bin.unpack(@format))
|
309
309
|
end
|
310
310
|
|
311
|
-
# @param offset [Fixnum] the offset to initialize
|
311
|
+
# @param offset [Fixnum] the offset to initialize with
|
312
312
|
# @param cmd [Fixnum] the load command's identifying number
|
313
313
|
# @param cmdsize [Fixnum] the size of the load command in bytes
|
314
|
-
# @private
|
315
|
-
def initialize(offset, cmd, cmdsize)
|
314
|
+
# @api private
|
315
|
+
def initialize(raw_data, offset, cmd, cmdsize)
|
316
|
+
@raw_data = raw_data
|
316
317
|
@offset = offset
|
317
318
|
@cmd = cmd
|
318
319
|
@cmdsize = cmdsize
|
@@ -322,6 +323,33 @@ module MachO
|
|
322
323
|
def to_s
|
323
324
|
LOAD_COMMANDS[cmd]
|
324
325
|
end
|
326
|
+
|
327
|
+
# Represents a Load Command string. A rough analogue to the lc_str
|
328
|
+
# struct used internally by OS X. This class allows ruby-macho to
|
329
|
+
# pretend that strings stored in LCs are immediately available without
|
330
|
+
# explicit operations on the raw Mach-O data.
|
331
|
+
class LCStr
|
332
|
+
# @param raw_data [String] the raw Mach-O data.
|
333
|
+
# @param lc [MachO::LoadCommand] the load command
|
334
|
+
# @param lc_str [Fixnum] the offset to the beginning of the string
|
335
|
+
# @api private
|
336
|
+
def initialize(raw_data, lc, lc_str)
|
337
|
+
@raw_data = raw_data
|
338
|
+
@lc = lc
|
339
|
+
@lc_str = lc_str
|
340
|
+
@str = @raw_data.slice(@lc.offset + @lc_str...@lc.offset + @lc.cmdsize).delete("\x00")
|
341
|
+
end
|
342
|
+
|
343
|
+
# @return [String] a string representation of the LCStr
|
344
|
+
def to_s
|
345
|
+
@str
|
346
|
+
end
|
347
|
+
|
348
|
+
# @return [Fixnum] the offset to the beginning of the string in the load command
|
349
|
+
def to_i
|
350
|
+
@lc_str
|
351
|
+
end
|
352
|
+
end
|
325
353
|
end
|
326
354
|
|
327
355
|
# A load command containing a single 128-bit unique random number identifying
|
@@ -333,9 +361,9 @@ module MachO
|
|
333
361
|
@format = "VVa16"
|
334
362
|
@sizeof = 24
|
335
363
|
|
336
|
-
# @private
|
337
|
-
def initialize(offset, cmd, cmdsize, uuid)
|
338
|
-
super(offset, cmd, cmdsize)
|
364
|
+
# @api private
|
365
|
+
def initialize(raw_data, offset, cmd, cmdsize, uuid)
|
366
|
+
super(raw_data, offset, cmd, cmdsize)
|
339
367
|
@uuid = uuid.unpack("C16") # re-unpack for the actual UUID array
|
340
368
|
end
|
341
369
|
|
@@ -384,10 +412,10 @@ module MachO
|
|
384
412
|
@format = "VVa16VVVVVVVV"
|
385
413
|
@sizeof = 56
|
386
414
|
|
387
|
-
# @private
|
388
|
-
def initialize(offset, cmd, cmdsize, segname, vmaddr, vmsize, fileoff,
|
415
|
+
# @api private
|
416
|
+
def initialize(raw_data, offset, cmd, cmdsize, segname, vmaddr, vmsize, fileoff,
|
389
417
|
filesize, maxprot, initprot, nsects, flags)
|
390
|
-
super(offset, cmd, cmdsize)
|
418
|
+
super(raw_data, offset, cmd, cmdsize)
|
391
419
|
@segname = segname
|
392
420
|
@vmaddr = vmaddr
|
393
421
|
@vmsize = vmsize
|
@@ -438,10 +466,10 @@ module MachO
|
|
438
466
|
@format = "VVa16QQQQVVVV"
|
439
467
|
@sizeof = 72
|
440
468
|
|
441
|
-
# @private
|
442
|
-
def initialize(offset, cmd, cmdsize, segname, vmaddr, vmsize, fileoff,
|
469
|
+
# @api private
|
470
|
+
def initialize(raw_data, offset, cmd, cmdsize, segname, vmaddr, vmsize, fileoff,
|
443
471
|
filesize, maxprot, initprot, nsects, flags)
|
444
|
-
super(offset, cmd, cmdsize)
|
472
|
+
super(raw_data, offset, cmd, cmdsize)
|
445
473
|
@segname = segname
|
446
474
|
@vmaddr = vmaddr
|
447
475
|
@vmsize = vmsize
|
@@ -463,7 +491,7 @@ module MachO
|
|
463
491
|
# on filetype. Corresponds to LC_ID_DYLIB, LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB,
|
464
492
|
# and LC_REEXPORT_DYLIB.
|
465
493
|
class DylibCommand < LoadCommand
|
466
|
-
# @return [
|
494
|
+
# @return [MachO::LoadCommand::LCStr] the library's path name as an LCStr
|
467
495
|
attr_reader :name
|
468
496
|
|
469
497
|
# @return [Fixnum] the library's build time stamp
|
@@ -478,11 +506,11 @@ module MachO
|
|
478
506
|
@format = "VVVVVV"
|
479
507
|
@sizeof = 24
|
480
508
|
|
481
|
-
# @private
|
482
|
-
def initialize(offset, cmd, cmdsize, name, timestamp, current_version,
|
509
|
+
# @api private
|
510
|
+
def initialize(raw_data, offset, cmd, cmdsize, name, timestamp, current_version,
|
483
511
|
compatibility_version)
|
484
|
-
super(offset, cmd, cmdsize)
|
485
|
-
@name = name
|
512
|
+
super(raw_data, offset, cmd, cmdsize)
|
513
|
+
@name = LCStr.new(raw_data, self, name)
|
486
514
|
@timestamp = timestamp
|
487
515
|
@current_version = current_version
|
488
516
|
@compatibility_version = compatibility_version
|
@@ -493,23 +521,23 @@ module MachO
|
|
493
521
|
# on filetype. Corresponds to LC_ID_DYLINKER, LC_LOAD_DYLINKER, and
|
494
522
|
# LC_DYLD_ENVIRONMENT.
|
495
523
|
class DylinkerCommand < LoadCommand
|
496
|
-
# @return [
|
524
|
+
# @return [MachO::LoadCommand::LCStr] the dynamic linker's path name as an LCStr
|
497
525
|
attr_reader :name
|
498
526
|
|
499
527
|
@format = "VVV"
|
500
528
|
@sizeof = 12
|
501
529
|
|
502
|
-
# @private
|
503
|
-
def initialize(offset, cmd, cmdsize, name)
|
504
|
-
super(offset, cmd, cmdsize)
|
505
|
-
@name = name
|
530
|
+
# @api private
|
531
|
+
def initialize(raw_data, offset, cmd, cmdsize, name)
|
532
|
+
super(raw_data, offset, cmd, cmdsize)
|
533
|
+
@name = LCStr.new(raw_data, self, name)
|
506
534
|
end
|
507
535
|
end
|
508
536
|
|
509
537
|
# A load command used to indicate dynamic libraries used in prebinding.
|
510
538
|
# Corresponds to LC_PREBOUND_DYLIB.
|
511
539
|
class PreboundDylibCommand < LoadCommand
|
512
|
-
# @return [
|
540
|
+
# @return [MachO::LoadCommand::LCStr] the library's path name as an LCStr
|
513
541
|
attr_reader :name
|
514
542
|
|
515
543
|
# @return [Fixnum] the number of modules in the library
|
@@ -521,10 +549,10 @@ module MachO
|
|
521
549
|
@format = "VVVVV"
|
522
550
|
@sizeof = 20
|
523
551
|
|
524
|
-
# @private
|
525
|
-
def initialize(offset, cmd, cmdsize, name, nmodules, linked_modules)
|
526
|
-
super(offset, cmd, cmdsize)
|
527
|
-
@name = name
|
552
|
+
# @api private
|
553
|
+
def initialize(raw_data, offset, cmd, cmdsize, name, nmodules, linked_modules)
|
554
|
+
super(raw_data, offset, cmd, cmdsize)
|
555
|
+
@name = LCStr.new(raw_data, self, name)
|
528
556
|
@nmodules = nmodules
|
529
557
|
@linked_modules = linked_modules
|
530
558
|
end
|
@@ -567,11 +595,11 @@ module MachO
|
|
567
595
|
@format = "VVVVVVVVVV"
|
568
596
|
@sizeof = 40
|
569
597
|
|
570
|
-
# @private
|
571
|
-
def initialize(offset, cmd, cmdsize, init_address, init_module,
|
598
|
+
# @api private
|
599
|
+
def initialize(raw_data, offset, cmd, cmdsize, init_address, init_module,
|
572
600
|
reserved1, reserved2, reserved3, reserved4, reserved5,
|
573
601
|
reserved6)
|
574
|
-
super(offset, cmd, cmdsize)
|
602
|
+
super(raw_data, offset, cmd, cmdsize)
|
575
603
|
@init_address = init_address
|
576
604
|
@init_module = init_module
|
577
605
|
@reserved1 = reserved1
|
@@ -614,11 +642,11 @@ module MachO
|
|
614
642
|
@format = "VVQQQQQQQQ"
|
615
643
|
@sizeof = 72
|
616
644
|
|
617
|
-
# @private
|
618
|
-
def initialize(offset, cmd, cmdsize, init_address, init_module,
|
645
|
+
# @api private
|
646
|
+
def initialize(raw_data, offset, cmd, cmdsize, init_address, init_module,
|
619
647
|
reserved1, reserved2, reserved3, reserved4, reserved5,
|
620
648
|
reserved6)
|
621
|
-
super(offset, cmd, cmdsize)
|
649
|
+
super(raw_data, offset, cmd, cmdsize)
|
622
650
|
@init_address = init_address
|
623
651
|
@init_module = init_module
|
624
652
|
@reserved1 = reserved1
|
@@ -633,64 +661,64 @@ module MachO
|
|
633
661
|
# A load command signifying membership of a subframework containing the name
|
634
662
|
# of an umbrella framework. Corresponds to LC_SUB_FRAMEWORK.
|
635
663
|
class SubFrameworkCommand < LoadCommand
|
636
|
-
# @return [
|
664
|
+
# @return [MachO::LoadCommand::LCStr] the umbrella framework name as an LCStr
|
637
665
|
attr_reader :umbrella
|
638
666
|
|
639
667
|
@format = "VVV"
|
640
668
|
@sizeof = 12
|
641
669
|
|
642
|
-
# @private
|
643
|
-
def initialize(offset, cmd, cmdsize, umbrella)
|
644
|
-
super(offset, cmd, cmdsize)
|
645
|
-
@umbrella = umbrella
|
670
|
+
# @api private
|
671
|
+
def initialize(raw_data, offset, cmd, cmdsize, umbrella)
|
672
|
+
super(raw_data, offset, cmd, cmdsize)
|
673
|
+
@umbrella = LCStr.new(raw_data, self, umbrella)
|
646
674
|
end
|
647
675
|
end
|
648
676
|
|
649
677
|
# A load command signifying membership of a subumbrella containing the name
|
650
678
|
# of an umbrella framework. Corresponds to LC_SUB_UMBRELLA.
|
651
679
|
class SubUmbrellaCommand < LoadCommand
|
652
|
-
# @return [
|
680
|
+
# @return [MachO::LoadCommand::LCStr] the subumbrella framework name as an LCStr
|
653
681
|
attr_reader :sub_umbrella
|
654
682
|
|
655
683
|
@format = "VVV"
|
656
684
|
@sizeof = 12
|
657
685
|
|
658
|
-
# @private
|
659
|
-
def initialize(offset, cmd, cmdsize, sub_umbrella)
|
660
|
-
super(offset, cmd, cmdsize)
|
661
|
-
@sub_umbrella = sub_umbrella
|
686
|
+
# @api private
|
687
|
+
def initialize(raw_data, offset, cmd, cmdsize, sub_umbrella)
|
688
|
+
super(raw_data, offset, cmd, cmdsize)
|
689
|
+
@sub_umbrella = LCStr.new(raw_data, self, sub_umbrella)
|
662
690
|
end
|
663
691
|
end
|
664
692
|
|
665
693
|
# A load command signifying a sublibrary of a shared library. Corresponds
|
666
694
|
# to LC_SUB_LIBRARY.
|
667
695
|
class SubLibraryCommand < LoadCommand
|
668
|
-
# @return [
|
696
|
+
# @return [MachO::LoadCommand::LCStr] the sublibrary name as an LCStr
|
669
697
|
attr_reader :sub_library
|
670
698
|
|
671
699
|
@format = "VVV"
|
672
700
|
@sizeof = 12
|
673
701
|
|
674
|
-
# @private
|
675
|
-
def initialize(offset, cmd, cmdsize, sub_library)
|
676
|
-
super(offset, cmd, cmdsize)
|
677
|
-
@sub_library = sub_library
|
702
|
+
# @api private
|
703
|
+
def initialize(raw_data, offset, cmd, cmdsize, sub_library)
|
704
|
+
super(raw_data, offset, cmd, cmdsize)
|
705
|
+
@sub_library = LCStr.new(raw_data, self, sub_library)
|
678
706
|
end
|
679
707
|
end
|
680
708
|
|
681
709
|
# A load command signifying a shared library that is a subframework of
|
682
710
|
# an umbrella framework. Corresponds to LC_SUB_CLIENT.
|
683
711
|
class SubClientCommand < LoadCommand
|
684
|
-
# @return [
|
712
|
+
# @return [MachO::LoadCommand::LCStr] the subclient name as an LCStr
|
685
713
|
attr_reader :sub_client
|
686
714
|
|
687
715
|
@format = "VVV"
|
688
716
|
@sizeof = 12
|
689
717
|
|
690
|
-
# @private
|
691
|
-
def initialize(offset, cmd, cmdsize, sub_client)
|
692
|
-
super(offset, cmd, cmdsize)
|
693
|
-
@sub_client = sub_client
|
718
|
+
# @api private
|
719
|
+
def initialize(raw_data, offset, cmd, cmdsize, sub_client)
|
720
|
+
super(raw_data, offset, cmd, cmdsize)
|
721
|
+
@sub_client = LCStr.new(raw_data, self, sub_client)
|
694
722
|
end
|
695
723
|
end
|
696
724
|
|
@@ -712,9 +740,9 @@ module MachO
|
|
712
740
|
@format = "VVVVVV"
|
713
741
|
@sizeof = 24
|
714
742
|
|
715
|
-
# @private
|
716
|
-
def initialize(offset, cmd, cmdsize, symoff, nsyms, stroff, strsize)
|
717
|
-
super(offset, cmd, cmdsize)
|
743
|
+
# @api private
|
744
|
+
def initialize(raw_data, offset, cmd, cmdsize, symoff, nsyms, stroff, strsize)
|
745
|
+
super(raw_data, offset, cmd, cmdsize)
|
718
746
|
@symoff = symoff
|
719
747
|
@nsyms = nsyms
|
720
748
|
@stroff = stroff
|
@@ -784,12 +812,12 @@ module MachO
|
|
784
812
|
@sizeof = 80
|
785
813
|
|
786
814
|
# ugh
|
787
|
-
# @private
|
788
|
-
def initialize(offset, cmd, cmdsize, ilocalsym, nlocalsym, iextdefsym,
|
815
|
+
# @api private
|
816
|
+
def initialize(raw_data, offset, cmd, cmdsize, ilocalsym, nlocalsym, iextdefsym,
|
789
817
|
nextdefsym, iundefsym, nundefsym, tocoff, ntoc, modtaboff,
|
790
818
|
nmodtab, extrefsymoff, nextrefsyms, indirectsymoff,
|
791
819
|
nindirectsyms, extreloff, nextrel, locreloff, nlocrel)
|
792
|
-
super(offset, cmd, cmdsize)
|
820
|
+
super(raw_data, offset, cmd, cmdsize)
|
793
821
|
@ilocalsym = ilocalsym
|
794
822
|
@nlocalsym = nlocalsym
|
795
823
|
@iextdefsym = iextdefsym
|
@@ -823,9 +851,9 @@ module MachO
|
|
823
851
|
@format = "VVVV"
|
824
852
|
@sizeof = 16
|
825
853
|
|
826
|
-
# @private
|
827
|
-
def initialize(offset, cmd, cmdsize, htoffset, nhints)
|
828
|
-
super(offset, cmd, cmdsize)
|
854
|
+
# @api private
|
855
|
+
def initialize(raw_data, offset, cmd, cmdsize, htoffset, nhints)
|
856
|
+
super(raw_data, offset, cmd, cmdsize)
|
829
857
|
@htoffset = htoffset
|
830
858
|
@nhints = nhints
|
831
859
|
end
|
@@ -840,9 +868,9 @@ module MachO
|
|
840
868
|
@format = "VVV"
|
841
869
|
@sizeof = 12
|
842
870
|
|
843
|
-
# @private
|
844
|
-
def initialize(offset, cmd, cmdsize, cksum)
|
845
|
-
super(offset, cmd, cmdsize)
|
871
|
+
# @api private
|
872
|
+
def initialize(raw_data, offset, cmd, cmdsize, cksum)
|
873
|
+
super(raw_data, offset, cmd, cmdsize)
|
846
874
|
@cksum = cksum
|
847
875
|
end
|
848
876
|
end
|
@@ -851,16 +879,16 @@ module MachO
|
|
851
879
|
# be added to the current run path used to find @rpath prefixed dylibs.
|
852
880
|
# Corresponds to LC_RPATH.
|
853
881
|
class RpathCommand < LoadCommand
|
854
|
-
# @return [
|
882
|
+
# @return [MachO::LoadCommand::LCStr] the path to add to the run path as an LCStr
|
855
883
|
attr_reader :path
|
856
884
|
|
857
885
|
@format = "VVV"
|
858
886
|
@sizeof = 12
|
859
887
|
|
860
|
-
# @private
|
861
|
-
def initialize(offset, cmd, cmdsize, path)
|
862
|
-
super(offset, cmd, cmdsize)
|
863
|
-
@path = path
|
888
|
+
# @api private
|
889
|
+
def initialize(raw_data, offset, cmd, cmdsize, path)
|
890
|
+
super(raw_data, offset, cmd, cmdsize)
|
891
|
+
@path = LCStr.new(raw_data, self, path)
|
864
892
|
end
|
865
893
|
end
|
866
894
|
|
@@ -877,9 +905,9 @@ module MachO
|
|
877
905
|
@format = "VVVV"
|
878
906
|
@sizeof = 16
|
879
907
|
|
880
|
-
# @private
|
881
|
-
def initialize(offset, cmd, cmdsize, dataoff, datasize)
|
882
|
-
super(offset, cmd, cmdsize)
|
908
|
+
# @api private
|
909
|
+
def initialize(raw_data, offset, cmd, cmdsize, dataoff, datasize)
|
910
|
+
super(raw_data, offset, cmd, cmdsize)
|
883
911
|
@dataoff = dataoff
|
884
912
|
@datasize = datasize
|
885
913
|
end
|
@@ -900,9 +928,9 @@ module MachO
|
|
900
928
|
@format = "VVVVV"
|
901
929
|
@sizeof = 20
|
902
930
|
|
903
|
-
# @private
|
904
|
-
def initialize(offset, cmd, cmdsize, cryptoff, cryptsize, cryptid)
|
905
|
-
super(offset, cmd, cmdsize)
|
931
|
+
# @api private
|
932
|
+
def initialize(raw_data, offset, cmd, cmdsize, cryptoff, cryptsize, cryptid)
|
933
|
+
super(raw_data, offset, cmd, cmdsize)
|
906
934
|
@cryptoff = cryptoff
|
907
935
|
@cryptsize = cryptsize
|
908
936
|
@cryptid = cryptid
|
@@ -927,9 +955,9 @@ module MachO
|
|
927
955
|
@format = "VVVVVV"
|
928
956
|
@sizeof = 24
|
929
957
|
|
930
|
-
# @private
|
931
|
-
def initialize(offset, cmd, cmdsize, cryptoff, cryptsize, cryptid)
|
932
|
-
super(offset, cmd, cmdsize)
|
958
|
+
# @api private
|
959
|
+
def initialize(raw_data, offset, cmd, cmdsize, cryptoff, cryptsize, cryptid)
|
960
|
+
super(raw_data, offset, cmd, cmdsize)
|
933
961
|
@cryptoff = cryptoff
|
934
962
|
@cryptsize = cryptsize
|
935
963
|
@cryptid = cryptid
|
@@ -949,9 +977,9 @@ module MachO
|
|
949
977
|
@format = "VVVV"
|
950
978
|
@sizeof = 16
|
951
979
|
|
952
|
-
# @private
|
953
|
-
def initialize(offset, cmd, cmdsize, version, sdk)
|
954
|
-
super(offset, cmd, cmdsize)
|
980
|
+
# @api private
|
981
|
+
def initialize(raw_data, offset, cmd, cmdsize, version, sdk)
|
982
|
+
super(raw_data, offset, cmd, cmdsize)
|
955
983
|
@version = version
|
956
984
|
@sdk = sdk
|
957
985
|
end
|
@@ -1016,11 +1044,11 @@ module MachO
|
|
1016
1044
|
@format = "VVVVVVVVVVVV"
|
1017
1045
|
@sizeof = 48
|
1018
1046
|
|
1019
|
-
# @private
|
1020
|
-
def initialize(offset, cmd, cmdsize, rebase_off, rebase_size, bind_off,
|
1047
|
+
# @api private
|
1048
|
+
def initialize(raw_data, offset, cmd, cmdsize, rebase_off, rebase_size, bind_off,
|
1021
1049
|
bind_size, weak_bind_off, weak_bind_size, lazy_bind_off,
|
1022
1050
|
lazy_bind_size, export_off, export_size)
|
1023
|
-
super(offset, cmd, cmdsize)
|
1051
|
+
super(raw_data, offset, cmd, cmdsize)
|
1024
1052
|
@rebase_off = rebase_off
|
1025
1053
|
@rebase_size = rebase_size
|
1026
1054
|
@bind_off = bind_off
|
@@ -1043,9 +1071,9 @@ module MachO
|
|
1043
1071
|
@format = "VVV"
|
1044
1072
|
@sizeof = 12
|
1045
1073
|
|
1046
|
-
# @private
|
1047
|
-
def initialize(offset, cmd, cmdsize, count)
|
1048
|
-
super(offset, cmd, cmdsize)
|
1074
|
+
# @api private
|
1075
|
+
def initialize(raw_data, offset, cmd, cmdsize, count)
|
1076
|
+
super(raw_data, offset, cmd, cmdsize)
|
1049
1077
|
@count = count
|
1050
1078
|
end
|
1051
1079
|
end
|
@@ -1061,9 +1089,9 @@ module MachO
|
|
1061
1089
|
@format = "VVQQ"
|
1062
1090
|
@sizeof = 24
|
1063
1091
|
|
1064
|
-
# @private
|
1065
|
-
def initialize(offset, cmd, cmdsize, entryoff, stacksize)
|
1066
|
-
super(offset, cmd, cmdsize)
|
1092
|
+
# @api private
|
1093
|
+
def initialize(raw_data, offset, cmd, cmdsize, entryoff, stacksize)
|
1094
|
+
super(raw_data, offset, cmd, cmdsize)
|
1067
1095
|
@entryoff = entryoff
|
1068
1096
|
@stacksize = stacksize
|
1069
1097
|
end
|
@@ -1078,9 +1106,9 @@ module MachO
|
|
1078
1106
|
@format = "VVQ"
|
1079
1107
|
@sizeof = 16
|
1080
1108
|
|
1081
|
-
# @private
|
1082
|
-
def initialize(offset, cmd, cmdsize, version)
|
1083
|
-
super(offset, cmd, cmdsize)
|
1109
|
+
# @api private
|
1110
|
+
def initialize(raw_data, offset, cmd, cmdsize, version)
|
1111
|
+
super(raw_data, offset, cmd, cmdsize)
|
1084
1112
|
@version = version
|
1085
1113
|
end
|
1086
1114
|
|
data/lib/macho/macho_file.rb
CHANGED
@@ -24,9 +24,9 @@ module MachO
|
|
24
24
|
|
25
25
|
# Creates a new FatFile from the given filename.
|
26
26
|
# @param filename [String] the Mach-O file to load from
|
27
|
-
# @
|
27
|
+
# @raise [ArgumentError] if the given filename does not exist
|
28
28
|
def initialize(filename)
|
29
|
-
raise ArgumentError.new("
|
29
|
+
raise ArgumentError.new("#{filetype}: no such file") unless File.exist?(filename)
|
30
30
|
|
31
31
|
@filename = filename
|
32
32
|
@raw_data = open(@filename, "rb") { |f| f.read }
|
@@ -34,7 +34,7 @@ module MachO
|
|
34
34
|
@load_commands = get_load_commands
|
35
35
|
end
|
36
36
|
|
37
|
-
# @private
|
37
|
+
# @api private
|
38
38
|
def initialize_from_bin(bin)
|
39
39
|
@filename = nil
|
40
40
|
@raw_data = bin
|
@@ -138,21 +138,15 @@ module MachO
|
|
138
138
|
# The Mach-O's dylib ID, or `nil` if not a dylib.
|
139
139
|
# @example
|
140
140
|
# file.dylib_id # => 'libBar.dylib'
|
141
|
-
# @return [String] the Mach-O's dylib ID
|
141
|
+
# @return [String, nil] the Mach-O's dylib ID
|
142
142
|
def dylib_id
|
143
143
|
if !dylib?
|
144
144
|
return nil
|
145
145
|
end
|
146
146
|
|
147
|
-
dylib_id_cmd = command(
|
148
|
-
|
149
|
-
cmdsize = dylib_id_cmd.cmdsize
|
150
|
-
offset = dylib_id_cmd.offset
|
151
|
-
stroffset = dylib_id_cmd.name
|
147
|
+
dylib_id_cmd = command("LC_ID_DYLIB").first
|
152
148
|
|
153
|
-
|
154
|
-
|
155
|
-
dylib_id.delete("\x00")
|
149
|
+
dylib_id_cmd.name.to_s
|
156
150
|
end
|
157
151
|
|
158
152
|
# Changes the Mach-O's dylib ID to `new_id`. Does nothing if not a dylib.
|
@@ -160,6 +154,7 @@ module MachO
|
|
160
154
|
# file.dylib_id = "libFoo.dylib"
|
161
155
|
# @param new_id [String] the dylib's new ID
|
162
156
|
# @return [void]
|
157
|
+
# @raise [ArgumentError] if `new_id` is not a String
|
163
158
|
def dylib_id=(new_id)
|
164
159
|
if !new_id.is_a?(String)
|
165
160
|
raise ArgumentError.new("argument must be a String")
|
@@ -169,7 +164,7 @@ module MachO
|
|
169
164
|
return nil
|
170
165
|
end
|
171
166
|
|
172
|
-
dylib_cmd = command(
|
167
|
+
dylib_cmd = command("LC_ID_DYLIB").first
|
173
168
|
old_id = dylib_id
|
174
169
|
|
175
170
|
set_name_in_dylib(dylib_cmd, old_id, new_id)
|
@@ -179,14 +174,10 @@ module MachO
|
|
179
174
|
# @return [Array<String>] an array of all shared libraries
|
180
175
|
def linked_dylibs
|
181
176
|
dylibs = []
|
182
|
-
dylib_cmds = command(
|
177
|
+
dylib_cmds = command("LC_LOAD_DYLIB")
|
183
178
|
|
184
179
|
dylib_cmds.each do |dylib_cmd|
|
185
|
-
|
186
|
-
offset = dylib_cmd.offset
|
187
|
-
stroffset = dylib_cmd.name
|
188
|
-
|
189
|
-
dylib = @raw_data.slice(offset + stroffset...offset + cmdsize).unpack("Z*").first
|
180
|
+
dylib = dylib_cmd.name.to_s
|
190
181
|
|
191
182
|
dylibs << dylib
|
192
183
|
end
|
@@ -200,6 +191,7 @@ module MachO
|
|
200
191
|
# @param old_name [String] the shared library's old name
|
201
192
|
# @param new_name [String] the shared library's new name
|
202
193
|
# @return [void]
|
194
|
+
# @raise [MachO::DylibUnknownError] if no shared library has the old name
|
203
195
|
def change_install_name(old_name, new_name)
|
204
196
|
idx = linked_dylibs.index(old_name)
|
205
197
|
raise DylibUnknownError.new(old_name) if idx.nil?
|
@@ -207,7 +199,7 @@ module MachO
|
|
207
199
|
# this is a bit of a hack - since there is a 1-1 ordered association
|
208
200
|
# between linked_dylibs and command('LC_LOAD_DYLIB'), we can use
|
209
201
|
# their indices interchangeably to avoid having to loop.
|
210
|
-
dylib_cmd = command(
|
202
|
+
dylib_cmd = command("LC_LOAD_DYLIB")[idx]
|
211
203
|
|
212
204
|
set_name_in_dylib(dylib_cmd, old_name, new_name)
|
213
205
|
end
|
@@ -215,6 +207,7 @@ module MachO
|
|
215
207
|
alias :change_dylib :change_install_name
|
216
208
|
|
217
209
|
# All sections of the segment `segment`.
|
210
|
+
# @param segment [MachO::SegmentCommand, MachO::SegmentCommand64] the segment being inspected
|
218
211
|
# @return [Array<MachO::Section>] if the Mach-O is 32-bit
|
219
212
|
# @return [Array<MachO::Section64>] if the Mach-O is 64-bit
|
220
213
|
def sections(segment)
|
@@ -253,6 +246,7 @@ module MachO
|
|
253
246
|
# Write all Mach-O data to the file used to initialize the instance.
|
254
247
|
# @raise [MachOError] if the instance was created from a binary string
|
255
248
|
# @return [void]
|
249
|
+
# @raise [MachO::MachOError] if the instance was initialized without a file
|
256
250
|
# @note Overwrites all data in the file!
|
257
251
|
def write!
|
258
252
|
if @filename.nil?
|
@@ -394,7 +388,7 @@ module MachO
|
|
394
388
|
# why do I do this? i don't like declaring constants below
|
395
389
|
# classes, and i need them to resolve...
|
396
390
|
klass = MachO.const_get "#{LC_STRUCTURES[cmd]}"
|
397
|
-
command = klass.new_from_bin(offset, @raw_data.slice(offset, klass.bytesize))
|
391
|
+
command = klass.new_from_bin(@raw_data, offset, @raw_data.slice(offset, klass.bytesize))
|
398
392
|
|
399
393
|
load_commands << command
|
400
394
|
offset += command.cmdsize
|
@@ -417,6 +411,7 @@ module MachO
|
|
417
411
|
# @param old_name [String] the old dylib name
|
418
412
|
# @param new_name [String] the new dylib name
|
419
413
|
# @return [void]
|
414
|
+
# @raise [MachO::HeaderPadError] if the new name exceeds the header pad buffer
|
420
415
|
# @private
|
421
416
|
def set_name_in_dylib(dylib_cmd, old_name, new_name)
|
422
417
|
if magic32?
|
@@ -465,10 +460,10 @@ module MachO
|
|
465
460
|
@raw_data[dylib_cmd.offset + 4, 4] = [new_size].pack("V")
|
466
461
|
|
467
462
|
# delete the old name
|
468
|
-
@raw_data.slice!(dylib_cmd.offset + dylib_cmd.name...dylib_cmd.offset + dylib_cmd.class.bytesize + old_name.size)
|
463
|
+
@raw_data.slice!(dylib_cmd.offset + dylib_cmd.name.to_i...dylib_cmd.offset + dylib_cmd.class.bytesize + old_name.size)
|
469
464
|
|
470
465
|
# insert the new id
|
471
|
-
@raw_data.insert(dylib_cmd.offset + dylib_cmd.name, new_name)
|
466
|
+
@raw_data.insert(dylib_cmd.offset + dylib_cmd.name.to_i, new_name)
|
472
467
|
|
473
468
|
# pad/unpad after new_sizeofcmds until offsets are corrected
|
474
469
|
null_pad = old_name.size - new_name.size
|
data/lib/macho/sections.rb
CHANGED
@@ -58,13 +58,43 @@ module MachO
|
|
58
58
|
|
59
59
|
# Represents a section of a segment for 32-bit architectures.
|
60
60
|
class Section < MachOStructure
|
61
|
-
|
62
|
-
attr_reader :
|
61
|
+
# @return [String] the name of the section, including null pad bytes
|
62
|
+
attr_reader :sectname
|
63
|
+
|
64
|
+
# @return [String] the name of the segment's section, including null pad bytes
|
65
|
+
attr_reader :segname
|
66
|
+
|
67
|
+
# @return [Fixnum] the memory address of the section
|
68
|
+
attr_reader :addr
|
69
|
+
|
70
|
+
# @return [Fixnum] the size, in bytes, of the section
|
71
|
+
attr_reader :size
|
72
|
+
|
73
|
+
# @return [Fixnum] the file offset of the section
|
74
|
+
attr_reader :offset
|
75
|
+
|
76
|
+
# @return [Fixnum] the section alignment (power of 2) of the section
|
77
|
+
attr_reader :align
|
78
|
+
|
79
|
+
# @return [Fixnum] the file offset of the section's relocation entries
|
80
|
+
attr_reader :reloff
|
81
|
+
|
82
|
+
# @return [Fixnum] the number of relocation entries
|
83
|
+
attr_reader :nreloc
|
84
|
+
|
85
|
+
# @return [Fixnum] flags for type and addrributes of the section
|
86
|
+
attr_reader :flags
|
87
|
+
|
88
|
+
# @return [void] reserved (for offset or index)
|
89
|
+
attr_reader :reserved1
|
90
|
+
|
91
|
+
# @return [void] reserved (for count or sizeof)
|
92
|
+
attr_reader :reserved2
|
63
93
|
|
64
94
|
@format = "a16a16VVVVVVVVV"
|
65
95
|
@sizeof = 68
|
66
96
|
|
67
|
-
# @private
|
97
|
+
# @api private
|
68
98
|
def initialize(sectname, segname, addr, size, offset, align, reloff,
|
69
99
|
nreloc, flags, reserved1, reserved2)
|
70
100
|
@sectname = sectname
|
@@ -101,13 +131,46 @@ module MachO
|
|
101
131
|
|
102
132
|
# Represents a section of a segment for 64-bit architectures.
|
103
133
|
class Section64 < MachOStructure
|
104
|
-
|
105
|
-
attr_reader :
|
134
|
+
# @return [String] the name of the section, including null pad bytes
|
135
|
+
attr_reader :sectname
|
136
|
+
|
137
|
+
# @return [String] the name of the segment's section, including null pad bytes
|
138
|
+
attr_reader :segname
|
139
|
+
|
140
|
+
# @return [Fixnum] the memory address of the section
|
141
|
+
attr_reader :addr
|
142
|
+
|
143
|
+
# @return [Fixnum] the size, in bytes, of the section
|
144
|
+
attr_reader :size
|
145
|
+
|
146
|
+
# @return [Fixnum] the file offset of the section
|
147
|
+
attr_reader :offset
|
148
|
+
|
149
|
+
# @return [Fixnum] the section alignment (power of 2) of the section
|
150
|
+
attr_reader :align
|
151
|
+
|
152
|
+
# @return [Fixnum] the file offset of the section's relocation entries
|
153
|
+
attr_reader :reloff
|
154
|
+
|
155
|
+
# @return [Fixnum] the number of relocation entries
|
156
|
+
attr_reader :nreloc
|
157
|
+
|
158
|
+
# @return [Fixnum] flags for type and addrributes of the section
|
159
|
+
attr_reader :flags
|
160
|
+
|
161
|
+
# @return [void] reserved (for offset or index)
|
162
|
+
attr_reader :reserved1
|
163
|
+
|
164
|
+
# @return [void] reserved (for count or sizeof)
|
165
|
+
attr_reader :reserved2
|
166
|
+
|
167
|
+
# @return [void] reserved
|
168
|
+
attr_reader :reserved3
|
106
169
|
|
107
170
|
@format = "a16a16QQVVVVVVVV"
|
108
171
|
@sizeof = 80
|
109
172
|
|
110
|
-
# @private
|
173
|
+
# @api private
|
111
174
|
def initialize(sectname, segname, addr, size, offset, align, reloff,
|
112
175
|
nreloc, flags, reserved1, reserved2, reserved3)
|
113
176
|
@sectname = sectname
|
data/lib/macho/structure.rb
CHANGED
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.3
|
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-10-
|
11
|
+
date: 2015-10-27 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
|