|
|
|
@ -2,17 +2,17 @@ package macho
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"encoding/binary"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"math/rand"
|
|
|
|
|
"strings"
|
|
|
|
|
"time"
|
|
|
|
|
"strings"
|
|
|
|
|
"encoding/binary"
|
|
|
|
|
|
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
|
|
|
|
|
|
"ios-wrapper/pkg/protomodel"
|
|
|
|
|
. "ios-wrapper/pkg/ios"
|
|
|
|
|
"ios-wrapper/pkg/protomodel"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// #include "fixups.h"
|
|
|
|
@ -285,10 +285,10 @@ func (mc *MachoContext) RemoveBindSymbols() {
|
|
|
|
|
} else {
|
|
|
|
|
mc.removeBindSymbolsLegacy()
|
|
|
|
|
}
|
|
|
|
|
// Objective-C stub replaces main which can only appears in executable
|
|
|
|
|
if mc.Header().IsExecutable() {
|
|
|
|
|
mc.ReworkForObjc()
|
|
|
|
|
}
|
|
|
|
|
// Objective-C stub replaces main which can only appears in executable
|
|
|
|
|
if mc.Header().IsExecutable() {
|
|
|
|
|
mc.ReworkForObjc()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// due to some limitations when design this tool
|
|
|
|
|
// we write the c code to stdout lol
|
|
|
|
@ -445,27 +445,27 @@ func (mc *MachoContext) ReworkForObjc() {
|
|
|
|
|
// arm also has different indexing instruction, so be careful
|
|
|
|
|
// https://developer.arm.com/documentation/102374/0101/Loads-and-stores---addressing
|
|
|
|
|
/*
|
|
|
|
|
adr x8, 0
|
|
|
|
|
# x9 = (offset end of __DATA) - (offset shellcode)
|
|
|
|
|
movz x9, #0x9999
|
|
|
|
|
add x8, x8, x9
|
|
|
|
|
adr x8, 0
|
|
|
|
|
# x9 = (offset end of __DATA) - (offset shellcode)
|
|
|
|
|
movz x9, #0x9999
|
|
|
|
|
add x8, x8, x9
|
|
|
|
|
|
|
|
|
|
stp x30, x8, [sp], #-0x10
|
|
|
|
|
stp x3, x2, [sp], #-0x10
|
|
|
|
|
stp x1, x0, [sp], #-0x10
|
|
|
|
|
stp x30, x8, [sp], #-0x10
|
|
|
|
|
stp x3, x2, [sp], #-0x10
|
|
|
|
|
stp x1, x0, [sp], #-0x10
|
|
|
|
|
|
|
|
|
|
# custom intializer
|
|
|
|
|
ldr x9, [x8]
|
|
|
|
|
blr x9
|
|
|
|
|
# custom intializer
|
|
|
|
|
ldr x9, [x8]
|
|
|
|
|
blr x9
|
|
|
|
|
|
|
|
|
|
ldp x1, x0, [sp, #0x10]!
|
|
|
|
|
ldp x3, x2, [sp, #0x10]!
|
|
|
|
|
ldp x30, x8, [sp, #0x10]!
|
|
|
|
|
ldp x1, x0, [sp, #0x10]!
|
|
|
|
|
ldp x3, x2, [sp, #0x10]!
|
|
|
|
|
ldp x30, x8, [sp, #0x10]!
|
|
|
|
|
|
|
|
|
|
# original main
|
|
|
|
|
# link register is set so jump only
|
|
|
|
|
ldr x9, [x8, #8]
|
|
|
|
|
br x9
|
|
|
|
|
# original main
|
|
|
|
|
# link register is set so jump only
|
|
|
|
|
ldr x9, [x8, #8]
|
|
|
|
|
br x9
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// TODO: fix to work with offset larger than 0xffff
|
|
|
|
@ -529,72 +529,72 @@ func (mc *MachoContext) ReworkForObjc() {
|
|
|
|
|
|
|
|
|
|
func (mc *MachoContext) RewriteImportsTable(keepSymbols []string) {
|
|
|
|
|
allSymbols := mc.CollectBindSymbols()
|
|
|
|
|
fixups, fixupsOffset := mc.Fixups()
|
|
|
|
|
fixups, fixupsOffset := mc.Fixups()
|
|
|
|
|
|
|
|
|
|
importTable := fixups.ImportsOffset(uint32(fixupsOffset))
|
|
|
|
|
symbolTable := fixups.SymbolsOffset(uint32(fixupsOffset))
|
|
|
|
|
symbolTablePtr := symbolTable
|
|
|
|
|
importTable := fixups.ImportsOffset(uint32(fixupsOffset))
|
|
|
|
|
symbolTable := fixups.SymbolsOffset(uint32(fixupsOffset))
|
|
|
|
|
symbolTablePtr := symbolTable
|
|
|
|
|
|
|
|
|
|
// in removeBindSymbolsModern, we erase these pointers in file
|
|
|
|
|
// but because we keep a few symbols, we need to rewrite the pointers
|
|
|
|
|
// as well as rebuild the import table and strings table, and bind values
|
|
|
|
|
// in removeBindSymbolsModern, we erase these pointers in file
|
|
|
|
|
// but because we keep a few symbols, we need to rewrite the pointers
|
|
|
|
|
// as well as rebuild the import table and strings table, and bind values
|
|
|
|
|
|
|
|
|
|
keepCount := uint32(0)
|
|
|
|
|
for _, symbol := range keepSymbols {
|
|
|
|
|
name := symbol
|
|
|
|
|
lib := ""
|
|
|
|
|
parts := strings.Split(symbol, ",")
|
|
|
|
|
if len(parts) == 2 {
|
|
|
|
|
name = parts[0]
|
|
|
|
|
lib = parts[1]
|
|
|
|
|
}
|
|
|
|
|
keepCount := uint32(0)
|
|
|
|
|
for _, symbol := range keepSymbols {
|
|
|
|
|
name := symbol
|
|
|
|
|
lib := ""
|
|
|
|
|
parts := strings.Split(symbol, ",")
|
|
|
|
|
if len(parts) == 2 {
|
|
|
|
|
name = parts[0]
|
|
|
|
|
lib = parts[1]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
symbolInfo := (*ImportSymbol)(nil)
|
|
|
|
|
for _, s := range allSymbols {
|
|
|
|
|
if s.Name() != name {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if lib == "" || lib == s.Dylib() {
|
|
|
|
|
symbolInfo = s
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if symbolInfo == nil {
|
|
|
|
|
// symbol not found
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
symbolInfo := (*ImportSymbol)(nil)
|
|
|
|
|
for _, s := range allSymbols {
|
|
|
|
|
if s.Name() != name {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if lib == "" || lib == s.Dylib() {
|
|
|
|
|
symbolInfo = s
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if symbolInfo == nil {
|
|
|
|
|
// symbol not found
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fmt.Printf("keep symbol %s\n", name)
|
|
|
|
|
fmt.Printf("importTable at 0x%x; stringTable at 0x%x\n", importTable, symbolTablePtr)
|
|
|
|
|
fmt.Printf("bind value at 0x%x\n", symbolInfo.file_address)
|
|
|
|
|
fmt.Printf("keep symbol %s\n", name)
|
|
|
|
|
fmt.Printf("importTable at 0x%x; stringTable at 0x%x\n", importTable, symbolTablePtr)
|
|
|
|
|
fmt.Printf("bind value at 0x%x\n", symbolInfo.file_address)
|
|
|
|
|
|
|
|
|
|
// write string to string table
|
|
|
|
|
mc.file.WriteAt([]byte(name), int64(symbolTablePtr))
|
|
|
|
|
// fix bind value
|
|
|
|
|
rebaseOpcodeBytes := make([]byte, 8)
|
|
|
|
|
mc.file.ReadAt(rebaseOpcodeBytes, int64(symbolInfo.file_address))
|
|
|
|
|
rebaseOpcode := mc.byteorder.Uint64(rebaseOpcodeBytes)
|
|
|
|
|
bindOpcode := C.MakeBindFixupOpcodeFromRebase(C.uint64_t(rebaseOpcode), C.uint(keepCount))
|
|
|
|
|
// write string to string table
|
|
|
|
|
mc.file.WriteAt([]byte(name), int64(symbolTablePtr))
|
|
|
|
|
// fix bind value
|
|
|
|
|
rebaseOpcodeBytes := make([]byte, 8)
|
|
|
|
|
mc.file.ReadAt(rebaseOpcodeBytes, int64(symbolInfo.file_address))
|
|
|
|
|
rebaseOpcode := mc.byteorder.Uint64(rebaseOpcodeBytes)
|
|
|
|
|
bindOpcode := C.MakeBindFixupOpcodeFromRebase(C.uint64_t(rebaseOpcode), C.uint(keepCount))
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
v := make([]byte, 8)
|
|
|
|
|
mc.byteorder.PutUint64(v, uint64(bindOpcode))
|
|
|
|
|
mc.file.WriteAt(v, int64(symbolInfo.file_address))
|
|
|
|
|
}
|
|
|
|
|
// write import data to import table
|
|
|
|
|
entry := C.MakeImportTableEntry(C.uint(symbolInfo.LibOrdinal()), C.uint(symbolTablePtr - symbolTable))
|
|
|
|
|
{
|
|
|
|
|
v := make([]byte, 4)
|
|
|
|
|
mc.byteorder.PutUint32(v, uint32(entry))
|
|
|
|
|
mc.file.WriteAt(v, int64(importTable))
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
v := make([]byte, 8)
|
|
|
|
|
mc.byteorder.PutUint64(v, uint64(bindOpcode))
|
|
|
|
|
mc.file.WriteAt(v, int64(symbolInfo.file_address))
|
|
|
|
|
}
|
|
|
|
|
// write import data to import table
|
|
|
|
|
entry := C.MakeImportTableEntry(C.uint(symbolInfo.LibOrdinal()), C.uint(symbolTablePtr-symbolTable))
|
|
|
|
|
{
|
|
|
|
|
v := make([]byte, 4)
|
|
|
|
|
mc.byteorder.PutUint32(v, uint32(entry))
|
|
|
|
|
mc.file.WriteAt(v, int64(importTable))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
keepCount += 1
|
|
|
|
|
importTable += 4
|
|
|
|
|
symbolTablePtr += uint32(len(name)) + 1
|
|
|
|
|
}
|
|
|
|
|
keepCount += 1
|
|
|
|
|
importTable += 4
|
|
|
|
|
symbolTablePtr += uint32(len(name)) + 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fixups.imports_count = keepCount
|
|
|
|
|
fixups.imports_count = keepCount
|
|
|
|
|
mc.file.WriteAt(fixups.Serialize(mc), int64(mc.fixups.dataoff))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -685,128 +685,128 @@ func (mc *MachoContext) RemoveExportTrie() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (mc *MachoContext) AddSection(segname string, name string, size int) Section {
|
|
|
|
|
// mc.file.WriteAt(mc.header.Serialize(mc), 0)
|
|
|
|
|
var ret Section
|
|
|
|
|
var buffer bytes.Buffer
|
|
|
|
|
// mc.file.WriteAt(mc.header.Serialize(mc), 0)
|
|
|
|
|
var ret Section
|
|
|
|
|
var buffer bytes.Buffer
|
|
|
|
|
for _, command := range mc.commands {
|
|
|
|
|
switch command.(type) {
|
|
|
|
|
case *Segment64:
|
|
|
|
|
var virtualAddr uint64
|
|
|
|
|
var fileOffset uint64
|
|
|
|
|
var virtualAddr uint64
|
|
|
|
|
var fileOffset uint64
|
|
|
|
|
|
|
|
|
|
var segment = command.(*Segment64)
|
|
|
|
|
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte(segname)) != 0 {
|
|
|
|
|
buffer.Write(segment.Serialize(mc))
|
|
|
|
|
continue
|
|
|
|
|
} else {
|
|
|
|
|
virtualAddr = segment.Vmaddr()
|
|
|
|
|
fileOffset = segment.Fileoff()
|
|
|
|
|
for _, section := range segment.Sections() {
|
|
|
|
|
virtualAddr += section.Size()
|
|
|
|
|
// if section.Offset() != 0 {
|
|
|
|
|
fileOffset += section.Size()
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte(segname)) != 0 {
|
|
|
|
|
buffer.Write(segment.Serialize(mc))
|
|
|
|
|
continue
|
|
|
|
|
} else {
|
|
|
|
|
virtualAddr = segment.Vmaddr()
|
|
|
|
|
fileOffset = segment.Fileoff()
|
|
|
|
|
for _, section := range segment.Sections() {
|
|
|
|
|
virtualAddr += section.Size()
|
|
|
|
|
// if section.Offset() != 0 {
|
|
|
|
|
fileOffset += section.Size()
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
align := uint64(4)
|
|
|
|
|
alignment := align - (fileOffset % align)
|
|
|
|
|
fileOffset += alignment
|
|
|
|
|
virtualAddr += alignment
|
|
|
|
|
align := uint64(4)
|
|
|
|
|
alignment := align - (fileOffset % align)
|
|
|
|
|
fileOffset += alignment
|
|
|
|
|
virtualAddr += alignment
|
|
|
|
|
|
|
|
|
|
enoughSpace := segment.Fileoff() + segment.Filesize() >= fileOffset + uint64(size)
|
|
|
|
|
if !enoughSpace {
|
|
|
|
|
fmt.Println("Not enough space to store saved info in __DATA segment, need resize (not supported now)")
|
|
|
|
|
panic("Not enough space to store saved info in __DATA segment, need resize (not supported now)")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
enoughSpace := segment.Fileoff()+segment.Filesize() >= fileOffset+uint64(size)
|
|
|
|
|
if !enoughSpace {
|
|
|
|
|
fmt.Println("Not enough space to store saved info in __DATA segment, need resize (not supported now)")
|
|
|
|
|
panic("Not enough space to store saved info in __DATA segment, need resize (not supported now)")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var section Section64
|
|
|
|
|
section.sectname = make([]byte, 16)
|
|
|
|
|
copy(section.sectname, name)
|
|
|
|
|
section.segname = make([]byte, 16)
|
|
|
|
|
copy(section.segname, segname)
|
|
|
|
|
section.size = uint64(size)
|
|
|
|
|
section.reloff = 0
|
|
|
|
|
section.nreloc = 0
|
|
|
|
|
section.flags = 0
|
|
|
|
|
section.align = 3
|
|
|
|
|
section.reserved1 = 0
|
|
|
|
|
section.reserved2 = 0
|
|
|
|
|
section.reserved3 = 0
|
|
|
|
|
var section Section64
|
|
|
|
|
section.sectname = make([]byte, 16)
|
|
|
|
|
copy(section.sectname, name)
|
|
|
|
|
section.segname = make([]byte, 16)
|
|
|
|
|
copy(section.segname, segname)
|
|
|
|
|
section.size = uint64(size)
|
|
|
|
|
section.reloff = 0
|
|
|
|
|
section.nreloc = 0
|
|
|
|
|
section.flags = 0
|
|
|
|
|
section.align = 3
|
|
|
|
|
section.reserved1 = 0
|
|
|
|
|
section.reserved2 = 0
|
|
|
|
|
section.reserved3 = 0
|
|
|
|
|
|
|
|
|
|
// addr will increment from the last section
|
|
|
|
|
// offset will increment from the last section + size
|
|
|
|
|
// be careful of Virtual section (bss)
|
|
|
|
|
section.addr = virtualAddr
|
|
|
|
|
section.offset = uint32(fileOffset)
|
|
|
|
|
segment.nsects += 1
|
|
|
|
|
buffer.Write(segment.Serialize(mc))
|
|
|
|
|
buffer.Write(section.Serialize(mc))
|
|
|
|
|
// addr will increment from the last section
|
|
|
|
|
// offset will increment from the last section + size
|
|
|
|
|
// be careful of Virtual section (bss)
|
|
|
|
|
section.addr = virtualAddr
|
|
|
|
|
section.offset = uint32(fileOffset)
|
|
|
|
|
segment.nsects += 1
|
|
|
|
|
buffer.Write(segment.Serialize(mc))
|
|
|
|
|
buffer.Write(section.Serialize(mc))
|
|
|
|
|
|
|
|
|
|
fmt.Printf("Add a new section with addr=0x%x, fileoffset=0x%x\n", section.addr, section.offset)
|
|
|
|
|
fmt.Printf("Add a new section with addr=0x%x, fileoffset=0x%x\n", section.addr, section.offset)
|
|
|
|
|
|
|
|
|
|
ret = §ion
|
|
|
|
|
continue
|
|
|
|
|
ret = §ion
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
buffer.Write(command.Serialize(mc))
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
buffer.Write(command.Serialize(mc))
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mc.header.sizeofcmds = uint32(buffer.Len())
|
|
|
|
|
header := mc.header.Serialize(mc)
|
|
|
|
|
mc.file.WriteAt(header, 0)
|
|
|
|
|
mc.file.WriteAt(buffer.Bytes(), int64(len(header)))
|
|
|
|
|
return ret
|
|
|
|
|
mc.header.sizeofcmds = uint32(buffer.Len())
|
|
|
|
|
header := mc.header.Serialize(mc)
|
|
|
|
|
mc.file.WriteAt(header, 0)
|
|
|
|
|
mc.file.WriteAt(buffer.Bytes(), int64(len(header)))
|
|
|
|
|
return ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (mc *MachoContext) WriteInfoToData(info *protomodel.MachoInfo) {
|
|
|
|
|
encode := func () []byte {
|
|
|
|
|
buffer := new(bytes.Buffer)
|
|
|
|
|
encode := func() []byte {
|
|
|
|
|
buffer := new(bytes.Buffer)
|
|
|
|
|
for _, table := range info.Symbols.Tables {
|
|
|
|
|
binary.Write(buffer, mc.byteorder, table.LibIndex)
|
|
|
|
|
binary.Write(buffer, mc.byteorder, table.Nsymbols)
|
|
|
|
|
binary.Write(buffer, mc.byteorder, table.LibIndex)
|
|
|
|
|
binary.Write(buffer, mc.byteorder, table.Nsymbols)
|
|
|
|
|
for _, symbol := range table.Symbols {
|
|
|
|
|
binary.Write(buffer, mc.byteorder, (symbol.SymbolIndex<<8)|symbol.SegmentIndex)
|
|
|
|
|
binary.Write(buffer, mc.byteorder, symbol.Offset)
|
|
|
|
|
binary.Write(buffer, mc.byteorder, (symbol.SymbolIndex<<8)|symbol.SegmentIndex)
|
|
|
|
|
binary.Write(buffer, mc.byteorder, symbol.Offset)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
instructions := buffer.Bytes()
|
|
|
|
|
instructions := buffer.Bytes()
|
|
|
|
|
|
|
|
|
|
buffer = new(bytes.Buffer)
|
|
|
|
|
buffer = new(bytes.Buffer)
|
|
|
|
|
for _, lib := range info.Symbols.Libs {
|
|
|
|
|
buffer.WriteString(lib)
|
|
|
|
|
buffer.WriteByte(0)
|
|
|
|
|
buffer.WriteString(lib)
|
|
|
|
|
buffer.WriteByte(0)
|
|
|
|
|
}
|
|
|
|
|
liblist := buffer.Bytes()
|
|
|
|
|
liblist := buffer.Bytes()
|
|
|
|
|
|
|
|
|
|
buffer = new(bytes.Buffer)
|
|
|
|
|
buffer = new(bytes.Buffer)
|
|
|
|
|
for _, symbol := range info.Symbols.Symbols {
|
|
|
|
|
buffer.WriteString(symbol)
|
|
|
|
|
buffer.WriteByte(0)
|
|
|
|
|
buffer.WriteString(symbol)
|
|
|
|
|
buffer.WriteByte(0)
|
|
|
|
|
}
|
|
|
|
|
symbollist := buffer.Bytes()
|
|
|
|
|
symbollist := buffer.Bytes()
|
|
|
|
|
|
|
|
|
|
buffer = new(bytes.Buffer)
|
|
|
|
|
// offset to liblist
|
|
|
|
|
binary.Write(buffer, mc.byteorder, uint32(len(instructions)))
|
|
|
|
|
// offset to symbollist
|
|
|
|
|
binary.Write(buffer, mc.byteorder, uint32(len(instructions) + len(liblist)))
|
|
|
|
|
buffer.Write(instructions)
|
|
|
|
|
buffer.Write(liblist)
|
|
|
|
|
buffer.Write(symbollist)
|
|
|
|
|
buffer = new(bytes.Buffer)
|
|
|
|
|
// offset to liblist
|
|
|
|
|
binary.Write(buffer, mc.byteorder, uint32(len(instructions)))
|
|
|
|
|
// offset to symbollist
|
|
|
|
|
binary.Write(buffer, mc.byteorder, uint32(len(instructions)+len(liblist)))
|
|
|
|
|
buffer.Write(instructions)
|
|
|
|
|
buffer.Write(liblist)
|
|
|
|
|
buffer.Write(symbollist)
|
|
|
|
|
|
|
|
|
|
return buffer.Bytes()
|
|
|
|
|
}
|
|
|
|
|
encoded := encode()
|
|
|
|
|
// encoded := []byte{0x11,0x22,0x33, 0x44}
|
|
|
|
|
section := mc.AddSection("__DATA", "selfbind", len(encoded))
|
|
|
|
|
if mc.Is64bit() {
|
|
|
|
|
var s *Section64 = section.(*Section64)
|
|
|
|
|
mc.file.WriteAt(encoded, int64(s.Offset()))
|
|
|
|
|
} else {
|
|
|
|
|
var s *Section32 = section.(*Section32)
|
|
|
|
|
mc.file.WriteAt(encoded, int64(s.Offset()))
|
|
|
|
|
}
|
|
|
|
|
return buffer.Bytes()
|
|
|
|
|
}
|
|
|
|
|
encoded := encode()
|
|
|
|
|
// encoded := []byte{0x11,0x22,0x33, 0x44}
|
|
|
|
|
section := mc.AddSection("__DATA", "selfbind", len(encoded))
|
|
|
|
|
if mc.Is64bit() {
|
|
|
|
|
var s *Section64 = section.(*Section64)
|
|
|
|
|
mc.file.WriteAt(encoded, int64(s.Offset()))
|
|
|
|
|
} else {
|
|
|
|
|
var s *Section32 = section.(*Section32)
|
|
|
|
|
mc.file.WriteAt(encoded, int64(s.Offset()))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|