123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- // Copyright 2018 Google Inc. All rights reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package symbol_inject
- import (
- "debug/macho"
- "encoding/binary"
- "fmt"
- "io"
- "os"
- "os/exec"
- "path/filepath"
- "sort"
- "strings"
- )
- func machoSymbolsFromFile(r io.ReaderAt) (*File, error) {
- machoFile, err := macho.NewFile(r)
- if err != nil {
- return nil, cantParseError{err}
- }
- return extractMachoSymbols(machoFile)
- }
- func extractMachoSymbols(machoFile *macho.File) (*File, error) {
- symbols := machoFile.Symtab.Syms
- sort.SliceStable(symbols, func(i, j int) bool {
- if symbols[i].Sect != symbols[j].Sect {
- return symbols[i].Sect < symbols[j].Sect
- }
- return symbols[i].Value < symbols[j].Value
- })
- file := &File{IsMachoFile: true}
- for _, section := range machoFile.Sections {
- file.Sections = append(file.Sections, &Section{
- Name: section.Name,
- Addr: section.Addr,
- Offset: uint64(section.Offset),
- Size: section.Size,
- })
- }
- for _, symbol := range symbols {
- if symbol.Sect > 0 {
- section := file.Sections[symbol.Sect-1]
- file.Symbols = append(file.Symbols, &Symbol{
- // symbols in macho files seem to be prefixed with an underscore
- Name: strings.TrimPrefix(symbol.Name, "_"),
- // MachO symbol value is virtual address of the symbol, convert it to offset into the section.
- Addr: symbol.Value - section.Addr,
- // MachO symbols don't have size information.
- Size: 0,
- Section: section,
- })
- }
- }
- return file, nil
- }
- func dumpMachoSymbols(r io.ReaderAt) error {
- machoFile, err := macho.NewFile(r)
- if err != nil {
- return cantParseError{err}
- }
- fmt.Println("&macho.File{")
- fmt.Println("\tSections: []*macho.Section{")
- for _, section := range machoFile.Sections {
- fmt.Printf("\t\t&macho.Section{SectionHeader: %#v},\n", section.SectionHeader)
- }
- fmt.Println("\t},")
- fmt.Println("\tSymtab: &macho.Symtab{")
- fmt.Println("\t\tSyms: []macho.Symbol{")
- for _, symbol := range machoFile.Symtab.Syms {
- fmt.Printf("\t\t\t%#v,\n", symbol)
- }
- fmt.Println("\t\t},")
- fmt.Println("\t},")
- fmt.Println("}")
- return nil
- }
- func CodeSignMachoFile(path string) error {
- filename := filepath.Base(path)
- cmd := exec.Command("/usr/bin/codesign", "--force", "-s", "-", "-i", filename, path)
- if err := cmd.Run(); err != nil {
- return err
- }
- return modifyCodeSignFlags(path)
- }
- const LC_CODE_SIGNATURE = 0x1d
- const CSSLOT_CODEDIRECTORY = 0
- // To make codesign not invalidated by stripping, modify codesign flags to 0x20002
- // (adhoc | linkerSigned).
- func modifyCodeSignFlags(path string) error {
- f, err := os.OpenFile(path, os.O_RDWR, 0)
- if err != nil {
- return err
- }
- defer f.Close()
- // Step 1: find code signature section.
- machoFile, err := macho.NewFile(f)
- if err != nil {
- return err
- }
- var codeSignSectionOffset uint32 = 0
- var codeSignSectionSize uint32 = 0
- for _, l := range machoFile.Loads {
- data := l.Raw()
- cmd := machoFile.ByteOrder.Uint32(data)
- if cmd == LC_CODE_SIGNATURE {
- codeSignSectionOffset = machoFile.ByteOrder.Uint32(data[8:])
- codeSignSectionSize = machoFile.ByteOrder.Uint32(data[12:])
- }
- }
- if codeSignSectionOffset == 0 {
- return fmt.Errorf("code signature section not found")
- }
- data := make([]byte, codeSignSectionSize)
- _, err = f.ReadAt(data, int64(codeSignSectionOffset))
- if err != nil {
- return err
- }
- // Step 2: get flags offset.
- blobCount := binary.BigEndian.Uint32(data[8:])
- off := 12
- var codeDirectoryOff uint32 = 0
- for blobCount > 0 {
- blobType := binary.BigEndian.Uint32(data[off:])
- if blobType == CSSLOT_CODEDIRECTORY {
- codeDirectoryOff = binary.BigEndian.Uint32(data[off+4:])
- break
- }
- blobCount--
- off += 8
- }
- if codeDirectoryOff == 0 {
- return fmt.Errorf("no code directory in code signature section")
- }
- flagsOff := codeSignSectionOffset + codeDirectoryOff + 12
- // Step 3: modify flags.
- flagsData := make([]byte, 4)
- _, err = f.ReadAt(flagsData, int64(flagsOff))
- if err != nil {
- return err
- }
- oldFlags := binary.BigEndian.Uint32(flagsData)
- if oldFlags != 0x2 {
- return fmt.Errorf("unexpected flags in code signature section: 0x%x", oldFlags)
- }
- binary.BigEndian.PutUint32(flagsData, 0x20002)
- _, err = f.WriteAt(flagsData, int64(flagsOff))
- return err
- }
|