ruby-macho 1.2.0 → 1.3.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/README.md +1 -1
- data/lib/macho.rb +1 -1
- data/lib/macho/fat_file.rb +9 -0
- data/lib/macho/headers.rb +48 -1
- data/lib/macho/load_commands.rb +372 -52
- data/lib/macho/macho_file.rb +10 -2
- data/lib/macho/sections.rb +30 -8
- data/lib/macho/structure.rb +10 -0
- data/lib/macho/view.rb +8 -0
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 73711cb2c95bea44060fc6ab6ebd99a66b06ee1a6187b512ae68527e8dc4e8f7
|
4
|
+
data.tar.gz: fefdf5b471bbf158af6d8a1bf766f5b327ad737e09badc60d8adae723ef3d3b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ed466ba6c6c0c62f1cb7fa365401faef73a322c636f9a1e97f3e655457f1787b83ef134360168618849f0d3253f1d6b8ed41aa0f085a9a40b3ca966ef1d437e4
|
7
|
+
data.tar.gz: 61781f5efc71e38eff94704c09de7338e53918030189abe0f0bb2e1b442e5685a58076c431f112d27518e921fe5177666ccea7e6015fea65a5d8460da7632d13
|
data/LICENSE
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c) 2015, 2016 William Woodruff <william @
|
3
|
+
Copyright (c) 2015, 2016, 2017, 2018 William Woodruff <william @ yossarian.net>
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -9,7 +9,7 @@ A Ruby library for examining and modifying Mach-O files.
|
|
9
9
|
|
10
10
|
### What is a Mach-O file?
|
11
11
|
|
12
|
-
The [Mach-O file format](https://en.wikipedia.org/wiki/Mach-O) is used by
|
12
|
+
The [Mach-O file format](https://en.wikipedia.org/wiki/Mach-O) is used by macOS
|
13
13
|
and iOS (among others) as a general purpose binary format for object files,
|
14
14
|
executables, dynamic libraries, and so forth.
|
15
15
|
|
data/lib/macho.rb
CHANGED
@@ -12,7 +12,7 @@ require "#{File.dirname(__FILE__)}/macho/tools"
|
|
12
12
|
# The primary namespace for ruby-macho.
|
13
13
|
module MachO
|
14
14
|
# release version
|
15
|
-
VERSION = "1.
|
15
|
+
VERSION = "1.3.0.pre.1".freeze
|
16
16
|
|
17
17
|
# Opens the given filename as a MachOFile or FatFile, depending on its magic.
|
18
18
|
# @param filename [String] the file being opened
|
data/lib/macho/fat_file.rb
CHANGED
@@ -265,6 +265,15 @@ module MachO
|
|
265
265
|
File.open(@filename, "wb") { |f| f.write(@raw_data) }
|
266
266
|
end
|
267
267
|
|
268
|
+
# @return [Hash] a hash representation of this {FatFile}
|
269
|
+
def to_h
|
270
|
+
{
|
271
|
+
"header" => header.to_h,
|
272
|
+
"fat_archs" => fat_archs.map(&:to_h),
|
273
|
+
"machos" => machos.map(&:to_h),
|
274
|
+
}
|
275
|
+
end
|
276
|
+
|
268
277
|
private
|
269
278
|
|
270
279
|
# Obtain the fat header from raw file data.
|
data/lib/macho/headers.rb
CHANGED
@@ -475,6 +475,15 @@ module MachO
|
|
475
475
|
def serialize
|
476
476
|
[magic, nfat_arch].pack(FORMAT)
|
477
477
|
end
|
478
|
+
|
479
|
+
# @return [Hash] a hash representation of this {FatHeader}
|
480
|
+
def to_h
|
481
|
+
{
|
482
|
+
"magic" => magic,
|
483
|
+
"magic_sym" => MH_MAGICS[magic],
|
484
|
+
"nfat_arch" => nfat_arch,
|
485
|
+
}.merge super
|
486
|
+
end
|
478
487
|
end
|
479
488
|
|
480
489
|
# Fat binary header architecture structure. A Fat binary has one or more of
|
@@ -508,7 +517,7 @@ module MachO
|
|
508
517
|
# @api private
|
509
518
|
def initialize(cputype, cpusubtype, offset, size, align)
|
510
519
|
@cputype = cputype
|
511
|
-
@cpusubtype = cpusubtype
|
520
|
+
@cpusubtype = cpusubtype & ~CPU_SUBTYPE_MASK
|
512
521
|
@offset = offset
|
513
522
|
@size = size
|
514
523
|
@align = align
|
@@ -518,6 +527,19 @@ module MachO
|
|
518
527
|
def serialize
|
519
528
|
[cputype, cpusubtype, offset, size, align].pack(FORMAT)
|
520
529
|
end
|
530
|
+
|
531
|
+
# @return [Hash] a hash representation of this {FatArch}
|
532
|
+
def to_h
|
533
|
+
{
|
534
|
+
"cputype" => cputype,
|
535
|
+
"cputype_sym" => CPU_TYPES[cputype],
|
536
|
+
"cpusubtype" => cpusubtype,
|
537
|
+
"cpusubtype_sym" => CPU_SUBTYPES[cputype][cpusubtype],
|
538
|
+
"offset" => offset,
|
539
|
+
"size" => size,
|
540
|
+
"align" => align,
|
541
|
+
}.merge super
|
542
|
+
end
|
521
543
|
end
|
522
544
|
|
523
545
|
# 32-bit Mach-O file header structure
|
@@ -639,6 +661,24 @@ module MachO
|
|
639
661
|
def alignment
|
640
662
|
magic32? ? 4 : 8
|
641
663
|
end
|
664
|
+
|
665
|
+
# @return [Hash] a hash representation of this {MachHeader}
|
666
|
+
def to_h
|
667
|
+
{
|
668
|
+
"magic" => magic,
|
669
|
+
"magic_sym" => MH_MAGICS[magic],
|
670
|
+
"cputype" => cputype,
|
671
|
+
"cputype_sym" => CPU_TYPES[cputype],
|
672
|
+
"cpusubtype" => cpusubtype,
|
673
|
+
"cpusubtype_sym" => CPU_SUBTYPES[cputype][cpusubtype],
|
674
|
+
"filetype" => filetype,
|
675
|
+
"filetype_sym" => MH_FILETYPES[filetype],
|
676
|
+
"ncmds" => ncmds,
|
677
|
+
"sizeofcmds" => sizeofcmds,
|
678
|
+
"flags" => flags,
|
679
|
+
"alignment" => alignment,
|
680
|
+
}.merge super
|
681
|
+
end
|
642
682
|
end
|
643
683
|
|
644
684
|
# 64-bit Mach-O file header structure
|
@@ -660,6 +700,13 @@ module MachO
|
|
660
700
|
super(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags)
|
661
701
|
@reserved = reserved
|
662
702
|
end
|
703
|
+
|
704
|
+
# @return [Hash] a hash representation of this {MachHeader64}
|
705
|
+
def to_h
|
706
|
+
{
|
707
|
+
"reserved" => reserved,
|
708
|
+
}.merge super
|
709
|
+
end
|
663
710
|
end
|
664
711
|
end
|
665
712
|
end
|
data/lib/macho/load_commands.rb
CHANGED
@@ -143,7 +143,7 @@ module MachO
|
|
143
143
|
:LC_LINKER_OPTIMIZATION_HINT => "LinkeditDataCommand",
|
144
144
|
:LC_VERSION_MIN_TVOS => "VersionMinCommand",
|
145
145
|
:LC_VERSION_MIN_WATCHOS => "VersionMinCommand",
|
146
|
-
:LC_NOTE => "
|
146
|
+
:LC_NOTE => "NoteCommand",
|
147
147
|
:LC_BUILD_VERSION => "BuildVersionCommand",
|
148
148
|
}.freeze
|
149
149
|
|
@@ -169,15 +169,16 @@ module MachO
|
|
169
169
|
:SG_PROTECTED_VERSION_1 => 0x8,
|
170
170
|
}.freeze
|
171
171
|
|
172
|
-
# Mach-O load command structure
|
173
|
-
#
|
174
|
-
#
|
175
|
-
# isn't available
|
172
|
+
# The top-level Mach-O load command structure.
|
173
|
+
#
|
174
|
+
# This is the most generic load command -- only the type ID and size are
|
175
|
+
# represented. Used when a more specific class isn't available or isn't implemented.
|
176
176
|
class LoadCommand < MachOStructure
|
177
|
-
# @return [MachO::MachOView] the raw view associated with the load command
|
177
|
+
# @return [MachO::MachOView, nil] the raw view associated with the load command,
|
178
|
+
# or nil if the load command was created via {create}.
|
178
179
|
attr_reader :view
|
179
180
|
|
180
|
-
# @return [Integer] the load command's
|
181
|
+
# @return [Integer] the load command's type ID
|
181
182
|
attr_reader :cmd
|
182
183
|
|
183
184
|
# @return [Integer] the size of the load command, in bytes
|
@@ -251,8 +252,8 @@ module MachO
|
|
251
252
|
view.offset
|
252
253
|
end
|
253
254
|
|
254
|
-
# @return [Symbol] a symbol representation of the load command's
|
255
|
-
#
|
255
|
+
# @return [Symbol, nil] a symbol representation of the load command's
|
256
|
+
# type ID, or nil if the ID doesn't correspond to a known load command class
|
256
257
|
def type
|
257
258
|
LOAD_COMMANDS[cmd]
|
258
259
|
end
|
@@ -265,6 +266,17 @@ module MachO
|
|
265
266
|
type.to_s
|
266
267
|
end
|
267
268
|
|
269
|
+
# @return [Hash] a hash representation of this load command
|
270
|
+
# @note Children should override this to include additional information.
|
271
|
+
def to_h
|
272
|
+
{
|
273
|
+
"view" => view.to_h,
|
274
|
+
"cmd" => cmd,
|
275
|
+
"cmdsize" => cmdsize,
|
276
|
+
"type" => type,
|
277
|
+
}.merge super
|
278
|
+
end
|
279
|
+
|
268
280
|
# Represents a Load Command string. A rough analogue to the lc_str
|
269
281
|
# struct used internally by OS X. This class allows ruby-macho to
|
270
282
|
# pretend that strings stored in LCs are immediately available without
|
@@ -304,6 +316,14 @@ module MachO
|
|
304
316
|
def to_i
|
305
317
|
@string_offset
|
306
318
|
end
|
319
|
+
|
320
|
+
# @return [Hash] a hash representation of this {LCStr}.
|
321
|
+
def to_h
|
322
|
+
{
|
323
|
+
"string" => to_s,
|
324
|
+
"offset" => to_i,
|
325
|
+
}
|
326
|
+
end
|
307
327
|
end
|
308
328
|
|
309
329
|
# Represents the contextual information needed by a load command to
|
@@ -364,6 +384,14 @@ module MachO
|
|
364
384
|
|
365
385
|
segs.join("-")
|
366
386
|
end
|
387
|
+
|
388
|
+
# @return [Hash] returns a hash representation of this {UUIDCommand}
|
389
|
+
def to_h
|
390
|
+
{
|
391
|
+
"uuid" => uuid,
|
392
|
+
"uuid_string" => uuid_string,
|
393
|
+
}.merge super
|
394
|
+
end
|
367
395
|
end
|
368
396
|
|
369
397
|
# A load command indicating that part of this file is to be mapped into
|
@@ -398,7 +426,7 @@ module MachO
|
|
398
426
|
|
399
427
|
# @see MachOStructure::FORMAT
|
400
428
|
# @api private
|
401
|
-
FORMAT = "L=
|
429
|
+
FORMAT = "L=2Z16L=4l=2L=2".freeze
|
402
430
|
|
403
431
|
# @see MachOStructure::SIZEOF
|
404
432
|
# @api private
|
@@ -408,7 +436,7 @@ module MachO
|
|
408
436
|
def initialize(view, cmd, cmdsize, segname, vmaddr, vmsize, fileoff,
|
409
437
|
filesize, maxprot, initprot, nsects, flags)
|
410
438
|
super(view, cmd, cmdsize)
|
411
|
-
@segname = segname
|
439
|
+
@segname = segname
|
412
440
|
@vmaddr = vmaddr
|
413
441
|
@vmsize = vmsize
|
414
442
|
@fileoff = fileoff
|
@@ -448,6 +476,22 @@ module MachO
|
|
448
476
|
return false if flag.nil?
|
449
477
|
flags & flag == flag
|
450
478
|
end
|
479
|
+
|
480
|
+
# @return [Hash] a hash representation of this {SegmentCommand}
|
481
|
+
def to_h
|
482
|
+
{
|
483
|
+
"segname" => segname,
|
484
|
+
"vmaddr" => vmaddr,
|
485
|
+
"vmsize" => vmsize,
|
486
|
+
"fileoff" => fileoff,
|
487
|
+
"filesize" => filesize,
|
488
|
+
"maxprot" => maxprot,
|
489
|
+
"initprot" => initprot,
|
490
|
+
"nsects" => nsects,
|
491
|
+
"flags" => flags,
|
492
|
+
"sections" => sections.map(&:to_h),
|
493
|
+
}.merge super
|
494
|
+
end
|
451
495
|
end
|
452
496
|
|
453
497
|
# A load command indicating that part of this file is to be mapped into
|
@@ -455,7 +499,7 @@ module MachO
|
|
455
499
|
class SegmentCommand64 < SegmentCommand
|
456
500
|
# @see MachOStructure::FORMAT
|
457
501
|
# @api private
|
458
|
-
FORMAT = "L=
|
502
|
+
FORMAT = "L=2Z16Q=4l=2L=2".freeze
|
459
503
|
|
460
504
|
# @see MachOStructure::SIZEOF
|
461
505
|
# @api private
|
@@ -510,6 +554,16 @@ module MachO
|
|
510
554
|
[cmd, cmdsize, string_offsets[:name], timestamp, current_version,
|
511
555
|
compatibility_version].pack(format) + string_payload
|
512
556
|
end
|
557
|
+
|
558
|
+
# @return [Hash] a hash representation of this {DylibCommand}
|
559
|
+
def to_h
|
560
|
+
{
|
561
|
+
"name" => name.to_h,
|
562
|
+
"timestamp" => timestamp,
|
563
|
+
"current_version" => current_version,
|
564
|
+
"compatibility_version" => compatibility_version,
|
565
|
+
}.merge super
|
566
|
+
end
|
513
567
|
end
|
514
568
|
|
515
569
|
# A load command representing some aspect of the dynamic linker, depending
|
@@ -546,6 +600,13 @@ module MachO
|
|
546
600
|
cmdsize = SIZEOF + string_payload.bytesize
|
547
601
|
[cmd, cmdsize, string_offsets[:name]].pack(format) + string_payload
|
548
602
|
end
|
603
|
+
|
604
|
+
# @return [Hash] a hash representation of this {DylinkerCommand}
|
605
|
+
def to_h
|
606
|
+
{
|
607
|
+
"name" => name.to_h,
|
608
|
+
}.merge super
|
609
|
+
end
|
549
610
|
end
|
550
611
|
|
551
612
|
# A load command used to indicate dynamic libraries used in prebinding.
|
@@ -576,6 +637,15 @@ module MachO
|
|
576
637
|
@nmodules = nmodules
|
577
638
|
@linked_modules = linked_modules
|
578
639
|
end
|
640
|
+
|
641
|
+
# @return [Hash] a hash representation of this {PreboundDylibCommand}
|
642
|
+
def to_h
|
643
|
+
{
|
644
|
+
"name" => name.to_h,
|
645
|
+
"nmodules" => nmodules,
|
646
|
+
"linked_modules" => linked_modules,
|
647
|
+
}.merge super
|
648
|
+
end
|
579
649
|
end
|
580
650
|
|
581
651
|
# A load command used to represent threads.
|
@@ -641,6 +711,20 @@ module MachO
|
|
641
711
|
@reserved5 = reserved5
|
642
712
|
@reserved6 = reserved6
|
643
713
|
end
|
714
|
+
|
715
|
+
# @return [Hash] a hash representation of this {RoutinesCommand}
|
716
|
+
def to_h
|
717
|
+
{
|
718
|
+
"init_address" => init_address,
|
719
|
+
"init_module" => init_module,
|
720
|
+
"reserved1" => reserved1,
|
721
|
+
"reserved2" => reserved2,
|
722
|
+
"reserved3" => reserved3,
|
723
|
+
"reserved4" => reserved4,
|
724
|
+
"reserved5" => reserved5,
|
725
|
+
"reserved6" => reserved6,
|
726
|
+
}.merge super
|
727
|
+
end
|
644
728
|
end
|
645
729
|
|
646
730
|
# A load command containing the address of the dynamic shared library
|
@@ -675,6 +759,13 @@ module MachO
|
|
675
759
|
super(view, cmd, cmdsize)
|
676
760
|
@umbrella = LCStr.new(self, umbrella)
|
677
761
|
end
|
762
|
+
|
763
|
+
# @return [Hash] a hash representation of this {SubFrameworkCommand}
|
764
|
+
def to_h
|
765
|
+
{
|
766
|
+
"umbrella" => umbrella.to_h,
|
767
|
+
}.merge super
|
768
|
+
end
|
678
769
|
end
|
679
770
|
|
680
771
|
# A load command signifying membership of a subumbrella containing the name
|
@@ -696,6 +787,13 @@ module MachO
|
|
696
787
|
super(view, cmd, cmdsize)
|
697
788
|
@sub_umbrella = LCStr.new(self, sub_umbrella)
|
698
789
|
end
|
790
|
+
|
791
|
+
# @return [Hash] a hash representation of this {SubUmbrellaCommand}
|
792
|
+
def to_h
|
793
|
+
{
|
794
|
+
"sub_umbrella" => sub_umbrella.to_h,
|
795
|
+
}.merge super
|
796
|
+
end
|
699
797
|
end
|
700
798
|
|
701
799
|
# A load command signifying a sublibrary of a shared library. Corresponds
|
@@ -717,6 +815,13 @@ module MachO
|
|
717
815
|
super(view, cmd, cmdsize)
|
718
816
|
@sub_library = LCStr.new(self, sub_library)
|
719
817
|
end
|
818
|
+
|
819
|
+
# @return [Hash] a hash representation of this {SubLibraryCommand}
|
820
|
+
def to_h
|
821
|
+
{
|
822
|
+
"sub_library" => sub_library.to_h,
|
823
|
+
}.merge super
|
824
|
+
end
|
720
825
|
end
|
721
826
|
|
722
827
|
# A load command signifying a shared library that is a subframework of
|
@@ -738,6 +843,13 @@ module MachO
|
|
738
843
|
super(view, cmd, cmdsize)
|
739
844
|
@sub_client = LCStr.new(self, sub_client)
|
740
845
|
end
|
846
|
+
|
847
|
+
# @return [Hash] a hash representation of this {SubClientCommand}
|
848
|
+
def to_h
|
849
|
+
{
|
850
|
+
"sub_client" => sub_client.to_h,
|
851
|
+
}.merge super
|
852
|
+
end
|
741
853
|
end
|
742
854
|
|
743
855
|
# A load command containing the offsets and sizes of the link-edit 4.3BSD
|
@@ -749,10 +861,10 @@ module MachO
|
|
749
861
|
# @return [Integer] the number of symbol table entries
|
750
862
|
attr_reader :nsyms
|
751
863
|
|
752
|
-
# @return the string table's offset
|
864
|
+
# @return [Integer] the string table's offset
|
753
865
|
attr_reader :stroff
|
754
866
|
|
755
|
-
# @return the string table size in bytes
|
867
|
+
# @return [Integer] the string table size in bytes
|
756
868
|
attr_reader :strsize
|
757
869
|
|
758
870
|
# @see MachOStructure::FORMAT
|
@@ -771,6 +883,16 @@ module MachO
|
|
771
883
|
@stroff = stroff
|
772
884
|
@strsize = strsize
|
773
885
|
end
|
886
|
+
|
887
|
+
# @return [Hash] a hash representation of this {SymtabCommand}
|
888
|
+
def to_h
|
889
|
+
{
|
890
|
+
"symoff" => symoff,
|
891
|
+
"nsyms" => nsyms,
|
892
|
+
"stroff" => stroff,
|
893
|
+
"strsize" => strsize,
|
894
|
+
}.merge super
|
895
|
+
end
|
774
896
|
end
|
775
897
|
|
776
898
|
# A load command containing symbolic information needed to support data
|
@@ -864,6 +986,30 @@ module MachO
|
|
864
986
|
@locreloff = locreloff
|
865
987
|
@nlocrel = nlocrel
|
866
988
|
end
|
989
|
+
|
990
|
+
# @return [Hash] a hash representation of this {DysymtabCommand}
|
991
|
+
def to_h
|
992
|
+
{
|
993
|
+
"ilocalsym" => ilocalsym,
|
994
|
+
"nlocalsym" => nlocalsym,
|
995
|
+
"iextdefsym" => iextdefsym,
|
996
|
+
"nextdefsym" => nextdefsym,
|
997
|
+
"iundefsym" => iundefsym,
|
998
|
+
"nundefsym" => nundefsym,
|
999
|
+
"tocoff" => tocoff,
|
1000
|
+
"ntoc" => ntoc,
|
1001
|
+
"modtaboff" => modtaboff,
|
1002
|
+
"nmodtab" => nmodtab,
|
1003
|
+
"extrefsymoff" => extrefsymoff,
|
1004
|
+
"nextrefsyms" => nextrefsyms,
|
1005
|
+
"indirectsymoff" => indirectsymoff,
|
1006
|
+
"nindirectsyms" => nindirectsyms,
|
1007
|
+
"extreloff" => extreloff,
|
1008
|
+
"nextrel" => nextrel,
|
1009
|
+
"locreloff" => locreloff,
|
1010
|
+
"nlocrel" => nlocrel,
|
1011
|
+
}.merge super
|
1012
|
+
end
|
867
1013
|
end
|
868
1014
|
|
869
1015
|
# A load command containing the offset and number of hints in the two-level
|
@@ -895,6 +1041,15 @@ module MachO
|
|
895
1041
|
@table = TwolevelHintsTable.new(view, htoffset, nhints)
|
896
1042
|
end
|
897
1043
|
|
1044
|
+
# @return [Hash] a hash representation of this {TwolevelHintsCommand}
|
1045
|
+
def to_h
|
1046
|
+
{
|
1047
|
+
"htoffset" => htoffset,
|
1048
|
+
"nhints" => nhints,
|
1049
|
+
"table" => table.hints.map(&:to_h),
|
1050
|
+
}.merge super
|
1051
|
+
end
|
1052
|
+
|
898
1053
|
# A representation of the two-level namespace lookup hints table exposed
|
899
1054
|
# by a {TwolevelHintsCommand} (`LC_TWOLEVEL_HINTS`).
|
900
1055
|
class TwolevelHintsTable
|
@@ -927,6 +1082,14 @@ module MachO
|
|
927
1082
|
@isub_image = blob >> 24
|
928
1083
|
@itoc = blob & 0x00FFFFFF
|
929
1084
|
end
|
1085
|
+
|
1086
|
+
# @return [Hash] a hash representation of this {TwolevelHint}
|
1087
|
+
def to_h
|
1088
|
+
{
|
1089
|
+
"isub_image" => isub_image,
|
1090
|
+
"itoc" => itoc,
|
1091
|
+
}
|
1092
|
+
end
|
930
1093
|
end
|
931
1094
|
end
|
932
1095
|
end
|
@@ -950,6 +1113,13 @@ module MachO
|
|
950
1113
|
super(view, cmd, cmdsize)
|
951
1114
|
@cksum = cksum
|
952
1115
|
end
|
1116
|
+
|
1117
|
+
# @return [Hash] a hash representation of this {PrebindCksumCommand}
|
1118
|
+
def to_h
|
1119
|
+
{
|
1120
|
+
"cksum" => cksum,
|
1121
|
+
}.merge super
|
1122
|
+
end
|
953
1123
|
end
|
954
1124
|
|
955
1125
|
# A load command representing an rpath, which specifies a path that should
|
@@ -984,6 +1154,13 @@ module MachO
|
|
984
1154
|
cmdsize = SIZEOF + string_payload.bytesize
|
985
1155
|
[cmd, cmdsize, string_offsets[:path]].pack(format) + string_payload
|
986
1156
|
end
|
1157
|
+
|
1158
|
+
# @return [Hash] a hash representation of this {RpathCommand}
|
1159
|
+
def to_h
|
1160
|
+
{
|
1161
|
+
"path" => path.to_h,
|
1162
|
+
}.merge super
|
1163
|
+
end
|
987
1164
|
end
|
988
1165
|
|
989
1166
|
# A load command representing the offsets and sizes of a blob of data in
|
@@ -1011,6 +1188,14 @@ module MachO
|
|
1011
1188
|
@dataoff = dataoff
|
1012
1189
|
@datasize = datasize
|
1013
1190
|
end
|
1191
|
+
|
1192
|
+
# @return [Hash] a hash representation of this {LinkeditDataCommand}
|
1193
|
+
def to_h
|
1194
|
+
{
|
1195
|
+
"dataoff" => dataoff,
|
1196
|
+
"datasize" => datasize,
|
1197
|
+
}.merge super
|
1198
|
+
end
|
1014
1199
|
end
|
1015
1200
|
|
1016
1201
|
# A load command representing the offset to and size of an encrypted
|
@@ -1040,20 +1225,20 @@ module MachO
|
|
1040
1225
|
@cryptsize = cryptsize
|
1041
1226
|
@cryptid = cryptid
|
1042
1227
|
end
|
1228
|
+
|
1229
|
+
# @return [Hash] a hash representation of this {EncryptionInfoCommand}
|
1230
|
+
def to_h
|
1231
|
+
{
|
1232
|
+
"cryptoff" => cryptoff,
|
1233
|
+
"cryptsize" => cryptsize,
|
1234
|
+
"cryptid" => cryptid,
|
1235
|
+
}.merge super
|
1236
|
+
end
|
1043
1237
|
end
|
1044
1238
|
|
1045
1239
|
# A load command representing the offset to and size of an encrypted
|
1046
1240
|
# segment. Corresponds to LC_ENCRYPTION_INFO_64.
|
1047
|
-
class EncryptionInfoCommand64 <
|
1048
|
-
# @return [Integer] the offset to the encrypted segment
|
1049
|
-
attr_reader :cryptoff
|
1050
|
-
|
1051
|
-
# @return [Integer] the size of the encrypted segment
|
1052
|
-
attr_reader :cryptsize
|
1053
|
-
|
1054
|
-
# @return [Integer] the encryption system, or 0 if not encrypted yet
|
1055
|
-
attr_reader :cryptid
|
1056
|
-
|
1241
|
+
class EncryptionInfoCommand64 < EncryptionInfoCommand
|
1057
1242
|
# @return [Integer] 64-bit padding value
|
1058
1243
|
attr_reader :pad
|
1059
1244
|
|
@@ -1067,12 +1252,16 @@ module MachO
|
|
1067
1252
|
|
1068
1253
|
# @api private
|
1069
1254
|
def initialize(view, cmd, cmdsize, cryptoff, cryptsize, cryptid, pad)
|
1070
|
-
super(view, cmd, cmdsize)
|
1071
|
-
@cryptoff = cryptoff
|
1072
|
-
@cryptsize = cryptsize
|
1073
|
-
@cryptid = cryptid
|
1255
|
+
super(view, cmd, cmdsize, cryptoff, cryptsize, cryptid)
|
1074
1256
|
@pad = pad
|
1075
1257
|
end
|
1258
|
+
|
1259
|
+
# @return [Hash] a hash representation of this {EncryptionInfoCommand64}
|
1260
|
+
def to_h
|
1261
|
+
{
|
1262
|
+
"pad" => pad,
|
1263
|
+
}.merge super
|
1264
|
+
end
|
1076
1265
|
end
|
1077
1266
|
|
1078
1267
|
# A load command containing the minimum OS version on which the binary
|
@@ -1121,6 +1310,16 @@ module MachO
|
|
1121
1310
|
|
1122
1311
|
segs.join(".")
|
1123
1312
|
end
|
1313
|
+
|
1314
|
+
# @return [Hash] a hash representation of this {VersionMinCommand}
|
1315
|
+
def to_h
|
1316
|
+
{
|
1317
|
+
"version" => version,
|
1318
|
+
"version_string" => version_string,
|
1319
|
+
"sdk" => sdk,
|
1320
|
+
"sdk_string" => sdk_string,
|
1321
|
+
}.merge super
|
1322
|
+
end
|
1124
1323
|
end
|
1125
1324
|
|
1126
1325
|
# A load command containing the minimum OS version on which
|
@@ -1156,6 +1355,40 @@ module MachO
|
|
1156
1355
|
@tool_entries = ToolEntries.new(view, ntools)
|
1157
1356
|
end
|
1158
1357
|
|
1358
|
+
# A string representation of the binary's minimum OS version.
|
1359
|
+
# @return [String] a string representing the minimum OS version.
|
1360
|
+
def minos_string
|
1361
|
+
binary = "%032b" % minos
|
1362
|
+
segs = [
|
1363
|
+
binary[0..15], binary[16..23], binary[24..31]
|
1364
|
+
].map { |s| s.to_i(2) }
|
1365
|
+
|
1366
|
+
segs.join(".")
|
1367
|
+
end
|
1368
|
+
|
1369
|
+
# A string representation of the binary's SDK version.
|
1370
|
+
# @return [String] a string representing the SDK version.
|
1371
|
+
def sdk_string
|
1372
|
+
binary = "%032b" % sdk
|
1373
|
+
segs = [
|
1374
|
+
binary[0..15], binary[16..23], binary[24..31]
|
1375
|
+
].map { |s| s.to_i(2) }
|
1376
|
+
|
1377
|
+
segs.join(".")
|
1378
|
+
end
|
1379
|
+
|
1380
|
+
# @return [Hash] a hash representation of this {BuildVersionCommand}
|
1381
|
+
def to_h
|
1382
|
+
{
|
1383
|
+
"platform" => platform,
|
1384
|
+
"minos" => minos,
|
1385
|
+
"minos_string" => minos_string,
|
1386
|
+
"sdk" => sdk,
|
1387
|
+
"sdk_string" => sdk_string,
|
1388
|
+
"tool_entries" => tool_entries.tools.map(&:to_h),
|
1389
|
+
}.merge super
|
1390
|
+
end
|
1391
|
+
|
1159
1392
|
# A representation of the tool versions exposed
|
1160
1393
|
# by a {BuildVersionCommand} (`LC_BUILD_VERSION`).
|
1161
1394
|
class ToolEntries
|
@@ -1181,36 +1414,22 @@ module MachO
|
|
1181
1414
|
# @return [Integer] the tool's version number
|
1182
1415
|
attr_reader :version
|
1183
1416
|
|
1184
|
-
# @param tool 32-bit integer
|
1185
|
-
#
|
1417
|
+
# @param tool [Integer] 32-bit integer
|
1418
|
+
# @param version [Integer] 32-bit integer
|
1186
1419
|
# @api private
|
1187
1420
|
def initialize(tool, version)
|
1188
1421
|
@tool = tool
|
1189
1422
|
@version = version
|
1190
1423
|
end
|
1191
|
-
end
|
1192
|
-
end
|
1193
1424
|
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
segs.join(".")
|
1203
|
-
end
|
1204
|
-
|
1205
|
-
# A string representation of the binary's SDK version.
|
1206
|
-
# @return [String] a string representing the SDK version.
|
1207
|
-
def sdk_string
|
1208
|
-
binary = "%032b" % sdk
|
1209
|
-
segs = [
|
1210
|
-
binary[0..15], binary[16..23], binary[24..31]
|
1211
|
-
].map { |s| s.to_i(2) }
|
1212
|
-
|
1213
|
-
segs.join(".")
|
1425
|
+
# @return [Hash] a hash representation of this {Tool}
|
1426
|
+
def to_h
|
1427
|
+
{
|
1428
|
+
"tool" => tool,
|
1429
|
+
"version" => version,
|
1430
|
+
}
|
1431
|
+
end
|
1432
|
+
end
|
1214
1433
|
end
|
1215
1434
|
end
|
1216
1435
|
|
@@ -1272,6 +1491,22 @@ module MachO
|
|
1272
1491
|
@export_off = export_off
|
1273
1492
|
@export_size = export_size
|
1274
1493
|
end
|
1494
|
+
|
1495
|
+
# @return [Hash] a hash representation of this {DyldInfoCommand}
|
1496
|
+
def to_h
|
1497
|
+
{
|
1498
|
+
"rebase_off" => rebase_off,
|
1499
|
+
"rebase_size" => rebase_size,
|
1500
|
+
"bind_off" => bind_off,
|
1501
|
+
"bind_size" => bind_size,
|
1502
|
+
"weak_bind_off" => weak_bind_off,
|
1503
|
+
"weak_bind_size" => weak_bind_size,
|
1504
|
+
"lazy_bind_off" => lazy_bind_off,
|
1505
|
+
"lazy_bind_size" => lazy_bind_size,
|
1506
|
+
"export_off" => export_off,
|
1507
|
+
"export_size" => export_size,
|
1508
|
+
}.merge super
|
1509
|
+
end
|
1275
1510
|
end
|
1276
1511
|
|
1277
1512
|
# A load command containing linker options embedded in object files.
|
@@ -1293,6 +1528,13 @@ module MachO
|
|
1293
1528
|
super(view, cmd, cmdsize)
|
1294
1529
|
@count = count
|
1295
1530
|
end
|
1531
|
+
|
1532
|
+
# @return [Hash] a hash representation of this {LinkerOptionCommand}
|
1533
|
+
def to_h
|
1534
|
+
{
|
1535
|
+
"count" => count,
|
1536
|
+
}.merge super
|
1537
|
+
end
|
1296
1538
|
end
|
1297
1539
|
|
1298
1540
|
# A load command specifying the offset of main(). Corresponds to LC_MAIN.
|
@@ -1317,6 +1559,14 @@ module MachO
|
|
1317
1559
|
@entryoff = entryoff
|
1318
1560
|
@stacksize = stacksize
|
1319
1561
|
end
|
1562
|
+
|
1563
|
+
# @return [Hash] a hash representation of this {EntryPointCommand}
|
1564
|
+
def to_h
|
1565
|
+
{
|
1566
|
+
"entryoff" => entryoff,
|
1567
|
+
"stacksize" => stacksize,
|
1568
|
+
}.merge super
|
1569
|
+
end
|
1320
1570
|
end
|
1321
1571
|
|
1322
1572
|
# A load command specifying the version of the sources used to build the
|
@@ -1350,6 +1600,14 @@ module MachO
|
|
1350
1600
|
|
1351
1601
|
segs.join(".")
|
1352
1602
|
end
|
1603
|
+
|
1604
|
+
# @return [Hash] a hash representation of this {SourceVersionCommand}
|
1605
|
+
def to_h
|
1606
|
+
{
|
1607
|
+
"version" => version,
|
1608
|
+
"version_string" => version_string,
|
1609
|
+
}.merge super
|
1610
|
+
end
|
1353
1611
|
end
|
1354
1612
|
|
1355
1613
|
# An obsolete load command containing the offset and size of the (GNU style)
|
@@ -1375,6 +1633,14 @@ module MachO
|
|
1375
1633
|
@offset = offset
|
1376
1634
|
@size = size
|
1377
1635
|
end
|
1636
|
+
|
1637
|
+
# @return [Hash] a hash representation of this {SymsegCommand}
|
1638
|
+
def to_h
|
1639
|
+
{
|
1640
|
+
"offset" => offset,
|
1641
|
+
"size" => size,
|
1642
|
+
}.merge super
|
1643
|
+
end
|
1378
1644
|
end
|
1379
1645
|
|
1380
1646
|
# An obsolete load command containing a free format string table. Each
|
@@ -1412,6 +1678,14 @@ module MachO
|
|
1412
1678
|
@name = LCStr.new(self, name)
|
1413
1679
|
@header_addr = header_addr
|
1414
1680
|
end
|
1681
|
+
|
1682
|
+
# @return [Hash] a hash representation of this {FvmfileCommand}
|
1683
|
+
def to_h
|
1684
|
+
{
|
1685
|
+
"name" => name.to_h,
|
1686
|
+
"header_addr" => header_addr,
|
1687
|
+
}.merge super
|
1688
|
+
end
|
1415
1689
|
end
|
1416
1690
|
|
1417
1691
|
# An obsolete load command containing the path to a library to be loaded
|
@@ -1440,6 +1714,52 @@ module MachO
|
|
1440
1714
|
@minor_version = minor_version
|
1441
1715
|
@header_addr = header_addr
|
1442
1716
|
end
|
1717
|
+
|
1718
|
+
# @return [Hash] a hash representation of this {FvmlibCommand}
|
1719
|
+
def to_h
|
1720
|
+
{
|
1721
|
+
"name" => name.to_h,
|
1722
|
+
"minor_version" => minor_version,
|
1723
|
+
"header_addr" => header_addr,
|
1724
|
+
}.merge super
|
1725
|
+
end
|
1726
|
+
end
|
1727
|
+
|
1728
|
+
# A load command containing an owner name and offset/size for an arbitrary data region.
|
1729
|
+
# Corresponds to LC_NOTE.
|
1730
|
+
class NoteCommand < LoadCommand
|
1731
|
+
# @return [String] the name of the owner for this note
|
1732
|
+
attr_reader :data_owner
|
1733
|
+
|
1734
|
+
# @return [Integer] the offset, within the file, of the note
|
1735
|
+
attr_reader :offset
|
1736
|
+
|
1737
|
+
# @return [Integer] the size, in bytes, of the note
|
1738
|
+
attr_reader :size
|
1739
|
+
|
1740
|
+
# @see MachOStructure::FORMAT
|
1741
|
+
# @api private
|
1742
|
+
FORMAT = "L=2Z16Q=2".freeze
|
1743
|
+
|
1744
|
+
# @see MachOStructure::SIZEOF
|
1745
|
+
# @api private
|
1746
|
+
SIZEOF = 48
|
1747
|
+
|
1748
|
+
def initialize(view, cmd, cmdsize, data_owner, offset, size)
|
1749
|
+
super(view, cmd, cmdsize)
|
1750
|
+
@data_owner = data_owner
|
1751
|
+
@offset = offset
|
1752
|
+
@size = size
|
1753
|
+
end
|
1754
|
+
|
1755
|
+
# @return [Hash] a hash representation of this {NoteCommand}
|
1756
|
+
def to_h
|
1757
|
+
{
|
1758
|
+
"data_owner" => data_owner,
|
1759
|
+
"offset" => offset,
|
1760
|
+
"size" => size,
|
1761
|
+
}.merge super
|
1762
|
+
end
|
1443
1763
|
end
|
1444
1764
|
end
|
1445
1765
|
end
|
data/lib/macho/macho_file.rb
CHANGED
@@ -25,7 +25,7 @@ module MachO
|
|
25
25
|
# @note load commands are provided in order of ascending offset.
|
26
26
|
attr_reader :load_commands
|
27
27
|
|
28
|
-
# Creates a new
|
28
|
+
# Creates a new instance from a binary string.
|
29
29
|
# @param bin [String] a binary string containing raw Mach-O data
|
30
30
|
# @return [MachOFile] a new MachOFile
|
31
31
|
def self.new_from_bin(bin)
|
@@ -35,7 +35,7 @@ module MachO
|
|
35
35
|
instance
|
36
36
|
end
|
37
37
|
|
38
|
-
# Creates a new
|
38
|
+
# Creates a new instance from data read from the given filename.
|
39
39
|
# @param filename [String] the Mach-O file to load from
|
40
40
|
# @raise [ArgumentError] if the given file does not exist
|
41
41
|
def initialize(filename)
|
@@ -408,6 +408,14 @@ module MachO
|
|
408
408
|
File.open(@filename, "wb") { |f| f.write(@raw_data) }
|
409
409
|
end
|
410
410
|
|
411
|
+
# @return [Hash] a hash representation of this {MachOFile}
|
412
|
+
def to_h
|
413
|
+
{
|
414
|
+
"header" => header.to_h,
|
415
|
+
"load_commands" => load_commands.map(&:to_h),
|
416
|
+
}
|
417
|
+
end
|
418
|
+
|
411
419
|
private
|
412
420
|
|
413
421
|
# The file's Mach-O header structure.
|
data/lib/macho/sections.rb
CHANGED
@@ -104,7 +104,7 @@ module MachO
|
|
104
104
|
attr_reader :reserved2
|
105
105
|
|
106
106
|
# @see MachOStructure::FORMAT
|
107
|
-
FORMAT = "
|
107
|
+
FORMAT = "Z16Z16L=9".freeze
|
108
108
|
|
109
109
|
# @see MachOStructure::SIZEOF
|
110
110
|
SIZEOF = 68
|
@@ -125,16 +125,14 @@ module MachO
|
|
125
125
|
@reserved2 = reserved2
|
126
126
|
end
|
127
127
|
|
128
|
-
# @return [String] the section's name
|
129
|
-
# removed
|
128
|
+
# @return [String] the section's name
|
130
129
|
def section_name
|
131
|
-
sectname
|
130
|
+
sectname
|
132
131
|
end
|
133
132
|
|
134
|
-
# @return [String] the parent segment's name
|
135
|
-
# characters removed
|
133
|
+
# @return [String] the parent segment's name
|
136
134
|
def segment_name
|
137
|
-
segname
|
135
|
+
segname
|
138
136
|
end
|
139
137
|
|
140
138
|
# @return [Boolean] whether the section is empty (i.e, {size} is 0)
|
@@ -151,6 +149,23 @@ module MachO
|
|
151
149
|
return false if flag.nil?
|
152
150
|
flags & flag == flag
|
153
151
|
end
|
152
|
+
|
153
|
+
# @return [Hash] a hash representation of this {Section}
|
154
|
+
def to_h
|
155
|
+
{
|
156
|
+
"sectname" => sectname,
|
157
|
+
"segname" => segname,
|
158
|
+
"addr" => addr,
|
159
|
+
"size" => size,
|
160
|
+
"offset" => offset,
|
161
|
+
"align" => align,
|
162
|
+
"reloff" => reloff,
|
163
|
+
"nreloc" => nreloc,
|
164
|
+
"flags" => flags,
|
165
|
+
"reserved1" => reserved1,
|
166
|
+
"reserved2" => reserved2,
|
167
|
+
}.merge super
|
168
|
+
end
|
154
169
|
end
|
155
170
|
|
156
171
|
# Represents a section of a segment for 64-bit architectures.
|
@@ -159,7 +174,7 @@ module MachO
|
|
159
174
|
attr_reader :reserved3
|
160
175
|
|
161
176
|
# @see MachOStructure::FORMAT
|
162
|
-
FORMAT = "
|
177
|
+
FORMAT = "Z16Z16Q=2L=8".freeze
|
163
178
|
|
164
179
|
# @see MachOStructure::SIZEOF
|
165
180
|
SIZEOF = 80
|
@@ -171,6 +186,13 @@ module MachO
|
|
171
186
|
nreloc, flags, reserved1, reserved2)
|
172
187
|
@reserved3 = reserved3
|
173
188
|
end
|
189
|
+
|
190
|
+
# @return [Hash] a hash representation of this {Section64}
|
191
|
+
def to_h
|
192
|
+
{
|
193
|
+
"reserved3" => reserved3,
|
194
|
+
}.merge super
|
195
|
+
end
|
174
196
|
end
|
175
197
|
end
|
176
198
|
end
|
data/lib/macho/structure.rb
CHANGED
@@ -26,5 +26,15 @@ module MachO
|
|
26
26
|
|
27
27
|
new(*bin.unpack(format))
|
28
28
|
end
|
29
|
+
|
30
|
+
# @return [Hash] a hash representation of this {MachOStructure}.
|
31
|
+
def to_h
|
32
|
+
{
|
33
|
+
"structure" => {
|
34
|
+
"format" => self.class::FORMAT,
|
35
|
+
"bytesize" => self.class.bytesize,
|
36
|
+
},
|
37
|
+
}
|
38
|
+
end
|
29
39
|
end
|
30
40
|
end
|
data/lib/macho/view.rb
CHANGED
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-macho
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0.pre.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- William Woodruff
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-06-
|
11
|
+
date: 2018-06-21 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A library for viewing and manipulating Mach-O files in Ruby.
|
14
|
-
email: william@
|
14
|
+
email: william@yossarian.net
|
15
15
|
executables: []
|
16
16
|
extensions: []
|
17
17
|
extra_rdoc_files: []
|
@@ -42,12 +42,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
42
42
|
requirements:
|
43
43
|
- - ">="
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
version: 2.
|
45
|
+
version: '2.1'
|
46
46
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
47
|
requirements:
|
48
|
-
- - "
|
48
|
+
- - ">"
|
49
49
|
- !ruby/object:Gem::Version
|
50
|
-
version:
|
50
|
+
version: 1.3.1
|
51
51
|
requirements: []
|
52
52
|
rubyforge_project:
|
53
53
|
rubygems_version: 2.7.6
|