GP-700: Improved support for Mach-O MH_OBJECT files

This commit is contained in:
Ryan Kurtz 2021-02-23 13:40:32 -05:00
parent 92b7728cd7
commit c2f60b15d3
27 changed files with 1542 additions and 653 deletions

View file

@ -0,0 +1,82 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.bin.format.macho.relocation;
/**
* {@link ARM_MachoRelocationHandler} constants
*
* @see <a href="https://opensource.apple.com/source/xnu/xnu-7195.81.3/EXTERNAL_HEADERS/mach-o/arm/reloc.h.auto.html">mach-o/arm/reloc.h</a>
*/
public class ARM_MachoRelocationConstants {
/**
* Generic relocation as described above
*/
public final static int ARM_RELOC_VANILLA = 0;
/**
* The second relocation entry of a pair
*/
public final static int ARM_RELOC_PAIR = 1;
/**
* A PAIR follows with subtract symbol value
*/
public final static int ARM_RELOC_SECTDIFF = 2;
/**
* Like ARM_RELOC_SECTDIFF, but the symbol referenced was local
*/
public final static int ARM_RELOC_LOCAL_SECTDIFF = 3;
/**
* Pre-bound lazy pointer
*/
public final static int ARM_RELOC_PB_LA_PTR = 4;
/**
* 24 bit branch displacement (to a word address)
*/
public final static int ARM_RELOC_BR24 = 5;
/**
* 22 bit branch displacement (to a half-word address)
*/
public final static int ARM_THUMB_RELOC_BR22 = 6;
/**
* Obsolete - a thumb 32-bit branch instruction possibly needing page-spanning branch workaround
*/
public final static int ARM_THUMB_32BIT_BRANCH = 7;
/**
* For these two r_type relocations they always have a pair following them and the r_length bits
* are used differently. The encoding of the r_length is as follows:
*
* low bit of r_length:
* 0 - :lower16: for movw instructions
* 1 - :upper16: for movt instructions
*
* high bit of r_length:
* 0 - arm instructions
* 1 - thumb instructions
*
* The other half of the relocated expression is in the following pair relocation entry in the
* low 16 bits of r_address field.
*/
public final static int ARM_RELOC_HALF = 8;
public final static int ARM_RELOC_HALF_SECTDIFF = 9;
}

View file

@ -0,0 +1,105 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.bin.format.macho.relocation;
import static ghidra.app.util.bin.format.macho.relocation.ARM_MachoRelocationConstants.*;
import ghidra.app.util.bin.format.macho.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.util.exception.NotFoundException;
/**
* A {@link MachoRelocationHandler} for ARM
*
* @see <a href="https://opensource.apple.com/source/xnu/xnu-7195.81.3/EXTERNAL_HEADERS/mach-o/arm/reloc.h.auto.html">mach-o/arm/reloc.h</a>
*/
public class ARM_MachoRelocationHandler extends MachoRelocationHandler {
@Override
public boolean canRelocate(MachHeader header) {
return header.getCpuType() == CpuTypes.CPU_TYPE_ARM;
}
@Override
public boolean isPairedRelocation(RelocationInfo relocation) {
return relocation.getType() == ARM_RELOC_SECTDIFF ||
relocation.getType() == ARM_RELOC_LOCAL_SECTDIFF ||
relocation.getType() == ARM_RELOC_HALF ||
relocation.getType() == ARM_RELOC_HALF_SECTDIFF;
}
@Override
public void relocate(MachoRelocation relocation)
throws MemoryAccessException, NotFoundException {
if (!relocation.requiresRelocation()) {
return;
}
RelocationInfo relocationInfo = relocation.getRelocationInfo();
Address targetAddr = relocation.getTargetAddress();
long orig = read(relocation);
switch (relocationInfo.getType()) {
case ARM_RELOC_VANILLA:
if (!relocationInfo.isPcRelocated()) {
write(relocation, targetAddr.getOffset());
}
else {
throw new NotFoundException("Unimplemented relocation");
}
break;
case ARM_THUMB_RELOC_BR22: {
// BL and BLX
boolean blx = (orig & 0xd000f800) == 0xc000f000;
long s = (orig >> 10) & 0x1;
long j1 = (orig >> 29) & 0x1;
long j2 = (orig >> 27) & 0x1;
long i1 = ~(j1 ^ s) & 0x1;
long i2 = ~(j2 ^ s) & 0x1;
long imm10 = orig & 0x3ff;
long imm11 = (orig >> 16) & 0x7ff;
long addend = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
addend |= s == 1 ? 0xfe000000 : 0; // sign extend
addend &= blx ? ~0x3 : ~0; // 4-byte align BLX
long value = targetAddr.getOffset() + addend;
s = (value >> 24) & 0x1;
i1 = (value >> 23) & 0x1;
i2 = (value >> 22) & 0x1;
j1 = ~(i1 ^ s) & 0x1;
j2 = ~(i2 ^ s) & 0x1;
imm10 = (value >> 12) & 0x3ff;
imm11 = (value >> 1) & 0x7ff;
long instr = orig & (blx ? 0xc000f800 : 0xd000f800);
instr |= (j1 << 29) | (j2 << 27) | (imm11 << 16) | (s << 10) | imm10;
write(relocation, instr);
break;
}
case ARM_RELOC_PAIR: // should never see on its own here
case ARM_RELOC_SECTDIFF: // relocation not required (scattered)
case ARM_RELOC_LOCAL_SECTDIFF: // relocation not required (scattered)
case ARM_RELOC_PB_LA_PTR: // not seen yet
case ARM_RELOC_BR24: // not seen yet
case ARM_THUMB_32BIT_BRANCH: // not seen yet
case ARM_RELOC_HALF: // relocation not required (scattered)
case ARM_RELOC_HALF_SECTDIFF: // relocation not required (scattered)
default:
throw new NotFoundException("Unimplemented relocation");
}
}
}