Skip to content

Instantly share code, notes, and snippets.

@steeve
Created December 23, 2019 00:54
Show Gist options
  • Save steeve/7887175a9895e1fd849dd1c9267ab7d8 to your computer and use it in GitHub Desktop.
Save steeve/7887175a9895e1fd849dd1c9267ab7d8 to your computer and use it in GitHub Desktop.
package main
import (
"bytes"
"debug/macho"
"encoding/binary"
"fmt"
"io"
"os"
)
const (
LoadCmdCodeSignature macho.LoadCmd = 0x1d
)
const (
CSMAGIC_REQUIREMENT = 0xfade0c00 /* single Requirement blob */
CSMAGIC_REQUIREMENTS = 0xfade0c01 /* Requirements vector (internal requirements) */
CSMAGIC_CODEDIRECTORY = 0xfade0c02 /* CodeDirectory blob */
CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0 /* embedded form of signature data */
CSMAGIC_DETACHED_SIGNATURE = 0xfade0cc1 /* multi-arch collection of embedded signatures */
CSSLOT_CODEDIRECTORY = 0 /* slot index for CodeDirectory */
)
type CodeSignatureCmd struct {
Cmd macho.LoadCmd
Len uint32
Offset uint32
Size uint32
}
type CodeSignature struct {
Magic uint32
Length uint32
Count uint32
}
type CodeSignatureBlobIndex struct {
Type uint32
Offset uint32
}
type CodeSignatureBlobBase struct {
Magic uint32
Length uint32
}
type CodeDirectory struct {
Magic uint32 /* magic number (CSMAGIC_CODEDIRECTORY) */
Length uint32 /* total length of CodeDirectory blob */
Version uint32 /* compatibility version */
Flags uint32 /* setup and mode flags */
HashOffset uint32 /* offset of hash slot element at index zero */
IdentOffset uint32 /* offset of identifier string */
NSpecialSlots uint32 /* number of special hash slots */
NCodeSlots uint32 /* number of ordinary (code) hash slots */
CodeLimit uint32 /* limit to main image signature range */
HashSize uint8 /* size of each hash in bytes */
HashType uint8 /* type of hash (cdHashType* constants) */
Spare1 uint8 /* unused (must be zero) */
PageSize uint8 /* log2(page size in bytes); 0 => infinite */
Spare2 uint32 /* unused (must be zero) */
/* followed by dynamic content as located by offset fields above */
}
type MachoFileEx struct {
*macho.File
io.ReaderAt
codeSigData []byte
}
func (f *MachoFileEx) CodeSignatureBytes() []byte {
if f.codeSigData != nil {
return f.codeSigData
}
for _, load := range f.Loads {
data := load.Raw()
cmd := macho.LoadCmd(f.ByteOrder.Uint32(data[0:4]))
switch cmd {
case LoadCmdCodeSignature:
buf := bytes.NewBuffer(data)
csCmd := &CodeSignatureCmd{}
binary.Read(buf, f.ByteOrder, csCmd)
f.codeSigData = make([]byte, int(csCmd.Size))
f.ReadAt(f.codeSigData, int64(csCmd.Offset))
}
}
return f.codeSigData
}
func (f *MachoFileEx) CodeSignature() {
buf := bytes.NewBuffer(f.CodeSignatureBytes())
cs := &CodeSignature{}
binary.Read(buf, binary.BigEndian, cs)
if cs.Magic != CSMAGIC_EMBEDDED_SIGNATURE {
panic("wrong CSMAGIC_EMBEDDED_SIGNATURE")
}
for i := 0; i < int(cs.Count); i++ {
blobIdx := &CodeSignatureBlobIndex{}
binary.Read(buf, binary.BigEndian, blobIdx)
data := f.CodeSignatureBytes()
magic := binary.BigEndian.Uint32(data[blobIdx.Offset : blobIdx.Offset+4])
blobLen := binary.BigEndian.Uint32(data[blobIdx.Offset+4 : blobIdx.Offset+8])
blobData := data[blobIdx.Offset : blobIdx.Offset+blobLen]
blobBuf := bytes.NewBuffer(blobData)
_ = blobBuf
switch magic {
case CSMAGIC_CODEDIRECTORY:
dir := &CodeDirectory{}
binary.Read(blobBuf, binary.BigEndian, dir)
ident := CString(blobData[dir.IdentOffset:])
fmt.Println("Ident:", ident)
}
}
}
func CString(buf []byte) string {
idx := bytes.IndexByte(buf, 0)
return string(buf[:idx-1])
}
func main() {
f, err := os.Open(os.Args[1])
if err != nil {
panic(err)
}
defer f.Close()
machoFile, err := macho.NewFile(f)
if err != nil {
panic(err)
}
f2 := MachoFileEx{
File: machoFile,
ReaderAt: f,
}
f2.CodeSignature()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment