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