@@ -180,6 +180,12 @@ func (s *Section) Data() ([]byte, error) {
180
180
// Open returns a new ReadSeeker reading the Mach-O section.
181
181
func (s * Section ) Open () io.ReadSeeker { return io .NewSectionReader (s .sr , 0 , 1 << 63 - 1 ) }
182
182
183
+ // A Dylinker represents a Mach-O load dynamic library command.
184
+ type Dylinker struct {
185
+ LoadBytes
186
+ Name string
187
+ }
188
+
183
189
// A Dylib represents a Mach-O load dynamic library command.
184
190
type Dylib struct {
185
191
LoadBytes
@@ -269,9 +275,19 @@ func (f *File) Close() error {
269
275
return err
270
276
}
271
277
272
- // NewFile creates a new File for accessing a Mach-O binary in an underlying reader.
273
- // The Mach-O binary is expected to start at position 0 in the ReaderAt.
278
+ // NewFile creates a new macho.File for accessing a Mach-o binary file in an underlying reader.
274
279
func NewFile (r io.ReaderAt ) (* File , error ) {
280
+ return newFileInternal (r , false )
281
+ }
282
+
283
+ // NewFileFromMemory creates a new macho.File for accessing a Mach-O binary in-memory image in an underlying reader.
284
+ func NewFileFromMemory (r io.ReaderAt ) (* File , error ) {
285
+ return newFileInternal (r , true )
286
+ }
287
+
288
+ // NewFile creates a new File for accessing a PE binary in an underlying reader.
289
+ func newFileInternal (r io.ReaderAt , memoryMode bool ) (* File , error ) {
290
+
275
291
f := new (File )
276
292
sr := io .NewSectionReader (r , 0 , 1 << 63 - 1 )
277
293
@@ -342,6 +358,20 @@ func NewFile(r io.ReaderAt) (*File, error) {
342
358
l .LoadBytes = LoadBytes (cmddat )
343
359
f .Loads [i ] = l
344
360
361
+ case LoadCmdDylinker :
362
+ var hdr DylinkerCmd
363
+ b := bytes .NewReader (cmddat )
364
+ if err := binary .Read (b , bo , & hdr ); err != nil {
365
+ return nil , err
366
+ }
367
+ l := new (Dylinker )
368
+ if hdr .Name >= uint32 (len (cmddat )) {
369
+ return nil , & FormatError {offset , "invalid name in dynamic library command" , hdr .Name }
370
+ }
371
+ l .Name = cstring (cmddat [hdr .Name :])
372
+ l .LoadBytes = LoadBytes (cmddat )
373
+ f .Loads [i ] = l
374
+
345
375
case LoadCmdDylib :
346
376
var hdr DylibCmd
347
377
b := bytes .NewReader (cmddat )
@@ -366,19 +396,52 @@ func NewFile(r io.ReaderAt) (*File, error) {
366
396
return nil , err
367
397
}
368
398
strtab := make ([]byte , hdr .Strsize )
369
- if _ , err := r .ReadAt (strtab , int64 (hdr .Stroff )); err != nil {
370
- return nil , err
399
+
400
+ var linkeditAddr , textAddr , linkeditOffset int64
401
+ if ! memoryMode {
402
+ if _ , err := r .ReadAt (strtab , int64 (hdr .Stroff )); err != nil {
403
+ return nil , err
404
+ }
405
+ } else {
406
+ // in memory, we have to translate the file offsets for strtab/symtab into offsets into LINKEDIT segment
407
+ for _ , load := range f .Loads {
408
+ switch segment := load .(type ) {
409
+ case * Segment :
410
+ if segment == nil {
411
+ continue
412
+ }
413
+ if segment .Name == "__LINKEDIT" {
414
+ linkeditAddr = int64 (segment .Addr )
415
+ linkeditOffset = int64 (segment .Offset )
416
+ } else if segment .Name == "__TEXT" {
417
+ textAddr = int64 (segment .Addr )
418
+ }
419
+ }
420
+ }
421
+ strtabAddr := (linkeditAddr - textAddr ) + (int64 (hdr .Stroff ) - linkeditOffset )
422
+ if _ , err := r .ReadAt (strtab , strtabAddr ); err != nil {
423
+ return nil , err
424
+ }
371
425
}
426
+
372
427
var symsz int
373
428
if f .Magic == Magic64 {
374
429
symsz = 16
375
430
} else {
376
431
symsz = 12
377
432
}
378
433
symdat := make ([]byte , int (hdr .Nsyms )* symsz )
379
- if _ , err := r .ReadAt (symdat , int64 (hdr .Symoff )); err != nil {
380
- return nil , err
434
+
435
+ if ! memoryMode {
436
+ if _ , err := r .ReadAt (symdat , int64 (hdr .Symoff )); err != nil {
437
+ return nil , err
438
+ }
439
+ } else {
440
+ if _ , err := r .ReadAt (symdat , (linkeditAddr - textAddr )+ (int64 (hdr .Symoff )- linkeditOffset )); err != nil {
441
+ return nil , err
442
+ }
381
443
}
444
+
382
445
st , err := f .parseSymtab (symdat , strtab , cmddat , & hdr , offset )
383
446
if err != nil {
384
447
return nil , err
@@ -453,53 +516,63 @@ func NewFile(r io.ReaderAt) (*File, error) {
453
516
var dylinkInfo DylinkInfo
454
517
// Rebase deets
455
518
if dylinkInfoCmd .Rebasesize > 0 {
456
- rebase := make ([]byte , dylinkInfoCmd .Rebasesize )
457
- if _ , err := r .ReadAt (rebase , int64 (dylinkInfoCmd .Rebaseoff )); err != nil {
458
- return nil , err
519
+ if ! memoryMode { // this data is in LINKEDIT already
520
+ rebase := make ([]byte , dylinkInfoCmd .Rebasesize )
521
+ if _ , err := r .ReadAt (rebase , int64 (dylinkInfoCmd .Rebaseoff )); err != nil {
522
+ return nil , err
523
+ }
524
+ dylinkInfo .RebaseDat = rebase
459
525
}
460
526
dylinkInfo .RebaseLen = dylinkInfoCmd .Rebasesize
461
527
dylinkInfo .RebaseOffset = uint64 (dylinkInfoCmd .Rebaseoff )
462
- dylinkInfo .RebaseDat = rebase
463
528
}
464
529
// BindingInfo deets
465
530
if dylinkInfoCmd .Bindinginfosize > 0 {
466
- binding := make ([]byte , dylinkInfoCmd .Bindinginfosize )
467
- if _ , err := r .ReadAt (binding , int64 (dylinkInfoCmd .Bindinginfooff )); err != nil {
468
- return nil , err
531
+ if ! memoryMode { // this data is in LINKEDIT already
532
+ binding := make ([]byte , dylinkInfoCmd .Bindinginfosize )
533
+ if _ , err := r .ReadAt (binding , int64 (dylinkInfoCmd .Bindinginfooff )); err != nil {
534
+ return nil , err
535
+ }
536
+ dylinkInfo .BindingInfoDat = binding
469
537
}
470
538
dylinkInfo .BindingInfoLen = dylinkInfoCmd .Bindinginfosize
471
539
dylinkInfo .BindingInfoOffset = uint64 (dylinkInfoCmd .Bindinginfooff )
472
- dylinkInfo .BindingInfoDat = binding
473
540
}
474
541
// Weak deets
475
542
if dylinkInfoCmd .Weakbindingsize > 0 {
476
- weak := make ([]byte , dylinkInfoCmd .Weakbindingsize )
477
- if _ , err := r .ReadAt (weak , int64 (dylinkInfoCmd .Weakbindingoff )); err != nil {
478
- return nil , err
543
+ if ! memoryMode { // this data is in LINKEDIT already
544
+ weak := make ([]byte , dylinkInfoCmd .Weakbindingsize )
545
+ if _ , err := r .ReadAt (weak , int64 (dylinkInfoCmd .Weakbindingoff )); err != nil {
546
+ return nil , err
547
+ }
548
+ dylinkInfo .WeakBindingDat = weak
479
549
}
480
550
dylinkInfo .WeakBindingLen = dylinkInfoCmd .Weakbindingsize
481
551
dylinkInfo .WeakBindingOffset = uint64 (dylinkInfoCmd .Weakbindingoff )
482
- dylinkInfo .WeakBindingDat = weak
483
552
}
484
553
// Lazy deets
485
554
if dylinkInfoCmd .Lazybindingsize > 0 {
486
- lazy := make ([]byte , dylinkInfoCmd .Lazybindingsize )
487
- if _ , err := r .ReadAt (lazy , int64 (dylinkInfoCmd .Lazybindingoff )); err != nil {
488
- return nil , err
555
+ if ! memoryMode { // this data is in LINKEDIT already
556
+ lazy := make ([]byte , dylinkInfoCmd .Lazybindingsize )
557
+ if _ , err := r .ReadAt (lazy , int64 (dylinkInfoCmd .Lazybindingoff )); err != nil {
558
+ return nil , err
559
+ }
560
+ dylinkInfo .LazyBindingDat = lazy
489
561
}
490
562
dylinkInfo .LazyBindingLen = dylinkInfoCmd .Lazybindingsize
491
563
dylinkInfo .LazyBindingOffset = uint64 (dylinkInfoCmd .Lazybindingoff )
492
- dylinkInfo .LazyBindingDat = lazy
493
564
}
494
565
// ExportInfo deets
495
566
if dylinkInfoCmd .Exportinfosize > 0 {
496
- export := make ([]byte , dylinkInfoCmd .Exportinfosize )
497
- if _ , err := r .ReadAt (export , int64 (dylinkInfoCmd .Exportinfooff )); err != nil {
498
- return nil , err
567
+ if ! memoryMode { // this data is in LINKEDIT already
568
+ export := make ([]byte , dylinkInfoCmd .Exportinfosize )
569
+ if _ , err := r .ReadAt (export , int64 (dylinkInfoCmd .Exportinfooff )); err != nil {
570
+ return nil , err
571
+ }
572
+ dylinkInfo .ExportInfoDat = export
499
573
}
500
574
dylinkInfo .ExportInfoLen = dylinkInfoCmd .Exportinfosize
501
575
dylinkInfo .ExportInfoOffset = uint64 (dylinkInfoCmd .Exportinfooff )
502
- dylinkInfo .ExportInfoDat = export
503
576
}
504
577
// Finalize the object
505
578
f .DylinkInfo = & dylinkInfo
@@ -623,10 +696,14 @@ func NewFile(r io.ReaderAt) (*File, error) {
623
696
if err := binary .Read (b , bo , & entryPoint ); err != nil {
624
697
return nil , err
625
698
}
626
- f .EntryPoint = entryPoint .entryoff
699
+ f .EntryPoint = entryPoint .EntryOff
627
700
}
628
701
if s != nil {
629
- s .sr = io .NewSectionReader (r , int64 (s .Offset ), int64 (s .Filesz ))
702
+ if ! memoryMode {
703
+ s .sr = io .NewSectionReader (r , int64 (s .Offset ), int64 (s .Filesz ))
704
+ } else {
705
+ s .sr = io .NewSectionReader (r , int64 (s .Addr ), int64 (s .Filesz ))
706
+ }
630
707
s .ReaderAt = s .sr
631
708
}
632
709
}
0 commit comments