mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-25 05:32:14 +00:00
Merge branch 'GP-5009_ryanmkurtz_ControlFlowGuard' into patch
(Closes #6960)
This commit is contained in:
commit
c8703a10d8
@ -17,6 +17,7 @@ package ghidra.app.util.bin.format.pe;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import ghidra.app.cmd.data.CreateArrayCmd;
|
import ghidra.app.cmd.data.CreateArrayCmd;
|
||||||
import ghidra.app.util.bin.format.pe.LoadConfigDirectory.GuardFlags;
|
import ghidra.app.util.bin.format.pe.LoadConfigDirectory.GuardFlags;
|
||||||
@ -30,7 +31,6 @@ import ghidra.program.model.mem.Memory;
|
|||||||
import ghidra.program.model.mem.MemoryAccessException;
|
import ghidra.program.model.mem.MemoryAccessException;
|
||||||
import ghidra.program.model.symbol.SourceType;
|
import ghidra.program.model.symbol.SourceType;
|
||||||
import ghidra.program.model.symbol.SymbolTable;
|
import ghidra.program.model.symbol.SymbolTable;
|
||||||
import ghidra.util.Msg;
|
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,82 +57,21 @@ public class ControlFlowGuard {
|
|||||||
public static void markup(LoadConfigDirectory lcd, Program program, MessageLog log,
|
public static void markup(LoadConfigDirectory lcd, Program program, MessageLog log,
|
||||||
NTHeader ntHeader) {
|
NTHeader ntHeader) {
|
||||||
|
|
||||||
boolean is64bit = ntHeader.getOptionalHeader().is64bit();
|
|
||||||
AddressSpace space = program.getAddressFactory().getDefaultAddressSpace();
|
|
||||||
Memory mem = program.getMemory();
|
|
||||||
SymbolTable symbolTable = program.getSymbolTable();
|
|
||||||
|
|
||||||
// ControlFlowGuard
|
// ControlFlowGuard
|
||||||
markupCfgCheckFunction(lcd, program, is64bit, space, mem, symbolTable);
|
markupCfgFunction("_guard_check_icall", "ControlFlowGuard check",
|
||||||
markupCfgDispatchFunction(lcd, program, is64bit, space, mem, symbolTable);
|
lcd::getCfgCheckFunctionPointer, program, ntHeader, log);
|
||||||
|
markupCfgFunction("_guard_dispatch_icall", "ControlFlowGuard dispatch",
|
||||||
|
lcd::getCfgDispatchFunctionPointer, program, ntHeader, log);
|
||||||
markupCfgFunctionTable(lcd, program, log);
|
markupCfgFunctionTable(lcd, program, log);
|
||||||
markupCfgAddressTakenIatEntryTable(lcd, program, log);
|
markupCfgAddressTakenIatEntryTable(lcd, program, log);
|
||||||
|
|
||||||
// ReturnFlowGuard
|
// ReturnFlowGuard
|
||||||
markupRfgFailureRoutine(lcd, program, space, symbolTable);
|
markupCfgFunction("_guard_ss_verify_failure", "ReturnFlowGuard failure",
|
||||||
markupRfgDefaultFailureRoutine(lcd, program, is64bit, space, mem, symbolTable);
|
lcd::getRfgFailureRoutine, program, ntHeader, log);
|
||||||
markupRfgDefaultStackPointerFunction(lcd, program, is64bit, space, mem, symbolTable);
|
markupCfgFunction("_guard_ss_verify_failure_default", "ReturnFlowGuard default failure",
|
||||||
}
|
lcd::getRfgFailureRoutineFunctionPointer, program, ntHeader, log);
|
||||||
|
markupCfgFunction("_guard_ss_verify_sp_default", "ReturnFlowGuard verify stack pointer",
|
||||||
/**
|
lcd::getRfgVerifyStackPointerFunctionPointer, program, ntHeader, log);
|
||||||
* Performs markup on the ControlFlowGuard check function, if it exists.
|
|
||||||
*
|
|
||||||
* @param lcd The PE LoadConfigDirectory.
|
|
||||||
* @param program The program.
|
|
||||||
* @param is64bit True if the PE is 64-bit; false if it's 32-bit.
|
|
||||||
* @param space The program's address space.
|
|
||||||
* @param mem The program's memory.
|
|
||||||
* @param symbolTable The program's symbol table.
|
|
||||||
*/
|
|
||||||
private static void markupCfgCheckFunction(LoadConfigDirectory lcd, Program program,
|
|
||||||
boolean is64bit, AddressSpace space, Memory mem, SymbolTable symbolTable) {
|
|
||||||
|
|
||||||
if (lcd.getCfgCheckFunctionPointer() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Address functionPointerAddr = space.getAddress(lcd.getCfgCheckFunctionPointer());
|
|
||||||
Address functionAddr = space.getAddress(
|
|
||||||
is64bit ? mem.getLong(functionPointerAddr) : mem.getInt(functionPointerAddr));
|
|
||||||
symbolTable.createLabel(functionAddr, "_guard_check_icall", SourceType.IMPORTED);
|
|
||||||
|
|
||||||
AbstractProgramLoader.markAsFunction(program, null, functionAddr);
|
|
||||||
}
|
|
||||||
catch (MemoryAccessException | AddressOutOfBoundsException | InvalidInputException e) {
|
|
||||||
Msg.warn(ControlFlowGuard.class, "Unable to label ControlFlowGuard check function.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs markup on the ControlFlowGuard dispatch function, if it exists.
|
|
||||||
*
|
|
||||||
* @param lcd The PE LoadConfigDirectory.
|
|
||||||
* @param program The program.
|
|
||||||
* @param is64bit True if the PE is 64-bit; false if it's 32-bit.
|
|
||||||
* @param space The program's address space.
|
|
||||||
* @param mem The program's memory.
|
|
||||||
* @param symbolTable The program's symbol table.
|
|
||||||
*/
|
|
||||||
private static void markupCfgDispatchFunction(LoadConfigDirectory lcd, Program program,
|
|
||||||
boolean is64bit, AddressSpace space, Memory mem, SymbolTable symbolTable) {
|
|
||||||
|
|
||||||
if (lcd.getCfgDispatchFunctionPointer() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Address functionPointerAddr = space.getAddress(lcd.getCfgDispatchFunctionPointer());
|
|
||||||
Address functionAddr = space.getAddress(
|
|
||||||
is64bit ? mem.getLong(functionPointerAddr) : mem.getInt(functionPointerAddr));
|
|
||||||
symbolTable.createLabel(functionAddr, "_guard_dispatch_icall", SourceType.IMPORTED);
|
|
||||||
|
|
||||||
AbstractProgramLoader.markAsFunction(program, null, functionAddr);
|
|
||||||
}
|
|
||||||
catch (MemoryAccessException | AddressOutOfBoundsException | InvalidInputException e) {
|
|
||||||
Msg.warn(ControlFlowGuard.class, "Unable to label ControlFlowGuard dispatch function.",
|
|
||||||
e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -164,7 +103,7 @@ public class ControlFlowGuard {
|
|||||||
.createLabel(tableAddr, GuardCFFunctionTableName, SourceType.IMPORTED);
|
.createLabel(tableAddr, GuardCFFunctionTableName, SourceType.IMPORTED);
|
||||||
}
|
}
|
||||||
catch (InvalidInputException e) {
|
catch (InvalidInputException e) {
|
||||||
Msg.warn(ControlFlowGuard.class, "Unable to label ControlFlowGuard function table.", e);
|
log.appendMsg("Unable to label ControlFlowGuard function table: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Each table entry is an RVA (32-bit image base offset), followed by 'n' extra bytes
|
// Each table entry is an RVA (32-bit image base offset), followed by 'n' extra bytes
|
||||||
@ -201,12 +140,12 @@ public class ControlFlowGuard {
|
|||||||
|
|
||||||
private static void createCfgFunctions(Program program, Data tableData, MessageLog log) {
|
private static void createCfgFunctions(Program program, Data tableData, MessageLog log) {
|
||||||
if (tableData == null) {
|
if (tableData == null) {
|
||||||
Msg.warn(ControlFlowGuard.class, "Couldn't find Control Flow Guard tables.");
|
log.appendMsg("Couldn't find Control Flow Guard tables.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tableData.isArray() || (tableData.getNumComponents() < 1)) {
|
if (!tableData.isArray() || (tableData.getNumComponents() < 1)) {
|
||||||
Msg.warn(ControlFlowGuard.class, "Control Flow Guard table seems to be empty.");
|
log.appendMsg("Control Flow Guard table seems to be empty.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,8 +162,8 @@ public class ControlFlowGuard {
|
|||||||
Data entry = table.getComponent(i);
|
Data entry = table.getComponent(i);
|
||||||
Data iboData = entry.getComponent(0);
|
Data iboData = entry.getComponent(0);
|
||||||
Object value = iboData.getValue();
|
Object value = iboData.getValue();
|
||||||
if (value instanceof Address) {
|
if (value instanceof Address addr) {
|
||||||
list.add((Address) value);
|
list.add(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
@ -266,102 +205,62 @@ public class ControlFlowGuard {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (AddressOutOfBoundsException | InvalidInputException e) {
|
catch (AddressOutOfBoundsException | InvalidInputException e) {
|
||||||
Msg.warn(ControlFlowGuard.class, "Unable to label ControlFlowGuard IAT table.", e);
|
log.appendMsg("Unable to label ControlFlowGuard IAT table: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs markup on the ReturnFlowGuard failure routine, if it exists.
|
* Performs markup on a ControlFlowGuard function, if it exists.
|
||||||
*
|
*
|
||||||
* @param lcd The PE LoadConfigDirectory.
|
* @param label The ControFlowGuard label to create.
|
||||||
* @param program The program
|
* @param description A short description of the ControlFlowGuard function type.
|
||||||
* @param space The program's address space.
|
* @param functionPointerGetter A method that returns the ControlFlowGuard function's pointer
|
||||||
* @param symbolTable The program's symbol table.
|
* address.
|
||||||
|
* @param program The program.
|
||||||
|
* @param ntHeader The PE NTHeader.
|
||||||
|
* @param log The log.
|
||||||
*/
|
*/
|
||||||
private static void markupRfgFailureRoutine(LoadConfigDirectory lcd, Program program,
|
private static void markupCfgFunction(String label, String description,
|
||||||
AddressSpace space, SymbolTable symbolTable) {
|
Supplier<Long> functionPointerGetter, Program program, NTHeader ntHeader,
|
||||||
|
MessageLog log) {
|
||||||
|
|
||||||
if (lcd.getRfgFailureRoutine() == 0) {
|
if (functionPointerGetter.get() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddressSpace space = program.getAddressFactory().getDefaultAddressSpace();
|
||||||
|
Memory mem = program.getMemory();
|
||||||
|
SymbolTable symbolTable = program.getSymbolTable();
|
||||||
|
boolean is64bit = ntHeader.getOptionalHeader().is64bit();
|
||||||
|
|
||||||
|
Address functionPointerAddr = space.getAddress(functionPointerGetter.get());
|
||||||
|
PeUtils.createData(program, functionPointerAddr, PointerDataType.dataType, log);
|
||||||
|
|
||||||
|
Address functionAddr;
|
||||||
|
try {
|
||||||
|
functionAddr = space.getAddress(
|
||||||
|
is64bit ? mem.getLong(functionPointerAddr) : mem.getInt(functionPointerAddr));
|
||||||
|
}
|
||||||
|
catch (MemoryAccessException e) {
|
||||||
|
log.appendMsg("Failed to read %s function pointer address at %s".formatted(description,
|
||||||
|
functionPointerAddr));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Address routineAddr = space.getAddress(lcd.getRfgFailureRoutine());
|
symbolTable.createLabel(functionAddr, label, SourceType.IMPORTED);
|
||||||
symbolTable.createLabel(routineAddr, "_guard_ss_verify_failure", SourceType.IMPORTED);
|
|
||||||
|
|
||||||
AbstractProgramLoader.markAsFunction(program, null, routineAddr);
|
|
||||||
}
|
}
|
||||||
catch (AddressOutOfBoundsException | InvalidInputException e) {
|
catch (AddressOutOfBoundsException | InvalidInputException e) {
|
||||||
Msg.warn(ControlFlowGuard.class, "Unable to label ReturnFlowGuard failure routine.", e);
|
log.appendMsg("Unable to apply label '%s' to %s function at %s: %s".formatted(label,
|
||||||
}
|
description, functionAddr, e.getMessage()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
if (program.getListing().getDefinedDataAt(functionAddr) == null) {
|
||||||
* Performs markup on the ReturnFlowGuard "default" failure routine function, if it exists.
|
|
||||||
*
|
|
||||||
* @param lcd The PE LoadConfigDirectory.
|
|
||||||
* @param program The program
|
|
||||||
* @param is64bit True if the PE is 64-bit; false if it's 32-bit.
|
|
||||||
* @param space The program's address space.
|
|
||||||
* @param mem The program's memory.
|
|
||||||
* @param symbolTable The program's symbol table.
|
|
||||||
*/
|
|
||||||
private static void markupRfgDefaultFailureRoutine(LoadConfigDirectory lcd, Program program,
|
|
||||||
boolean is64bit, AddressSpace space, Memory mem, SymbolTable symbolTable) {
|
|
||||||
|
|
||||||
if (lcd.getRfgFailureRoutineFunctionPointer() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Address functionPointerAddr =
|
|
||||||
space.getAddress(lcd.getRfgFailureRoutineFunctionPointer());
|
|
||||||
Address functionAddr = space.getAddress(
|
|
||||||
is64bit ? mem.getLong(functionPointerAddr) : mem.getInt(functionPointerAddr));
|
|
||||||
symbolTable.createLabel(functionAddr, "_guard_ss_verify_failure_default",
|
|
||||||
SourceType.IMPORTED);
|
|
||||||
|
|
||||||
AbstractProgramLoader.markAsFunction(program, null, functionAddr);
|
AbstractProgramLoader.markAsFunction(program, null, functionAddr);
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (MemoryAccessException | AddressOutOfBoundsException | InvalidInputException e) {
|
else {
|
||||||
Msg.warn(ControlFlowGuard.class,
|
log.appendMsg("Unable to mark %s as function at %s. Data is already defined there."
|
||||||
"Unable to label ReturnFlowGuard default failure routine.", e);
|
.formatted(description, functionAddr));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs markup on the ReturnFlowGuard verify stack pointer function, if it exists.
|
|
||||||
*
|
|
||||||
* @param lcd The PE LoadConfigDirectory.
|
|
||||||
* @param program The program
|
|
||||||
* @param is64bit True if the PE is 64-bit; false if it's 32-bit.
|
|
||||||
* @param space The program's address space.
|
|
||||||
* @param mem The program's memory.
|
|
||||||
* @param symbolTable The program's symbol table.
|
|
||||||
*/
|
|
||||||
private static void markupRfgDefaultStackPointerFunction(LoadConfigDirectory lcd,
|
|
||||||
Program program, boolean is64bit, AddressSpace space, Memory mem,
|
|
||||||
SymbolTable symbolTable) {
|
|
||||||
|
|
||||||
if (lcd.getRfgVerifyStackPointerFunctionPointer() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Address functionPointerAddr =
|
|
||||||
space.getAddress(lcd.getRfgVerifyStackPointerFunctionPointer());
|
|
||||||
Address functionAddr = space.getAddress(
|
|
||||||
is64bit ? mem.getLong(functionPointerAddr) : mem.getInt(functionPointerAddr));
|
|
||||||
symbolTable.createLabel(functionAddr, "_guard_ss_verify_sp_default",
|
|
||||||
SourceType.IMPORTED);
|
|
||||||
|
|
||||||
AbstractProgramLoader.markAsFunction(program, null, functionAddr);
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (MemoryAccessException | AddressOutOfBoundsException | InvalidInputException e) {
|
|
||||||
Msg.warn(ControlFlowGuard.class,
|
|
||||||
"Unable to label ReturnFlowGuard verify stack pointer function.", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -433,8 +433,6 @@ public class PeLoader extends AbstractPeDebugLoader {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.appendMsg("Delay imports detected");
|
|
||||||
|
|
||||||
AddressSpace space = program.getAddressFactory().getDefaultAddressSpace();
|
AddressSpace space = program.getAddressFactory().getDefaultAddressSpace();
|
||||||
Listing listing = program.getListing();
|
Listing listing = program.getListing();
|
||||||
ReferenceManager refManager = program.getReferenceManager();
|
ReferenceManager refManager = program.getReferenceManager();
|
||||||
|
Loading…
Reference in New Issue
Block a user