add old go tooling

This commit is contained in:
2023-05-31 16:17:03 +07:00
commit 54f1f3eb38
57 changed files with 5791 additions and 0 deletions

View File

@ -0,0 +1,33 @@
package action
import (
. "ios-wrapper/internal/wrapper/ofile"
)
// Actions on MachoFile
type Action interface {
withMacho(mf *MachoFile) error
withFat(ff *FatFile) error
// TODO: error context
}
func RunAction(action Action, ofile OFile) error {
switch ofile.(type) {
case *MachoFile:
return action.withMacho(ofile.(*MachoFile))
case *FatFile:
return action.withFat(ofile.(*FatFile))
}
// not likely
return nil
}
func defaultWithFat(action Action, ff *FatFile) error {
for _, macho := range ff.Machos() {
err := action.withMacho(macho)
if err != nil {
return err
}
}
return nil
}

View File

@ -0,0 +1,31 @@
package action
import (
log "github.com/sirupsen/logrus"
. "ios-wrapper/internal/wrapper/ofile"
)
type addDylib struct {
dylib_to_add []string
}
func (action *addDylib) withMacho(mf *MachoFile) error {
for _, dylib := range action.dylib_to_add {
mf.Context().AddDylib(dylib)
log.WithFields(log.Fields{
"dylib": dylib,
}).Info("Add Load Dylib Command")
}
return nil
}
func (action *addDylib) withFat(ff *FatFile) error {
return defaultWithFat(action, ff)
}
func NewAddDylibAction(dylib_to_add []string) *addDylib {
return &addDylib{
dylib_to_add,
}
}

View File

@ -0,0 +1,31 @@
package action
import (
log "github.com/sirupsen/logrus"
. "ios-wrapper/internal/wrapper/ofile"
)
type addRpath struct {
rpath []string
}
func (action *addRpath) withMacho(mf *MachoFile) error {
for _, rpath := range action.rpath {
mf.Context().AddRPath(rpath)
log.WithFields(log.Fields{
"rpath": rpath,
}).Info("Add Rpath Command")
}
return nil
}
func (action *addRpath) withFat(ff *FatFile) error {
return defaultWithFat(action, ff)
}
func NewAddRpathAction(rpath []string) *addRpath {
return &addRpath{
rpath,
}
}

View File

@ -0,0 +1,20 @@
package action
import (
. "ios-wrapper/internal/wrapper/ofile"
)
type removeClassicSymbol struct{}
func (action *removeClassicSymbol) withMacho(mf *MachoFile) error {
mf.Context().RemoveClassicSymbol()
return nil
}
func (action *removeClassicSymbol) withFat(ff *FatFile) error {
return defaultWithFat(action, ff)
}
func NewRemoveClassicSymbolAction() *removeClassicSymbol {
return &removeClassicSymbol{}
}

View File

@ -0,0 +1,20 @@
package action
import (
. "ios-wrapper/internal/wrapper/ofile"
)
type removeCodeSignature struct{}
func (action *removeCodeSignature) withMacho(mf *MachoFile) error {
mf.Context().RemoveCodesign()
return nil
}
func (action *removeCodeSignature) withFat(ff *FatFile) error {
return defaultWithFat(action, ff)
}
func NewRemoveCodeSignatureAction() *removeCodeSignature {
return &removeCodeSignature{}
}

View File

@ -0,0 +1,20 @@
package action
import (
. "ios-wrapper/internal/wrapper/ofile"
)
type removeInitPointer struct{}
func (action *removeInitPointer) withMacho(mf *MachoFile) error {
mf.Context().RemoveInitFunctions()
return nil
}
func (action *removeInitPointer) withFat(ff *FatFile) error {
return defaultWithFat(action, ff)
}
func NewRemoveInitPointerAction() *removeInitPointer {
return &removeInitPointer{}
}

View File

@ -0,0 +1,20 @@
package action
import (
. "ios-wrapper/internal/wrapper/ofile"
)
type removeUnnecessaryInfo struct{}
func (action *removeUnnecessaryInfo) withMacho(mf *MachoFile) error {
mf.Context().RemoveUnnecessaryInfo()
return nil
}
func (action *removeUnnecessaryInfo) withFat(ff *FatFile) error {
return defaultWithFat(action, ff)
}
func NewRemoveUnnecessaryInfoAction() *removeUnnecessaryInfo {
return &removeUnnecessaryInfo{}
}

View File

@ -0,0 +1,68 @@
package action
import (
"fmt"
"io/ioutil"
"google.golang.org/protobuf/proto"
. "ios-wrapper/internal/wrapper/ofile"
"ios-wrapper/pkg/protomodel"
)
type saveBcellFile struct {
bcellfile string
content *protomodel.BcellFile
signed bool
}
func (action *saveBcellFile) addMacho(mf *MachoFile) {
action.content.MachoInfos[mf.Context().ArchName()] = mf.Info()
}
func (action *saveBcellFile) writeFile() error {
outfile := fmt.Sprintf(action.bcellfile)
content, err := proto.Marshal(action.content)
if err != nil {
return err
}
if action.signed {
blocks := []*protomodel.Block{
{
Key: 0,
Value: content,
},
}
signed_data := protomodel.SignedData{
Blocks: blocks,
}
content, err = proto.Marshal(&signed_data)
}
return ioutil.WriteFile(outfile, content, 0644)
}
func (action *saveBcellFile) withMacho(mf *MachoFile) error {
action.addMacho(mf)
return action.writeFile()
}
func (action *saveBcellFile) withFat(ff *FatFile) error {
for _, macho := range ff.Machos() {
action.addMacho(macho)
}
return action.writeFile()
}
func NewSaveBcellFileAction(userconfig *protomodel.Config, bcellfile string, signed bool) *saveBcellFile {
content := &protomodel.BcellFile{
BcellConfig: userconfig,
MachoInfos: make(map[string]*protomodel.MachoInfo),
}
return &saveBcellFile{
bcellfile,
content,
signed,
}
}

View File

@ -0,0 +1,34 @@
package action
import (
log "github.com/sirupsen/logrus"
. "ios-wrapper/internal/wrapper/ofile"
"ios-wrapper/pkg/protomodel"
)
type saveInitPointer struct{}
func (action *saveInitPointer) withMacho(mf *MachoFile) error {
init_pointers := []*protomodel.MachoInfo_InitPointer{}
for _, ptr := range mf.Context().InitFunctions() {
init_pointers = append(init_pointers,
&protomodel.MachoInfo_InitPointer{
Offset: ptr.Offset(),
Value: ptr.Value(),
})
}
log.WithFields(log.Fields{
"pointers": init_pointers,
}).Info("Saved Init Pointers")
mf.Info().InitPointers = init_pointers
return nil
}
func (action *saveInitPointer) withFat(ff *FatFile) error {
return defaultWithFat(action, ff)
}
func NewSaveInitPointerAction() *saveInitPointer {
return &saveInitPointer{}
}

View File

@ -0,0 +1,32 @@
package action
import (
"io/ioutil"
. "ios-wrapper/internal/wrapper/ofile"
"ios-wrapper/pkg/ios/fat"
)
type writeFile struct {
outfile string
}
func (action *writeFile) withMacho(mf *MachoFile) error {
data, _ := ioutil.ReadFile(mf.TmpFile())
return ioutil.WriteFile(action.outfile, data, 0644)
}
func (action *writeFile) withFat(ff *FatFile) error {
var files []string
for _, macho := range ff.Machos() {
files = append(files, macho.TmpFile())
}
fat.FatJoin(files, action.outfile)
return nil
}
func NewWriteFileAction(outfile string) *writeFile {
return &writeFile{
outfile,
}
}

View File

@ -0,0 +1,48 @@
package addr2line
import (
"strconv"
. "ios-wrapper/pkg/ios/macho"
)
// Try to get Image base of a DWARF binary
// using __mh_execute_header symbol
func TryGetImageBase(mc *MachoContext, symbols []*Symbol) uint64 {
try := mc.ImageBase()
if try != 0 {
return try
}
for _, symbol := range symbols {
if symbol.Name() == "__mh_execute_header" {
return symbol.Address()
}
}
return 0
}
// find the symbol name from dysymtab
// the address given is somewhere in the function,
// assuming that the address is sorted, we find the last symbol
// has its address smaller than `tofind`
// I'm not sure this would work always, ;)
func FindSymbol(symbols []*Symbol, tofind uint64) string {
var lastSymbol string = ""
for _, symbol := range symbols {
if symbol.Address() > tofind {
return lastSymbol
} else {
lastSymbol = symbol.Name()
}
}
return ""
}
func ParseAddressString(s string) (uint64, error) {
s_, err := strconv.ParseInt(s, 0, 64)
v := uint64(s_)
if err != nil {
return 0, err
}
return v, nil
}

View File

@ -0,0 +1,81 @@
package addr2line
import (
"errors"
"fmt"
. "ios-wrapper/pkg/ios/macho"
)
type Resolver struct {
symbols []*Symbol
debuglineInfo *DebuglineInfo
aslr uint64
addresses []string
}
type Resolved struct {
Raw uint64
Base uint64
Symbol string
File string
Line uint32
}
func (r *Resolved) Valid() bool {
return r.File == "" && r.Line == 0
}
func (resolver *Resolver) HasNext() bool {
return len(resolver.addresses) > 0
}
func (resolver *Resolver) Next() (*Resolved, error) {
if !resolver.HasNext() {
return nil, errors.New("There is no more address to resolve")
}
head, tail := resolver.addresses[0], resolver.addresses[1:]
resolver.addresses = tail
tofind_aslr, err := ParseAddressString(head)
if err != nil {
return nil, fmt.Errorf("Cannot parse hex address (%s)", head)
}
tofind := tofind_aslr - resolver.aslr
symbol := FindSymbol(resolver.symbols, tofind)
fileLine := resolver.debuglineInfo.Find(tofind)
if fileLine == nil {
return &Resolved{
Raw: tofind_aslr,
Base: tofind,
Symbol: symbol,
File: "",
Line: 0,
}, nil
}
return &Resolved{
Raw: tofind_aslr,
Base: tofind,
Symbol: symbol,
File: fileLine.File,
Line: fileLine.Line,
}, nil
}
func NewResolver(mc *MachoContext, loadaddr uint64, addresses []string) *Resolver {
symbols := mc.CollectSymbols()
debuglineInfo := mc.DebugLineInfo()
imagebase := TryGetImageBase(mc, symbols)
aslr := loadaddr - imagebase
return &Resolver{
symbols,
debuglineInfo,
aslr,
addresses,
}
}

View File

@ -0,0 +1,190 @@
package wrapper
import (
"fmt"
"io/ioutil"
"os"
"github.com/alecthomas/kong"
log "github.com/sirupsen/logrus"
"google.golang.org/protobuf/proto"
"ios-wrapper/internal/wrapper/addr2line"
. "ios-wrapper/internal/wrapper/ofile"
"ios-wrapper/pkg/ios/fat"
"ios-wrapper/pkg/protomodel"
)
const envLogLevel = "LOG_LEVEL"
const defaultLogLevel = log.InfoLevel
func getLogLevel() log.Level {
levelString, exists := os.LookupEnv(envLogLevel)
if !exists {
return defaultLogLevel
}
level, err := log.ParseLevel(levelString)
if err != nil {
return defaultLogLevel
}
return level
}
func Cli() {
var cli Argument
ctx := kong.Parse(&cli)
command := ctx.Selected().Name
log.SetLevel(getLogLevel())
if command == "info" {
arg := cli.Info
printOFile(arg.OFile)
return
} else if command == "signed-bcell" {
arg := cli.SignedBcell
makeSignedBcell(arg.Out, arg.Bcell)
return
} else if command == "display-bcell" {
arg := cli.DisplayBcell
displayBcell(arg.Bcell)
return
} else if command == "addr2line" {
arg := cli.Addr2Line
resolveAddresses(arg.Dwarf, arg.Load, arg.Addresses)
return
} else if command == "lipo split" {
arg := cli.Lipo.Split
fat.FatSplit(arg.Fat)
return
} else if command == "lipo join" {
arg := cli.Lipo.Join
fat.FatJoin(arg.Macho, arg.Out)
return
}
var pc ProgramContext
var ofile OFile = nil
switch command {
case "wrap":
arg := cli.Wrap
ofile = NewOFile(arg.OFile)
pc.remove_codesign = true
pc.strip_init_pointers = true
pc.dylib_to_add = []string{"@rpath/bcell.framework/bcell"}
pc.rpath_to_add = []string{"@executable_path/Frameworks"}
pc.outfile = arg.Out
pc.bcellfile = arg.Bcell
pc.signed = arg.Signed
pc.ReadUserConfig(arg.Config)
case "vltk":
arg := cli.Vltk
ofile = NewOFile(arg.OFile)
pc.remove_codesign = true
pc.dylib_to_add = []string{"@rpath/GTJetModule.framework/GTJetModule"}
pc.outfile = arg.Out
case "remove-codesign", "remove-signature":
arg := cli.RemoveCodesign
ofile = NewOFile(arg.OFile)
pc.remove_codesign = true
pc.outfile = arg.Out
default:
return
}
pc.Process(ofile)
ofile.Cleanup()
}
func printOFile(ofile string) {
f, _ := os.OpenFile(ofile, os.O_RDWR, 0644)
printer := InfoPrinterFromFile(f)
printer.Print()
}
func makeSignedBcell(outfile string, infile string) {
raw_data, err := ioutil.ReadFile(infile)
if err != nil {
log.Panic("Cannot read bcell.dat")
}
data := &protomodel.BcellFile{}
err = proto.Unmarshal(raw_data, data)
if err != nil {
log.Panic("Invalid bcell.dat")
}
blocks := []*protomodel.Block{
{
Key: 0,
Value: raw_data,
},
}
signed_data := protomodel.SignedData{
Blocks: blocks,
}
signed_data_b, err := proto.Marshal(&signed_data)
err = ioutil.WriteFile(outfile, signed_data_b, 0644)
if err != nil {
log.Panic("Cannot write SignedData to file")
}
}
func displayBcell(bfile string) {
raw_data, err := ioutil.ReadFile(bfile)
if err != nil {
log.Panic("Invalid Protobuf<BcellFile> bcell.dat (1)")
}
data := &protomodel.BcellFile{}
err = proto.Unmarshal(raw_data, data)
if err != nil {
log.Panic("Invalid Protobuf<BcellFile> bcell.dat (2)")
}
fmt.Printf("[+] User Config: %+v\n", data.BcellConfig)
for arch, info := range data.MachoInfos {
fmt.Printf("[+] Arch %s:\n", arch)
fmt.Printf(" | PointerSize : %+v\n", info.PointerSize)
fmt.Printf(" | Image Base : 0x%x\n", info.ImageBase)
fmt.Printf(" | Init Pointers:\n")
for _, init_ptr := range info.InitPointers {
fmt.Printf(
" | offset 0x%x => addr 0x%x\n",
init_ptr.Offset,
init_ptr.Value,
)
}
}
}
func resolveAddresses(dwarf string, load string, addresses []string) {
mf, valid_macho := NewOFile(dwarf).(*MachoFile)
if !valid_macho {
log.Error("Input DWARF file is not a valid Macho binary")
return
}
loadaddr, err := addr2line.ParseAddressString(load)
if err != nil {
log.Error("Load address is not a valid hex number (%s)", load)
return
}
resolver := addr2line.NewResolver(mf.Context(), loadaddr, addresses)
for ; ; resolver.HasNext() {
resolved, err := resolver.Next()
if err != nil {
fmt.Printf("[?] Error: %s\n", err)
} else if resolved.Valid() {
fmt.Printf("[+] Found 0x%x => 0x%x %s %s:%d\n",
resolved.Raw, resolved.Base, resolved.Symbol, resolved.File, resolved.Line)
} else {
fmt.Printf("[-] Not found 0x%x\n", resolved.Raw)
}
}
}

View File

@ -0,0 +1,66 @@
package wrapper
type WrapArgument struct {
Config string `short:"c" required help:"User config.json" type:"existingfile"`
Out string `short:"o" required name:"outfile" help:"Modified Mach-O/Fat binary output file" type:"path"`
Bcell string `short:"b" required help:"bcell.dat output file" type:"path"`
Signed bool `short:"s" required help:"Output Protobuf<SignedData> for bcell.dat"`
OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"`
}
type VltkArgument struct {
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"`
}
type InfoArgument struct {
OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"`
All bool `short:"a" help:"If print all information"`
Arch string `help:"Only print information in this arch"`
}
type RemoveCodesignArgument struct {
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"`
}
type SignedBcellArgument struct {
Out string `short:"o" required name:"outfile" help:"bcell.dat.signed output file" type:"existingfile"`
Bcell string `arg short:"b" required help:"bcell.dat input file" type:"existingfile"`
}
type DisplayBcellArgument struct {
Bcell string `arg short:"b" required help:"Protobuf<BcellFile> bcell.dat input file" type:"existingfile"`
}
type Addr2LineArgument struct {
Load string `short:"l" required help:"Load address of binary"`
Dwarf string `short:"d" required help:"Path to Mach-O DWARF binary file" type:"existingfile"`
Addresses []string `arg help:"Addresses to resolve"`
}
type LipoArgument struct {
Join struct {
Out string `short:"o" required help:"Output Fat binary file" type:"path"`
Macho []string `arg help:"Macho binaries to join" type:"existingfile"`
} `cmd help:"Join Macho binaries into Fat binary"`
Split struct {
Fat string `arg help:"Fat binary to split" type:"existingfile"`
} `cmd help:"Split fat binary into files, named <name>_<arch>"`
}
type PepeArgument struct {
OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"`
}
type Argument struct {
Wrap WrapArgument `cmd help:"Modifies Mach-O/Fat binary"`
Vltk VltkArgument `cmd help:"Modifies Mach-O/Fat binary"`
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"`
SignedBcell SignedBcellArgument `cmd name:"signed-bcell" help:"Change Protobuf<BcellFile> into Protobuf<SignedData>"`
DisplayBcell DisplayBcellArgument `cmd name:"display-bcell" help:"Display Protobuf<BcellFile> content"`
Addr2Line Addr2LineArgument `cmd name:"addr2line" help:"Resolve crash address from DWARF file"`
Lipo LipoArgument `cmd help:"split Fat binary or join Mach-O binares"`
Pepe PepeArgument `cmd help:"split Fat binary or join Mach-O binares"`
}

View File

@ -0,0 +1,110 @@
package wrapper
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"os"
. "ios-wrapper/pkg/ios"
. "ios-wrapper/pkg/ios/fat"
. "ios-wrapper/pkg/ios/macho"
)
type InfoPrinter struct {
contexts []*MachoContext
}
func (printer *InfoPrinter) Print() {
for _, mc := range printer.contexts {
fmt.Printf("Mach-O arch: %s\n", mc.ArchName())
for i, cmd := range mc.Commands() {
fmt.Printf("%d: %s\n", i, cmd.Cmdname())
}
fmt.Printf("Image Base: 0x%x\n", mc.ImageBase())
init_funcs := mc.InitFunctions()
if len(init_funcs) == 0 {
fmt.Println("No Init functions")
}
for _, fun := range init_funcs {
fmt.Printf("Init functions at offset %s\n", &fun)
}
symbols := mc.CollectLazyBindSymbols()
if len(symbols) > 0 {
fmt.Println("Lazy Symbols")
for _, sym := range symbols {
fmt.Printf(
"%s\n\tStub=0x%x Address=0x%x\n\tDylib=%s\n",
sym.Name(),
sym.Stub(),
sym.Address(),
sym.Dylib(),
)
}
} else {
fmt.Println("No lazy symbols")
}
fmt.Println("======")
}
}
func machoPrinter(file *os.File) *InfoPrinter {
var mc MachoContext
err := mc.ParseFile(file, 0)
if err != nil {
return &InfoPrinter{
contexts: []*MachoContext{},
}
} else {
return &InfoPrinter{
contexts: []*MachoContext{&mc},
}
}
}
func fatPrinter(file *os.File) *InfoPrinter {
var fat FatContext
fat.ParseFile(file)
var contexts []*MachoContext
for _, m := range fat.Machos() {
buf := make([]byte, m.Size)
file.Seek(int64(m.Offset), io.SeekStart)
file.Read(buf)
var mc MachoContext
mc.ParseBuffer(buf)
contexts = append(contexts, &mc)
}
return &InfoPrinter{
contexts,
}
}
func InfoPrinterFromFile(file *os.File) *InfoPrinter {
var magic uint32
magic_buf := []byte{0, 0, 0, 0}
file.Read(magic_buf)
magic_r := bytes.NewReader(magic_buf)
binary.Read(magic_r, binary.LittleEndian, &magic)
file.Seek(0, io.SeekStart)
if magic == MagicFat || magic == CigamFat {
return fatPrinter(file)
}
if magic == Magic32 || magic == Magic64 || magic == Cigam32 ||
magic == Cigam64 {
return machoPrinter(file)
}
return &InfoPrinter{}
}

View File

@ -0,0 +1,58 @@
package ofile
import (
"io/ioutil"
"os"
log "github.com/sirupsen/logrus"
"ios-wrapper/pkg/ios/fat"
)
type FatFile struct {
machos []*MachoFile
files []string
tmp_file string
}
func (ff *FatFile) Machos() []*MachoFile {
return ff.machos
}
func (ff *FatFile) Cleanup() {
for _, macho := range ff.machos {
macho.Cleanup()
}
os.Remove(ff.tmp_file)
}
func NewFatFile(f string) *FatFile {
// create a tmp working file
tmp, _ := ioutil.TempFile("", "bcell_*")
data, _ := ioutil.ReadFile(f)
ioutil.WriteFile(tmp.Name(), data, 0644)
var machos []*MachoFile
var files []string
splitted_files, err := fat.FatSplit(tmp.Name())
if err != nil {
log.WithFields(log.Fields{
"err": err,
"splitted_ok": splitted_files,
}).Panic("Cannot split Fat binary")
}
for _, splitted_file := range splitted_files {
macho := NewMachoFile(splitted_file)
machos = append(machos, macho)
files = append(files, macho.tmp_file)
// NewMachoFile creates another tmp file, remove this temp splitted file
os.Remove(splitted_file)
}
return &FatFile{
machos: machos,
tmp_file: tmp.Name(),
files: files,
}
}

View File

@ -0,0 +1,56 @@
package ofile
import (
"io/ioutil"
"os"
// log "github.com/sirupsen/logrus"
"ios-wrapper/pkg/ios/macho"
"ios-wrapper/pkg/protomodel"
)
type MachoFile struct {
mc *macho.MachoContext
tmp_file string
info *protomodel.MachoInfo
}
func (mf *MachoFile) Context() *macho.MachoContext {
return mf.mc
}
func (mf *MachoFile) Info() *protomodel.MachoInfo {
return mf.info
}
func (mf *MachoFile) TmpFile() string {
return mf.tmp_file
}
func (mf *MachoFile) Cleanup() {
os.Remove(mf.tmp_file)
}
func NewMachoFile(f string) *MachoFile {
// create a tmp working file
tmp, _ := ioutil.TempFile("", "bcell_*")
data, _ := ioutil.ReadFile(f)
ioutil.WriteFile(tmp.Name(), data, 0644)
var mc macho.MachoContext
tmp, _ = os.OpenFile(tmp.Name(), os.O_RDWR, 0644)
mc.ParseFile(tmp, 0)
return &MachoFile{
mc: &mc,
tmp_file: tmp.Name(),
info: &protomodel.MachoInfo{
PointerSize: map[bool]protomodel.MachoInfo_PointerSize{
false: protomodel.MachoInfo_p32,
true: protomodel.MachoInfo_p64,
}[mc.Is64bit()],
ImageBase: mc.ImageBase(),
},
}
}

View File

@ -0,0 +1,47 @@
package ofile
import (
"bufio"
"bytes"
"encoding/binary"
"os"
log "github.com/sirupsen/logrus"
. "ios-wrapper/pkg/ios"
)
type OFile interface {
Cleanup()
}
func NewOFile(f string) OFile {
file, err := os.Open(f)
if err != nil {
return nil
}
r := bufio.NewReader(file)
var magic uint32
magic_buf, _ := r.Peek(4)
magic_r := bytes.NewReader(magic_buf)
binary.Read(magic_r, binary.LittleEndian, &magic)
if magic != Magic32 && magic != Magic64 && magic != Cigam32 && magic != Cigam64 && magic != MagicFat &&
magic != CigamFat {
log.Panic("Magic does not match %x", magic)
return nil
}
if magic == Magic32 || magic == Magic64 || magic == Cigam32 ||
magic == Cigam64 {
return NewMachoFile(f)
}
if magic == MagicFat || magic == CigamFat {
return NewFatFile(f)
}
// not likely
return nil
}

View File

@ -0,0 +1,110 @@
package wrapper
import (
"encoding/json"
"io/ioutil"
log "github.com/sirupsen/logrus"
. "ios-wrapper/internal/wrapper/action"
. "ios-wrapper/internal/wrapper/ofile"
"ios-wrapper/pkg/protomodel"
)
type UserConfig struct {
Repack bool `json:"repack"`
Hook bool `json:"hook"`
Emulator bool `json:"emulator"`
Debug bool `json:"debug"`
Root bool `json:"root"`
ServerURL string `json:"server_url"`
ReportType int32 `json:"report_type"`
RemoteConfigURL string `json:"remote_config_url"`
DomainID string `json:"domain_id"`
}
func (uc *UserConfig) Protomodel() *protomodel.Config {
return &protomodel.Config{
Hook: uc.Hook,
Repack: uc.Repack,
Emulator: uc.Emulator,
Debug: uc.Debug,
Root: uc.Root,
ServerUrl: uc.ServerURL,
ReportType: uc.ReportType,
RemoteConfigUrl: uc.RemoteConfigURL,
DomainId: uc.DomainID,
}
}
type ProgramContext struct {
strip_init_pointers bool
remove_codesign bool
dylib_to_add []string
rpath_to_add []string
outfile string
actions []Action
err error
user_config UserConfig
bcellfile string
signed bool // true: Protobuf<SignedData>; false: Protobuf<BcellFile>
}
func (pc *ProgramContext) ExplainError(err error) {
log.WithFields(log.Fields{
"pc error": pc.err,
"ofile error": err,
}).Error("OFile Process gone wrong")
}
func (pc *ProgramContext) ReadUserConfig(f string) {
json_data, err := ioutil.ReadFile(f)
if err != nil {
log.Panic("User Config file is invalid")
}
json.Unmarshal(json_data, &pc.user_config)
}
func (pc *ProgramContext) AddAction(action Action) {
pc.actions = append(pc.actions, action)
}
func (pc *ProgramContext) dispatchActions(ofile OFile) {
for _, action := range pc.actions {
err := RunAction(action, ofile)
if err != nil {
pc.err = err
break
}
}
}
func (pc *ProgramContext) Process(ofile OFile) {
if pc.remove_codesign {
pc.AddAction(NewRemoveCodeSignatureAction())
}
if pc.strip_init_pointers {
pc.AddAction(NewSaveInitPointerAction())
pc.AddAction(NewRemoveInitPointerAction())
}
ExperimentalFeature("Remove Unnecessary Info", func() {
pc.AddAction(NewRemoveUnnecessaryInfoAction())
})
ExperimentalFeature("Remove Classic Symbol", func() {
pc.AddAction(NewRemoveClassicSymbolAction())
})
pc.AddAction(NewAddRpathAction(pc.rpath_to_add))
pc.AddAction(NewAddDylibAction(pc.dylib_to_add))
if pc.bcellfile != "" {
pc.AddAction(NewSaveBcellFileAction(pc.user_config.Protomodel(), pc.bcellfile, pc.signed))
} else {
log.Warn("bcellfile is not set, no output bcellfile")
}
pc.AddAction(NewWriteFileAction(pc.outfile))
pc.dispatchActions(ofile)
}

View File

@ -0,0 +1,30 @@
package wrapper
import (
"fmt"
"os"
log "github.com/sirupsen/logrus"
)
func FileExist(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}
func CheckFileExistence(filename string) {
if !FileExist(filename) {
fmt.Printf("File %s does not exists\n", filename)
os.Exit(1)
}
}
func ExperimentalFeature(feature string, foo func()) {
if os.Getenv("EXPERIMENTAL") == "1" {
log.Info(fmt.Sprintf("Running Experimental Feature %s", feature))
foo()
}
}