198 lines
4.6 KiB
Go
198 lines
4.6 KiB
Go
package macho
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"os"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
. "ios-wrapper/pkg/ios"
|
|
)
|
|
|
|
func (mc *MachoContext) ArchName() string {
|
|
if mc.header.cputype == 12 && mc.header.cpusubtype == 9 {
|
|
return "armv7"
|
|
}
|
|
if mc.header.cputype == 12 && mc.header.cpusubtype == 11 {
|
|
return "armv7s"
|
|
}
|
|
if mc.header.cputype == 0x100000C && mc.header.cpusubtype == 0 {
|
|
return "arm64"
|
|
}
|
|
if mc.header.cputype == 0x100000C && mc.header.cpusubtype == 2 {
|
|
return "arm64e"
|
|
}
|
|
if mc.header.cputype == 7 && mc.header.cpusubtype == 3 {
|
|
return "i386"
|
|
}
|
|
if mc.header.cputype == 0x1000007 && mc.header.cpusubtype == 3 {
|
|
return "x86_64"
|
|
}
|
|
if mc.header.cputype == 0x1000007 && mc.header.cpusubtype == 0x80000003 {
|
|
return "x86_64-lib64"
|
|
}
|
|
return fmt.Sprintf("arch-%x-%x", mc.header.cputype, mc.header.cpusubtype)
|
|
}
|
|
|
|
func MachosFromFiles(files []string) ([]*MachoContext, error) {
|
|
var r []*MachoContext
|
|
for _, filename := range files {
|
|
var mc MachoContext
|
|
f, _ := os.OpenFile(filename, os.O_RDWR, 0644)
|
|
err := mc.ParseFile(f, 0)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
r = append(r, &mc)
|
|
}
|
|
return r, nil
|
|
}
|
|
|
|
func CheckDuplicateArch(machos []*MachoContext) bool {
|
|
for i := 0; i < len(machos)-1; i++ {
|
|
for j := i + 1; j < len(machos); j++ {
|
|
i_cputype := machos[i].Header().Cputype()
|
|
j_cputype := machos[j].Header().Cputype()
|
|
i_cpusubtype := machos[i].Header().Cpusubtype()
|
|
j_cpusubtype := machos[j].Header().Cpusubtype()
|
|
if i_cputype == j_cputype &&
|
|
i_cpusubtype == j_cpusubtype {
|
|
log.WithFields(log.Fields{
|
|
"cputype": i_cputype,
|
|
"cpusubtype": i_cpusubtype,
|
|
}).Warn("Duplicate Mach-O Arch")
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (mc *MachoContext) PaddingSize() uint64 {
|
|
if mc.Is64bit() {
|
|
return mc.entryoff - (Header_size_64 + uint64(mc.header.sizeofcmds))
|
|
} else {
|
|
return mc.entryoff - (Header_size + uint64(mc.header.sizeofcmds))
|
|
}
|
|
|
|
}
|
|
|
|
func (mc *MachoContext) DylibExisted(name string) bool {
|
|
// simple check
|
|
// Advanced check requires expansion of @rpath
|
|
for _, dylib := range mc.dylibs {
|
|
dylib_ := bytes.Trim(dylib.name, "\x00")
|
|
match := bytes.Compare(dylib_, []byte(name)) == 0
|
|
log.WithFields(log.Fields{
|
|
"left": dylib_,
|
|
"right": []byte(name),
|
|
"match": match,
|
|
}).Trace("Dylib check")
|
|
if match {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (mc *MachoContext) RPathExisted(path string) bool {
|
|
// simple check
|
|
// Advanced check requires expansion of @rpath
|
|
for _, rpath := range mc.rpaths {
|
|
rpath_ := bytes.Trim(rpath.path, "\x00")
|
|
match := bytes.Compare(rpath_, []byte(path)) == 0
|
|
log.WithFields(log.Fields{
|
|
"left": rpath_,
|
|
"right": []byte(path),
|
|
"match": match,
|
|
}).Trace("Rpath check")
|
|
if match {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (mc *MachoContext) FindSection(name string) Section {
|
|
for _, segment := range mc.segments {
|
|
for _, section := range segment.Sections() {
|
|
sectname := bytes.Trim(section.SectName(), "\x00")
|
|
if bytes.Compare(sectname, []byte(name)) == 0 {
|
|
return section
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (mc *MachoContext) FindSegment(name string) Segment {
|
|
for _, segment := range mc.segments {
|
|
sectname := bytes.Trim(segment.SegName(), "\x00")
|
|
if bytes.Compare(sectname, []byte(name)) == 0 {
|
|
return segment
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (mc *MachoContext) Cut(offset uint64, size uint64) []byte {
|
|
return mc.buf[offset : offset+size]
|
|
}
|
|
|
|
// INIT POINTER
|
|
|
|
type InitPointer struct {
|
|
offset uint64
|
|
low uint32
|
|
high uint32
|
|
}
|
|
|
|
func (ptr *InitPointer) Offset() uint64 {
|
|
return ptr.offset
|
|
}
|
|
|
|
func (ptr *InitPointer) Value() uint64 {
|
|
return (uint64(ptr.high) << 32) | uint64(ptr.low)
|
|
}
|
|
|
|
func (ptr *InitPointer) String() string {
|
|
return fmt.Sprintf("0x%x -> 0x%x",
|
|
ptr.offset, (uint64(ptr.high)<<32)|uint64(ptr.low))
|
|
}
|
|
|
|
func (mc *MachoContext) InitFunctions() []InitPointer {
|
|
var valid_sections []Section
|
|
for _, segment := range mc.segments {
|
|
for _, section := range segment.Sections() {
|
|
if section.Type() == S_MOD_INIT_FUNC_POINTERS {
|
|
valid_sections = append(valid_sections, section)
|
|
}
|
|
}
|
|
}
|
|
|
|
var funcs []InitPointer
|
|
for _, section := range valid_sections {
|
|
offset := uint64(section.Offset())
|
|
size := section.Size()
|
|
|
|
data := mc.buf[offset : offset+size]
|
|
|
|
// TODO: assert len(data) // mc.pointersize
|
|
|
|
count := size / uint64(mc.pointersize)
|
|
data_buf := bytes.NewBuffer(data)
|
|
for i := uint64(0); i < count; i++ {
|
|
var fun InitPointer
|
|
fun.offset = offset + i*uint64(mc.pointersize)
|
|
binary.Read(data_buf, mc.byteorder, &fun.low)
|
|
if mc.Is64bit() {
|
|
binary.Read(data_buf, mc.byteorder, &fun.high)
|
|
}
|
|
funcs = append(funcs, fun)
|
|
}
|
|
}
|
|
return funcs
|
|
}
|