GP-5505 Improved RecoverClassesFromRTTIScript abilty to use the LowCodeModeBit to find code references.

This commit is contained in:
ghidra007 2025-03-21 18:40:16 +00:00
parent fa554361d5
commit 2f83e26c0e
3 changed files with 217 additions and 246 deletions

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -16,52 +16,21 @@
//DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS. //DO NOT RUN. THIS IS NOT A SCRIPT! THIS IS A CLASS THAT IS USED BY SCRIPTS.
package classrecovery; package classrecovery;
import java.util.ArrayList; import java.util.*;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import ghidra.app.cmd.function.CreateFunctionCmd; import ghidra.app.cmd.function.CreateFunctionCmd;
import ghidra.app.plugin.core.analysis.ReferenceAddressPair; import ghidra.app.plugin.core.analysis.ReferenceAddressPair;
import ghidra.app.util.PseudoDisassembler; import ghidra.app.util.PseudoDisassembler;
import ghidra.program.flatapi.FlatProgramAPI; import ghidra.program.flatapi.FlatProgramAPI;
import ghidra.program.model.address.Address; import ghidra.program.model.address.*;
import ghidra.program.model.address.AddressOutOfBoundsException;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.block.CodeBlock; import ghidra.program.model.block.CodeBlock;
import ghidra.program.model.block.IsolatedEntrySubModel; import ghidra.program.model.block.IsolatedEntrySubModel;
import ghidra.program.model.data.CategoryPath; import ghidra.program.model.data.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.IBO32DataType;
import ghidra.program.model.data.LongDataType;
import ghidra.program.model.data.Pointer;
import ghidra.program.model.data.PointerDataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.Undefined4DataType;
import ghidra.program.model.data.Undefined8DataType;
import ghidra.program.model.lang.Register; import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.Data; import ghidra.program.model.listing.*;
import ghidra.program.model.listing.Function; import ghidra.program.model.mem.*;
import ghidra.program.model.listing.Instruction;
import ghidra.program.model.listing.InstructionIterator;
import ghidra.program.model.listing.Listing;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.DumbMemBufferImpl;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.scalar.Scalar; import ghidra.program.model.scalar.Scalar;
import ghidra.program.model.symbol.FlowType; import ghidra.program.model.symbol.*;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.Reference;
import ghidra.program.model.symbol.ReferenceIterator;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolIterator;
import ghidra.program.model.symbol.SymbolTable;
import ghidra.program.model.symbol.SymbolType;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
@ -133,6 +102,97 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
} }
} }
/**
* Method to determine if the given address contains a possible function pointer
* @param program the given program
*
* @param address the given address
* @return true if the given address contains a possible function pointer or
* false otherwise
* @throws CancelledException if cancelled
*/
public boolean isPossibleFunctionPointer(Program program, Address address)
throws CancelledException {
Address referencedAddress = getPointer(address);
if (referencedAddress == null) {
return false;
}
Address normalizedReferencedAddress =
PseudoDisassembler.getNormalizedDisassemblyAddress(program, referencedAddress);
if (normalizedReferencedAddress == null) {
return false;
}
Function function = getFunctionAt(normalizedReferencedAddress);
if (function != null) {
return true;
}
AddressSetView executeSet = program.getMemory().getExecuteSet();
if (!executeSet.contains(normalizedReferencedAddress)) {
return false;
}
Instruction instruction = getInstructionAt(normalizedReferencedAddress);
if (instruction != null) {
createFunction(normalizedReferencedAddress, null);
return true;
}
boolean disassemble = disassemble(normalizedReferencedAddress);
if (disassemble) {
Listing listing = program.getListing();
// check for the case where there is conflicting data at the thumb offset function
// pointer and if so clear the data and redisassemble and remove the bad bookmark
// long originalLongValue = extendedFlatAPI.getLongValueAt(address);
if (!referencedAddress.equals(normalizedReferencedAddress)) {
Data dataAt = listing.getDataAt(referencedAddress);
if (dataAt != null && dataAt.isDefined()) {
clearListing(referencedAddress);
disassemble = disassemble(address);
Bookmark bookmark =
getBookmarkAt(program, normalizedReferencedAddress, BookmarkType.ERROR,
"Bad Instruction", "conflicting data");
if (bookmark != null) {
removeBookmark(bookmark);
}
}
}
createFunction(normalizedReferencedAddress, null);
return true;
}
return false;
}
public Bookmark getBookmarkAt(Program program, Address address, String bookmarkType,
String category,
String commentContains) throws CancelledException {
Bookmark[] bookmarks = program.getBookmarkManager().getBookmarks(address);
for (Bookmark bookmark : bookmarks) {
monitor.checkCancelled();
if (bookmark.getType().getTypeString().equals(bookmarkType) &&
bookmark.getCategory().equals(category) &&
bookmark.getComment().contains(commentContains)) {
return bookmark;
}
}
return null;
}
/** /**
* Method to check to see if there is a valid function pointer at the given address. If it is * Method to check to see if there is a valid function pointer at the given address. If it is
* valid but not created, create it * valid but not created, create it
@ -254,18 +314,16 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
if (referencesFrom.size() != 1) { if (referencesFrom.size() != 1) {
return null; return null;
} }
Address functionAddress = referencesFrom.get(0); Address functionAddress = referencesFrom.get(0);
Register lowBitCodeMode = currentProgram.getRegister("LowBitCodeMode"); Register lowBitCodeMode = currentProgram.getRegister("LowBitCodeMode");
if(lowBitCodeMode != null) { if (lowBitCodeMode != null) {
long longValue = functionAddress.getOffset(); long longValue = functionAddress.getOffset();
longValue = longValue & ~0x1; longValue = longValue & ~0x1;
functionAddress = functionAddress.getNewAddress(longValue); functionAddress = functionAddress.getNewAddress(longValue);
} }
Function function = getFunctionAt(functionAddress); Function function = getFunctionAt(functionAddress);
if (function == null) { if (function == null) {
// try to create function // try to create function
@ -581,7 +639,6 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
return subroutineAddresses; return subroutineAddresses;
} }
/** /**
* Method to get a list of symbols either matching exactly (if exact flag is true) or containing (if exact flag is false) the given symbol name * Method to get a list of symbols either matching exactly (if exact flag is true) or containing (if exact flag is false) the given symbol name
* @param addressSet the address set to find matching symbols in * @param addressSet the address set to find matching symbols in
@ -641,7 +698,7 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
if (addressSize == 32) { if (addressSize == 32) {
long offset32 = getInt(address); long offset32 = getInt(address);
Address newAddr = address.getNewAddress(offset32); Address newAddr = address.getNewAddress(offset32);
if(currentProgram.getMemory().contains(newAddr)) { if (currentProgram.getMemory().contains(newAddr)) {
return newAddr; return newAddr;
} }
return null; return null;
@ -651,7 +708,7 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
long offset64 = getLong(address); long offset64 = getLong(address);
Address newAddr = address.getNewAddress(offset64); Address newAddr = address.getNewAddress(offset64);
if(currentProgram.getMemory().contains(newAddr)) { if (currentProgram.getMemory().contains(newAddr)) {
return newAddr; return newAddr;
} }
return null; return null;
@ -666,11 +723,11 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
} }
} }
public long getLongValueAt(Address address) { public long getLongValueAt(Address address) {
MemBuffer buf = new DumbMemBufferImpl(currentProgram.getMemory(), address); MemBuffer buf = new DumbMemBufferImpl(currentProgram.getMemory(), address);
LongDataType longDT = new LongDataType(); LongDataType longDT = new LongDataType();
Scalar value = Scalar value =
@ -856,7 +913,6 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
return false; return false;
} }
/** /**
* Method to retrieve a single referenced address from the given address * Method to retrieve a single referenced address from the given address
* @param address the given address to look for a single referenced address * @param address the given address to look for a single referenced address
@ -1363,5 +1419,4 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
return buffer.toString(); return buffer.toString();
} }
} }

View file

@ -24,6 +24,7 @@ import org.apache.commons.lang3.StringUtils;
import ghidra.app.cmd.label.DemanglerCmd; import ghidra.app.cmd.label.DemanglerCmd;
import ghidra.app.plugin.core.analysis.ReferenceAddressPair; import ghidra.app.plugin.core.analysis.ReferenceAddressPair;
import ghidra.app.util.NamespaceUtils; import ghidra.app.util.NamespaceUtils;
import ghidra.app.util.PseudoDisassembler;
import ghidra.app.util.demangler.DemangledObject; import ghidra.app.util.demangler.DemangledObject;
import ghidra.app.util.demangler.DemanglerUtil; import ghidra.app.util.demangler.DemanglerUtil;
import ghidra.framework.plugintool.ServiceProvider; import ghidra.framework.plugintool.ServiceProvider;
@ -31,7 +32,6 @@ import ghidra.program.flatapi.FlatProgramAPI;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.data.DataUtilities.ClearDataMode; import ghidra.program.model.data.DataUtilities.ClearDataMode;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.*;
import ghidra.program.model.scalar.Scalar; import ghidra.program.model.scalar.Scalar;
@ -4395,68 +4395,59 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
*/ */
private boolean isPossibleFunctionPointer(Address address) throws CancelledException { private boolean isPossibleFunctionPointer(Address address) throws CancelledException {
// TODO: make one that works for all casea in helper Address referencedAddress = extendedFlatAPI.getSingleReferencedAddress(address);
if (referencedAddress == null) {
long longValue = extendedFlatAPI.getLongValueAt(address);
Register lowBitCodeMode = program.getRegister("LowBitCodeMode");
if (lowBitCodeMode != null) {
longValue = longValue & ~0x1;
}
Address possibleFunctionPointer = null;
try {
possibleFunctionPointer = address.getNewAddress(longValue);
}
catch (AddressOutOfBoundsException e) {
return false; return false;
} }
if (possibleFunctionPointer == null) { Address normalizedReferencedAddress =
PseudoDisassembler.getNormalizedDisassemblyAddress(program, referencedAddress);
if (normalizedReferencedAddress == null) {
return false; return false;
} }
Function function = api.getFunctionAt(possibleFunctionPointer); Function function = api.getFunctionAt(normalizedReferencedAddress);
if (function != null) { if (function != null) {
return true; return true;
} }
AddressSetView executeSet = program.getMemory().getExecuteSet(); AddressSetView executeSet = program.getMemory().getExecuteSet();
if (!executeSet.contains(possibleFunctionPointer)) { if (!executeSet.contains(normalizedReferencedAddress)) {
return false; return false;
} }
Instruction instruction = api.getInstructionAt(possibleFunctionPointer); Instruction instruction = api.getInstructionAt(normalizedReferencedAddress);
if (instruction != null) { if (instruction != null) {
api.createFunction(possibleFunctionPointer, null); api.createFunction(normalizedReferencedAddress, null);
return true; return true;
} }
boolean disassemble = api.disassemble(possibleFunctionPointer); boolean disassemble = api.disassemble(normalizedReferencedAddress);
if (disassemble) { if (disassemble) {
// check for the case where there is conflicting data at the thumb offset function // check for the case where there is conflicting data at the thumb offset function
// pointer and if so clear the data and redisassemble and remove the bad bookmark // pointer and if so clear the data and redisassemble and remove the bad bookmark
long originalLongValue = extendedFlatAPI.getLongValueAt(address); // long originalLongValue = extendedFlatAPI.getLongValueAt(address);
if (originalLongValue != longValue) { if (!referencedAddress.equals(normalizedReferencedAddress)) {
Address offsetPointer = address.getNewAddress(originalLongValue);
Data dataAt = listing.getDataAt(offsetPointer); Data dataAt = listing.getDataAt(referencedAddress);
if (dataAt != null && dataAt.isDefined()) { if (dataAt != null && dataAt.isDefined()) {
api.clearListing(offsetPointer); api.clearListing(referencedAddress);
disassemble = api.disassemble(address); disassemble = api.disassemble(address);
Bookmark bookmark = getBookmarkAt(possibleFunctionPointer, BookmarkType.ERROR, Bookmark bookmark =
"Bad Instruction", "conflicting data"); getBookmarkAt(normalizedReferencedAddress, BookmarkType.ERROR,
"Bad Instruction", "conflicting data");
if (bookmark != null) { if (bookmark != null) {
api.removeBookmark(bookmark); api.removeBookmark(bookmark);
} }
} }
} }
api.createFunction(possibleFunctionPointer, null); api.createFunction(normalizedReferencedAddress, null);
return true; return true;
} }
return false; return false;

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -20,7 +20,6 @@ import java.util.List;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.*;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
@ -64,9 +63,8 @@ public class Vtable {
DataTypeManager dataTypeManager; DataTypeManager dataTypeManager;
Listing listing; Listing listing;
public Vtable(Program program, Address vtableAddress, GccTypeinfoRef typeinfoRef,
boolean isSpecial, boolean inExternalMemory,
public Vtable(Program program, Address vtableAddress, GccTypeinfoRef typeinfoRef, boolean isSpecial, boolean inExternalMemory,
Vtable primaryVtable, Boolean isConstruction, TaskMonitor monitor) Vtable primaryVtable, Boolean isConstruction, TaskMonitor monitor)
throws CancelledException { throws CancelledException {
@ -92,21 +90,24 @@ public class Vtable {
functionManager = program.getFunctionManager(); functionManager = program.getFunctionManager();
dataTypeManager = program.getDataTypeManager(); dataTypeManager = program.getDataTypeManager();
listing = program.getListing(); listing = program.getListing();
setup(); setup();
} }
public Vtable(Program program, Address vtableAddress, GccTypeinfoRef typeinfoRef, boolean isSpecial, boolean inExternalMemory, TaskMonitor monitor) public Vtable(Program program, Address vtableAddress, GccTypeinfoRef typeinfoRef,
boolean isSpecial, boolean inExternalMemory, TaskMonitor monitor)
throws CancelledException { throws CancelledException {
this(program, vtableAddress, typeinfoRef, isSpecial, inExternalMemory, null, null, monitor); this(program, vtableAddress, typeinfoRef, isSpecial, inExternalMemory, null, null, monitor);
} }
public Vtable(Program program, Address vtableAddress, GccTypeinfoRef typeinfoRef, boolean isSpecial, boolean inExternalMemory, boolean isConstruction, public Vtable(Program program, Address vtableAddress, GccTypeinfoRef typeinfoRef,
boolean isSpecial, boolean inExternalMemory, boolean isConstruction,
TaskMonitor monitor) throws CancelledException { TaskMonitor monitor) throws CancelledException {
this(program, vtableAddress, typeinfoRef, isSpecial, inExternalMemory, null, isConstruction, monitor); this(program, vtableAddress, typeinfoRef, isSpecial, inExternalMemory, null, isConstruction,
monitor);
} }
protected void setup() throws CancelledException { protected void setup() throws CancelledException {
checkValidTop(); checkValidTop();
@ -127,7 +128,7 @@ public class Vtable {
} }
figureOutNamespace(); figureOutNamespace();
setHasVfunctions(); setHasVfunctions();
if (!isValid) { if (!isValid) {
@ -143,10 +144,11 @@ public class Vtable {
if (!isValid) { if (!isValid) {
return; return;
} }
try { try {
applyVtableData(); applyVtableData();
} catch (Exception e) { }
catch (Exception e) {
isValid = false; isValid = false;
} }
@ -196,16 +198,15 @@ public class Vtable {
return isValid; return isValid;
} }
public Address getTypeinfoRefAddress() { public Address getTypeinfoRefAddress() {
return typeinfoRef.getAddress(); return typeinfoRef.getAddress();
} }
public GccTypeinfo getReferencedTypeinfo() { public GccTypeinfo getReferencedTypeinfo() {
return (GccTypeinfo) typeinfoRef.getReferencedTypeinfo(); return (GccTypeinfo) typeinfoRef.getReferencedTypeinfo();
} }
protected void setTypeinfoAddress() { protected void setTypeinfoAddress() {
typeinfoAddress = typeinfo.getAddress(); typeinfoAddress = typeinfo.getAddress();
typeinfoNamespace = typeinfo.getNamespace(); typeinfoNamespace = typeinfo.getNamespace();
@ -221,13 +222,14 @@ public class Vtable {
try { try {
Address topOffset = typeinfoRefAddress.subtract(defaultPointerSize); Address topOffset = typeinfoRefAddress.subtract(defaultPointerSize);
if (topOffset.getOffset() < vtableAddress.getOffset()) { if (topOffset.getOffset() < vtableAddress.getOffset()) {
Msg.debug(this,"No offset field in vtable at " + vtableAddress.toString()); Msg.debug(this, "No offset field in vtable at " + vtableAddress.toString());
isValid = false; isValid = false;
return; return;
} }
topOffsetValue = extendedFlatAPI.getLongValueAt(topOffset); topOffsetValue = extendedFlatAPI.getLongValueAt(topOffset);
} catch (IllegalArgumentException e) { }
catch (IllegalArgumentException e) {
Msg.debug(this, "Invalid vtable: " + vtableAddress.toString() + " No offset field"); Msg.debug(this, "Invalid vtable: " + vtableAddress.toString() + " No offset field");
isValid = false; isValid = false;
} }
@ -252,7 +254,8 @@ public class Vtable {
// otherwise, use the topOffsetValue to figure it out // otherwise, use the topOffsetValue to figure it out
if (topOffsetValue == 0L) { if (topOffsetValue == 0L) {
isPrimary = true; isPrimary = true;
} else { }
else {
isPrimary = false; isPrimary = false;
} }
} }
@ -289,15 +292,17 @@ public class Vtable {
try { try {
Address possVfunctionTop = typeinfoRefAddress.add(defaultPointerSize); Address possVfunctionTop = typeinfoRefAddress.add(defaultPointerSize);
numVfunctions = getNumFunctionPointers(possVfunctionTop, true, false); numVfunctions = getNumFunctionPointers(possVfunctionTop, true, false);
if (numVfunctions == 0) { if (numVfunctions == 0) {
hasVfunctions = false; hasVfunctions = false;
} else { }
else {
hasVfunctions = true; hasVfunctions = true;
vfunctionTop = possVfunctionTop; vfunctionTop = possVfunctionTop;
} }
} catch (AddressOutOfBoundsException e) { }
catch (AddressOutOfBoundsException e) {
hasVfunctions = false; hasVfunctions = false;
} }
@ -308,17 +313,19 @@ public class Vtable {
int numFunctionPointers = 0; int numFunctionPointers = 0;
Address address = topAddress; Address address = topAddress;
// if it has a primary non-default symbol and it isn't "vftable" then it isn't a vftable // if it has a primary non-default symbol and it isn't "vftable" then it isn't a vftable
Symbol primarySymbol = symbolTable.getPrimarySymbol(topAddress); Symbol primarySymbol = symbolTable.getPrimarySymbol(topAddress);
if(primarySymbol != null && primarySymbol.getSource() != SourceType.DEFAULT && !primarySymbol.getName().contains("vftable")) { if (primarySymbol != null && primarySymbol.getSource() != SourceType.DEFAULT &&
!primarySymbol.getName().contains("vftable")) {
return numFunctionPointers; return numFunctionPointers;
} }
MemoryBlock currentBlock = program.getMemory().getBlock(topAddress); MemoryBlock currentBlock = program.getMemory().getBlock(topAddress);
boolean stillInCurrentTable = true; boolean stillInCurrentTable = true;
while (address != null && currentBlock.contains(address) && stillInCurrentTable while (address != null && currentBlock.contains(address) && stillInCurrentTable &&
&& (isPossibleFunctionPointer(address) || (allowNullFunctionPtrs && isPossibleNullPointer(address)))) { (extendedFlatAPI.isPossibleFunctionPointer(program, address) ||
(allowNullFunctionPtrs && isPossibleNullPointer(address)))) {
numFunctionPointers++; numFunctionPointers++;
address = address.add(defaultPointerSize); address = address.add(defaultPointerSize);
@ -336,33 +343,34 @@ public class Vtable {
stillInCurrentTable = false; stillInCurrentTable = false;
} }
} }
//NEW: TESTING Don't allow single null pointer at top of vftable //NEW: TESTING Don't allow single null pointer at top of vftable
//OR test to see if nulls then typeinfo ptr //OR test to see if nulls then typeinfo ptr
// if(isPossibleNullPointer(topAddress) && numFunctionPointers == 1) { // if(isPossibleNullPointer(topAddress) && numFunctionPointers == 1) {
// return 0; // return 0;
// } // }
// check to see if last is null ptr and next addr after that is typeinfo ref - indicating the null is really top of next vtable // check to see if last is null ptr and next addr after that is typeinfo ref - indicating the null is really top of next vtable
Address lastAddress = topAddress.add((numFunctionPointers-1)*defaultPointerSize); Address lastAddress = topAddress.add((numFunctionPointers - 1) * defaultPointerSize);
if(isPossibleNullPointer(lastAddress) && (isTypeinfoRef(lastAddress.add(defaultPointerSize)))){ if (isPossibleNullPointer(lastAddress) &&
(isTypeinfoRef(lastAddress.add(defaultPointerSize)))) {
numFunctionPointers--; numFunctionPointers--;
} }
return numFunctionPointers; return numFunctionPointers;
} }
private boolean isTypeinfoRef(Address addr) { private boolean isTypeinfoRef(Address addr) {
Address referencedAddress = getReferencedAddress(addr); Address referencedAddress = getReferencedAddress(addr);
if(referencedAddress == null) { if (referencedAddress == null) {
return false; return false;
} }
Data data = program.getListing().getDataAt(referencedAddress); Data data = program.getListing().getDataAt(referencedAddress);
if(data == null) { if (data == null) {
return false; return false;
} }
if(data.getBaseDataType().getName().contains("ClassTypeInfoStructure")) { if (data.getBaseDataType().getName().contains("ClassTypeInfoStructure")) {
return true; return true;
} }
return false; return false;
@ -382,97 +390,6 @@ public class Vtable {
return true; return true;
} }
/**
* Method to determine if the given address contains a possible function pointer
*
* @param address the given address
* @return true if the given address contains a possible function pointer or
* false otherwise
* @throws CancelledException if cancelled
*/
private boolean isPossibleFunctionPointer(Address address) throws CancelledException {
long longValue = extendedFlatAPI.getLongValueAt(address);
Register lowBitCodeMode = program.getRegister("LowBitCodeMode");
if (lowBitCodeMode != null) {
longValue = longValue & ~0x1;
}
Address possibleFunctionPointer = null;
try {
possibleFunctionPointer = address.getNewAddress(longValue);
} catch (AddressOutOfBoundsException e) {
return false;
}
if (possibleFunctionPointer == null) {
return false;
}
Function function = extendedFlatAPI.getFunctionAt(possibleFunctionPointer);
if (function != null) {
return true;
}
AddressSetView executeSet = program.getMemory().getExecuteSet();
if (!executeSet.contains(possibleFunctionPointer)) {
return false;
}
Instruction instruction = extendedFlatAPI.getInstructionAt(possibleFunctionPointer);
if (instruction != null) {
extendedFlatAPI.createFunction(possibleFunctionPointer, null);
return true;
}
boolean disassemble = extendedFlatAPI.disassemble(possibleFunctionPointer);
if (disassemble) {
// check for the case where there is conflicting data at the thumb offset
// function
// pointer and if so clear the data and redisassemble and remove the bad
// bookmark
long originalLongValue = extendedFlatAPI.getLongValueAt(address);
if (originalLongValue != longValue) {
Address offsetPointer = address.getNewAddress(originalLongValue);
if (extendedFlatAPI.getDataAt(offsetPointer) != null) {
extendedFlatAPI.clearListing(offsetPointer);
disassemble = extendedFlatAPI.disassemble(address);
Bookmark bookmark = getBookmarkAt(possibleFunctionPointer, BookmarkType.ERROR, "Bad Instruction",
"conflicting data");
if (bookmark != null) {
extendedFlatAPI.removeBookmark(bookmark);
}
}
}
extendedFlatAPI.createFunction(possibleFunctionPointer, null);
return true;
}
return false;
}
private Bookmark getBookmarkAt(Address address, String bookmarkType, String category, String commentContains)
throws CancelledException {
Bookmark[] bookmarks = program.getBookmarkManager().getBookmarks(address);
for (Bookmark bookmark : bookmarks) {
monitor.checkCancelled();
if (bookmark.getType().getTypeString().equals(bookmarkType) && bookmark.getCategory().equals(category)
&& bookmark.getComment().contains(commentContains)) {
return bookmark;
}
}
return null;
}
public void setHasVfunctions(boolean flag) { public void setHasVfunctions(boolean flag) {
hasVfunctions = flag; hasVfunctions = flag;
} }
@ -492,7 +409,8 @@ public class Vtable {
return; return;
} }
if (!hasVfunctions) { if (!hasVfunctions) {
length = (int) (typeinfoRefAddress.getOffset() + defaultPointerSize - vtableAddress.getOffset()); length = (int) (typeinfoRefAddress.getOffset() + defaultPointerSize -
vtableAddress.getOffset());
return; return;
} }
@ -539,7 +457,7 @@ public class Vtable {
} }
boolean keepChecking = true; boolean keepChecking = true;
int limit = length; int limit = length;
while (keepChecking) { while (keepChecking) {
@ -547,20 +465,22 @@ public class Vtable {
monitor.checkCancelled(); monitor.checkCancelled();
Address nextAddr = vtableAddress.add(length); Address nextAddr = vtableAddress.add(length);
Address typeinfoAddr = typeinfo.getAddress(); Address typeinfoAddr = typeinfo.getAddress();
int alignment = nextAddr.getSize()/8; int alignment = nextAddr.getSize() / 8;
Address nextTypeinfoRefAddr = getNextReferenceTo(nextAddr, typeinfoAddr, alignment, limit); Address nextTypeinfoRefAddr =
if(nextTypeinfoRefAddr == null) { getNextReferenceTo(nextAddr, typeinfoAddr, alignment, limit);
if (nextTypeinfoRefAddr == null) {
keepChecking = false; keepChecking = false;
continue; continue;
} }
GccTypeinfoRef internalTypenfoRef = new GccTypeinfoRef(nextTypeinfoRefAddr, typeinfo, true);
Vtable possibleInternalVtable = new Vtable(program, nextAddr,internalTypenfoRef, isSpecial, inExternalMemory, GccTypeinfoRef internalTypenfoRef =
new GccTypeinfoRef(nextTypeinfoRefAddr, typeinfo, true);
Vtable possibleInternalVtable =
new Vtable(program, nextAddr, internalTypenfoRef, isSpecial, inExternalMemory,
this, isConstruction, monitor); this, isConstruction, monitor);
if (!possibleInternalVtable.isValid()) { if (!possibleInternalVtable.isValid()) {
keepChecking = false; keepChecking = false;
@ -575,20 +495,22 @@ public class Vtable {
Namespace internalVtableNamespace = possibleInternalVtable.getNamespace(); Namespace internalVtableNamespace = possibleInternalVtable.getNamespace();
if (internalVtableNamespace != null && internalVtableNamespace.equals(classNamespace)) { if (internalVtableNamespace != null && internalVtableNamespace.equals(classNamespace)) {
addInternalVtable(possibleInternalVtable); addInternalVtable(possibleInternalVtable);
} else { }
else {
keepChecking = false; keepChecking = false;
} }
} }
} }
private Address getNextReferenceTo(Address startAddress, Address refdAddress, int alignment, int limit) { private Address getNextReferenceTo(Address startAddress, Address refdAddress, int alignment,
int limit) {
int offset = alignment; int offset = alignment;
while(offset < limit) { while (offset < limit) {
Address addr = startAddress.add(offset); Address addr = startAddress.add(offset);
Address referencedAddress = getReferencedAddress(addr); Address referencedAddress = getReferencedAddress(addr);
if(referencedAddress != null && referencedAddress.equals(refdAddress)) { if (referencedAddress != null && referencedAddress.equals(refdAddress)) {
return addr; return addr;
} }
offset += alignment; offset += alignment;
@ -604,7 +526,7 @@ public class Vtable {
public List<Vtable> getInternalVtables() { public List<Vtable> getInternalVtables() {
return internalVtables; return internalVtables;
} }
public void setIsConstructionVtable(Boolean setting) { public void setIsConstructionVtable(Boolean setting) {
isConstruction = setting; isConstruction = setting;
} }
@ -614,8 +536,8 @@ public class Vtable {
} }
private void figureOutNamespace() { private void figureOutNamespace() {
if(isConstruction == null) { if (isConstruction == null) {
setNamespace(globalNamespace); setNamespace(globalNamespace);
return; return;
} }
@ -635,7 +557,8 @@ public class Vtable {
// if not primary and the primary has same namespace then it is an internal // if not primary and the primary has same namespace then it is an internal
// vtable and can // vtable and can
// set the namespace to the typeinfo namespace // set the namespace to the typeinfo namespace
if (!primaryVtable.getNamespace().isGlobal() && primaryVtable.getNamespace().equals(typeinfoNamespace)) { if (!primaryVtable.getNamespace().isGlobal() &&
primaryVtable.getNamespace().equals(typeinfoNamespace)) {
setNamespace(typeinfoNamespace); setNamespace(typeinfoNamespace);
return; return;
} }
@ -647,7 +570,7 @@ public class Vtable {
public void setNamespace(Namespace namespace) { public void setNamespace(Namespace namespace) {
classNamespace = namespace; classNamespace = namespace;
for(Vtable internalVtable : internalVtables) { for (Vtable internalVtable : internalVtables) {
internalVtable.setNamespace(namespace); internalVtable.setNamespace(namespace);
} }
} }
@ -657,7 +580,7 @@ public class Vtable {
} }
protected boolean applyVtableData() throws CancelledException, Exception { protected boolean applyVtableData() throws CancelledException, Exception {
Data dataAt = listing.getDataAt(vtableAddress); Data dataAt = listing.getDataAt(vtableAddress);
// first check to see it is an erroneous vtable that has been made a byte array // first check to see it is an erroneous vtable that has been made a byte array
@ -699,15 +622,16 @@ public class Vtable {
throws AddressOutOfBoundsException { throws AddressOutOfBoundsException {
listing.clearCodeUnits(vftableAddress, listing.clearCodeUnits(vftableAddress,
vftableAddress.add((numFunctionPointers * defaultPointerSize - 1)), false); vftableAddress.add((numFunctionPointers * defaultPointerSize - 1)), false);
DataType pointerDataType = dataTypeManager.getPointer(null); DataType pointerDataType = dataTypeManager.getPointer(null);
ArrayDataType vftableArrayDataType = new ArrayDataType(pointerDataType, numFunctionPointers, ArrayDataType vftableArrayDataType = new ArrayDataType(pointerDataType, numFunctionPointers,
defaultPointerSize); defaultPointerSize);
try { try {
Data vftableArrayData = listing.createData(vftableAddress, vftableArrayDataType); Data vftableArrayData = listing.createData(vftableAddress, vftableArrayDataType);
return vftableArrayData; return vftableArrayData;
} catch (Exception e) { }
catch (Exception e) {
return null; return null;
} }
@ -725,21 +649,21 @@ public class Vtable {
private void createLongs(Address start, Address end) throws CancelledException, Exception { private void createLongs(Address start, Address end) throws CancelledException, Exception {
DataType longDT = new LongDataType(dataTypeManager); DataType longDT = new LongDataType(dataTypeManager);
if (defaultPointerSize == 8) { if (defaultPointerSize == 8) {
longDT = new LongLongDataType(); longDT = new LongLongDataType();
} }
int offset = 0; int offset = 0;
Address address = start; Address address = start;
while (address != null && !address.equals(end)) { while (address != null && !address.equals(end)) {
listing.clearCodeUnits(address, address.add(defaultPointerSize - 1),false); listing.clearCodeUnits(address, address.add(defaultPointerSize - 1), false);
listing.createData(address, longDT); listing.createData(address, longDT);
offset += defaultPointerSize; offset += defaultPointerSize;
address = getAddress(start, offset); address = getAddress(start, offset);
} }
} }
/** /**
* Method to get address at address + offset * Method to get address at address + offset
* *
@ -751,21 +675,22 @@ public class Vtable {
try { try {
Address newAddress = address.add(offset); Address newAddress = address.add(offset);
return newAddress; return newAddress;
} catch (AddressOutOfBoundsException e) { }
catch (AddressOutOfBoundsException e) {
return null; return null;
} }
} }
private Address getReferencedAddress(Address address) { private Address getReferencedAddress(Address address) {
int addressSize = address.getSize(); int addressSize = address.getSize();
Memory memory = program.getMemory(); Memory memory = program.getMemory();
try { try {
if (addressSize == 32) { if (addressSize == 32) {
long offset32 = memory.getInt(address); long offset32 = memory.getInt(address);
Address newAddr = address.getNewAddress(offset32); Address newAddr = address.getNewAddress(offset32);
if(memory.contains(newAddr)) { if (memory.contains(newAddr)) {
return newAddr; return newAddr;
} }
return null; return null;
@ -775,7 +700,7 @@ public class Vtable {
long offset64 = memory.getLong(address); long offset64 = memory.getLong(address);
Address newAddr = address.getNewAddress(offset64); Address newAddr = address.getNewAddress(offset64);
if(memory.contains(newAddr)) { if (memory.contains(newAddr)) {
return newAddr; return newAddr;
} }
return null; return null;