Created
May 7, 2021 23:50
-
-
Save 0x36/5ea657f0815801e9d20b5eb3f16afcc9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Fixing LC_DYLD_CHAINED_FIXUPS for macOS M1 kext drivers | |
# -*- coding: utf-8 -*- | |
#@category macOS.kext | |
from generic.continues import RethrowContinuesFactory | |
from ghidra.app.script import GhidraScript | |
from ghidra.app.util.bin import ByteProvider, RandomAccessByteProvider, BinaryReader | |
from ghidra.app.util.bin.format.macho import MachHeader,Section, commands | |
from ghidra.program.model.address import Address | |
from java.io import File | |
from java.io import ByteArrayInputStream; | |
from ghidra.program.model.data import PointerDataType | |
import struct | |
MH_EXECUTE = 0x00000002 | |
MH_KEXT_BUNDLE = 0x0000000b | |
LC_DYLD_CHAINED_FIXUPS = 0x80000034 | |
def depac(): | |
print "[+] Fixing PAC'd pointers ... ", | |
f = File( currentProgram.getExecutablePath()) | |
assert f.exists() == True | |
mem = currentProgram.getMemory() | |
image_base = currentProgram.getImageBase() | |
provider = RandomAccessByteProvider(f) | |
header = MachHeader.createMachHeader( RethrowContinuesFactory.INSTANCE, provider ) | |
header.parse() | |
if header.getFileType() != MH_KEXT_BUNDLE: | |
print "Kernel image not supported, only KEXT" | |
return | |
depac_kext(provider,header) | |
def depac_kext(provider,header): | |
read64 = lambda off: struct.unpack("<Q",br.readByteArray(off,8))[0] | |
read32 = lambda off: struct.unpack("<I",br.readByteArray(off,4))[0] | |
image_base = currentProgram.getImageBase() | |
cmds = header.getLoadCommands() | |
mem = currentProgram.getMemory() | |
listing = currentProgram.getListing() | |
tcmd = None | |
for cmd in cmds: | |
if cmd.getCommandType() & 0xffffffff != LC_DYLD_CHAINED_FIXUPS: | |
continue | |
tcmd = cmd | |
break | |
assert tcmd != None | |
index = tcmd.getStartIndex() | |
br = BinaryReader(provider,True) | |
ll = br.readIntArray(index,cmd.getCommandSize()/4) | |
cmd = ll[0] & 0xffffffff | |
cmdsize = ll[1] | |
dataoff = ll[2] | |
datasize = ll[3] | |
off = dataoff | |
fixup =br.readIntArray(dataoff,7) | |
symbols_offset = fixup[3] | |
imports_offset = fixup[2] | |
starts_offset = fixup[1] | |
import_off = dataoff + imports_offset | |
syms_off = dataoff + symbols_offset | |
segs_off = off + starts_offset | |
segs_count = read32(segs_off) | |
segs = br.readIntArray(segs_off + 4,segs_count) | |
for seg_i in range(segs_count): | |
if segs[seg_i] == 0: | |
continue | |
starts_off = segs_off + segs[seg_i] | |
starts = br.readByteArray(starts_off,24) | |
tmp = struct.unpack("<IHHQIHH",starts) | |
page_count = tmp[5] | |
page_starts = br.readByteArray(starts_off+22,page_count*2) | |
page_starts = struct.unpack("<"+"H" * page_count,page_starts) | |
page_size, segment_offset = tmp[1],tmp[3] | |
i = 0 | |
for idx in page_starts: | |
if idx == 0xffff: | |
continue | |
addr = image_base.add(segment_offset + i * page_size + idx ) | |
off = segment_offset + i * page_size + idx | |
i+=1 | |
while True and monitor.isCancelled() == False: | |
content = read64(off) | |
offset = content & 0xffffffff | |
nxt = (content >> 51) & 2047 | |
bind = (content >> 62) & 1 | |
tag = (content >> 32) & 0xffff | |
if bind == 1: | |
name_off = read32(import_off + offset * 4) | |
name_off = (name_off >> 9) | |
symbol = br.readAsciiString(syms_off + name_off ) | |
symbolTable = currentProgram.getSymbolTable() | |
ns = symbolTable.getNamespace("Global",None) | |
sm = symbolTable.getSymbol(symbol,ns) | |
if sm != None: | |
sym_addr = sm.getAddress().toString() | |
b = struct.pack("<Q",int(sym_addr,16)) | |
mem.setBytes(addr,b,0,8) | |
else: | |
target = image_base.add(offset) | |
b = struct.pack("<Q",int(target.toString(),16)) | |
mem.setBytes(addr,b,0,8) | |
listing.clearCodeUnits(addr,addr.add(8),False) | |
listing.createData(addr,PointerDataType()) | |
skip = nxt * 4 | |
addr = addr.add(skip) | |
off+=skip | |
if skip == 0: | |
break | |
print "OK" | |
if __name__ == "__main__": | |
depac() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment