macho/macho-go/pkg/ios/macho/util.go
2023-05-31 16:31:52 +07:00

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
}