Adjustments to FID

This commit is contained in:
caheckman 2020-05-28 10:15:30 -04:00
parent 034f156718
commit 2d224cff27
6 changed files with 396 additions and 203 deletions

View file

@ -27,6 +27,7 @@ import ghidra.program.database.ProgramContentHandler;
import ghidra.program.model.lang.Language; import ghidra.program.model.lang.Language;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.symbol.Symbol;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException; import ghidra.util.exception.VersionException;
@ -64,7 +65,9 @@ public class FidStatistics extends GhidraScript {
@Override @Override
public int compareTo(SymbolPair o) { public int compareTo(SymbolPair o) {
int val = sym1.compareTo(o.sym1); int val = sym1.compareTo(o.sym1);
if (val != 0) return val; if (val != 0) {
return val;
}
return sym2.compareTo(o.sym2); return sym2.compareTo(o.sym2);
} }
@ -118,6 +121,7 @@ public class FidStatistics extends GhidraScript {
public int totalFunction; public int totalFunction;
public int matchUniquely; public int matchUniquely;
public int matchMultiply; public int matchMultiply;
public int hitCount;
public int noMatch; public int noMatch;
public int nameMatched; public int nameMatched;
public int falsePositive; public int falsePositive;
@ -126,15 +130,17 @@ public class FidStatistics extends GhidraScript {
totalFunction = 0; totalFunction = 0;
matchUniquely = 0; matchUniquely = 0;
matchMultiply = 0; matchMultiply = 0;
hitCount = 0;
noMatch = 0; noMatch = 0;
nameMatched = 0; nameMatched = 0;
falsePositive = 0; falsePositive = 0;
} }
public static void indent(StringBuilder buf,String last) { public static void indent(StringBuilder buf,String last) {
for(int i=last.length();i<10;++i) for(int i=last.length();i<10;++i) {
buf.append(' '); buf.append(' ');
} }
}
public void print(StringBuilder buf) { public void print(StringBuilder buf) {
String str = Integer.toString(totalFunction); String str = Integer.toString(totalFunction);
@ -146,6 +152,9 @@ public class FidStatistics extends GhidraScript {
str = Integer.toString(matchUniquely + matchMultiply); str = Integer.toString(matchUniquely + matchMultiply);
buf.append(str); buf.append(str);
indent(buf, str); indent(buf, str);
str = Integer.toString(hitCount);
buf.append(str);
indent(buf, str);
str = '(' + Integer.toString(matchUniquely) + ',' + Integer.toString(matchMultiply) + ')'; str = '(' + Integer.toString(matchUniquely) + ',' + Integer.toString(matchMultiply) + ')';
buf.append(str); buf.append(str);
indent(buf,str); indent(buf,str);
@ -157,7 +166,7 @@ public class FidStatistics extends GhidraScript {
} }
public static String getColumns() { public static String getColumns() {
return "Total No Match Hits uniq/mult N-Match False"; return "Total No Match Possible Hits uniq/mult N-Match False";
} }
} }
@ -331,6 +340,8 @@ public class FidStatistics extends GhidraScript {
addEquivSymbols("WPP_SF_qqDD","WPP_SF_qqdd"); addEquivSymbols("WPP_SF_qqDD","WPP_SF_qqdd");
addEquivSymbols("WPP_SF_DqD","WPP_SF_dqd"); addEquivSymbols("WPP_SF_DqD","WPP_SF_dqd");
addEquivSymbols("WPP_SF_Dq","WPP_SF_dq"); addEquivSymbols("WPP_SF_Dq","WPP_SF_dq");
addEquivSymbols("std::vector<>::_Assign_rv", "std::vector<>::_Move_assign_from");
addEquivSymbols("std::vector<>::_Assign_rv", "std::vector<>::_Move_from");
} }
private void findDomainFiles(LinkedList<DomainFile> programs, DomainFolder folder) private void findDomainFiles(LinkedList<DomainFile> programs, DomainFolder folder)
@ -350,11 +361,25 @@ public class FidStatistics extends GhidraScript {
} }
private boolean checkNames(String a,String b) { private boolean checkNames(String a,String b) {
if (a.equals(b)) if (a.equals(b)) {
return true; return true;
}
return equivSymbols.contains(new SymbolPair(a,b)); return equivSymbols.contains(new SymbolPair(a,b));
} }
private String chooseFunctionName(FidSearchResult result) {
Program program = result.function.getProgram();
Symbol[] symbols = program.getSymbolTable().getSymbols(result.function.getEntryPoint());
if (symbols.length > 1) {
for (Symbol symbol : symbols) {
if (matchAnalysis.containsRawName(symbol.getName())) {
return symbol.getName();
}
}
}
return result.function.getName();
}
private void processFunctionResult(FidSearchResult result) private void processFunctionResult(FidSearchResult result)
throws CancelledException, IOException { throws CancelledException, IOException {
StatRecord record = statRecord; StatRecord record = statRecord;
@ -378,7 +403,8 @@ public class FidStatistics extends GhidraScript {
matchHappened = true; // FID will put down a single match matchHappened = true; // FID will put down a single match
finalMatchName = matchAnalysis.getNameIterator().next(); finalMatchName = matchAnalysis.getNameIterator().next();
} }
NameVersions nameVersions = NameVersions.generate(result.function.getName(), program); String funcName = chooseFunctionName(result);
NameVersions nameVersions = NameVersions.generate(funcName, program);
String strippedTemplateName = null; String strippedTemplateName = null;
if (nameVersions.demangledBaseName != null) { if (nameVersions.demangledBaseName != null) {
strippedTemplateName = strippedTemplateName =
@ -389,7 +415,9 @@ public class FidStatistics extends GhidraScript {
while(iter.hasNext()) { while(iter.hasNext()) {
String raw = iter.next(); String raw = iter.next();
NameVersions matchNames = NameVersions.generate(raw, program); NameVersions matchNames = NameVersions.generate(raw, program);
if (matchNames.rawName == null) continue; if (matchNames.rawName == null) {
continue;
}
if (checkNames(nameVersions.rawName,matchNames.rawName)) { if (checkNames(nameVersions.rawName,matchNames.rawName)) {
exactNameMatch = true; exactNameMatch = true;
break; break;
@ -398,8 +426,26 @@ public class FidStatistics extends GhidraScript {
exactNameMatch = true; exactNameMatch = true;
break; break;
} }
if (nameVersions.demangledBaseName == null) continue; if (nameVersions.demangledBaseName != null) {
if (matchNames.demangledBaseName == null) continue; if (checkNames(nameVersions.demangledBaseName, matchNames.rawName) ||
checkNames(nameVersions.demangledBaseName, matchNames.similarName)) {
exactNameMatch = true;
break;
}
}
if (matchNames.demangledBaseName != null) {
if (checkNames(nameVersions.rawName, matchNames.demangledBaseName) ||
checkNames(nameVersions.similarName, matchNames.demangledBaseName)) {
exactNameMatch = true;
break;
}
}
if (nameVersions.demangledBaseName == null) {
continue;
}
if (matchNames.demangledBaseName == null) {
continue;
}
if (checkNames(nameVersions.demangledBaseName,matchNames.demangledBaseName)) { if (checkNames(nameVersions.demangledBaseName,matchNames.demangledBaseName)) {
exactNameMatch = true; exactNameMatch = true;
break; break;
@ -408,17 +454,21 @@ public class FidStatistics extends GhidraScript {
String strippedName = String strippedName =
MatchNameAnalysis.removeTemplateParams(matchNames.demangledBaseName); MatchNameAnalysis.removeTemplateParams(matchNames.demangledBaseName);
if (strippedName != null) { if (strippedName != null) {
if (strippedName.equals(strippedTemplateName)) { if (checkNames(strippedName, strippedTemplateName)) {
exactNameMatch = true; exactNameMatch = true;
break; break;
} }
} }
} }
} }
if (exactNameMatch) if (exactNameMatch) {
record.nameMatched += 1; record.nameMatched += 1;
}
float score = result.matches.get(0).getOverallScore(); float score = result.matches.get(0).getOverallScore();
if (score >= scoreThreshold && matchHappened) {
record.hitCount += 1;
}
if (exactNameMatch && ((score < scoreThreshold) || !matchHappened)) { if (exactNameMatch && ((score < scoreThreshold) || !matchHappened)) {
MatchRecord matchRecord = new MatchRecord(result,null,false); MatchRecord matchRecord = new MatchRecord(result,null,false);
StringBuilder buffer = new StringBuilder(); StringBuilder buffer = new StringBuilder();
@ -440,13 +490,19 @@ public class FidStatistics extends GhidraScript {
private void processProgram(Program program,FidQueryService queryService) throws MemoryAccessException, CancelledException, VersionException, IOException { private void processProgram(Program program,FidQueryService queryService) throws MemoryAccessException, CancelledException, VersionException, IOException {
FidProgramSeeker programSeeker = service.getProgramSeeker(program,queryService, 10.0f); FidProgramSeeker programSeeker = service.getProgramSeeker(program,queryService, 10.0f);
monitor.setMessage("Processing " + program.getName());
monitor.initialize(program.getFunctionManager().getFunctionCount());
FunctionIterator iter = program.getFunctionManager().getFunctionsNoStubs(true); FunctionIterator iter = program.getFunctionManager().getFunctionsNoStubs(true);
while(iter.hasNext()) { while(iter.hasNext()) {
Function func = iter.next(); Function func = iter.next();
if (func.getName().startsWith("FUN_") || func.getName().startsWith("Ordinal_")) monitor.incrementProgress(1);
if (func.getName().startsWith("FUN_") || func.getName().startsWith("Ordinal_")) {
continue; continue;
}
FidSearchResult searchResult = programSeeker.searchFunction(func, monitor); FidSearchResult searchResult = programSeeker.searchFunction(func, monitor);
if (searchResult == null) continue; // Could not hash function if (searchResult == null) {
continue; // Could not hash function
}
processFunctionResult(searchResult); processFunctionResult(searchResult);
} }
} }
@ -496,8 +552,9 @@ public class FidStatistics extends GhidraScript {
try { try {
program = (Program) domainFile.getDomainObject(this, false, false, monitor); program = (Program) domainFile.getDomainObject(this, false, false, monitor);
if (queryService == null || !lastLanguage.equals(program.getLanguage())) { if (queryService == null || !lastLanguage.equals(program.getLanguage())) {
if (queryService != null) if (queryService != null) {
queryService.close(); queryService.close();
}
lastLanguage = program.getLanguage(); lastLanguage = program.getLanguage();
queryService = service.openFidQueryService(lastLanguage, false); queryService = service.openFidQueryService(lastLanguage, false);
} }
@ -508,10 +565,11 @@ public class FidStatistics extends GhidraScript {
monitor.setProgress(counter); monitor.setProgress(counter);
} }
finally { finally {
if (program != null) if (program != null) {
program.release(this); program.release(this);
} }
} }
}
} catch(CancelledException ex) { } catch(CancelledException ex) {
// A cancel in middle of processing still allows results to get printed // A cancel in middle of processing still allows results to get printed
} }

View file

@ -28,6 +28,7 @@ import ghidra.feature.fid.db.*;
*/ */
public class RemoveFunctions extends GhidraScript { public class RemoveFunctions extends GhidraScript {
private LinkedList<Pair<Short, Long>> REMOVE_HASHES = new LinkedList<>(); private LinkedList<Pair<Short, Long>> REMOVE_HASHES = new LinkedList<>();
private LinkedList<Pair<Short, Long>> REMOVE_SPECHASHES = new LinkedList<>();
private LinkedList<Pair<Short, Long>> FORCE_SPECIFIC = new LinkedList<>(); private LinkedList<Pair<Short, Long>> FORCE_SPECIFIC = new LinkedList<>();
private LinkedList<Pair<Short, Long>> FORCE_RELATION = new LinkedList<>(); private LinkedList<Pair<Short, Long>> FORCE_RELATION = new LinkedList<>();
private LinkedList<Pair<Short, Long>> AUTO_PASS = new LinkedList<>(); private LinkedList<Pair<Short, Long>> AUTO_PASS = new LinkedList<>();
@ -146,6 +147,7 @@ public class RemoveFunctions extends GhidraScript {
FORCE_RELATION.add(fh(15, 0x3cd4904368bf315cL)); // ??_G?$_MallocaArrayHolder@PAVContext@Concurrency@@@details@Concurrency@@UAEPAXI@Z FORCE_RELATION.add(fh(15, 0x3cd4904368bf315cL)); // ??_G?$_MallocaArrayHolder@PAVContext@Concurrency@@@details@Concurrency@@UAEPAXI@Z
FORCE_RELATION.add(fh(4, 0xb8db1dacc3441a8fL)); // ??1_Timer@details@Concurrency@@MAE@XZ FORCE_RELATION.add(fh(4, 0xb8db1dacc3441a8fL)); // ??1_Timer@details@Concurrency@@MAE@XZ
FORCE_RELATION.add(fh(14, 0x7b2255d33cddad65L)); // ??_GThreadInternalContext@details@Concurrency@@UAEPAXI@Z FORCE_RELATION.add(fh(14, 0x7b2255d33cddad65L)); // ??_GThreadInternalContext@details@Concurrency@@UAEPAXI@Z
FORCE_RELATION.add(fh(15, 0xfe727990231ca423L)); // Generic constructor
REMOVE_HASHES.add(fh(4, 0x8f0554c0936e0e0dL)); // ?AddPaneToList@CPaneContainerManager@@QAEXPAVCDockablePane@@@Z REMOVE_HASHES.add(fh(4, 0x8f0554c0936e0e0dL)); // ?AddPaneToList@CPaneContainerManager@@QAEXPAVCDockablePane@@@Z
REMOVE_HASHES.add(fh(17, 0x6875ba2bfa94ae88L)); // ??1?$CComPtrBase@UIAccessibleProxy@@@ATL@@QAE@XZ REMOVE_HASHES.add(fh(17, 0x6875ba2bfa94ae88L)); // ??1?$CComPtrBase@UIAccessibleProxy@@@ATL@@QAE@XZ
@ -261,6 +263,47 @@ public class RemoveFunctions extends GhidraScript {
REMOVE_HASHES.add(fh(23, 0x1c009fbde7812ed5L)); // ??0failure@ios_base@std@@QEAA@AEBV012@@Z REMOVE_HASHES.add(fh(23, 0x1c009fbde7812ed5L)); // ??0failure@ios_base@std@@QEAA@AEBV012@@Z
REMOVE_HASHES.add(fh(10, 0x7e10fbe69b976818L)); // ??1CAudioMediaType@@MEAA@XZ REMOVE_HASHES.add(fh(10, 0x7e10fbe69b976818L)); // ??1CAudioMediaType@@MEAA@XZ
REMOVE_HASHES.add(fh(15, 0x79c797eb8032b47L)); // ??_G?$CList@IAEAI@@UEAAPEAXI@Z REMOVE_HASHES.add(fh(15, 0x79c797eb8032b47L)); // ??_G?$CList@IAEAI@@UEAAPEAXI@Z
REMOVE_HASHES.add(fh(6, 0x1198931964e874fbL)); // ??0XRibbonInfoParserRoot@CMFCRibbonInfo@@IEAA@XZ
REMOVE_HASHES.add(fh(6, 0x1524536d78c0da92L)); // ??1?$shared_ptr@V__ExceptionPtr@@@std@@QEAA@XZ
REMOVE_HASHES.add(fh(7, 0x020d6fdf4571e246L)); // max_size
REMOVE_HASHES.add(fh(13, 0x225ba93763be05b1L)); // operator==
REMOVE_HASHES.add(fh(13, 0x287ae8c33777713cL)); // ??1CStreamOnCString@@UEAA@XZ
REMOVE_HASHES.add(fh(9, 0x288020713ca1ea5bL)); // ??0?$move_iterator@V?$_Vector_iterator@V?$_Vector_val@U?$_Simple_types@V?$shared_ptr@U?$_Task_impl@E@details@Concurrency@@@std@@@std@@@std@@@std@@@std@@QEAA@AEBV01@@Z
REMOVE_HASHES.add(fh(10, 0x2b3bd58383bd38e9L)); // ??1VirtualProcessorRoot@details@Concurrency@@UEAA@XZ
REMOVE_HASHES.add(fh(7, 0x30a80a215b0bb2c4L)); // Generic destructor
REMOVE_HASHES.add(fh(7, 0x53a0821862961cb4L)); // constructor
REMOVE_HASHES.add(fh(4, 0x556c824f94bb014fL)); // return value derefed from first parameter ptr
REMOVE_HASHES.add(fh(12, 0x6581a15f3efa819eL)); // copy two fields between pointer parameters
REMOVE_HASHES.add(fh(9, 0x65e3ed6682944d20L)); // ??1CTraceSnapshot@@QEAA@XZ
REMOVE_HASHES.add(fh(8, 0x6ce601a9094cc769L)); // destructor
REMOVE_HASHES.add(fh(7, 0x6e6e4f635fd59012L)); // destructor
REMOVE_HASHES.add(fh(8, 0xad4b1b8ef3775874L)); // pass derefed first param to subfunc
REMOVE_HASHES.add(fh(8, 0xba8d3a7590fcc497L)); // destructor
REMOVE_HASHES.add(fh(7, 0xc4312b6b7324334aL)); // destructor
REMOVE_HASHES.add(fh(11, 0xd6650c343cfb0baeL)); // constructor
REMOVE_HASHES.add(fh(13, 0xe6202628da545409L)); // ??0CXMLParserRoot@@QEAA@XZ
REMOVE_HASHES.add(fh(6, 0xebd9388fe0c5b3d5L)); // operator++
REMOVE_HASHES.add(fh(8, 0xebfa00c4b493da85L)); // constructor
REMOVE_HASHES.add(fh(11, 0xf5d1f9d9b010f936L)); // constructor
REMOVE_HASHES.add(fh(11, 0xf7f34c91b43fa7d3L)); // destructor
REMOVE_HASHES.add(fh(8, 0xfcffed6fce4974a8L)); // constructor
REMOVE_HASHES.add(fh(9, 0x1c82d67f2be6ec3cL)); // constructor
REMOVE_HASHES.add(fh(10, 0x7dd643f9a75d75c4L)); // constructor
REMOVE_HASHES.add(fh(5, 0x88b326842c8ac560L)); // constructor
REMOVE_HASHES.add(fh(6, 0xa03ab775e8816d83L)); // wrapper
REMOVE_HASHES.add(fh(15, 0xe964369cf92d003fL)); // constructor
REMOVE_HASHES.add(fh(10, 0xf36c24d70ec93888L)); // wrapper
REMOVE_HASHES.add(fh(7, 0x763a8202f3d3c655L)); // constructor
REMOVE_HASHES.add(fh(12, 0x108d55ea8a0d124cL)); // scalar_deleting_destructor
REMOVE_HASHES.add(fh(13, 0x73f55a446deac3b1L)); // scalar_deleting_destructor
REMOVE_HASHES.add(fh(14, 0x3266cd569ab4eeffL)); // comparator
REMOVE_HASHES.add(fh(34, 0x8069e1fe2475e7c0L)); // inlined copies followed by method call
REMOVE_HASHES.add(fh(8, 0xa5c0d8da585783d3L)); // constructor
REMOVE_HASHES.add(fh(14, 0xad597a6e08b319b6L)); // destructor
REMOVE_HASHES.add(fh(17, 0xa552112bff535b06L)); // destructor
REMOVE_HASHES.add(fh(13, 0xac7036a5a6a27973L)); // destructor
REMOVE_HASHES.add(fh(6, 0x561ffc1c6cdb8a09L)); // Mysize
REMOVE_HASHES.add(fh(8, 0x6838c16db21b0fcdL)); // ??1_AsyncTaskCollection@details@Concurrency@@UEAA@XZ
FORCE_RELATION.add(fh(6, 0x508d431b82512d5bL)); // Generic wrapper, one obvious child FORCE_RELATION.add(fh(6, 0x508d431b82512d5bL)); // Generic wrapper, one obvious child
FORCE_RELATION.add(fh(19, 0x1e68c4d4d83e7585L)); // A little too generic stream thing, force parent FORCE_RELATION.add(fh(19, 0x1e68c4d4d83e7585L)); // A little too generic stream thing, force parent
@ -275,12 +318,59 @@ public class RemoveFunctions extends GhidraScript {
FORCE_RELATION.add(fh(25, 0x6a5c4f8adc931359L)); // scalar_deleting_destructor force parent FORCE_RELATION.add(fh(25, 0x6a5c4f8adc931359L)); // scalar_deleting_destructor force parent
FORCE_RELATION.add(fh(13, 0xf1e4167aedf569aL)); // Generic form, with many children FORCE_RELATION.add(fh(13, 0xf1e4167aedf569aL)); // Generic form, with many children
FORCE_RELATION.add(fh(20, 0x678b611a60783c98L)); // Generic form with children FORCE_RELATION.add(fh(20, 0x678b611a60783c98L)); // Generic form with children
FORCE_RELATION.add(fh(15, 0x51980975b49f9f73L)); // ??1SchedulingNode@details@Concurrency@@QEAA@XZ
FORCE_RELATION.add(fh(18, 0xcf323a39c909432bL)); // ?_Future_error_map@std@@YAPEBDH@Z
FORCE_RELATION.add(fh(14, 0x41110421841870bdL)); // iterator::operator=
FORCE_SPECIFIC.add(fh(26, 0xf0f7f2439683bfeaL)); // Variants with specialized constants FORCE_SPECIFIC.add(fh(26, 0xf0f7f2439683bfeaL)); // Variants with specialized constants
FORCE_SPECIFIC.add(fh(17, 0xf468f6c40495d8caL)); // Dispatcher form with lots of specific constants FORCE_SPECIFIC.add(fh(17, 0xf468f6c40495d8caL)); // Dispatcher form with lots of specific constants
FORCE_SPECIFIC.add(fh(13, 0x8779436db6c1d90L)); // ??1?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@V_STL70@@@std@@QEAA@XZ FORCE_SPECIFIC.add(fh(13, 0x8779436db6c1d90L)); // ??1?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@V_STL70@@@std@@QEAA@XZ
FORCE_SPECIFIC.add(fh(75, 0x48156d182763009dL)); // _write confused with _read FORCE_SPECIFIC.add(fh(75, 0x48156d182763009dL)); // _write confused with _read
FORCE_SPECIFIC.add(fh(51, 0x5c02a83d7b53cabbL)); // ??1CCommandLineInfo@@UEAA@XZ FORCE_SPECIFIC.add(fh(51, 0x5c02a83d7b53cabbL)); // ??1CCommandLineInfo@@UEAA@XZ
FORCE_SPECIFIC.add(fh(15, 0x4389c3585fa0606aL)); // has_flag
FORCE_SPECIFIC.add(fh(15, 0xcc72f3219032eacfL)); // ?__acrt_stdio_parse_mode_D@@YA_NAEAU__acrt_stdio_stream_mode@@@Z
FORCE_SPECIFIC.add(fh(36, 0xa07803de9bbbebbbL)); // vector deleting destructor
FORCE_SPECIFIC.add(fh(12, 0x1997c3c57f1359d6L)); // ?dtor$9@?0??AddMenuCommands@CMFCToolBarsCustomizeDialog@@QEAAXPEBVCMenu@@HPEB_W1@Z@4HA
FORCE_RELATION.add(fh(12, 0x1997c3c57f1359d6L));
FORCE_SPECIFIC.add(fh(11, 0x2c36a67a489920daL)); // ??1ContextBase@details@Concurrency@@UEAA@XZ
FORCE_RELATION.add(fh(11, 0x2c36a67a489920daL));
FORCE_SPECIFIC.add(fh(15, 0x69156cfc34e915e7L)); // ??0<lambda_6dd2c61d572e92a64c8eda4035773505>@@QEAA@AEBV0@@Z
FORCE_RELATION.add(fh(15, 0x69156cfc34e915e7L));
FORCE_SPECIFIC.add(fh(11, 0x781f34966e8ef7deL)); // FreeNode
FORCE_RELATION.add(fh(11, 0x781f34966e8ef7deL));
FORCE_SPECIFIC.add(fh(11, 0x86b8837a96bb2fadL)); // ??0NumaInformation@SchedulerBase@details@Concurrency@@QEAA@XZ
FORCE_RELATION.add(fh(11, 0x86b8837a96bb2fadL));
FORCE_SPECIFIC.add(fh(10, 0x87dd953d6c34861eL)); // get_allocator
FORCE_RELATION.add(fh(10, 0x87dd953d6c34861eL));
FORCE_SPECIFIC.add(fh(14, 0x8c77a958beb620dfL)); // ?HasRealizedChores@ScheduleGroupSegmentBase@details@Concurrency@@IEBA_NXZ
FORCE_RELATION.add(fh(14, 0x8c77a958beb620dfL));
FORCE_SPECIFIC.add(fh(10, 0x90181c81962ce711L)); // ??1CStreamOnCString@@QEAA@XZ
FORCE_RELATION.add(fh(10, 0x90181c81962ce711L));
FORCE_SPECIFIC.add(fh(17, 0x9248e909511b8ddaL)); // ??0FreeVirtualProcessorRoot@details@Concurrency@@QEAA@PEAVSchedulerProxy@12@PEAUSchedulerNode@12@I@Z
FORCE_RELATION.add(fh(17, 0x9248e909511b8ddaL));
FORCE_SPECIFIC.add(fh(15, 0x977e6c2c25e8f389L)); // ??1CMFCVisualManagerBitmapCache@@UEAA@XZ
FORCE_RELATION.add(fh(15, 0x977e6c2c25e8f389L));
FORCE_SPECIFIC.add(fh(17, 0xad2d41b71db78df0L)); // ??1COleDispatchException@@UEAA@XZ
FORCE_RELATION.add(fh(17, 0xad2d41b71db78df0L));
FORCE_SPECIFIC.add(fh(26, 0xb5b192b00955d1feL)); // ??1_Locinfo@std@@QEAA@XZ
FORCE_RELATION.add(fh(26, 0xb5b192b00955d1feL));
FORCE_SPECIFIC.add(fh(10, 0xd6a5fc3691b7f101L)); // DelRegTree
FORCE_RELATION.add(fh(10, 0xd6a5fc3691b7f101L));
FORCE_SPECIFIC.add(fh(13, 0xd75e6989aec2a5a9L)); // destructor form
FORCE_RELATION.add(fh(13, 0xd75e6989aec2a5a9L));
FORCE_SPECIFIC.add(fh(13, 0xdcfdfd3a9345b3a5L)); // constructor form
FORCE_RELATION.add(fh(13, 0xdcfdfd3a9345b3a5L));
FORCE_SPECIFIC.add(fh(14, 0xf323b038a8b540faL)); // ?GetPolicy@SchedulerBase@details@Concurrency@@UEBA?AVSchedulerPolicy@3@XZ
FORCE_RELATION.add(fh(14, 0xf323b038a8b540faL));
FORCE_SPECIFIC.add(fh(10, 0x6862321b024d5c83L)); // constructor
FORCE_RELATION.add(fh(10, 0x6862321b024d5c83L));
FORCE_SPECIFIC.add(fh(11, 0xa61ae8d54cfc35d6L)); // comparator, empty
FORCE_RELATION.add(fh(11, 0xa61ae8d54cfc35d6L));
FORCE_SPECIFIC.add(fh(12, 0x892067d7b5484452L)); // anonymous destructor
FORCE_RELATION.add(fh(12, 0x892067d7b5484452L));
FORCE_SPECIFIC.add(fh(12, 0x2155a28b83bb2704L)); // destructor
FORCE_RELATION.add(fh(12, 0x2155a28b83bb2704L));
FORCE_SPECIFIC.add(fh(10, 0x5c4a91ec77ecc3d2L)); // strnlen FORCE_SPECIFIC.add(fh(10, 0x5c4a91ec77ecc3d2L)); // strnlen
AUTO_PASS.add(fh(10, 0x5c4a91ec77ecc3d2L)); AUTO_PASS.add(fh(10, 0x5c4a91ec77ecc3d2L));
@ -292,6 +382,16 @@ public class RemoveFunctions extends GhidraScript {
AUTO_PASS.add(fh(10, 0xaba76591680821c6L)); AUTO_PASS.add(fh(10, 0xaba76591680821c6L));
FORCE_SPECIFIC.add(fh(10, 0x6244ea7ccad27b93L)); // wcsnlen FORCE_SPECIFIC.add(fh(10, 0x6244ea7ccad27b93L)); // wcsnlen
AUTO_PASS.add(fh(10, 0x6244ea7ccad27b93L)); AUTO_PASS.add(fh(10, 0x6244ea7ccad27b93L));
FORCE_SPECIFIC.add(fh(9, 0x347bdce6848098d1L)); // strncnt
AUTO_PASS.add(fh(9, 0x347bdce6848098d1L));
FORCE_SPECIFIC.add(fh(10, 0x668ac85a3d5bf04bL)); // raise_securityfailure
AUTO_PASS.add(fh(10, 0x668ac85a3d5bf04bL));
// Must exhibit relation and constants, plus one specific set of constants are marked as auto-fail
FORCE_SPECIFIC.add(fh(11, 0xf8ff33ae3bb6b9e9L)); // constructor
FORCE_RELATION.add(fh(11, 0xf8ff33ae3bb6b9e9L));
REMOVE_SPECHASHES.add(fh(11, 0xc03985b32a1f76ceL));
} }
private static Pair<Short, Long> fh(int codeUnits, long digest) { private static Pair<Short, Long> fh(int codeUnits, long digest) {
@ -403,6 +503,17 @@ public class RemoveFunctions extends GhidraScript {
monitor.incrementProgress(1); monitor.incrementProgress(1);
} }
monitor.setMaximum(REMOVE_SPECHASHES.size());
monitor.setProgress(0);
for (Pair<Short, Long> pair : REMOVE_SPECHASHES) {
List<FunctionRecord> listSpecHash =
modifiableFidDB.findFunctionsBySpecificHash(pair.second.longValue());
for (FunctionRecord funcRec : listSpecHash) {
modifiableFidDB.setAutoFailOnFunction(funcRec, true);
}
monitor.checkCanceled();
monitor.incrementProgress(1);
}
modifiableFidDB.saveDatabase("", monitor); modifiableFidDB.saveDatabase("", monitor);
} }
finally { finally {

View file

@ -18,6 +18,7 @@ package ghidra.feature.fid.cmd;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
import ghidra.app.cmd.label.SetLabelPrimaryCmd;
import ghidra.app.util.demangler.DemangledObject; import ghidra.app.util.demangler.DemangledObject;
import ghidra.feature.fid.db.FidQueryService; import ghidra.feature.fid.db.FidQueryService;
import ghidra.feature.fid.service.*; import ghidra.feature.fid.service.*;
@ -32,12 +33,16 @@ import ghidra.util.task.TaskMonitor;
public class ApplyFidEntriesCommand extends BackgroundCommand { public class ApplyFidEntriesCommand extends BackgroundCommand {
public static final String FID_CONFLICT = "FID_conflict:"; public static final String FID_CONFLICT = "FID_conflict:";
public static final String FID_BOOKMARK_CATEGORY = "Function ID Analyzer";
public static final String FIDCONFLICT_BOOKMARK_CATEGORY = "Function ID Conflict";
public static final int MAGIC_MULTIPLE_MATCH_LIMIT = 10; public static final int MAGIC_MULTIPLE_MATCH_LIMIT = 10;
public static final int MAGIC_MULTIPLE_LIBRARY_LIMIT = 5; public static final int MAGIC_MULTIPLE_LIBRARY_LIMIT = 5;
public static final int MAX_PLATE_COMMENT_LINE_LENGTH = 58; public static final int MAX_PLATE_COMMENT_LINE_LENGTH = 58;
private MatchNameAnalysis nameAnalysis = new MatchNameAnalysis(); private MatchNameAnalysis nameAnalysis = new MatchNameAnalysis();
private AddressSet affectedLocations = new AddressSet(); private AddressSet affectedLocations = new AddressSet();
private TreeMap<String, Address> multiMatchNames = new TreeMap<String, Address>();
private LinkedList<Address> conflictFunctions = new LinkedList<Address>();
private boolean alwaysApplyFidLabels; private boolean alwaysApplyFidLabels;
private float scoreThreshold; private float scoreThreshold;
private float multiNameScoreThreshold; private float multiNameScoreThreshold;
@ -66,6 +71,7 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
try (FidQueryService fidQueryService = try (FidQueryService fidQueryService =
service.openFidQueryService(program.getLanguage(), false)) { service.openFidQueryService(program.getLanguage(), false)) {
monitor.setMessage("FID Analysis");
List<FidSearchResult> processProgram = List<FidSearchResult> processProgram =
service.processProgram(program, fidQueryService, scoreThreshold, monitor); service.processProgram(program, fidQueryService, scoreThreshold, monitor);
if (processProgram == null) { if (processProgram == null) {
@ -88,6 +94,7 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
" at " + entry.function.getEntryPoint()); " at " + entry.function.getEntryPoint());
} }
} }
applyConflictLabels(program);
} }
catch (CancelledException e) { catch (CancelledException e) {
return false; return false;
@ -143,8 +150,8 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
} }
// multiple matches - TODO: change to show classes vs libraries - libraries with same name don't put "base" name only for class ones // multiple matches - TODO: change to show classes vs libraries - libraries with same name don't put "base" name only for class ones
plateCommentContents = generateComment(plateCommentContents, true, false, monitor); plateCommentContents = generateComment(plateCommentContents, monitor);
bookmarkContents = generateBookmark(bookmarkContents, true, false, monitor); bookmarkContents = generateBookmark(bookmarkContents);
applyMarkup(result.function, newFunctionName, plateCommentContents, bookmarkContents, applyMarkup(result.function, newFunctionName, plateCommentContents, bookmarkContents,
monitor); monitor);
@ -155,20 +162,19 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
int counter = 0; int counter = 0;
if (nameAnalysis.numNames() < MAGIC_MULTIPLE_MATCH_LIMIT) {
buffer.append("Name: ");
Iterator<String> iterator = nameAnalysis.getNameIterator(); Iterator<String> iterator = nameAnalysis.getNameIterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
monitor.checkCanceled(); monitor.checkCanceled();
if (counter != 0) { buffer.append(' ');
buffer.append(", ");
}
buffer.append(iterator.next()); buffer.append(iterator.next());
buffer.append('\n');
counter++; counter++;
if (counter > 3) {
break;
} }
} }
else { if (iterator.hasNext()) {
buffer.append("Names: " + nameAnalysis.numSimilarNames() + " - too many to list"); buffer.append(" " + nameAnalysis.numNames() + " names - too many to list\n");
} }
return buffer.toString(); return buffer.toString();
@ -203,8 +209,7 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
return buffer.toString(); return buffer.toString();
} }
private String generateComment(String header, boolean includeNames, boolean includeNamespaces, private String generateComment(String header, TaskMonitor monitor) throws CancelledException {
TaskMonitor monitor) throws CancelledException {
StringBuilder buffer = new StringBuilder(); StringBuilder buffer = new StringBuilder();
buffer.append(header); buffer.append(header);
@ -217,18 +222,13 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
return buffer.toString(); return buffer.toString();
} }
private String generateBookmark(String bookmark, boolean includeNames, private String generateBookmark(String bookmark) {
boolean includeNamespaces, TaskMonitor monitor) throws CancelledException {
StringBuilder buffer = new StringBuilder(); StringBuilder buffer = new StringBuilder();
if (createBookmarksEnabled) { if (createBookmarksEnabled) {
buffer.append(bookmark); buffer.append(bookmark);
// append names, class, and library info buffer
buffer.append(" "); buffer.append(" ");
buffer.append(listNames(monitor)); buffer.append(nameAnalysis.getNameIterator().next());
buffer.append(", ");
buffer.append(listLibraries(monitor));
} }
return buffer.toString(); return buffer.toString();
@ -242,25 +242,22 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
return; return;
} }
int numUniqueLabelNames;
// single name case ok // single name case ok
if (newFunctionName != null) { if (newFunctionName != null) {
addFunctionLabel(function, newFunctionName, monitor); addFunctionLabel(function, newFunctionName, monitor);
numUniqueLabelNames = 1;
} }
// multiple names // multiple names
else { else {
numUniqueLabelNames = addFunctionLabelMultipleMatches(function, monitor); addFunctionLabelMultipleMatches(function, monitor);
} }
if (numUniqueLabelNames < MAGIC_MULTIPLE_MATCH_LIMIT) {
if (plateCommentContents != null && !plateCommentContents.equals("")) { if (plateCommentContents != null && !plateCommentContents.equals("")) {
function.setComment(plateCommentContents); function.setComment(plateCommentContents);
} }
if (bookmarkContents != null && !bookmarkContents.equals("")) { if (bookmarkContents != null && !bookmarkContents.equals("")) {
function.getProgram().getBookmarkManager().setBookmark(function.getEntryPoint(), function.getProgram()
BookmarkType.ANALYSIS, "Function ID Analyzer", bookmarkContents); .getBookmarkManager()
} .setBookmark(function.getEntryPoint(),
BookmarkType.ANALYSIS, FID_BOOKMARK_CATEGORY, bookmarkContents);
} }
} }
@ -283,8 +280,7 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
return false; return false;
} }
private void addFunctionLabel(Function function, String newFunctionName, TaskMonitor monitor) private void addFunctionLabel(Function function, String newFunctionName, TaskMonitor monitor) {
throws CancelledException {
removeConflictSymbols(function, newFunctionName, monitor); removeConflictSymbols(function, newFunctionName, monitor);
@ -292,158 +288,158 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
addSymbolToFunction(function, newFunctionName); addSymbolToFunction(function, newFunctionName);
} }
/**
* Delete a symbol of the given name and address, knowing there are multiple Symbols at the address.
* If the symbol is primary, make another Symbol at the address primary before deleting
* @param matchName is the given Symbol name
* @param addr is the given Address
* @param program is the Program
* @return the number of Symbols remaining at the address
*/
private int deleteSymbol(String matchName, Address addr, Program program) {
int numSymbols = 0;
for (int i = 0; i < 2; ++i) { // Try to find non-primary matching Symbol at most twice
Symbol[] symbols = program.getSymbolTable().getSymbols(addr);
numSymbols = symbols.length;
if (numSymbols <= 1) {
break;
}
for (Symbol sym : symbols) { // Among Symbols at the Address
if (sym.getName().equals(matchName)) { // Find one with matching name
if (!sym.isPrimary()) { // If it is not primary
sym.delete(); // delete it immediately
numSymbols -= 1;
break; // and we are done
}
Symbol otherSym = symbols[0];
if (otherSym == sym) { // Otherwise find another Symbol, which must not be primary
otherSym = symbols[1];
}
// Set the other symbol to primary
SetLabelPrimaryCmd cmd = new SetLabelPrimaryCmd(addr, otherSym.getName(),
otherSym.getParentNamespace());
cmd.applyTo(program);
break;
}
}
}
return numSymbols;
}
// This is called when a single library match is made. It checks to see if the label of the single match is contained in // This is called when a single library match is made. It checks to see if the label of the single match is contained in
// any "libID_conflict" labels. If it is, that label is removed from the other function(s) since it is no longer a possibility. // the set of "FID conflict" functions with multiple matches.
// Also checks those locations to see if there is only one other libID_conflict label left and if so, removes the "libID_conflict" // If it is, that label is removed from the other function(s) since it is no longer a possibility.
// prefix // Also checks those locations to see if there is only one label left and if so, removes the "FID conflict" bookmark.
private void removeConflictSymbols(Function function, String matchName, TaskMonitor monitor) private void removeConflictSymbols(Function function, String matchName, TaskMonitor monitor) {
throws CancelledException {
Address addr = multiMatchNames.get(matchName);
if (addr == null) {
return;
}
Program program = function.getProgram(); Program program = function.getProgram();
SymbolTable symTab = program.getSymbolTable(); int numSymbols = deleteSymbol(matchName, addr, program);
if (numSymbols <= 1) {
//get all currently created FID functions // Only one symbol left, delete the "FID conflict" bookmark
BookmarkManager bkMgr = program.getBookmarkManager(); BookmarkManager bookmarkManager = program.getBookmarkManager();
Iterator<Bookmark> bkmkIterator = bkMgr.getBookmarksIterator("Function ID Analyzer"); Bookmark bookmark = bookmarkManager.getBookmark(addr, BookmarkType.ANALYSIS,
FIDCONFLICT_BOOKMARK_CATEGORY);
//iterate over all instances of libID_conflict_<matchName>_<possibly addr> and delete them if (bookmark != null) {
while (bkmkIterator.hasNext()) { bookmarkManager.removeBookmark(bookmark);
monitor.checkCanceled();
Bookmark nextBkmark = bkmkIterator.next();
Symbol symbols[] = symTab.getSymbols(nextBkmark.getAddress());
for (Symbol symbol : symbols) {
monitor.checkCanceled();
//if the symbol matches prefix+matchName exactly
//OR if no _ exists immediately after the prefix + matchName part of the found symbol (meaning there is no address following)
//OR if there is an _ immediately following the prefix+Name AND and address directly following it we can be sure it is a good symbol match and can delete it
//otherwise it contains extra characters indicating an invalid match and we don't want to delete it
String name = symbol.getName();
if (name.startsWith(FID_CONFLICT)) {
String baseName = name.substring(FID_CONFLICT.length());
Address symAddr = symbol.getAddress();
if (baseName.equals(matchName)) {
symbol.delete();
// check to see if there is only one symbol left on that function
// that has a libID_conflict name and if so remove the conflict part
removeConflictFromSymbolWhenOnlyOneLeft(symTab, symAddr, monitor);
break;
} }
} }
} }
}
}
//check to see if there is only one symbol left on that function
// that has a libID_conflict name and if so remove the conflict part
private void removeConflictFromSymbolWhenOnlyOneLeft(SymbolTable symTab, Address symAddr,
TaskMonitor monitor) throws CancelledException {
//First get all symbols at the removed symbol address
Symbol[] symbols = symTab.getSymbols(symAddr);
//Next, check to see if there is only one symbol, if it has prefix remove the prefix, otherwise just skip to end
if (symbols.length == 1) {
if (symbols[0].getName().startsWith(FID_CONFLICT)) {
removeConflictFromSymbol(symbols[0].getSource(), symbols[0]);
}
}
// if more than one symbol, check to see if only one has libIDconflict
else {
int conflictCount = 0;
Symbol keepSymbol = null;
SourceType keepSymbolSource = null;
for (Symbol symbol : symbols) {
monitor.checkCanceled();
if (conflictCount > 1) {
keepSymbol = null;
keepSymbolSource = null;
break;
}
if (symbol.getName().startsWith(FID_CONFLICT)) {
conflictCount++;
keepSymbol = symbol;
keepSymbolSource = symbol.getSource();
}
}
if (keepSymbol != null) {
removeConflictFromSymbol(keepSymbolSource, keepSymbol);
}
}
}
private void removeConflictFromSymbol(SourceType sourceType, Symbol symbol) {
String newName = symbol.getName().substring(FID_CONFLICT.length());
try {
symbol.setName(newName, sourceType);
}
catch (DuplicateNameException e) {
Msg.warn(SymbolUtilities.class,
"Duplicate symbol name \"" + newName + "\" at " + symbol.getAddress());
}
catch (InvalidInputException e) {
throw new AssertException(e); // unexpected
}
}
private int addFunctionLabelMultipleMatches(Function function, TaskMonitor monitor) private int addFunctionLabelMultipleMatches(Function function, TaskMonitor monitor)
throws CancelledException { throws CancelledException {
Program program = function.getProgram(); Program program = function.getProgram();
Set<String> matchNames = nameAnalysis.getAppriateNamesSet();
if (matchNames.size() >= MAGIC_MULTIPLE_MATCH_LIMIT) { if (nameAnalysis.numNames() >= MAGIC_MULTIPLE_MATCH_LIMIT) {
return matchNames.size(); return nameAnalysis.numNames();
} }
Set<String> unusedNames = getFIDNamesThatDontExistSomewhereElse(program, matchNames); Symbol symbol = function.getSymbol();
boolean preexistingSymbol = (symbol != null && symbol.getSource() != SourceType.DEFAULT);
for (String baseName : unusedNames) { Set<String> unusedNames =
getFIDNamesThatDontExistSomewhereElse(program, nameAnalysis.getNameIterator());
Address addr = function.getEntryPoint();
for (String functionName : unusedNames) {
monitor.checkCanceled(); monitor.checkCanceled();
String functionName = getFunctionNameForBaseName(program, baseName, unusedNames);
addSymbolToFunction(function, functionName); addSymbolToFunction(function, functionName);
multiMatchNames.put(functionName, addr);
} }
if (unusedNames.size() > 1) {
if (!preexistingSymbol) {
conflictFunctions.add(addr);
}
if (createBookmarksEnabled) {
BookmarkManager bookmarkManager = function.getProgram().getBookmarkManager();
bookmarkManager.setBookmark(addr, BookmarkType.ANALYSIS,
FIDCONFLICT_BOOKMARK_CATEGORY,
"Multiple likely matching functions");
}
}
return unusedNames.size(); return unusedNames.size();
} }
/** /**
* Returns the symbol name to use based on if there are multiple conficts for a function * Apply special FID_CONFLICT to the primary symbol on functions where we had multiple matches
* If there is only one matching name, then it is used directly. Otherwise, "FID_conflict:" * @param program is the Program
* is prepended to the name.
*/ */
private String getFunctionNameForBaseName(Program program, String baseName, private void applyConflictLabels(Program program) {
Set<String> unusedNames) { SymbolTable symbolTable = program.getSymbolTable();
if (unusedNames.size() == 1) { for (Address addr : conflictFunctions) {
return baseName; Symbol[] symbols = symbolTable.getSymbols(addr);
if (symbols.length <= 1) {
continue; // Only apply conflict label if more than one symbol at address
}
Symbol symbol = null;
for (Symbol symbol2 : symbols) {
if (symbol2.isPrimary()) {
symbol = symbol2;
break;
}
}
if (symbol == null || !symbol.isGlobal()) {
continue;
}
String baseName = symbol.getName();
if (baseName.startsWith(FID_CONFLICT)) {
continue; // Conflict label previously applied
}
DemangledObject demangle = NameVersions.demangle(program, baseName);
if (demangle != null) {
baseName = demangle.getName();
}
baseName = FID_CONFLICT + baseName;
try {
symbol = symbolTable.createLabel(addr, baseName, null, SourceType.ANALYSIS);
SetLabelPrimaryCmd cmd =
new SetLabelPrimaryCmd(addr, symbol.getName(), symbol.getParentNamespace());
cmd.applyTo(program);
}
catch (InvalidInputException e) {
Msg.warn(SymbolUtilities.class,
"Invalid symbol name: \"" + baseName + "\" at " + addr);
} }
DemangledObject demangledObj = NameVersions.demangle(program, baseName);
if (demangledObj != null) {
baseName = demangledObj.getName();
} }
return FID_CONFLICT + baseName;
} }
/** /**
* Takes a set of FID matching names and returns a subset that includes only names that don't exist * Takes a set of FID matching names and returns a subset that includes only names that don't exist
* somewhere else in the program. * somewhere else in the program.
*/ */
private Set<String> getFIDNamesThatDontExistSomewhereElse(Program program, private static Set<String> getFIDNamesThatDontExistSomewhereElse(Program program,
Set<String> matchNames) { Iterator<String> iter) {
Set<String> unusedNames = new HashSet<String>(); Set<String> unusedNames = new HashSet<String>();
for (String name : matchNames) { SymbolTable symbolTable = program.getSymbolTable();
if (!nameExistsSomewhereElse(program.getSymbolTable(), name)) { while (iter.hasNext()) {
String name = iter.next();
if (!nameExistsSomewhereElse(symbolTable, name)) {
unusedNames.add(name); unusedNames.add(name);
} }
} }
@ -451,7 +447,7 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
} }
//Check to see if other functions exist with the same baseName or _baseName or __baseName //Check to see if other functions exist with the same baseName or _baseName or __baseName
private boolean nameExistsSomewhereElse(SymbolTable symTab, String baseName) { private static boolean nameExistsSomewhereElse(SymbolTable symTab, String baseName) {
//I did it this way because doing it with an iterator and wildcard was really really slow //I did it this way because doing it with an iterator and wildcard was really really slow
List<Symbol> globalSymbols = symTab.getLabelOrFunctionSymbols(baseName, null); List<Symbol> globalSymbols = symTab.getLabelOrFunctionSymbols(baseName, null);
@ -470,7 +466,6 @@ public class ApplyFidEntriesCommand extends BackgroundCommand {
} }
return false; return false;
} }
private void addSymbolToFunction(Function function, String name) { private void addSymbolToFunction(Function function, String name) {

View file

@ -342,6 +342,10 @@ public class FidProgramSeeker {
} }
} }
if (functionRecord.isForceRelation() && childCodeUnits == 0) {
return null;
}
int parentCodeUnits = 0; int parentCodeUnits = 0;
if (family.getParents().size() < MAX_NUM_PARENTS_FOR_SCORE) { if (family.getParents().size() < MAX_NUM_PARENTS_FOR_SCORE) {
@ -355,12 +359,6 @@ public class FidProgramSeeker {
float functionScore = functionCodeUnits; float functionScore = functionCodeUnits;
functionScore += 0.67 * specificCodeUnits; // Each specific constant count is worth 2/3 of a whole code unit functionScore += 0.67 * specificCodeUnits; // Each specific constant count is worth 2/3 of a whole code unit
if (functionRecord.isForceRelation()) {
// If both auto-pass and force-relation are on, do not ding score if some children match
if (!functionRecord.autoPass() || (childCodeUnits == 0)) {
functionScore = 0;
}
}
float childScore = childCodeUnits; float childScore = childCodeUnits;
float parentScore = parentCodeUnits; float parentScore = parentCodeUnits;
if (functionScore + childScore + parentScore < scoreThreshold) { if (functionScore + childScore + parentScore < scoreThreshold) {

View file

@ -47,6 +47,10 @@ public class MatchNameAnalysis {
return rawNames.iterator(); return rawNames.iterator();
} }
public boolean containsRawName(String name) {
return rawNames.contains(name);
}
public Iterator<String> getNameIterator() { public Iterator<String> getNameIterator() {
return finalNameList.iterator(); return finalNameList.iterator();
} }
@ -89,12 +93,14 @@ public class MatchNameAnalysis {
if (nameVersions.rawName != null) { if (nameVersions.rawName != null) {
rawNames.add(nameVersions.rawName); // Dedup the raw names rawNames.add(nameVersions.rawName); // Dedup the raw names
similarBaseNames.add(nameVersions.similarName); // Dedup names with underscores removed similarBaseNames.add(nameVersions.similarName); // Dedup names with underscores removed
if (nameVersions.demangledBaseName != null) // If we can demangle if (nameVersions.demangledBaseName != null) {
exactDemangledBaseNames.add(nameVersions.demangledBaseName); // Dedup demangled base name exactDemangledBaseNames.add(nameVersions.demangledBaseName); // Dedup demangled base name
else }
else {
cannotDemangle += 1; cannotDemangle += 1;
} }
} }
}
String singleName = null; String singleName = null;
mostOptimisticCount = rawNames.size(); mostOptimisticCount = rawNames.size();
@ -117,6 +123,12 @@ public class MatchNameAnalysis {
mostOptimisticCount = 1; mostOptimisticCount = 1;
finalNameList = Collections.singleton(singleName); finalNameList = Collections.singleton(singleName);
} }
else if (rawNames.size() > similarBaseNames.size()) {
// if names are the same except for underscores use the similar name
// list to remove dupes
finalNameList = similarBaseNames;
}
if (matches.size() > 0) { if (matches.size() > 0) {
overallScore = matches.get(0).getOverallScore(); overallScore = matches.get(0).getOverallScore();
} }
@ -132,9 +144,10 @@ public class MatchNameAnalysis {
if (library != null) { if (library != null) {
libraries.add(library); libraries.add(library);
} }
if (libraries.size() >= libraryLimit) if (libraries.size() >= libraryLimit) {
break; break;
} }
}
if (libraries.size() >= libraryLimit) { // Too many libraries to directly display if (libraries.size() >= libraryLimit) { // Too many libraries to directly display
// Try getting rid of the variant field, to see if we can reduce the count // Try getting rid of the variant field, to see if we can reduce the count
libraries.clear(); libraries.clear();
@ -164,8 +177,9 @@ public class MatchNameAnalysis {
} }
private String findCommonBaseName() { private String findCommonBaseName() {
if (similarBaseNames.size() == 1) if (similarBaseNames.size() == 1) {
return rawNames.iterator().next(); return rawNames.iterator().next();
}
return null; return null;
} }
@ -223,25 +237,4 @@ public class MatchNameAnalysis {
} }
return finalName; return finalName;
} }
/**
* returns the appropriate set of names to use for laying down fid symbols
*/
public Set<String> getAppriateNamesSet() {
// if the names were originally mangled and they demangle to more than
// one base name use the demangled base names
if (exactDemangledBaseNames.size() > 1 && rawNames.size() > 1) {
return exactDemangledBaseNames;
}
// if names are the same except for underscores use the similar name
// list to remove dupes
if (rawNames.size() == similarBaseNames.size() * 2) {
return similarBaseNames;
}
// else the names are not the same or similar so use the list of exact
// names
return rawNames;
}
} }

View file

@ -15,8 +15,7 @@
*/ */
package ghidra.feature.fid.service; package ghidra.feature.fid.service;
import ghidra.app.util.demangler.DemangledObject; import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.DemanglerUtil;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
public class NameVersions { public class NameVersions {
@ -44,12 +43,51 @@ public class NameVersions {
return null; return null;
} }
private static String getBaseClass(Demangled namespace) {
String name = namespace.getNamespaceName(); // First level of namespace
// Check for evidence of anonymous or unnamed namespace, which won't be distinguishing
if (name.length() > 1 && name.charAt(0) == '`') {
char firstChar = name.charAt(1);
if (firstChar >= '0' && firstChar <= '9') {
return namespace.getNamespaceString(); // Get full namespace
}
}
return name;
}
private static String constructBaseName(DemangledObject demangledObj) {
String origName = demangledObj.getName();
String name = origName.replaceFirst("_*", "");
Demangled namespace = demangledObj.getNamespace();
if (namespace != null) {
if (name.endsWith("destructor'") ||
name.startsWith("operator") ||
name.startsWith("dtor$")) {
String baseClassName = getBaseClass(namespace);
if (baseClassName == null) {
return null;
}
return baseClassName + "::" + origName;
}
String fullString = namespace.getNamespaceString();
if (fullString != null && fullString.startsWith("std::")) {
// Common containers, make sure we keep the whole name
if (fullString.startsWith("std::vector") || fullString.startsWith("std::list") ||
fullString.startsWith("std::map") || fullString.startsWith("std::set") ||
fullString.startsWith("std::basic_string")) {
return fullString + "::" + origName;
}
}
}
return name;
}
public static NameVersions generate(String rawName,Program program) { public static NameVersions generate(String rawName,Program program) {
NameVersions result = new NameVersions(rawName); NameVersions result = new NameVersions(rawName);
if (rawName != null) { if (rawName != null) {
DemangledObject demangledObj = demangle(program, rawName); DemangledObject demangledObj = demangle(program, rawName);
if (demangledObj != null) { if (demangledObj != null) {
result.demangledBaseName = demangledObj.getName().replaceFirst("_*", ""); result.demangledBaseName = constructBaseName(demangledObj);
} }
// Put base names with underscores removed in a HashSet // Put base names with underscores removed in a HashSet