mirror of
https://github.com/blacktop/ipsw.git
synced 2026-05-08 12:22:26 +00:00
chore: refactor disassembly code to use new instruction representation
- Updated disassembly functions to utilize the new `disassemble.Inst` type instead of `disassemble.Instruction`. - Modified operand retrieval functions to accommodate the new instruction structure. - Enhanced error handling and logging for instruction decoding failures. - Improved JSON output for disassembly to ensure disassembly strings are preserved. - Refactored various components across the disassembly package, including Mach-O and dyld handling, to streamline instruction processing. - Added tests to validate the new disassembly behavior and ensure backward compatibility.
This commit is contained in:
+140
-82
@@ -172,35 +172,86 @@ func IsBranchOp(op disassemble.Operation) bool {
|
||||
}
|
||||
|
||||
// IsLoadLiteral returns true if the instruction is a PC-relative literal load
|
||||
func IsLoadLiteral(instr *disassemble.Instruction) bool {
|
||||
func IsLoadLiteral(instr *disassemble.Inst) bool {
|
||||
switch instr.Operation {
|
||||
case disassemble.ARM64_LDR, disassemble.ARM64_LDRSW, disassemble.ARM64_PRFM:
|
||||
return len(instr.Operands) > 1 && instr.Operands[1].Class == disassemble.LABEL
|
||||
return instr != nil && instr.NumOps > 1 && instr.Operands[1].Class == disassemble.LABEL
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func operandRegister(instr *disassemble.Instruction, idx int) (disassemble.Register, bool) {
|
||||
if instr == nil || len(instr.Operands) <= idx || len(instr.Operands[idx].Registers) == 0 {
|
||||
func operandRegister(instr *disassemble.Inst, idx int) (disassemble.Register, bool) {
|
||||
if instr == nil || int(instr.NumOps) <= idx || instr.Operands[idx].NumRegisters == 0 {
|
||||
return disassemble.REG_NONE, false
|
||||
}
|
||||
return instr.Operands[idx].Registers[0], true
|
||||
}
|
||||
|
||||
func operandImmediate(instr *disassemble.Instruction, idx int) (uint64, bool) {
|
||||
if instr == nil || len(instr.Operands) <= idx {
|
||||
func operandImmediate(instr *disassemble.Inst, idx int) (uint64, bool) {
|
||||
if instr == nil || int(instr.NumOps) <= idx {
|
||||
return 0, false
|
||||
}
|
||||
return instr.Operands[idx].Immediate, true
|
||||
}
|
||||
|
||||
func operandShiftValue(instr *disassemble.Instruction, idx int) (uint64, bool) {
|
||||
if instr == nil || len(instr.Operands) <= idx {
|
||||
func operandShiftValue(instr *disassemble.Inst, idx int) (uint64, bool) {
|
||||
if instr == nil || int(instr.NumOps) <= idx {
|
||||
return 0, false
|
||||
}
|
||||
return uint64(instr.Operands[idx].ShiftValue), true
|
||||
}
|
||||
|
||||
func implSpecificSysReg(op *disassemble.Op) (string, bool) {
|
||||
if op == nil || !op.HasImplSpec {
|
||||
return "", false
|
||||
}
|
||||
|
||||
sysReg := disassemble.SystemReg(op.ImplSpec[0])<<14 |
|
||||
disassemble.SystemReg(op.ImplSpec[1])<<11 |
|
||||
disassemble.SystemReg(op.ImplSpec[2])<<7 |
|
||||
disassemble.SystemReg(op.ImplSpec[3])<<3 |
|
||||
disassemble.SystemReg(op.ImplSpec[4])
|
||||
|
||||
name := sysReg.String()
|
||||
if len(name) == 0 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
return name, true
|
||||
}
|
||||
|
||||
func invalidInstruction(addr uint64, raw uint32, err error) disassemble.Instruction {
|
||||
return disassemble.Instruction{
|
||||
Address: addr,
|
||||
Raw: raw,
|
||||
Encoding: 0,
|
||||
Operation: 0,
|
||||
Operands: nil,
|
||||
SetFlags: 0,
|
||||
Disassembly: fmt.Sprintf(".long\t%#x ; (%s)\n", raw, err.Error()),
|
||||
}
|
||||
}
|
||||
|
||||
func logStubDecodeContext(
|
||||
instruction *disassemble.Inst,
|
||||
queue *[2]disassemble.Inst,
|
||||
queueValid *[2]bool,
|
||||
) {
|
||||
if instruction != nil {
|
||||
if text, err := instruction.Disassemble(); err == nil {
|
||||
log.Debugf("%#08x: %s\t%s", instruction.Address, disassemble.GetOpCodeByteString(instruction.Raw), text)
|
||||
}
|
||||
}
|
||||
|
||||
for idx := range queue {
|
||||
if queueValid[idx] {
|
||||
if text, err := queue[idx].Disassemble(); err == nil {
|
||||
log.Debugf("%#08x: %s\t%s", queue[idx].Address, disassemble.GetOpCodeByteString(queue[idx].Raw), text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const maxCStringCommentLen = 200
|
||||
|
||||
func cstringComment(d Disass, addr uint64) string {
|
||||
@@ -237,8 +288,9 @@ func Disassemble(d Disass) string {
|
||||
var sb strings.Builder
|
||||
var instrStr string
|
||||
var instrValue uint32
|
||||
var results [1024]byte
|
||||
var prevInstr *disassemble.Instruction
|
||||
var decoder disassemble.Decoder
|
||||
var prevInstr disassemble.Inst
|
||||
var hasPrev bool
|
||||
var instructions []disassemble.Instruction
|
||||
|
||||
r := bytes.NewReader(d.Data())
|
||||
@@ -254,8 +306,8 @@ func Disassemble(d Disass) string {
|
||||
|
||||
if !d.AsJSON() {
|
||||
var comment string
|
||||
instruction, err := disassemble.Decompose(startAddr, instrValue, &results)
|
||||
if err != nil {
|
||||
var instruction disassemble.Inst
|
||||
if err := decoder.DecomposeInto(startAddr, instrValue, &instruction); err != nil {
|
||||
var op string
|
||||
var oprs string
|
||||
if instrValue == 0xfeedfacf {
|
||||
@@ -272,7 +324,7 @@ func Disassemble(d Disass) string {
|
||||
op = ".long"
|
||||
oprs = fmt.Sprintf("%#x", instrValue)
|
||||
comment = " ; (probably a jump-table)"
|
||||
} else if prevInstr != nil && strings.Contains(prevInstr.Operation.String(), "braa") {
|
||||
} else if hasPrev && strings.Contains(prevInstr.Operation.String(), "braa") {
|
||||
break // TODO: why did I do this again?
|
||||
} else if (instrValue & 0xfffffC00) == 0x00201000 {
|
||||
Xr := disassemble.Register((instrValue & 0x1F) + 34)
|
||||
@@ -323,7 +375,20 @@ func Disassemble(d Disass) string {
|
||||
goto INCR_ADDR
|
||||
}
|
||||
|
||||
instrStr = instruction.String()
|
||||
if instrStr, err = instruction.Disassemble(); err != nil {
|
||||
if d.Color() {
|
||||
fmt.Fprintf(&sb, "%s: %s %s %s%s\n",
|
||||
colorAddr("%#08x", uint64(startAddr)),
|
||||
colorOpCodes(disassemble.GetOpCodeByteString(instrValue)),
|
||||
colorOp("%-7s", ".long"),
|
||||
ColorOperands(fmt.Sprintf(" %#x", instrValue)),
|
||||
colorComment(fmt.Sprintf(" ; (%s)", err.Error())),
|
||||
)
|
||||
} else {
|
||||
fmt.Fprintf(&sb, "%#08x: %s .long\t%#x ; (%s)\n", uint64(startAddr), disassemble.GetOpCodeByteString(instrValue), instrValue, err.Error())
|
||||
}
|
||||
goto INCR_ADDR
|
||||
}
|
||||
|
||||
if !d.Quite() {
|
||||
// check for start of a new function
|
||||
@@ -369,14 +434,14 @@ func Disassemble(d Disass) string {
|
||||
if instruction.Operation == disassemble.ARM64_MRS || instruction.Operation == disassemble.ARM64_MSR {
|
||||
var ops []string
|
||||
replaced := false
|
||||
for idx, op := range instruction.Operands {
|
||||
for idx := 0; idx < int(instruction.NumOps); idx++ {
|
||||
op := instruction.Operands[idx]
|
||||
if op.Class == disassemble.REG {
|
||||
if reg, ok := operandRegister(instruction, idx); ok {
|
||||
if reg, ok := operandRegister(&instruction, idx); ok {
|
||||
ops = append(ops, reg.String())
|
||||
}
|
||||
} else if op.Class == disassemble.IMPLEMENTATION_SPECIFIC {
|
||||
sysRegFix := op.ImplSpec.GetSysReg().String()
|
||||
if len(sysRegFix) > 0 {
|
||||
if sysRegFix, ok := implSpecificSysReg(&op); ok {
|
||||
ops = append(ops, sysRegFix)
|
||||
replaced = true
|
||||
}
|
||||
@@ -387,7 +452,8 @@ func Disassemble(d Disass) string {
|
||||
}
|
||||
} else if ok, loc := d.IsBranchLocation(instruction.Address); ok {
|
||||
opStr := strings.TrimPrefix(instrStr, fmt.Sprintf("%s\t", instruction.Operation))
|
||||
for _, operand := range instruction.Operands {
|
||||
for idx := 0; idx < int(instruction.NumOps); idx++ {
|
||||
operand := instruction.Operands[idx]
|
||||
if operand.Class == disassemble.LABEL {
|
||||
if name, ok := d.FindSymbol(uint64(operand.Immediate)); ok {
|
||||
display := symbols.FormatSymbol(name, d.Demangle())
|
||||
@@ -409,21 +475,21 @@ func Disassemble(d Disass) string {
|
||||
}
|
||||
instrStr = fmt.Sprintf("%s\t%s", instruction.Operation, opStr)
|
||||
} else if instruction.Operation == disassemble.ARM64_BL || instruction.Operation == disassemble.ARM64_B {
|
||||
if target, ok := operandImmediate(instruction, 0); ok {
|
||||
if target, ok := operandImmediate(&instruction, 0); ok {
|
||||
if name, ok := d.FindSymbol(target); ok {
|
||||
display := symbols.FormatSymbol(name, d.Demangle())
|
||||
instrStr = fmt.Sprintf("%s\t%s", instruction.Operation, display)
|
||||
comment = appendComment(comment, cstringComment(d, target))
|
||||
}
|
||||
}
|
||||
} else if IsLoadLiteral(instruction) {
|
||||
} else if IsLoadLiteral(&instruction) {
|
||||
if name, ok := d.FindSymbol(uint64(instruction.Operands[1].Immediate)); ok {
|
||||
display := symbols.FormatSymbol(name, d.Demangle())
|
||||
comment = fmt.Sprintf(" ; %s", display)
|
||||
comment = appendComment(comment, cstringComment(d, uint64(instruction.Operands[1].Immediate)))
|
||||
}
|
||||
} else if instruction.Operation == disassemble.ARM64_CBZ || instruction.Operation == disassemble.ARM64_CBNZ {
|
||||
if target, ok := operandImmediate(instruction, 1); ok {
|
||||
if target, ok := operandImmediate(&instruction, 1); ok {
|
||||
if name, ok := d.FindSymbol(target); ok {
|
||||
display := symbols.FormatSymbol(name, d.Demangle())
|
||||
comment = fmt.Sprintf(" ; %s", display)
|
||||
@@ -432,7 +498,8 @@ func Disassemble(d Disass) string {
|
||||
}
|
||||
} else if instruction.Operation == disassemble.ARM64_ADR {
|
||||
opStr := strings.TrimPrefix(instrStr, fmt.Sprintf("%s\t", instruction.Operation))
|
||||
for _, operand := range instruction.Operands {
|
||||
for idx := 0; idx < int(instruction.NumOps); idx++ {
|
||||
operand := instruction.Operands[idx]
|
||||
if operand.Class == disassemble.LABEL {
|
||||
if name, ok := d.FindSymbol(uint64(operand.Immediate)); ok {
|
||||
display := symbols.FormatSymbol(name, d.Demangle())
|
||||
@@ -450,29 +517,29 @@ func Disassemble(d Disass) string {
|
||||
}
|
||||
}
|
||||
instrStr = fmt.Sprintf("%s\t%s", instruction.Operation, opStr)
|
||||
} else if (prevInstr != nil && prevInstr.Operation == disassemble.ARM64_ADRP) &&
|
||||
} else if hasPrev && prevInstr.Operation == disassemble.ARM64_ADRP &&
|
||||
(instruction.Operation == disassemble.ARM64_ADD ||
|
||||
instruction.Operation == disassemble.ARM64_LDR ||
|
||||
instruction.Operation == disassemble.ARM64_LDRB ||
|
||||
instruction.Operation == disassemble.ARM64_LDRSW ||
|
||||
instruction.Operation == disassemble.ARM64_STRB) {
|
||||
adrpRegister, ok := operandRegister(prevInstr, 0)
|
||||
adrpRegister, ok := operandRegister(&prevInstr, 0)
|
||||
if ok {
|
||||
adrpImm, ok := operandImmediate(prevInstr, 1)
|
||||
adrpImm, ok := operandImmediate(&prevInstr, 1)
|
||||
if ok {
|
||||
srcRegister, ok := operandRegister(instruction, 1)
|
||||
srcRegister, ok := operandRegister(&instruction, 1)
|
||||
if ok {
|
||||
validPattern := true
|
||||
if adrpRegister == srcRegister {
|
||||
switch instruction.Operation {
|
||||
case disassemble.ARM64_LDR, disassemble.ARM64_LDRB, disassemble.ARM64_LDRSW, disassemble.ARM64_STRB:
|
||||
if imm, ok := operandImmediate(instruction, 1); ok {
|
||||
if imm, ok := operandImmediate(&instruction, 1); ok {
|
||||
adrpImm += imm
|
||||
} else {
|
||||
validPattern = false
|
||||
}
|
||||
case disassemble.ARM64_ADD:
|
||||
if imm, ok := operandImmediate(instruction, 2); ok {
|
||||
if imm, ok := operandImmediate(&instruction, 2); ok {
|
||||
adrpImm += imm
|
||||
} else {
|
||||
validPattern = false
|
||||
@@ -545,21 +612,19 @@ func Disassemble(d Disass) string {
|
||||
}
|
||||
|
||||
prevInstr = instruction
|
||||
hasPrev = true
|
||||
} else { // output as JSON
|
||||
instruction, err := disassemble.Decompose(startAddr, instrValue, &results) // TODO: it would probably be valuable to add a "comment" field and capture the analysis above for JSON peeps
|
||||
if err != nil {
|
||||
instructions = append(instructions, disassemble.Instruction{
|
||||
Address: startAddr,
|
||||
Raw: instrValue,
|
||||
Encoding: 0,
|
||||
Operation: 0,
|
||||
Operands: nil,
|
||||
SetFlags: 0,
|
||||
Disassembly: fmt.Sprintf(".long\t%#x ; (%s)\n", instrValue, err.Error()), // TODO: same with error enhancements above
|
||||
})
|
||||
var instruction disassemble.Inst
|
||||
if err := decoder.DecomposeInto(startAddr, instrValue, &instruction); err != nil { // TODO: it would probably be valuable to add a "comment" field and capture the analysis above for JSON peeps
|
||||
instructions = append(instructions, invalidInstruction(startAddr, instrValue, err)) // TODO: same with error enhancements above
|
||||
goto INCR_ADDR
|
||||
}
|
||||
instructions = append(instructions, *instruction)
|
||||
converted := instruction.ToInstruction()
|
||||
if converted.Disassembly, err = instruction.Disassemble(); err != nil {
|
||||
instructions = append(instructions, invalidInstruction(startAddr, instrValue, err))
|
||||
goto INCR_ADDR
|
||||
}
|
||||
instructions = append(instructions, *converted)
|
||||
}
|
||||
INCR_ADDR:
|
||||
startAddr += uint64(binary.Size(uint32(0)))
|
||||
@@ -661,9 +726,9 @@ func ParseStubsForMachO(m *macho.File) (map[uint64]uint64, error) {
|
||||
|
||||
func ParseStubsASM(data []byte, begin uint64, readPtr func(uint64) (uint64, error)) (map[uint64]uint64, error) {
|
||||
var instrValue uint32
|
||||
var results [1024]byte
|
||||
|
||||
queue := make([]*disassemble.Instruction, 2)
|
||||
var decoder disassemble.Decoder
|
||||
var queue [2]disassemble.Inst
|
||||
var queueValid [2]bool
|
||||
|
||||
stubs := make(map[uint64]uint64)
|
||||
|
||||
@@ -678,22 +743,23 @@ func ParseStubsASM(data []byte, begin uint64, readPtr func(uint64) (uint64, erro
|
||||
break
|
||||
}
|
||||
|
||||
instruction, err := disassemble.Decompose(startAddr, instrValue, &results)
|
||||
if err != nil {
|
||||
var instruction disassemble.Inst
|
||||
if err := decoder.DecomposeInto(startAddr, instrValue, &instruction); err != nil {
|
||||
startAddr += uint64(binary.Size(uint32(0)))
|
||||
queue[1] = queue[0] // push instruction onto const length FIFO queue
|
||||
queue[0] = instruction
|
||||
queueValid[1] = queueValid[0]
|
||||
queueValid[0] = false
|
||||
continue
|
||||
}
|
||||
|
||||
if (queue[1] != nil && queue[1].Operation == disassemble.ARM64_ADRP) &&
|
||||
(queue[0] != nil && queue[0].Operation == disassemble.ARM64_ADD) &&
|
||||
if queueValid[1] && queue[1].Operation == disassemble.ARM64_ADRP &&
|
||||
queueValid[0] && queue[0].Operation == disassemble.ARM64_ADD &&
|
||||
instruction.Operation == disassemble.ARM64_LDR {
|
||||
adrpRegister, ok := operandRegister(queue[1], 0)
|
||||
adrpRegister, ok := operandRegister(&queue[1], 0)
|
||||
if ok {
|
||||
if addRegister, ok := operandRegister(queue[0], 0); ok {
|
||||
if adrpBase, ok := operandImmediate(queue[1], 1); ok {
|
||||
if addImm, ok := operandImmediate(queue[0], 2); ok {
|
||||
if addRegister, ok := operandRegister(&queue[0], 0); ok {
|
||||
if adrpBase, ok := operandImmediate(&queue[1], 1); ok {
|
||||
if addImm, ok := operandImmediate(&queue[0], 2); ok {
|
||||
if adrpRegister == addRegister {
|
||||
// adrp x17, 0x221baf000
|
||||
stubTarget := adrpBase
|
||||
@@ -701,19 +767,14 @@ func ParseStubsASM(data []byte, begin uint64, readPtr func(uint64) (uint64, erro
|
||||
stubTarget += addImm
|
||||
stubAddr := queue[1].Address // address of beginning of stub (adrp)
|
||||
// ldr x16, [x17]
|
||||
if ldrRegister, ok := operandRegister(instruction, 1); ok &&
|
||||
if ldrRegister, ok := operandRegister(&instruction, 1); ok &&
|
||||
(addRegister == ldrRegister) { // check add reg and ldr reg are the same
|
||||
if ldrImm, ok := operandImmediate(instruction, 1); ok && ldrImm != 0 { // check for immediate
|
||||
if ldrImm, ok := operandImmediate(&instruction, 1); ok && ldrImm != 0 { // check for immediate
|
||||
stubTarget += ldrImm
|
||||
}
|
||||
addr, err := readPtr(stubTarget)
|
||||
if err != nil {
|
||||
log.Debugf("%#08x: %s\t%s", instruction.Address, disassemble.GetOpCodeByteString(instruction.Raw), instruction) // TODO: DRY this up
|
||||
for _, i := range queue {
|
||||
if i != nil {
|
||||
log.Debugf("%#08x: %s\t%s", i.Address, disassemble.GetOpCodeByteString(i.Raw), i)
|
||||
}
|
||||
}
|
||||
logStubDecodeContext(&instruction, &queue, &queueValid)
|
||||
return nil, fmt.Errorf("failed to read stub target pointer at %#x: %v", stubTarget, err)
|
||||
}
|
||||
// braa x16, x17
|
||||
@@ -724,14 +785,14 @@ func ParseStubsASM(data []byte, begin uint64, readPtr func(uint64) (uint64, erro
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (queue[1] != nil && queue[1].Operation == disassemble.ARM64_ADRP) &&
|
||||
(queue[0] != nil && queue[0].Operation == disassemble.ARM64_ADD) &&
|
||||
} else if queueValid[1] && queue[1].Operation == disassemble.ARM64_ADRP &&
|
||||
queueValid[0] && queue[0].Operation == disassemble.ARM64_ADD &&
|
||||
(IsBranchOp(instruction.Operation) || instruction.Operation == disassemble.ARM64_BR) {
|
||||
adrpRegister, ok := operandRegister(queue[1], 0)
|
||||
adrpRegister, ok := operandRegister(&queue[1], 0)
|
||||
if ok {
|
||||
if addRegister, ok := operandRegister(queue[0], 0); ok {
|
||||
if adrpBase, ok := operandImmediate(queue[1], 1); ok {
|
||||
if addImm, ok := operandImmediate(queue[0], 2); ok {
|
||||
if addRegister, ok := operandRegister(&queue[0], 0); ok {
|
||||
if adrpBase, ok := operandImmediate(&queue[1], 1); ok {
|
||||
if addImm, ok := operandImmediate(&queue[0], 2); ok {
|
||||
if adrpRegister == addRegister {
|
||||
// adrp x16, 0x19089b000
|
||||
stubTarget := adrpBase
|
||||
@@ -746,25 +807,20 @@ func ParseStubsASM(data []byte, begin uint64, readPtr func(uint64) (uint64, erro
|
||||
}
|
||||
}
|
||||
// brk #0x1
|
||||
} else if (queue[0] != nil && queue[0].Operation == disassemble.ARM64_ADRP) &&
|
||||
} else if queueValid[0] && queue[0].Operation == disassemble.ARM64_ADRP &&
|
||||
instruction.Operation == disassemble.ARM64_LDR {
|
||||
if adrpRegister, ok := operandRegister(queue[0], 0); ok {
|
||||
if adrpBase, ok := operandImmediate(queue[0], 1); ok {
|
||||
if adrpRegister, ok := operandRegister(&queue[0], 0); ok {
|
||||
if adrpBase, ok := operandImmediate(&queue[0], 1); ok {
|
||||
// adrp x16, #0x1e3be9000
|
||||
stubTarget := adrpBase // #0x1e3be9000
|
||||
// ldr x16, [x16, #0x560]
|
||||
if ldrRegister, ok := operandRegister(instruction, 0); ok && adrpRegister == ldrRegister {
|
||||
if ldrImm, ok := operandImmediate(instruction, 1); ok {
|
||||
if ldrRegister, ok := operandRegister(&instruction, 0); ok && adrpRegister == ldrRegister {
|
||||
if ldrImm, ok := operandImmediate(&instruction, 1); ok {
|
||||
stubTarget += ldrImm
|
||||
stubAddr := queue[0].Address
|
||||
addr, err := readPtr(stubTarget)
|
||||
if err != nil {
|
||||
log.Debugf("%#08x: %s\t%s", instruction.Address, disassemble.GetOpCodeByteString(instruction.Raw), instruction)
|
||||
for _, i := range queue {
|
||||
if i != nil {
|
||||
log.Debugf("%#08x: %s\t%s", i.Address, disassemble.GetOpCodeByteString(i.Raw), i)
|
||||
}
|
||||
}
|
||||
logStubDecodeContext(&instruction, &queue, &queueValid)
|
||||
return nil, fmt.Errorf("failed to read stub target pointer at %#x: %v", stubTarget, err)
|
||||
}
|
||||
stubs[stubAddr] = addr
|
||||
@@ -777,7 +833,9 @@ func ParseStubsASM(data []byte, begin uint64, readPtr func(uint64) (uint64, erro
|
||||
// fmt.Printf("%#08x: %s\t%s\n", instruction.Address, disassemble.GetOpCodeByteString(instrValue), instruction)
|
||||
|
||||
queue[1] = queue[0] // push instruction onto const length FIFO queue
|
||||
queueValid[1] = queueValid[0]
|
||||
queue[0] = instruction
|
||||
queueValid[0] = true
|
||||
startAddr += uint64(binary.Size(uint32(0)))
|
||||
}
|
||||
|
||||
@@ -786,7 +844,7 @@ func ParseStubsASM(data []byte, begin uint64, readPtr func(uint64) (uint64, erro
|
||||
|
||||
func ParseHelpersASM(m *macho.File) (map[uint64]uint64, error) {
|
||||
var instrValue uint32
|
||||
var results [1024]byte
|
||||
var decoder disassemble.Decoder
|
||||
|
||||
helpers := make(map[uint64]uint64)
|
||||
|
||||
@@ -815,8 +873,8 @@ func ParseHelpersASM(m *macho.File) (map[uint64]uint64, error) {
|
||||
break
|
||||
}
|
||||
|
||||
instruction, err := disassemble.Decompose(startAddr, instrValue, &results)
|
||||
if err != nil {
|
||||
var instruction disassemble.Inst
|
||||
if err := decoder.DecomposeInto(startAddr, instrValue, &instruction); err != nil {
|
||||
startAddr += uint64(binary.Size(uint32(0)))
|
||||
continue
|
||||
}
|
||||
@@ -829,7 +887,7 @@ func ParseHelpersASM(m *macho.File) (map[uint64]uint64, error) {
|
||||
continue
|
||||
}
|
||||
if instruction.Encoding == disassemble.ENC_BL_ONLY_BRANCH_IMM {
|
||||
if target, ok := operandImmediate(instruction, 0); ok {
|
||||
if target, ok := operandImmediate(&instruction, 0); ok {
|
||||
helpers[stubHelperFnStart] = target
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,38 @@ package disass
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/blacktop/arm64-cgo/disassemble"
|
||||
)
|
||||
|
||||
type stubDisass struct {
|
||||
data []byte
|
||||
startAddr uint64
|
||||
asJSON bool
|
||||
}
|
||||
|
||||
func (s stubDisass) Triage() error { return nil }
|
||||
func (s stubDisass) IsFunctionStart(uint64) (bool, string) { return false, "" }
|
||||
func (s stubDisass) IsLocation(uint64) bool { return false }
|
||||
func (s stubDisass) IsBranchLocation(uint64) (bool, uint64) { return false, 0 }
|
||||
func (s stubDisass) IsData(uint64) (bool, *AddrDetails) { return false, nil }
|
||||
func (s stubDisass) IsPointer(uint64) (bool, *AddrDetails) { return false, nil }
|
||||
func (s stubDisass) FindSymbol(uint64) (string, bool) { return "", false }
|
||||
func (s stubDisass) FindSwiftString(uint64) (string, bool) { return "", false }
|
||||
func (s stubDisass) GetCString(uint64) (string, error) { return "", fmt.Errorf("no cstring") }
|
||||
func (s stubDisass) Demangle() bool { return false }
|
||||
func (s stubDisass) Quite() bool { return true }
|
||||
func (s stubDisass) Color() bool { return false }
|
||||
func (s stubDisass) AsJSON() bool { return s.asJSON }
|
||||
func (s stubDisass) Data() []byte { return s.data }
|
||||
func (s stubDisass) StartAddr() uint64 { return s.startAddr }
|
||||
func (s stubDisass) Middle() uint64 { return 0 }
|
||||
func (s stubDisass) ReadAddr(uint64) (uint64, error) { return 0, fmt.Errorf("no pointer") }
|
||||
|
||||
func TestParseStubsASMADRPAndLDRStubDoesNotPanicOnTrailingBR(t *testing.T) {
|
||||
data := []byte{
|
||||
0x10, 0x00, 0x00, 0xd0, // adrp x16, ...
|
||||
@@ -40,9 +66,9 @@ func TestParseStubsASMADRPAndAddBranchParsesStub(t *testing.T) {
|
||||
0x00, 0x02, 0x1f, 0xd6, // br x16
|
||||
}
|
||||
|
||||
var results [1024]byte
|
||||
adrp, err := disassemble.Decompose(begin, binary.LittleEndian.Uint32(data[0:4]), &results)
|
||||
if err != nil {
|
||||
var decoder disassemble.Decoder
|
||||
var adrp disassemble.Inst
|
||||
if err := decoder.DecomposeInto(begin, binary.LittleEndian.Uint32(data[0:4]), &adrp); err != nil {
|
||||
t.Fatalf("failed to decompose adrp: %v", err)
|
||||
}
|
||||
want := adrp.Operands[1].Immediate + 0x8
|
||||
@@ -112,3 +138,29 @@ func TestParseStubsASMMismatchedRegistersDoNotCreateStaleStubEntry(t *testing.T)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestDisassembleJSONPreservesDisassemblyString(t *testing.T) {
|
||||
out := Disassemble(stubDisass{
|
||||
data: []byte{0x1f, 0x20, 0x03, 0xd5}, // nop
|
||||
startAddr: 0x1000,
|
||||
asJSON: true,
|
||||
})
|
||||
|
||||
var got []map[string]any
|
||||
if err := json.Unmarshal([]byte(strings.TrimSpace(out)), &got); err != nil {
|
||||
t.Fatalf("failed to unmarshal JSON disassembly output: %v\noutput=%s", err, out)
|
||||
}
|
||||
if len(got) != 1 {
|
||||
t.Fatalf("expected 1 instruction, got %d", len(got))
|
||||
}
|
||||
if addr, ok := got[0]["addr"].(float64); !ok || uint64(addr) != 0x1000 {
|
||||
t.Fatalf("unexpected instruction address payload: %#v", got[0]["addr"])
|
||||
}
|
||||
disassText, ok := got[0]["disass"].(string)
|
||||
if !ok {
|
||||
t.Fatalf("expected disass string in JSON payload, got %#v", got[0]["disass"])
|
||||
}
|
||||
if !strings.Contains(disassText, "nop") {
|
||||
t.Fatalf("expected JSON disassembly to contain nop, got %q", disassText)
|
||||
}
|
||||
}
|
||||
|
||||
+28
-22
@@ -31,6 +31,7 @@ type MachoDisass struct {
|
||||
a2s map[uint64]string
|
||||
sinfo map[uint64]uint64
|
||||
swiftstrs map[uint64]string
|
||||
decoder disassemble.Decoder
|
||||
}
|
||||
|
||||
func NewMachoDisass(f *macho.File, cfg *Config) *MachoDisass {
|
||||
@@ -69,8 +70,8 @@ func (d MachoDisass) ReadAddr(addr uint64) (uint64, error) {
|
||||
// Triage walks a function and analyzes all immediates
|
||||
func (d *MachoDisass) Triage() error {
|
||||
var instrValue uint32
|
||||
var results [1024]byte
|
||||
var prevInstr *disassemble.Instruction
|
||||
var prevInstr disassemble.Inst
|
||||
var hasPrev bool
|
||||
|
||||
d.tr = &Triage{
|
||||
Addresses: make(map[uint64]uint64),
|
||||
@@ -87,45 +88,48 @@ func (d *MachoDisass) Triage() error {
|
||||
break
|
||||
}
|
||||
|
||||
instruction, err := disassemble.Decompose(startAddr, instrValue, &results)
|
||||
if err != nil {
|
||||
var instruction disassemble.Inst
|
||||
if err := d.decoder.DecomposeInto(startAddr, instrValue, &instruction); err != nil {
|
||||
startAddr += uint64(binary.Size(uint32(0)))
|
||||
continue
|
||||
}
|
||||
|
||||
if IsBranchOp(instruction.Operation) {
|
||||
for _, op := range instruction.Operands {
|
||||
for idx := 0; idx < int(instruction.NumOps); idx++ {
|
||||
op := instruction.Operands[idx]
|
||||
if op.Class == disassemble.LABEL {
|
||||
d.tr.Addresses[instruction.Address] = uint64(op.Immediate)
|
||||
}
|
||||
}
|
||||
} else if IsLoadLiteral(instruction) {
|
||||
} else if IsLoadLiteral(&instruction) {
|
||||
d.tr.Addresses[instruction.Address] = uint64(instruction.Operands[1].Immediate)
|
||||
} else if (prevInstr != nil && prevInstr.Operation == disassemble.ARM64_ADRP) &&
|
||||
} else if hasPrev && prevInstr.Operation == disassemble.ARM64_ADRP &&
|
||||
(instruction.Operation == disassemble.ARM64_ADD ||
|
||||
instruction.Operation == disassemble.ARM64_LDR ||
|
||||
instruction.Operation == disassemble.ARM64_LDRB ||
|
||||
instruction.Operation == disassemble.ARM64_LDRSW) {
|
||||
adrpRegister, ok := operandRegister(prevInstr, 0)
|
||||
adrpRegister, ok := operandRegister(&prevInstr, 0)
|
||||
if !ok {
|
||||
prevInstr = instruction
|
||||
hasPrev = true
|
||||
startAddr += uint64(binary.Size(uint32(0)))
|
||||
continue
|
||||
}
|
||||
adrpImm, ok := operandImmediate(prevInstr, 1)
|
||||
adrpImm, ok := operandImmediate(&prevInstr, 1)
|
||||
if !ok {
|
||||
prevInstr = instruction
|
||||
hasPrev = true
|
||||
startAddr += uint64(binary.Size(uint32(0)))
|
||||
continue
|
||||
}
|
||||
if srcRegister, ok := operandRegister(instruction, 1); ok && adrpRegister == srcRegister {
|
||||
if srcRegister, ok := operandRegister(&instruction, 1); ok && adrpRegister == srcRegister {
|
||||
switch instruction.Operation {
|
||||
case disassemble.ARM64_LDR, disassemble.ARM64_LDRB, disassemble.ARM64_LDRSW:
|
||||
if imm, ok := operandImmediate(instruction, 1); ok {
|
||||
if imm, ok := operandImmediate(&instruction, 1); ok {
|
||||
adrpImm += imm
|
||||
}
|
||||
case disassemble.ARM64_ADD:
|
||||
if imm, ok := operandImmediate(instruction, 2); ok {
|
||||
if imm, ok := operandImmediate(&instruction, 2); ok {
|
||||
adrpImm += imm
|
||||
}
|
||||
}
|
||||
@@ -134,6 +138,7 @@ func (d *MachoDisass) Triage() error {
|
||||
}
|
||||
|
||||
prevInstr = instruction
|
||||
hasPrev = true
|
||||
startAddr += uint64(binary.Size(uint32(0)))
|
||||
}
|
||||
|
||||
@@ -178,8 +183,8 @@ func (d *MachoDisass) Triage() error {
|
||||
// ref - stdlib/public/core/StringObject.swift
|
||||
func (d *MachoDisass) FindSwiftStrings() (out map[uint64]string, err error) {
|
||||
var instrValue uint32
|
||||
var results [1024]byte
|
||||
var prevInstr *disassemble.Instruction
|
||||
var prevInstr disassemble.Inst
|
||||
var hasPrev bool
|
||||
|
||||
d.tr = &Triage{
|
||||
Addresses: make(map[uint64]uint64),
|
||||
@@ -207,15 +212,15 @@ func (d *MachoDisass) FindSwiftStrings() (out map[uint64]string, err error) {
|
||||
break
|
||||
}
|
||||
|
||||
instruction, err := disassemble.Decompose(startAddr, instrValue, &results)
|
||||
if err != nil {
|
||||
var instruction disassemble.Inst
|
||||
if err := d.decoder.DecomposeInto(startAddr, instrValue, &instruction); err != nil {
|
||||
startAddr += uint64(binary.Size(uint32(0)))
|
||||
continue
|
||||
}
|
||||
|
||||
if instruction.Operation == disassemble.ARM64_MOV {
|
||||
if dstRegister, ok := operandRegister(instruction, 0); ok {
|
||||
if imm, ok := operandImmediate(instruction, 1); ok {
|
||||
if dstRegister, ok := operandRegister(&instruction, 0); ok {
|
||||
if imm, ok := operandImmediate(&instruction, 1); ok {
|
||||
if reg == disassemble.REG_NONE {
|
||||
strAddr = instruction.Address
|
||||
reg = dstRegister
|
||||
@@ -232,12 +237,12 @@ func (d *MachoDisass) FindSwiftStrings() (out map[uint64]string, err error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if prevInstr != nil &&
|
||||
} else if hasPrev &&
|
||||
((prevInstr.Operation == disassemble.ARM64_MOV && instruction.Operation == disassemble.ARM64_MOVK) ||
|
||||
(prevInstr.Operation == disassemble.ARM64_MOVK && instruction.Operation == disassemble.ARM64_MOVK)) {
|
||||
if dstRegister, ok := operandRegister(instruction, 0); ok {
|
||||
if imm, ok := operandImmediate(instruction, 1); ok {
|
||||
if shift, ok := operandShiftValue(instruction, 1); ok {
|
||||
if dstRegister, ok := operandRegister(&instruction, 0); ok {
|
||||
if imm, ok := operandImmediate(&instruction, 1); ok {
|
||||
if shift, ok := operandShiftValue(&instruction, 1); ok {
|
||||
if reg == dstRegister {
|
||||
regVal += imm << shift
|
||||
} else if next == dstRegister {
|
||||
@@ -275,6 +280,7 @@ func (d *MachoDisass) FindSwiftStrings() (out map[uint64]string, err error) {
|
||||
}
|
||||
|
||||
prevInstr = instruction
|
||||
hasPrev = true
|
||||
startAddr += uint64(binary.Size(uint32(0)))
|
||||
}
|
||||
|
||||
|
||||
+24
-21
@@ -16,10 +16,11 @@ import (
|
||||
)
|
||||
|
||||
type DyldDisass struct {
|
||||
f *File
|
||||
cfg *disass.Config
|
||||
tr *disass.Triage
|
||||
dylibs []*CacheImage
|
||||
f *File
|
||||
cfg *disass.Config
|
||||
tr *disass.Triage
|
||||
dylibs []*CacheImage
|
||||
decoder disassemble.Decoder
|
||||
}
|
||||
|
||||
func NewDyldDisass(f *File, cfg *disass.Config) *DyldDisass {
|
||||
@@ -124,15 +125,15 @@ func (d DyldDisass) IsPointer(imm uint64) (bool, *disass.AddrDetails) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func operandRegister(instr *disassemble.Instruction, idx int) (disassemble.Register, bool) {
|
||||
if instr == nil || len(instr.Operands) <= idx || len(instr.Operands[idx].Registers) == 0 {
|
||||
func operandRegister(instr *disassemble.Inst, idx int) (disassemble.Register, bool) {
|
||||
if instr == nil || int(instr.NumOps) <= idx || instr.Operands[idx].NumRegisters == 0 {
|
||||
return disassemble.REG_NONE, false
|
||||
}
|
||||
return instr.Operands[idx].Registers[0], true
|
||||
}
|
||||
|
||||
func operandImmediate(instr *disassemble.Instruction, idx int) (uint64, bool) {
|
||||
if instr == nil || len(instr.Operands) <= idx {
|
||||
func operandImmediate(instr *disassemble.Inst, idx int) (uint64, bool) {
|
||||
if instr == nil || int(instr.NumOps) <= idx {
|
||||
return 0, false
|
||||
}
|
||||
return instr.Operands[idx].Immediate, true
|
||||
@@ -141,8 +142,8 @@ func operandImmediate(instr *disassemble.Instruction, idx int) (uint64, bool) {
|
||||
// Triage walks a function and analyzes all immediates
|
||||
func (d *DyldDisass) Triage() error {
|
||||
var instrValue uint32
|
||||
var results [1024]byte
|
||||
var prevInstr *disassemble.Instruction
|
||||
var prevInstr disassemble.Inst
|
||||
var hasPrev bool
|
||||
|
||||
d.tr = &disass.Triage{
|
||||
Addresses: make(map[uint64]uint64),
|
||||
@@ -172,45 +173,46 @@ func (d *DyldDisass) Triage() error {
|
||||
break
|
||||
}
|
||||
|
||||
instruction, err := disassemble.Decompose(startAddr, instrValue, &results)
|
||||
if err != nil {
|
||||
var instruction disassemble.Inst
|
||||
if err := d.decoder.DecomposeInto(startAddr, instrValue, &instruction); err != nil {
|
||||
startAddr += uint64(binary.Size(uint32(0)))
|
||||
continue
|
||||
}
|
||||
|
||||
if disass.IsBranchOp(instruction.Operation) {
|
||||
for _, op := range instruction.Operands {
|
||||
for idx := 0; idx < int(instruction.NumOps); idx++ {
|
||||
op := instruction.Operands[idx]
|
||||
if op.Class == disassemble.LABEL {
|
||||
d.tr.Addresses[instruction.Address] = uint64(op.Immediate)
|
||||
}
|
||||
}
|
||||
} else if disass.IsLoadLiteral(instruction) {
|
||||
if imm, ok := operandImmediate(instruction, 1); ok {
|
||||
} else if disass.IsLoadLiteral(&instruction) {
|
||||
if imm, ok := operandImmediate(&instruction, 1); ok {
|
||||
d.tr.Addresses[instruction.Address] = imm
|
||||
}
|
||||
} else if (prevInstr != nil && prevInstr.Operation == disassemble.ARM64_ADRP) &&
|
||||
} else if hasPrev && prevInstr.Operation == disassemble.ARM64_ADRP &&
|
||||
(instruction.Operation == disassemble.ARM64_ADD ||
|
||||
instruction.Operation == disassemble.ARM64_LDR ||
|
||||
instruction.Operation == disassemble.ARM64_LDRB ||
|
||||
instruction.Operation == disassemble.ARM64_LDRSW ||
|
||||
instruction.Operation == disassemble.ARM64_STRB) {
|
||||
adrpRegister, ok := operandRegister(prevInstr, 0)
|
||||
adrpRegister, ok := operandRegister(&prevInstr, 0)
|
||||
if ok {
|
||||
adrpImm, ok := operandImmediate(prevInstr, 1)
|
||||
adrpImm, ok := operandImmediate(&prevInstr, 1)
|
||||
if ok {
|
||||
srcRegister, ok := operandRegister(instruction, 1)
|
||||
srcRegister, ok := operandRegister(&instruction, 1)
|
||||
if ok {
|
||||
validPattern := true
|
||||
if adrpRegister == srcRegister {
|
||||
switch instruction.Operation {
|
||||
case disassemble.ARM64_LDR, disassemble.ARM64_LDRB, disassemble.ARM64_LDRSW, disassemble.ARM64_STRB:
|
||||
if imm, ok := operandImmediate(instruction, 1); ok {
|
||||
if imm, ok := operandImmediate(&instruction, 1); ok {
|
||||
adrpImm += imm
|
||||
} else {
|
||||
validPattern = false
|
||||
}
|
||||
case disassemble.ARM64_ADD:
|
||||
if imm, ok := operandImmediate(instruction, 2); ok {
|
||||
if imm, ok := operandImmediate(&instruction, 2); ok {
|
||||
adrpImm += imm
|
||||
} else {
|
||||
validPattern = false
|
||||
@@ -260,6 +262,7 @@ func (d *DyldDisass) Triage() error {
|
||||
// }
|
||||
|
||||
prevInstr = instruction
|
||||
hasPrev = true
|
||||
startAddr += uint64(binary.Size(uint32(0)))
|
||||
}
|
||||
|
||||
|
||||
+24
-13
@@ -27,9 +27,18 @@ func colorOperands(operands string) string {
|
||||
return operands
|
||||
}
|
||||
|
||||
func diss(startAddr uint64, data []byte) (instruction *disassemble.Instruction) {
|
||||
func printDecodeFailure(startAddr uint64, instrValue uint32, err error) {
|
||||
fmt.Printf("%s: %s\t%s\t%#-18x ; (%s)\n",
|
||||
colorAddr("%#08x", uint64(startAddr)),
|
||||
colorOp("%-7s", ".long"),
|
||||
colorOpCodes(disassemble.GetOpCodeByteString(instrValue)),
|
||||
instrValue,
|
||||
err.Error())
|
||||
}
|
||||
|
||||
func diss(startAddr uint64, data []byte) {
|
||||
var instrValue uint32
|
||||
var results [1024]byte
|
||||
var decoder disassemble.Decoder
|
||||
|
||||
r := bytes.NewReader(data)
|
||||
|
||||
@@ -40,17 +49,21 @@ func diss(startAddr uint64, data []byte) (instruction *disassemble.Instruction)
|
||||
break
|
||||
}
|
||||
|
||||
instruction, err = disassemble.Decompose(startAddr, instrValue, &results)
|
||||
if err != nil {
|
||||
fmt.Printf("%s: %s\t%s\t%#-18x ; (%s)\n",
|
||||
colorAddr("%#08x", uint64(startAddr)),
|
||||
colorOp("%-7s", ".long"),
|
||||
colorOpCodes(disassemble.GetOpCodeByteString(instrValue)),
|
||||
instrValue,
|
||||
err.Error())
|
||||
var instruction disassemble.Inst
|
||||
if err := decoder.DecomposeInto(startAddr, instrValue, &instruction); err != nil {
|
||||
printDecodeFailure(startAddr, instrValue, err)
|
||||
startAddr += uint64(binary.Size(uint32(0)))
|
||||
continue
|
||||
}
|
||||
|
||||
opStr := strings.TrimSpace(strings.TrimPrefix(instruction.String(), instruction.Operation.String()))
|
||||
disass, err := instruction.Disassemble()
|
||||
if err != nil {
|
||||
printDecodeFailure(startAddr, instrValue, err)
|
||||
startAddr += uint64(binary.Size(uint32(0)))
|
||||
continue
|
||||
}
|
||||
|
||||
opStr := strings.TrimSpace(strings.TrimPrefix(disass, instruction.Operation.String()))
|
||||
|
||||
fmt.Printf("%s: %s %s %s\n",
|
||||
colorAddr("%#08x", uint64(startAddr)),
|
||||
@@ -61,6 +74,4 @@ func diss(startAddr uint64, data []byte) (instruction *disassemble.Instruction)
|
||||
|
||||
startAddr += uint64(binary.Size(uint32(0)))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
+4
-4
@@ -156,7 +156,7 @@ func getBaseAddress(r *bytes.Reader) (uint64, error) {
|
||||
|
||||
var startAddr uint64 = 0
|
||||
var instrValue uint32
|
||||
var results [1024]byte
|
||||
var decoder disassemble.Decoder
|
||||
|
||||
for {
|
||||
err := binary.Read(r, binary.LittleEndian, &instrValue)
|
||||
@@ -167,12 +167,12 @@ func getBaseAddress(r *bytes.Reader) (uint64, error) {
|
||||
return 0, fmt.Errorf("failed to read instruction @ %#x: %v", startAddr, err)
|
||||
}
|
||||
|
||||
instruction, err := disassemble.Decompose(startAddr, instrValue, &results)
|
||||
if err != nil {
|
||||
var instruction disassemble.Inst
|
||||
if err := decoder.DecomposeInto(startAddr, instrValue, &instruction); err != nil {
|
||||
return 0, fmt.Errorf("failed to decompose instruction @ %#x: %v", startAddr, err)
|
||||
}
|
||||
|
||||
if disass.IsLoadLiteral(instruction) {
|
||||
if disass.IsLoadLiteral(&instruction) {
|
||||
if _, err := r.Seek(int64(instruction.Operands[1].Immediate), io.SeekStart); err != nil {
|
||||
return 0, fmt.Errorf("failed to seek to base address: %v", err)
|
||||
}
|
||||
|
||||
+18
-16
@@ -278,15 +278,15 @@ func getMigInitFunc(m *macho.File) (*types.Function, error) {
|
||||
return nil, fmt.Errorf("failed to find 'mig_init' address")
|
||||
}
|
||||
|
||||
func migOperandRegister(instr *disassemble.Instruction, idx int) (disassemble.Register, bool) {
|
||||
if instr == nil || len(instr.Operands) <= idx || len(instr.Operands[idx].Registers) == 0 {
|
||||
func migOperandRegister(instr *disassemble.Inst, idx int) (disassemble.Register, bool) {
|
||||
if instr == nil || int(instr.NumOps) <= idx || instr.Operands[idx].NumRegisters == 0 {
|
||||
return disassemble.REG_NONE, false
|
||||
}
|
||||
return instr.Operands[idx].Registers[0], true
|
||||
}
|
||||
|
||||
func migOperandImmediate(instr *disassemble.Instruction, idx int) (uint64, bool) {
|
||||
if instr == nil || len(instr.Operands) <= idx {
|
||||
func migOperandImmediate(instr *disassemble.Inst, idx int) (uint64, bool) {
|
||||
if instr == nil || int(instr.NumOps) <= idx {
|
||||
return 0, false
|
||||
}
|
||||
return instr.Operands[idx].Immediate, true
|
||||
@@ -296,8 +296,9 @@ func getMigE(r *bytes.Reader, migInit *types.Function) (uint64, error) {
|
||||
var migE uint64
|
||||
|
||||
var instrValue uint32
|
||||
var results [1024]byte
|
||||
var prevInstr *disassemble.Instruction
|
||||
var decoder disassemble.Decoder
|
||||
var prevInstr disassemble.Inst
|
||||
var hasPrev bool
|
||||
|
||||
startAddr := migInit.StartAddr
|
||||
|
||||
@@ -310,39 +311,39 @@ func getMigE(r *bytes.Reader, migInit *types.Function) (uint64, error) {
|
||||
return 0, fmt.Errorf("failed to read instruction @ %#x: %v", startAddr, err)
|
||||
}
|
||||
|
||||
instruction, err := disassemble.Decompose(startAddr, instrValue, &results)
|
||||
if err != nil {
|
||||
var instruction disassemble.Inst
|
||||
if err := decoder.DecomposeInto(startAddr, instrValue, &instruction); err != nil {
|
||||
startAddr += uint64(binary.Size(uint32(0)))
|
||||
continue
|
||||
}
|
||||
|
||||
if disass.IsLoadLiteral(instruction) {
|
||||
if imm, ok := migOperandImmediate(instruction, 1); ok {
|
||||
if disass.IsLoadLiteral(&instruction) {
|
||||
if imm, ok := migOperandImmediate(&instruction, 1); ok {
|
||||
migE = imm
|
||||
break
|
||||
}
|
||||
} else if (prevInstr != nil && prevInstr.Operation == disassemble.ARM64_ADRP) &&
|
||||
} else if hasPrev && prevInstr.Operation == disassemble.ARM64_ADRP &&
|
||||
(instruction.Operation == disassemble.ARM64_ADD ||
|
||||
instruction.Operation == disassemble.ARM64_LDR ||
|
||||
instruction.Operation == disassemble.ARM64_LDRB ||
|
||||
instruction.Operation == disassemble.ARM64_LDRSW) {
|
||||
adrpRegister, ok := migOperandRegister(prevInstr, 0)
|
||||
adrpRegister, ok := migOperandRegister(&prevInstr, 0)
|
||||
if ok {
|
||||
adrpImm, ok := migOperandImmediate(prevInstr, 1)
|
||||
adrpImm, ok := migOperandImmediate(&prevInstr, 1)
|
||||
if ok {
|
||||
srcRegister, ok := migOperandRegister(instruction, 1)
|
||||
srcRegister, ok := migOperandRegister(&instruction, 1)
|
||||
if ok {
|
||||
validPattern := true
|
||||
if adrpRegister == srcRegister {
|
||||
switch instruction.Operation {
|
||||
case disassemble.ARM64_LDR, disassemble.ARM64_LDRB, disassemble.ARM64_LDRSW:
|
||||
if imm, ok := migOperandImmediate(instruction, 1); ok {
|
||||
if imm, ok := migOperandImmediate(&instruction, 1); ok {
|
||||
adrpImm += imm
|
||||
} else {
|
||||
validPattern = false
|
||||
}
|
||||
case disassemble.ARM64_ADD:
|
||||
if imm, ok := migOperandImmediate(instruction, 2); ok {
|
||||
if imm, ok := migOperandImmediate(&instruction, 2); ok {
|
||||
adrpImm += imm
|
||||
} else {
|
||||
validPattern = false
|
||||
@@ -360,6 +361,7 @@ func getMigE(r *bytes.Reader, migInit *types.Function) (uint64, error) {
|
||||
// fmt.Printf("%#08x: %s\t%s\n", uint64(startAddr), disassemble.GetOpCodeByteString(instrValue), instruction)
|
||||
|
||||
prevInstr = instruction
|
||||
hasPrev = true
|
||||
startAddr += uint64(binary.Size(uint32(0)))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user