format code
This commit is contained in:
parent
e3453ae127
commit
841a50f8e1
@ -1,12 +1,12 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"ios-wrapper/pkg/ios/macho"
|
|
||||||
"github.com/alecthomas/kong"
|
"github.com/alecthomas/kong"
|
||||||
|
"ios-wrapper/pkg/ios/macho"
|
||||||
|
|
||||||
"os"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"bytes"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Argument struct {
|
type Argument struct {
|
||||||
@ -18,30 +18,30 @@ func main() {
|
|||||||
var cli Argument
|
var cli Argument
|
||||||
kong.Parse(&cli)
|
kong.Parse(&cli)
|
||||||
|
|
||||||
compare(cli.One, cli.Two)
|
compare(cli.One, cli.Two)
|
||||||
}
|
}
|
||||||
|
|
||||||
func compare(one string, two string) {
|
func compare(one string, two string) {
|
||||||
f1, _ := os.OpenFile(one, os.O_RDONLY, 0644)
|
f1, _ := os.OpenFile(one, os.O_RDONLY, 0644)
|
||||||
f2, _ := os.OpenFile(two, os.O_RDONLY, 0644)
|
f2, _ := os.OpenFile(two, os.O_RDONLY, 0644)
|
||||||
|
|
||||||
var mc1 macho.MachoContext
|
var mc1 macho.MachoContext
|
||||||
var mc2 macho.MachoContext
|
var mc2 macho.MachoContext
|
||||||
mc1.ParseFile(f1, 0)
|
mc1.ParseFile(f1, 0)
|
||||||
mc2.ParseFile(f2, 0)
|
mc2.ParseFile(f2, 0)
|
||||||
|
|
||||||
s1 := mc1.FindSection("__text")
|
s1 := mc1.FindSection("__text")
|
||||||
s2 := mc2.FindSection("__text")
|
s2 := mc2.FindSection("__text")
|
||||||
|
|
||||||
if (s1.Size() == s2.Size()) {
|
if s1.Size() == s2.Size() {
|
||||||
fmt.Println("Size is equal")
|
fmt.Println("Size is equal")
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("%x <> %x\n", s1.Size(), s2.Size())
|
fmt.Printf("%x <> %x\n", s1.Size(), s2.Size())
|
||||||
}
|
}
|
||||||
|
|
||||||
data1 := mc1.Cut(uint64(s1.Offset()), s1.Size())
|
data1 := mc1.Cut(uint64(s1.Offset()), s1.Size())
|
||||||
data2 := mc1.Cut(uint64(s2.Offset()), s2.Size())
|
data2 := mc1.Cut(uint64(s2.Offset()), s2.Size())
|
||||||
if (bytes.Compare(data1, data2) == 0) {
|
if bytes.Compare(data1, data2) == 0 {
|
||||||
fmt.Println("Data is equal")
|
fmt.Println("Data is equal")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,13 +57,13 @@ func Cli() {
|
|||||||
return
|
return
|
||||||
} else if command == "lipo split" {
|
} else if command == "lipo split" {
|
||||||
arg := cli.Lipo.Split
|
arg := cli.Lipo.Split
|
||||||
fat.FatSplit(arg.Fat)
|
fat.FatSplit(arg.Fat)
|
||||||
return
|
return
|
||||||
} else if command == "lipo join" {
|
} else if command == "lipo join" {
|
||||||
arg := cli.Lipo.Join
|
arg := cli.Lipo.Join
|
||||||
fat.FatJoin(arg.Macho, arg.Out)
|
fat.FatJoin(arg.Macho, arg.Out)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var pc ProgramContext
|
var pc ProgramContext
|
||||||
var ofile OFile = nil
|
var ofile OFile = nil
|
||||||
@ -81,7 +81,7 @@ func Cli() {
|
|||||||
pc.signed = arg.Signed
|
pc.signed = arg.Signed
|
||||||
pc.ReadUserConfig(arg.Config)
|
pc.ReadUserConfig(arg.Config)
|
||||||
|
|
||||||
case "vltk":
|
case "vltk":
|
||||||
arg := cli.Vltk
|
arg := cli.Vltk
|
||||||
ofile = NewOFile(arg.OFile)
|
ofile = NewOFile(arg.OFile)
|
||||||
pc.remove_codesign = true
|
pc.remove_codesign = true
|
||||||
|
@ -9,14 +9,14 @@ type WrapArgument struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type VltkArgument struct {
|
type VltkArgument struct {
|
||||||
Out string `short:"o" required name:"outfile" help:"Modified Mach-O/Fat binary output file" type:"path"`
|
Out string `short:"o" required name:"outfile" help:"Modified Mach-O/Fat binary output file" type:"path"`
|
||||||
OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"`
|
OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type InfoArgument struct {
|
type InfoArgument struct {
|
||||||
OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"`
|
OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"`
|
||||||
All bool `short:"a" help:"If print all information"`
|
All bool `short:"a" help:"If print all information"`
|
||||||
Arch string `help:"Only print information in this arch"`
|
Arch string `help:"Only print information in this arch"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RemoveCodesignArgument struct {
|
type RemoveCodesignArgument struct {
|
||||||
@ -40,17 +40,17 @@ type Addr2LineArgument struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type LipoArgument struct {
|
type LipoArgument struct {
|
||||||
Join struct {
|
Join struct {
|
||||||
Out string `short:"o" required help:"Output Fat binary file" type:"path"`
|
Out string `short:"o" required help:"Output Fat binary file" type:"path"`
|
||||||
Macho []string `arg help:"Macho binaries to join" type:"existingfile"`
|
Macho []string `arg help:"Macho binaries to join" type:"existingfile"`
|
||||||
} `cmd help:"Join Macho binaries into Fat binary"`
|
} `cmd help:"Join Macho binaries into Fat binary"`
|
||||||
Split struct {
|
Split struct {
|
||||||
Fat string `arg help:"Fat binary to split" type:"existingfile"`
|
Fat string `arg help:"Fat binary to split" type:"existingfile"`
|
||||||
} `cmd help:"Split fat binary into files, named <name>_<arch>"`
|
} `cmd help:"Split fat binary into files, named <name>_<arch>"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PepeArgument struct {
|
type PepeArgument struct {
|
||||||
OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"`
|
OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Argument struct {
|
type Argument struct {
|
||||||
@ -59,8 +59,8 @@ type Argument struct {
|
|||||||
Info InfoArgument `cmd help:"Show Mach-O/Fat binary information"`
|
Info InfoArgument `cmd help:"Show Mach-O/Fat binary information"`
|
||||||
RemoveCodesign RemoveCodesignArgument `cmd aliases:"remove-signature" name:"remove-codesign" help:"Remove LC_CODE_SIGNATURE from Mach-O/Fat binary"`
|
RemoveCodesign RemoveCodesignArgument `cmd aliases:"remove-signature" name:"remove-codesign" help:"Remove LC_CODE_SIGNATURE from Mach-O/Fat binary"`
|
||||||
SignedBcell SignedBcellArgument `cmd name:"signed-bcell" help:"Change Protobuf<BcellFile> into Protobuf<SignedData>"`
|
SignedBcell SignedBcellArgument `cmd name:"signed-bcell" help:"Change Protobuf<BcellFile> into Protobuf<SignedData>"`
|
||||||
DisplayBcell DisplayBcellArgument `cmd name:"display-bcell" help:"Display Protobuf<BcellFile> content"`
|
DisplayBcell DisplayBcellArgument `cmd name:"display-bcell" help:"Display Protobuf<BcellFile> content"`
|
||||||
Addr2Line Addr2LineArgument `cmd name:"addr2line" help:"Resolve crash address from DWARF file"`
|
Addr2Line Addr2LineArgument `cmd name:"addr2line" help:"Resolve crash address from DWARF file"`
|
||||||
Lipo LipoArgument `cmd help:"split Fat binary or join Mach-O binares"`
|
Lipo LipoArgument `cmd help:"split Fat binary or join Mach-O binares"`
|
||||||
Pepe PepeArgument `cmd help:"split Fat binary or join Mach-O binares"`
|
Pepe PepeArgument `cmd help:"split Fat binary or join Mach-O binares"`
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,6 @@ func (printer *InfoPrinter) Print() {
|
|||||||
fmt.Printf("Init functions at offset %s\n", &fun)
|
fmt.Printf("Init functions at offset %s\n", &fun)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
symbols := mc.CollectLazyBindSymbols()
|
symbols := mc.CollectLazyBindSymbols()
|
||||||
if len(symbols) > 0 {
|
if len(symbols) > 0 {
|
||||||
fmt.Println("Lazy Symbols")
|
fmt.Println("Lazy Symbols")
|
||||||
|
@ -92,8 +92,8 @@ const (
|
|||||||
LC_VERSION_MIN_TVOS uint32 = 0x2F
|
LC_VERSION_MIN_TVOS uint32 = 0x2F
|
||||||
LC_VERSION_MIN_WATCHOS uint32 = 0x30
|
LC_VERSION_MIN_WATCHOS uint32 = 0x30
|
||||||
LC_BUILD_VERSION uint32 = 0x32
|
LC_BUILD_VERSION uint32 = 0x32
|
||||||
LC_DYLD_EXPORTS_TRIE uint32 = 0x33 | 0x80000000
|
LC_DYLD_EXPORTS_TRIE uint32 = 0x33 | 0x80000000
|
||||||
LC_DYLD_CHAINED_FIXUPS uint32 = 0x34 | 0x80000000
|
LC_DYLD_CHAINED_FIXUPS uint32 = 0x34 | 0x80000000
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
/// Contains the declaration of FatHeader and FatArch
|
// / Contains the declaration of FatHeader and FatArch
|
||||||
/// These structs are always written using Big-Endian,
|
// / These structs are always written using Big-Endian,
|
||||||
/// as documented in the mach-o/fat.h
|
// / as documented in the mach-o/fat.h
|
||||||
/// This file also has a CreateFat function to generate
|
// / This file also has a CreateFat function to generate
|
||||||
/// Fat file from a list of MachoContext
|
// / Fat file from a list of MachoContext
|
||||||
package fat
|
package fat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -16,8 +16,8 @@ import (
|
|||||||
macho "ios-wrapper/pkg/ios/macho"
|
macho "ios-wrapper/pkg/ios/macho"
|
||||||
)
|
)
|
||||||
|
|
||||||
/// Get the alignment for the Mach-O in Fat binary
|
// / Get the alignment for the Mach-O in Fat binary
|
||||||
/// The returned value is the multiplier of 2
|
// / The returned value is the multiplier of 2
|
||||||
func GetAlignment(h *macho.Header) uint32 {
|
func GetAlignment(h *macho.Header) uint32 {
|
||||||
switch h.Cputype() {
|
switch h.Cputype() {
|
||||||
case CPU_TYPE_ARM, CPU_TYPE_ARM64:
|
case CPU_TYPE_ARM, CPU_TYPE_ARM64:
|
||||||
@ -46,17 +46,17 @@ func MachosToFatArchs(machos []*macho.MachoContext) []*FatArch {
|
|||||||
return fa
|
return fa
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a Fat binary from MachoContext
|
// / Create a Fat binary from MachoContext
|
||||||
/// Convert MachoContext to FatArch
|
// / Convert MachoContext to FatArch
|
||||||
/// Calculate the alignment, now using basic calculation
|
// / Calculate the alignment, now using basic calculation
|
||||||
/// because iOS always has valid archs ARM
|
// / because iOS always has valid archs ARM
|
||||||
///
|
// /
|
||||||
/// Sort the Fat arch as per the cctools/lipo
|
// / Sort the Fat arch as per the cctools/lipo
|
||||||
/// Calculate the offset with each Mach-O
|
// / Calculate the offset with each Mach-O
|
||||||
///
|
// /
|
||||||
/// Write the FatHeader
|
// / Write the FatHeader
|
||||||
/// Write the FatArchs
|
// / Write the FatArchs
|
||||||
/// Write the Mach-Os
|
// / Write the Mach-Os
|
||||||
func CreateFat(machos []*macho.MachoContext, outfilename string) error {
|
func CreateFat(machos []*macho.MachoContext, outfilename string) error {
|
||||||
archs := MachosToFatArchs(machos)
|
archs := MachosToFatArchs(machos)
|
||||||
sort.SliceStable(archs, func(i, j int) bool {
|
sort.SliceStable(archs, func(i, j int) bool {
|
||||||
@ -139,9 +139,9 @@ func (fw *fatWriter) WriteFatArchs(w io.Writer, archs []*FatArch) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// for each fat arch sorted, we locate the MachoContext and
|
// / for each fat arch sorted, we locate the MachoContext and
|
||||||
/// use it to Write to the buffer
|
// / use it to Write to the buffer
|
||||||
/// locating the macho by its cputype and cpusubtype
|
// / locating the macho by its cputype and cpusubtype
|
||||||
func (fw *fatWriter) WriteMachos(
|
func (fw *fatWriter) WriteMachos(
|
||||||
w io.WriteSeeker,
|
w io.WriteSeeker,
|
||||||
archs []*FatArch,
|
archs []*FatArch,
|
||||||
|
@ -46,41 +46,41 @@ func (sym *ImportSymbol) Stub() uint64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (mc *MachoContext) CollectLazyBindSymbols() []*ImportSymbol {
|
func (mc *MachoContext) CollectLazyBindSymbols() []*ImportSymbol {
|
||||||
if mc.dyldinfo == nil {
|
if mc.dyldinfo == nil {
|
||||||
return mc.CollectLazyBindSymbolsModern()
|
return mc.CollectLazyBindSymbolsModern()
|
||||||
} else {
|
} else {
|
||||||
return mc.CollectLazyBindSymbolsLegacy()
|
return mc.CollectLazyBindSymbolsLegacy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// New convention using LC_DYLD_CHAINED_FIXUPS
|
// New convention using LC_DYLD_CHAINED_FIXUPS
|
||||||
func (mc *MachoContext) CollectLazyBindSymbolsModern() []*ImportSymbol {
|
func (mc *MachoContext) CollectLazyBindSymbolsModern() []*ImportSymbol {
|
||||||
var buf []byte
|
var buf []byte
|
||||||
for _, cmd := range mc.Linkedits() {
|
for _, cmd := range mc.Linkedits() {
|
||||||
if (cmd.Cmd() != LC_DYLD_CHAINED_FIXUPS) {
|
if cmd.Cmd() != LC_DYLD_CHAINED_FIXUPS {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
count_offset := int64(cmd.Dataoff()) + 16
|
count_offset := int64(cmd.Dataoff()) + 16
|
||||||
mc.file.WriteAt([]byte{0, 0, 0, 0}, count_offset)
|
mc.file.WriteAt([]byte{0, 0, 0, 0}, count_offset)
|
||||||
|
|
||||||
symbol_offset := int64(0x4000)
|
symbol_offset := int64(0x4000)
|
||||||
mc.file.WriteAt([]byte{0, 0, 0, 0, 0, 0, 0, 0}, symbol_offset)
|
mc.file.WriteAt([]byte{0, 0, 0, 0, 0, 0, 0, 0}, symbol_offset)
|
||||||
|
|
||||||
buf = mc.buf[cmd.Dataoff():cmd.Dataoff() + cmd.Datasize()]
|
buf = mc.buf[cmd.Dataoff() : cmd.Dataoff()+cmd.Datasize()]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
r := bytes.NewReader(buf)
|
r := bytes.NewReader(buf)
|
||||||
rr := bufio.NewReader(r)
|
rr := bufio.NewReader(r)
|
||||||
|
|
||||||
var fixups_version int32
|
var fixups_version int32
|
||||||
var starts_offset int32
|
var starts_offset int32
|
||||||
var imports_offset int32
|
var imports_offset int32
|
||||||
var symbols_offset int32
|
var symbols_offset int32
|
||||||
var imports_count int32
|
var imports_count int32
|
||||||
var imports_format int32
|
var imports_format int32
|
||||||
var symbols_format int32
|
var symbols_format int32
|
||||||
binary.Read(rr, mc.byteorder, &fixups_version)
|
binary.Read(rr, mc.byteorder, &fixups_version)
|
||||||
binary.Read(rr, mc.byteorder, &starts_offset)
|
binary.Read(rr, mc.byteorder, &starts_offset)
|
||||||
binary.Read(rr, mc.byteorder, &imports_offset)
|
binary.Read(rr, mc.byteorder, &imports_offset)
|
||||||
@ -88,36 +88,36 @@ func (mc *MachoContext) CollectLazyBindSymbolsModern() []*ImportSymbol {
|
|||||||
binary.Read(rr, mc.byteorder, &imports_count)
|
binary.Read(rr, mc.byteorder, &imports_count)
|
||||||
binary.Read(rr, mc.byteorder, &imports_format)
|
binary.Read(rr, mc.byteorder, &imports_format)
|
||||||
binary.Read(rr, mc.byteorder, &symbols_format)
|
binary.Read(rr, mc.byteorder, &symbols_format)
|
||||||
fmt.Printf(
|
fmt.Printf(
|
||||||
"HMMGE %x %x\n",
|
"HMMGE %x %x\n",
|
||||||
imports_offset,
|
imports_offset,
|
||||||
imports_count,
|
imports_count,
|
||||||
)
|
)
|
||||||
|
|
||||||
return []*ImportSymbol{}
|
return []*ImportSymbol{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Old convention using LC_DYLD_INFO_ONLY section and bytecode runner
|
// Old convention using LC_DYLD_INFO_ONLY section and bytecode runner
|
||||||
func (mc *MachoContext) CollectLazyBindSymbolsLegacy() []*ImportSymbol {
|
func (mc *MachoContext) CollectLazyBindSymbolsLegacy() []*ImportSymbol {
|
||||||
start := mc.dyldinfo.lazy_bind_off
|
start := mc.dyldinfo.lazy_bind_off
|
||||||
size := mc.dyldinfo.lazy_bind_size
|
size := mc.dyldinfo.lazy_bind_size
|
||||||
end := start + size
|
end := start + size
|
||||||
|
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
return []*ImportSymbol{}
|
return []*ImportSymbol{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear this whole section to 0x00 BIND_OPCODE_DONE
|
// clear this whole section to 0x00 BIND_OPCODE_DONE
|
||||||
dummy := []byte{
|
dummy := []byte{
|
||||||
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
|
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
|
||||||
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
|
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
|
||||||
}
|
}
|
||||||
// make LINK EDIT section writable
|
// make LINK EDIT section writable
|
||||||
// mc.file.WriteAt([]byte{0x03}, int64(0x3f8))
|
// mc.file.WriteAt([]byte{0x03}, int64(0x3f8))
|
||||||
// set number of symbols to 0
|
// set number of symbols to 0
|
||||||
mc.file.WriteAt([]byte{0, 0, 0, 0}, int64(0x444))
|
mc.file.WriteAt([]byte{0, 0, 0, 0}, int64(0x444))
|
||||||
mc.file.WriteAt([]byte{0, 0, 0, 0}, int64(0x44c))
|
mc.file.WriteAt([]byte{0, 0, 0, 0}, int64(0x44c))
|
||||||
mc.file.WriteAt([]byte{0, 0, 0, 0}, int64(0x48c))
|
mc.file.WriteAt([]byte{0, 0, 0, 0}, int64(0x48c))
|
||||||
mc.file.WriteAt(dummy, int64(start))
|
mc.file.WriteAt(dummy, int64(start))
|
||||||
|
|
||||||
buf := bytes.NewBuffer(mc.buf[start:end])
|
buf := bytes.NewBuffer(mc.buf[start:end])
|
||||||
|
@ -40,12 +40,13 @@ func rewriteLoadcommandsWithoutCodesignature(mc *MachoContext) {
|
|||||||
// CODE_SIGNATURE load commands points to the codesign data offset and size.
|
// CODE_SIGNATURE load commands points to the codesign data offset and size.
|
||||||
// __LINKEDIT section points to data offset and size.
|
// __LINKEDIT section points to data offset and size.
|
||||||
// We have:
|
// We have:
|
||||||
// linkedit = (section*) LC_SEGMENT.section[0] // name="__LINKEDIT"
|
|
||||||
// codesign = (linkedit_data_command*) LC_CODE_SIGNATURE
|
|
||||||
// BinarySize = { f.seek(0, SEEKEND); return f.tell() }
|
|
||||||
//
|
//
|
||||||
// linkedit->fileoff + linkedit->filesize == codesign->dataOff + codesign->dataSize
|
// linkedit = (section*) LC_SEGMENT.section[0] // name="__LINKEDIT"
|
||||||
// linkedit->fileoff + linkedit->filesize == BinarySize
|
// codesign = (linkedit_data_command*) LC_CODE_SIGNATURE
|
||||||
|
// BinarySize = { f.seek(0, SEEKEND); return f.tell() }
|
||||||
|
//
|
||||||
|
// linkedit->fileoff + linkedit->filesize == codesign->dataOff + codesign->dataSize
|
||||||
|
// linkedit->fileoff + linkedit->filesize == BinarySize
|
||||||
//
|
//
|
||||||
// To remove the codesign data, we truncate the file to remove the codesign data.
|
// To remove the codesign data, we truncate the file to remove the codesign data.
|
||||||
// Then we update the linkedit->filesize to linkedit->filesize - codesign->dataSize
|
// Then we update the linkedit->filesize to linkedit->filesize - codesign->dataSize
|
||||||
|
@ -456,7 +456,7 @@ func (lcmd *Symtab) Cmdsize() uint32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (lcmd *Symtab) Cmdname() string {
|
func (lcmd *Symtab) Cmdname() string {
|
||||||
return fmt.Sprintf("%s symoff:0x%x nsyms:%d stroff:0x%x strsize:0x%x",
|
return fmt.Sprintf("%s symoff:0x%x nsyms:%d stroff:0x%x strsize:0x%x",
|
||||||
lcmd.c.Cmdname(), lcmd.symoff, lcmd.nsyms, lcmd.stroff, lcmd.strsize)
|
lcmd.c.Cmdname(), lcmd.symoff, lcmd.nsyms, lcmd.stroff, lcmd.strsize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,10 +71,12 @@ func (mc *MachoContext) WriteBufferTo(w io.Writer) (int, error) {
|
|||||||
// Parse the provided Mach-O binary from a file
|
// Parse the provided Mach-O binary from a file
|
||||||
// The first 4 bytes of the file must be the MachO magic
|
// The first 4 bytes of the file must be the MachO magic
|
||||||
// That is:
|
// That is:
|
||||||
// file.Seek(0, io.SeekStart)
|
//
|
||||||
// magic := make([]byte, 4)
|
// file.Seek(0, io.SeekStart)
|
||||||
// file.Read(magic)
|
// magic := make([]byte, 4)
|
||||||
// assert magic == []byte{macho magic bytes}
|
// file.Read(magic)
|
||||||
|
// assert magic == []byte{macho magic bytes}
|
||||||
|
//
|
||||||
// or else, parsing error is panic
|
// or else, parsing error is panic
|
||||||
func (mc *MachoContext) ParseFile(file *os.File, length int) error {
|
func (mc *MachoContext) ParseFile(file *os.File, length int) error {
|
||||||
file.Seek(0, io.SeekStart)
|
file.Seek(0, io.SeekStart)
|
||||||
|
@ -83,8 +83,8 @@ func (mc *MachoContext) DylibExisted(name string) bool {
|
|||||||
// simple check
|
// simple check
|
||||||
// Advanced check requires expansion of @rpath
|
// Advanced check requires expansion of @rpath
|
||||||
for _, dylib := range mc.dylibs {
|
for _, dylib := range mc.dylibs {
|
||||||
dylib_ := bytes.Trim(dylib.name, "\x00")
|
dylib_ := bytes.Trim(dylib.name, "\x00")
|
||||||
match := bytes.Compare(dylib_, []byte(name)) == 0
|
match := bytes.Compare(dylib_, []byte(name)) == 0
|
||||||
log.WithFields(log.Fields{
|
log.WithFields(log.Fields{
|
||||||
"left": dylib_,
|
"left": dylib_,
|
||||||
"right": []byte(name),
|
"right": []byte(name),
|
||||||
@ -101,8 +101,8 @@ func (mc *MachoContext) RPathExisted(path string) bool {
|
|||||||
// simple check
|
// simple check
|
||||||
// Advanced check requires expansion of @rpath
|
// Advanced check requires expansion of @rpath
|
||||||
for _, rpath := range mc.rpaths {
|
for _, rpath := range mc.rpaths {
|
||||||
rpath_ := bytes.Trim(rpath.path, "\x00")
|
rpath_ := bytes.Trim(rpath.path, "\x00")
|
||||||
match := bytes.Compare(rpath_, []byte(path)) == 0
|
match := bytes.Compare(rpath_, []byte(path)) == 0
|
||||||
log.WithFields(log.Fields{
|
log.WithFields(log.Fields{
|
||||||
"left": rpath_,
|
"left": rpath_,
|
||||||
"right": []byte(path),
|
"right": []byte(path),
|
||||||
@ -138,7 +138,7 @@ func (mc *MachoContext) FindSegment(name string) Segment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (mc *MachoContext) Cut(offset uint64, size uint64) []byte {
|
func (mc *MachoContext) Cut(offset uint64, size uint64) []byte {
|
||||||
return mc.buf[offset : offset + size];
|
return mc.buf[offset : offset+size]
|
||||||
}
|
}
|
||||||
|
|
||||||
// INIT POINTER
|
// INIT POINTER
|
||||||
|
@ -1,39 +1,40 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <mach-o/dyld.h>
|
#include <mach-o/dyld.h>
|
||||||
#include <mach/mach.h>
|
#include <mach/mach.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
const uint32_t magic64 = 0xfeedfacf;
|
const uint32_t magic64 = 0xfeedfacf;
|
||||||
const uint32_t magic32 = 0xfeedface;
|
const uint32_t magic32 = 0xfeedface;
|
||||||
|
|
||||||
struct ProgramVars {
|
struct ProgramVars {
|
||||||
void* mh; // mach_header or mach_header64
|
void *mh; // mach_header or mach_header64
|
||||||
int* NXArgcPtr;
|
int *NXArgcPtr;
|
||||||
const char*** NXArgvPtr;
|
const char ***NXArgvPtr;
|
||||||
const char*** environPtr;
|
const char ***environPtr;
|
||||||
const char** __prognamePtr;
|
const char **__prognamePtr;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C" uint32_t dyld_get_sdk_version(const mach_header* mh);
|
extern "C" uint32_t dyld_get_sdk_version(const mach_header *mh);
|
||||||
|
|
||||||
void decode_uleb128(char*& addr, uint32_t* ret) {
|
void decode_uleb128(char *&addr, uint32_t *ret) {
|
||||||
uint32_t result = 0;
|
uint32_t result = 0;
|
||||||
int shift = 0;
|
int shift = 0;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
unsigned char byte = *(unsigned char*)(addr);
|
unsigned char byte = *(unsigned char *)(addr);
|
||||||
addr++;
|
addr++;
|
||||||
|
|
||||||
result |= (byte & 0x7f) << shift;
|
result |= (byte & 0x7f) << shift;
|
||||||
shift += 7;
|
shift += 7;
|
||||||
|
|
||||||
if (!(byte & 0x80)) break;
|
if (!(byte & 0x80))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
*ret = result;
|
*ret = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* find_header(void* _func) {
|
void *find_header(void *_func) {
|
||||||
// Approach 1: (not stable)
|
// Approach 1: (not stable)
|
||||||
// we assume that text section is small enough to fit on 1 page
|
// we assume that text section is small enough to fit on 1 page
|
||||||
// so the header should stay at the top of the page due to allocation logic
|
// so the header should stay at the top of the page due to allocation logic
|
||||||
@ -63,41 +64,41 @@ void* find_header(void* _func) {
|
|||||||
uint64_t func = (uint64_t)_func;
|
uint64_t func = (uint64_t)_func;
|
||||||
uint64_t potential_head = func + (0x1000 - (func % page_size));
|
uint64_t potential_head = func + (0x1000 - (func % page_size));
|
||||||
|
|
||||||
void* head = 0;
|
void *head = 0;
|
||||||
uint32_t* x = (uint32_t*)(potential_head);
|
uint32_t *x = (uint32_t *)(potential_head);
|
||||||
while (*x != magic64 && *x != magic32) {
|
while (*x != magic64 && *x != magic32) {
|
||||||
x -= 0x1000/4;
|
x -= 0x1000 / 4;
|
||||||
}
|
}
|
||||||
return (void*)x;
|
return (void *)x;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_macho_summary(const void* header) {
|
void print_macho_summary(const void *header) {
|
||||||
const uint32_t magic = *(uint32_t*)header;
|
const uint32_t magic = *(uint32_t *)header;
|
||||||
char* ptr = (char*)header;
|
char *ptr = (char *)header;
|
||||||
if (magic == magic64) {
|
if (magic == magic64) {
|
||||||
ptr += 0x20;
|
ptr += 0x20;
|
||||||
} else {
|
} else {
|
||||||
ptr += 0x20 - 0x4;
|
ptr += 0x20 - 0x4;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t ncmds = *((uint32_t*)header + 4);
|
const uint32_t ncmds = *((uint32_t *)header + 4);
|
||||||
printf("parsing macho at %p\n", header);
|
printf("parsing macho at %p\n", header);
|
||||||
printf("ncmds %x\n", ncmds);
|
printf("ncmds %x\n", ncmds);
|
||||||
for (int i = 0; i < ncmds; i++) {
|
for (int i = 0; i < ncmds; i++) {
|
||||||
const uint32_t cmd = *((uint32_t*)ptr + 0);
|
const uint32_t cmd = *((uint32_t *)ptr + 0);
|
||||||
const uint32_t cmdsize = *((uint32_t*)ptr + 1);
|
const uint32_t cmdsize = *((uint32_t *)ptr + 1);
|
||||||
printf(" cmd %x %x\n", cmd, cmdsize);
|
printf(" cmd %x %x\n", cmd, cmdsize);
|
||||||
if (cmd == LC_DYLD_EXPORTS_TRIE) {
|
if (cmd == LC_DYLD_EXPORTS_TRIE) {
|
||||||
const uint32_t offset = *((uint32_t*)ptr + 2);
|
const uint32_t offset = *((uint32_t *)ptr + 2);
|
||||||
const uint32_t size = *((uint32_t*)ptr + 3);
|
const uint32_t size = *((uint32_t *)ptr + 3);
|
||||||
printf(" export trie: offset=0x%x size=0x%x\n", offset, size);
|
printf(" export trie: offset=0x%x size=0x%x\n", offset, size);
|
||||||
}
|
}
|
||||||
if (cmd == LC_SEGMENT_64) {
|
if (cmd == LC_SEGMENT_64) {
|
||||||
char* name = (char*)((uint64_t*)ptr + 1);
|
char *name = (char *)((uint64_t *)ptr + 1);
|
||||||
uint64_t vmaddr = *((uint64_t*)ptr + 3);
|
uint64_t vmaddr = *((uint64_t *)ptr + 3);
|
||||||
uint64_t vmsize = *((uint64_t*)ptr + 4);
|
uint64_t vmsize = *((uint64_t *)ptr + 4);
|
||||||
uint64_t fileoffset = *((uint64_t*)ptr + 5);
|
uint64_t fileoffset = *((uint64_t *)ptr + 5);
|
||||||
uint64_t filesize = *((uint64_t*)ptr + 6);
|
uint64_t filesize = *((uint64_t *)ptr + 6);
|
||||||
if (strcmp(name, "__TEXT") == 0) {
|
if (strcmp(name, "__TEXT") == 0) {
|
||||||
uint64_t slide = (uint64_t)header - vmaddr;
|
uint64_t slide = (uint64_t)header - vmaddr;
|
||||||
printf(" --- slide=0x%llx ---\n", slide);
|
printf(" --- slide=0x%llx ---\n", slide);
|
||||||
@ -110,9 +111,9 @@ void print_macho_summary(const void* header) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void* get_export_trie(const void* header, uint32_t& size) {
|
void *get_export_trie(const void *header, uint32_t &size) {
|
||||||
const uint32_t magic = *(uint32_t*)header;
|
const uint32_t magic = *(uint32_t *)header;
|
||||||
char* ptr = (char*)header;
|
char *ptr = (char *)header;
|
||||||
if (magic == magic64) {
|
if (magic == magic64) {
|
||||||
ptr += 0x20;
|
ptr += 0x20;
|
||||||
} else {
|
} else {
|
||||||
@ -122,20 +123,20 @@ void* get_export_trie(const void* header, uint32_t& size) {
|
|||||||
uint64_t slice = 0;
|
uint64_t slice = 0;
|
||||||
uint64_t linkedit_vmaddr = 0;
|
uint64_t linkedit_vmaddr = 0;
|
||||||
uint64_t linkedit_fileoffset = 0;
|
uint64_t linkedit_fileoffset = 0;
|
||||||
const uint32_t ncmds = *((uint32_t*)header + 4);
|
const uint32_t ncmds = *((uint32_t *)header + 4);
|
||||||
for (int i = 0; i < ncmds; i++) {
|
for (int i = 0; i < ncmds; i++) {
|
||||||
const uint32_t cmd = *((uint32_t*)ptr + 0);
|
const uint32_t cmd = *((uint32_t *)ptr + 0);
|
||||||
const uint32_t cmdsize = *((uint32_t*)ptr + 1);
|
const uint32_t cmdsize = *((uint32_t *)ptr + 1);
|
||||||
if (cmd == LC_DYLD_EXPORTS_TRIE) {
|
if (cmd == LC_DYLD_EXPORTS_TRIE) {
|
||||||
const uint32_t offset = *((uint32_t*)ptr + 2);
|
const uint32_t offset = *((uint32_t *)ptr + 2);
|
||||||
size = *((uint32_t*)ptr + 3);
|
size = *((uint32_t *)ptr + 3);
|
||||||
uint64_t offset_in_linkedit = (uint64_t)offset - linkedit_fileoffset;
|
uint64_t offset_in_linkedit = (uint64_t)offset - linkedit_fileoffset;
|
||||||
return (void*)(linkedit_vmaddr + slice + offset_in_linkedit);
|
return (void *)(linkedit_vmaddr + slice + offset_in_linkedit);
|
||||||
}
|
}
|
||||||
if (cmd == LC_SEGMENT_64) {
|
if (cmd == LC_SEGMENT_64) {
|
||||||
char* name = (char*)((uint64_t*)ptr + 1);
|
char *name = (char *)((uint64_t *)ptr + 1);
|
||||||
uint64_t vmaddr = *((uint64_t*)ptr + 3);
|
uint64_t vmaddr = *((uint64_t *)ptr + 3);
|
||||||
uint64_t fileoffset = *((uint64_t*)ptr + 5);
|
uint64_t fileoffset = *((uint64_t *)ptr + 5);
|
||||||
if (strcmp(name, "__TEXT") == 0) {
|
if (strcmp(name, "__TEXT") == 0) {
|
||||||
slice = (uint64_t)header - vmaddr;
|
slice = (uint64_t)header - vmaddr;
|
||||||
} else if (strcmp(name, "__LINKEDIT") == 0) {
|
} else if (strcmp(name, "__LINKEDIT") == 0) {
|
||||||
@ -148,9 +149,9 @@ void* get_export_trie(const void* header, uint32_t& size) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t should_follow_symbol(char*& buffer, char*& _find) {
|
uint32_t should_follow_symbol(char *&buffer, char *&_find) {
|
||||||
// printf("follow check %s has prefix: %s\n", _find, buffer);
|
// printf("follow check %s has prefix: %s\n", _find, buffer);
|
||||||
char* find = _find;
|
char *find = _find;
|
||||||
char is_prefix = true;
|
char is_prefix = true;
|
||||||
while (1) {
|
while (1) {
|
||||||
int find_end = *find == 0;
|
int find_end = *find == 0;
|
||||||
@ -183,11 +184,11 @@ uint32_t should_follow_symbol(char*& buffer, char*& _find) {
|
|||||||
return is_prefix;
|
return is_prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* find_in_export_trie(const void* header, void* trie, char* symbol) {
|
void *find_in_export_trie(const void *header, void *trie, char *symbol) {
|
||||||
uint32_t func = 0;
|
uint32_t func = 0;
|
||||||
|
|
||||||
char* ptr = (char*)trie;
|
char *ptr = (char *)trie;
|
||||||
char* find = symbol;
|
char *find = symbol;
|
||||||
while (1) {
|
while (1) {
|
||||||
// terminal node will have data
|
// terminal node will have data
|
||||||
uint32_t data_count = 0;
|
uint32_t data_count = 0;
|
||||||
@ -206,7 +207,7 @@ void* find_in_export_trie(const void* header, void* trie, char* symbol) {
|
|||||||
uint32_t follow_offset;
|
uint32_t follow_offset;
|
||||||
decode_uleb128(ptr, &follow_offset);
|
decode_uleb128(ptr, &follow_offset);
|
||||||
if (still_following) {
|
if (still_following) {
|
||||||
ptr = (char*)trie + follow_offset;
|
ptr = (char *)trie + follow_offset;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,10 +222,10 @@ void* find_in_export_trie(const void* header, void* trie, char* symbol) {
|
|||||||
ptr++; // flags
|
ptr++; // flags
|
||||||
// uleb128 offset
|
// uleb128 offset
|
||||||
decode_uleb128(ptr, &func);
|
decode_uleb128(ptr, &func);
|
||||||
return (void*)((char*)header + func);
|
return (void *)((char *)header + func);
|
||||||
}
|
}
|
||||||
|
|
||||||
int hook_printf (const char * format, ... ) {
|
int hook_printf(const char *format, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
|
|
||||||
@ -236,16 +237,17 @@ int hook_printf (const char * format, ... ) {
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((constructor))
|
__attribute__((constructor)) static void
|
||||||
static void bruh(int argc, const char* const argv[], const char* const envp[], const char* const apple[], const struct ProgramVars* vars) {
|
bruh(int argc, const char *const argv[], const char *const envp[],
|
||||||
|
const char *const apple[], const struct ProgramVars *vars) {
|
||||||
// ProgramVars contains pointer to main executable (mapped) file
|
// ProgramVars contains pointer to main executable (mapped) file
|
||||||
const void* main = (int*)(vars->mh);
|
const void *main = (int *)(vars->mh);
|
||||||
// Find our lib (mapped) file
|
// Find our lib (mapped) file
|
||||||
const void* thislib = find_header((void*)bruh);
|
const void *thislib = find_header((void *)bruh);
|
||||||
// Find dyld lib (mapped) file using a no-sus function
|
// Find dyld lib (mapped) file using a no-sus function
|
||||||
const void* libdyld = find_header((void*)dyld_get_sdk_version);
|
const void *libdyld = find_header((void *)dyld_get_sdk_version);
|
||||||
|
|
||||||
const void* libc = find_header((void*)printf);
|
const void *libc = find_header((void *)printf);
|
||||||
|
|
||||||
// From libdyld header, we can list exports table
|
// From libdyld header, we can list exports table
|
||||||
// to find all function we want to use
|
// to find all function we want to use
|
||||||
@ -273,16 +275,16 @@ static void bruh(int argc, const char* const argv[], const char* const envp[], c
|
|||||||
printf("libdyld header at %p\n", libdyld);
|
printf("libdyld header at %p\n", libdyld);
|
||||||
|
|
||||||
for (int i = 0; i < _dyld_image_count(); i++) {
|
for (int i = 0; i < _dyld_image_count(); i++) {
|
||||||
void* header = (void*)_dyld_get_image_header(i);
|
void *header = (void *)_dyld_get_image_header(i);
|
||||||
char* name = (char*)_dyld_get_image_name(i);
|
char *name = (char *)_dyld_get_image_name(i);
|
||||||
int offset = _dyld_get_image_vmaddr_slide(i);
|
int offset = _dyld_get_image_vmaddr_slide(i);
|
||||||
printf("%p 0x%x name=%s\n", header, offset, name);
|
printf("%p 0x%x name=%s\n", header, offset, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t trie_size;
|
uint32_t trie_size;
|
||||||
void* thislib_export_trie = get_export_trie(thislib, trie_size);
|
void *thislib_export_trie = get_export_trie(thislib, trie_size);
|
||||||
void* libdyld_export_trie = get_export_trie(libdyld, trie_size);
|
void *libdyld_export_trie = get_export_trie(libdyld, trie_size);
|
||||||
void* libc_export_trie = get_export_trie(libc, trie_size);
|
void *libc_export_trie = get_export_trie(libc, trie_size);
|
||||||
|
|
||||||
// printf("export this lib address %p\n", thislib_export_trie);
|
// printf("export this lib address %p\n", thislib_export_trie);
|
||||||
// for (int i = 0; i < 136; i++) {
|
// for (int i = 0; i < 136; i++) {
|
||||||
@ -291,7 +293,6 @@ static void bruh(int argc, const char* const argv[], const char* const envp[], c
|
|||||||
// }
|
// }
|
||||||
// printf("\n");
|
// printf("\n");
|
||||||
|
|
||||||
|
|
||||||
// printf("export dyld lib address %llx\n", (uint64_t)libdyld_export_trie);
|
// printf("export dyld lib address %llx\n", (uint64_t)libdyld_export_trie);
|
||||||
// for (int i = 0; i < 0x11e0; i++) {
|
// for (int i = 0; i < 0x11e0; i++) {
|
||||||
// if (i % 0x10 == 0) printf("\n");
|
// if (i % 0x10 == 0) printf("\n");
|
||||||
@ -310,22 +311,24 @@ static void bruh(int argc, const char* const argv[], const char* const envp[], c
|
|||||||
// fwrite(system_export_trie, trie_size, 1, write_ptr);
|
// fwrite(system_export_trie, trie_size, 1, write_ptr);
|
||||||
|
|
||||||
struct test_find_export {
|
struct test_find_export {
|
||||||
const char* name;
|
const char *name;
|
||||||
const void* lib;
|
const void *lib;
|
||||||
void* trie;
|
void *trie;
|
||||||
void* original;
|
void *original;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct test_find_export find_export_testcases[] = {
|
struct test_find_export find_export_testcases[] = {
|
||||||
{"__Z11find_headerPv", thislib, thislib_export_trie, (void*)find_header},
|
{"__Z11find_headerPv", thislib, thislib_export_trie, (void *)find_header},
|
||||||
{"__dyld_get_image_name", libdyld, libdyld_export_trie, (void*)_dyld_get_image_name},
|
{"__dyld_get_image_name", libdyld, libdyld_export_trie,
|
||||||
{"__dyld_image_count", libdyld, libdyld_export_trie, (void*)_dyld_image_count},
|
(void *)_dyld_get_image_name},
|
||||||
{"_printf",libc, libc_export_trie, (void*)printf},
|
{"__dyld_image_count", libdyld, libdyld_export_trie,
|
||||||
|
(void *)_dyld_image_count},
|
||||||
|
{"_printf", libc, libc_export_trie, (void *)printf},
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
struct test_find_export test = find_export_testcases[i];
|
struct test_find_export test = find_export_testcases[i];
|
||||||
void* found = find_in_export_trie(test.lib, test.trie, (char*)test.name);
|
void *found = find_in_export_trie(test.lib, test.trie, (char *)test.name);
|
||||||
printf("%s: Found=%p | Expect=%p\n", test.name, found, test.original);
|
printf("%s: Found=%p | Expect=%p\n", test.name, found, test.original);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,11 +337,11 @@ static void bruh(int argc, const char* const argv[], const char* const envp[], c
|
|||||||
// modern symbol resolve
|
// modern symbol resolve
|
||||||
// fix got
|
// fix got
|
||||||
|
|
||||||
uint64_t* got = (uint64_t*)((char*)main + 0x4000);
|
uint64_t *got = (uint64_t *)((char *)main + 0x4000);
|
||||||
|
|
||||||
|
|
||||||
printf("BEFORE symbol bind code is %llx\n", *got);
|
printf("BEFORE symbol bind code is %llx\n", *got);
|
||||||
vm_protect(mach_task_self(), (uint64_t)got, 0x4000, 0, VM_PROT_READ | VM_PROT_WRITE);
|
vm_protect(mach_task_self(), (uint64_t)got, 0x4000, 0,
|
||||||
|
VM_PROT_READ | VM_PROT_WRITE);
|
||||||
|
|
||||||
// fix got table
|
// fix got table
|
||||||
// *got = (uint64_t)find_in_export_trie(libc, libc_export_trie, "_printf");
|
// *got = (uint64_t)find_in_export_trie(libc, libc_export_trie, "_printf");
|
||||||
|
Loading…
Reference in New Issue
Block a user