/* ### * IP: GHIDRA * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Calculate false positive/negative statistics given "marked" programs //@category FunctionID import java.io.*; import java.util.*; import ghidra.app.script.GhidraScript; import ghidra.feature.fid.db.FidQueryService; import ghidra.feature.fid.service.*; import ghidra.framework.model.DomainFile; import ghidra.framework.model.DomainFolder; import ghidra.program.database.ProgramContentHandler; import ghidra.program.model.lang.Language; import ghidra.program.model.listing.*; import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.symbol.Symbol; import ghidra.program.model.symbol.SymbolIterator; import ghidra.util.exception.CancelledException; import ghidra.util.exception.VersionException; /** * Runs through recursively through a set of folders provided by the user. * Programs are assumed to be "marked", meaning that functions all have their correct labels. * Each function in each program is searched within the active FID databases and various statistics * are calculated. * 1) Match found/not found * 2) Are any matches found correct (as compared to existing symbol) * 3) Are there multiple potential matches (whether correct or not) * * If program symbols are mangled, this script assumes the primary symbol is not demangled. */ public class FidStatistics extends GhidraScript { private StatRecord statRecord; private FidService service; private MatchNameAnalysis matchAnalysis; private FileWriter highFalsePositive; // Incorrect matches that scored high private FileWriter lowTruePositive; // Correct matches that score low private TreeSet equivSymbols; private float scoreThreshold; public static class SymbolPair implements Comparable { private String sym1; private String sym2; public SymbolPair(String a, String b) { sym1 = a; sym2 = b; } @Override public int compareTo(SymbolPair o) { int val = sym1.compareTo(o.sym1); if (val != 0) { return val; } return sym2.compareTo(o.sym2); } } public static class MatchRecord { private String progName; private String funcName; private String matchName; private long fullHash; private long address; private float score; private float childScore; private float parentScore; public MatchRecord(FidSearchResult result, String finalMatchName, boolean isFalse) { this.progName = result.function.getProgram().getDomainFile().getPathname(); this.fullHash = result.hashQuad.getFullHash(); this.funcName = result.function.getName(); this.matchName = finalMatchName; this.address = result.function.getEntryPoint().getOffset(); FidMatch fidMatch = result.matches.get(0); this.score = fidMatch.getOverallScore(); this.childScore = fidMatch.getChildFunctionCodeUnitScore(); this.parentScore = fidMatch.getParentFunctionCodeUnitScore(); } public void print(StringBuilder buf) { buf.append("score= "); buf.append(score); buf.append(" fh=0x"); buf.append(Long.toHexString(fullHash)); buf.append(" child=").append(childScore); buf.append(" par=").append(parentScore); buf.append(" address="); buf.append(Long.toHexString(address)); buf.append(" name="); buf.append(funcName); buf.append(" prog="); buf.append(progName); if (matchName != null) { buf.append(" match="); buf.append(matchName); } // if (isFalsePositive) // buf.append(" FALSE"); } } public static class StatRecord { public int totalFunction; public int matchUniquely; public int matchMultiply; public int hitCount; public int noMatch; public int nameMatched; public int falsePositive; public StatRecord() { totalFunction = 0; matchUniquely = 0; matchMultiply = 0; hitCount = 0; noMatch = 0; nameMatched = 0; falsePositive = 0; } public static void indent(StringBuilder buf, String last) { for (int i = last.length(); i < 10; ++i) { buf.append(' '); } } public void print(StringBuilder buf) { String str = Integer.toString(totalFunction); buf.append(str); indent(buf, str); str = Integer.toString(noMatch); buf.append(str); indent(buf, str); str = Integer.toString(matchUniquely + matchMultiply); buf.append(str); indent(buf, str); str = Integer.toString(hitCount); buf.append(str); indent(buf, str); str = '(' + Integer.toString(matchUniquely) + ',' + Integer.toString(matchMultiply) + ')'; buf.append(str); indent(buf, str); str = Integer.toString(nameMatched); buf.append(str); indent(buf, str); str = Integer.toString(falsePositive); buf.append(str); } public static String getColumns() { return "Total No Match Possible Hits uniq/mult N-Match False"; } } private void addEquivSymbols(String a, String b) { SymbolPair pair = new SymbolPair(a, b); equivSymbols.add(pair); pair = new SymbolPair(b, a); equivSymbols.add(pair); } private void initialize() { statRecord = new StatRecord(); service = new FidService(); matchAnalysis = new MatchNameAnalysis(); equivSymbols = new TreeSet(); addEquivSymbols("entry", "_WinMainCRTStartup"); addEquivSymbols("__alloca_probe", "__chkstk"); addEquivSymbols("_strncpy_s_downlevel", "_strncpy_s"); addEquivSymbols("_strcpy_s_downlevel", "_strcpy_s"); addEquivSymbols("strcat_s_downlevel", "strcat_s"); addEquivSymbols("_memcpy_s_downlevel", "_memcpy_s"); addEquivSymbols("_memmove_s_downlevel", "_memmove_s"); addEquivSymbols("__ftol2_downlevel", "__ftol2"); addEquivSymbols("_wmakepath_s_downlevel", "_wmakepath_s"); addEquivSymbols("entry", "_wWinMainCRTStartup"); addEquivSymbols("entry", "_wmainCRTStartup"); addEquivSymbols("entry", "_mainCRTStartup"); addEquivSymbols("entry", "__DllMainCRTStartup@12"); addEquivSymbols("_errno", "__doserrno"); addEquivSymbols("?StringCchCopyW@@YGJPAGIPBG@Z", "_StringCchCopyW@12"); addEquivSymbols("_StringCchCopyNW@16", "?StringCchCopyNW@@YGJPAGIPBGI@Z"); addEquivSymbols("_StringCchLengthW@12", "?StringCchLengthW@@YGJPB_WIPAI@Z"); addEquivSymbols("_StringCchLengthA@12", "?StringCchLengthA@@YGJPBDIPAI@Z"); addEquivSymbols("_RtlStringCchCopyW@12", "=_StringCchCopyW@12"); addEquivSymbols("?RtlStringCchCopyW@@YGJPAGIPBG@Z", "_StringCchCopyA@12"); addEquivSymbols("_RtlStringCchCopyW@12", "_StringCchCopyW@12"); addEquivSymbols("_RtlStringCchCopyNW@16", "?StringCchCopyNW@@YGJPAGIPBGI@Z"); addEquivSymbols("?RtlStringCchLengthW@@YGJPBGIPAI@Z", "?StringCchLengthW@@YGJPB_WIPAI@Z"); addEquivSymbols("_RtlStringCchLengthW@12", "?StringCchLengthW@@YGJPB_WIPAI@Z"); addEquivSymbols("?RtlStringCchCatW@@YGJPAGIPBG@Z", "_StringCchCatA@12"); addEquivSymbols("?StringCchCatW@@YGJPAGIPBG@Z", "_StringCchCatA@12"); addEquivSymbols("_StringCchCatW@12", "_StringCchCatA@12"); addEquivSymbols("?StringCchCopyW@@YGJPAGIPBG@Z", "_StringCchCopyA@12"); addEquivSymbols("?ULongLongToUInt@@YGJ_KPAI@Z", "_ULongLongToULong@12"); addEquivSymbols("_ULongLongToUInt@12", "_ULongLongToULong@12"); addEquivSymbols("_ULongLongToUInt@12", "_ULongLongToULong@12"); addEquivSymbols("?ULongLongToULong@@YGJ_KPAK@Z", "_ULongLongToULong@12"); addEquivSymbols("_RtlULongLongToULong@12", "_ULongLongToULong@12"); addEquivSymbols("_RtlULongLongToUInt@12", "_ULongLongToULong@12"); addEquivSymbols("?RtlULongLongToULong@@YGJ_KPAK@Z", "_ULongLongToULong@12"); addEquivSymbols("?ULongPtrAdd@@YGJKKPAK@Z", "_ULongAdd@12"); addEquivSymbols("_ULongAdd@12", "?ULongAdd@@YGJKKPAK@Z"); addEquivSymbols("_ULongAdd@12", "?SizeTAdd@@YGJIIPAI@Z"); addEquivSymbols("_ULongAdd@12", "?UIntAdd@@YGJIIPAI@Z"); addEquivSymbols("_ULongAdd@12", "?SIZETAdd@@YGJKKPAK@Z"); addEquivSymbols("_RtlULongAdd@12", "?RtlULongAdd@@YGJKKPAK@Z"); addEquivSymbols("_RtlSIZETAdd@12", "?RtlULongAdd@@YGJKKPAK@Z"); addEquivSymbols("_UIntAdd@12", "_ULongAdd@12"); addEquivSymbols("LoadStringA", "LoadStringW"); addEquivSymbols("_StringCchCopyW@12", "_StringCchCopyA@12"); addEquivSymbols("?StringCchCopyA@@YGJPADIPBD@Z", "_StringCchCopyA@12"); addEquivSymbols("StringCchVPrintfA", "StringCchVPrintfW"); addEquivSymbols("?StringCchCatW@@YGJPAGIPBG@Z", "_StringCchCatW@12"); addEquivSymbols("__safecrt_fassign", "__fassign_l"); addEquivSymbols("?StringLengthWorkerW@@YGJPBGIPAI@Z", "_StringLengthWorkerW@12"); addEquivSymbols("?StringCatWorkerW@@YGJPAGIPBG@Z", "_StringCatWorkerW@12"); addEquivSymbols("_decode_aligned_offset_block@12", "_decode_verbatim_block@12"); addEquivSymbols( "??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@V_STL70@@@std@@QAE@ABV01@@Z", "??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@ABV01@@Z"); addEquivSymbols("??0?$CSimpleStringT@G$0A@@ATL@@QAE@PBGHPAUIAtlStringMgr@1@@Z", "??0?$CSimpleStringT@_W$0A@@ATL@@QAE@PB_WHPAUIAtlStringMgr@1@@Z"); addEquivSymbols("_NFMdeco_destroy@8", "_NFMcomp_destroy@8"); addEquivSymbols("_StringCchVPrintfW@16", "?StringCchVPrintfW@@YGJPAGIPBGPAD@Z"); addEquivSymbols("_StringCbVPrintfA@16", "?StringCchVPrintfW@@YGJPAGIPBGPAD@Z"); addEquivSymbols("?StringCchPrintfA@@YAJPADIPBDZZ", "?StringCchPrintfW@@YAJPAGIPBGZZ"); addEquivSymbols("_StringCchPrintfW", "?StringCchPrintfW@@YAJPAGIPBGZZ"); addEquivSymbols("_StringCbPrintfA", "?StringCchPrintfW@@YAJPAGIPBGZZ"); addEquivSymbols("?AtlA2WHelper@@YGPAGPAGPBDH@Z", "?AfxA2WHelper@@YGPA_WPA_WPBDH@Z"); addEquivSymbols("??0?$CSimpleStringT@G$0A@@ATL@@QAE@PAUIAtlStringMgr@1@@Z", "??0?$CSimpleStringT@D$0A@@ATL@@QAE@PAUIAtlStringMgr@1@@Z"); addEquivSymbols("_RtlStringCchCopyA@12", "?StringCchCopyA@@YGJPADIPBD@Z"); addEquivSymbols( "??0?$CStringT@GV?$StrTraitATL@GV?$ChTraitsCRT@G@ATL@@@ATL@@@ATL@@QAE@PBGHPAUIAtlStringMgr@1@@Z", "??0?$CStringT@DV?$StrTraitMFC@DV?$ChTraitsCRT@D@ATL@@@@@ATL@@QAE@PBDHPAUIAtlStringMgr@1@@Z"); addEquivSymbols("??0?$CSimpleStringT@G$0A@@ATL@@QAE@ABV01@@Z", "??0?$CSimpleStringT@D$0A@@ATL@@QAE@ABV01@@Z"); addEquivSymbols( "??0?$CStringT@GV?$StrTraitATL@GV?$ChTraitsCRT@G@ATL@@@ATL@@@ATL@@QAE@PBGPAUIAtlStringMgr@1@@Z", "??0?$CStringT@DV?$StrTraitMFC@DV?$ChTraitsCRT@D@ATL@@@@@ATL@@QAE@PB_WPAUIAtlStringMgr@1@@Z"); addEquivSymbols( "??0?$CStringT@GV?$StrTraitATL@GV?$ChTraitsCRT@G@ATL@@@ATL@@@ATL@@QAE@ABV01@@Z", "??0?$CStringT@DV?$StrTraitMFC@DV?$ChTraitsCRT@D@ATL@@@@@ATL@@QAE@ABV01@@Z"); addEquivSymbols("__ltoa_s_downlevel", "__ltow_s"); addEquivSymbols( "??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@V_STL70@@@std@@QAE@XZ", "??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ"); addEquivSymbols("_StringCchPrintfA", "?StringCchPrintfW@@YAJPAGIPBGZZ"); addEquivSymbols("?StringCbPrintfA@@YAJPADIPBDZZ", "?StringCchPrintfW@@YAJPAGIPBGZZ"); addEquivSymbols("?ULongMult@@YGJKKPAK@Z", "_ULongMult@12"); addEquivSymbols("?_Getwctypes@@YAPB_WPB_W0PAFPBU_Ctypevec@@@Z", "__Getwctypes"); addEquivSymbols("?_Getwctype@@YAF_WPBU_Ctypevec@@@Z", "__Getwctype"); addEquivSymbols("?_Getwctype@@YAF_WPEBU_Ctypevec@@@Z", "_Getwctype"); addEquivSymbols("?AtlW2AHelper@@YGPADPADPBGH@Z", "?AfxW2AHelper@@YGPADPADPB_WH@Z"); addEquivSymbols( "??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@V_STL70@@@std@@QAE@ID@Z", "??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@ID@Z"); addEquivSymbols("?StringCchPrintfA@@YAJPADIPBDZZ", "?StringCbPrintfA@@YAJPADIPBDZZ"); addEquivSymbols( "??0?$CStringT@DV?$StrTraitATL@DV?$ChTraitsCRT@D@ATL@@@ATL@@@ATL@@QAE@PBDHPAUIAtlStringMgr@1@@Z", "??0?$CStringT@DV?$StrTraitMFC@DV?$ChTraitsCRT@D@ATL@@@@@ATL@@QAE@PBDHPAUIAtlStringMgr@1@@Z"); addEquivSymbols("_wmemcpy_s", "?CopyCharsOverlapped@?$CSimpleStringT@_W$0A@@ATL@@SAXPA_WIPB_WH@Z"); addEquivSymbols("?StringCbCopyA@@YGJPADIPBD@Z", "_StringCbCopyA@12"); addEquivSymbols( "??0?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@V_STL70@@@std@@QAE@IG@Z", "??0?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QAE@IG@Z"); addEquivSymbols("??1?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@QEAA@XZ", "??1?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@V_STL70@@@std@@QEAA@XZ"); addEquivSymbols("?CopyChars@?$CSimpleStringT@G$0A@@ATL@@SAXPAGIPBGH@Z", "?CopyCharsOverlapped@?$CSimpleStringT@_W$0A@@ATL@@SAXPA_WIPB_WH@Z"); addEquivSymbols( "??0?$CStringT@GV?$StrTraitATL@GV?$ChTraitsCRT@G@ATL@@@ATL@@@ATL@@QAE@PBGPAUIAtlStringMgr@1@@Z", "??0?$CStringT@DV?$StrTraitMFC@DV?$ChTraitsCRT@D@ATL@@@@@ATL@@QAE@PB_WPAUIAtlStringMgr@1@@Z"); addEquivSymbols("wcscpy_s_downlevel", "wcscpy_s"); addEquivSymbols("_StringCbCopyA@12", "_StringCchCopyA@12"); addEquivSymbols("_wcscat_s_downlevel", "_wcscat_s"); addEquivSymbols( "??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@V_STL70@@@std@@QAE@PBD@Z", "??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@PBD@Z"); addEquivSymbols("?_Towupper@@YA_W_WPBU_Ctypevec@@@Z", "__Towupper"); addEquivSymbols("?_Towlower@@YA_W_WPBU_Ctypevec@@@Z", "__Towlower"); addEquivSymbols("?_Towupper@@YA_W_WPEBU_Ctypevec@@@Z", "_Towupper"); addEquivSymbols("?_Towlower@@YA_W_WPEBU_Ctypevec@@@Z", "_Towlower"); addEquivSymbols("_wcsncpy_s_downlevel", "_wcsncpy_s"); addEquivSymbols("_strnlen_downlevel", "_strnlen"); addEquivSymbols("GetProxyDllInfo", "_GetProxyDllInfo@8"); addEquivSymbols("DllGetClassObject", "_DllGetClassObject@12"); addEquivSymbols("_PrxDllGetClassObject@12", "_DllGetClassObject@12"); addEquivSymbols("__itoa_s_downlevel", "__itow_s"); addEquivSymbols("?StringCbVPrintfA@@YGJPADIPBD0@Z", "?StringCchVPrintfW@@YGJPAGIPBGPAD@Z"); addEquivSymbols("?UShortMult@@YGJGGPAG@Z", "?RtlUShortMult@@YGJGGPAG@Z"); addEquivSymbols("??1?$CStringT@GV?$StrTraitATL@GV?$ChTraitsCRT@G@ATL@@@ATL@@@ATL@@QAE@XZ", "??1?$CStringT@_WV?$StrTraitMFC@_WV?$ChTraitsOS@_W@ATL@@@@@ATL@@QAE@XZ"); addEquivSymbols("?memcpy_s@Checked@ATL@@YAXPAXIPBXI@Z", "?memmove_s@Checked@ATL@@YAXPAXIPBXI@Z"); addEquivSymbols("?tcsncpy_s@Checked@ATL@@YAHPAGIPBGI@Z", "?memmove_s@Checked@ATL@@YAXPAXIPBXI@Z"); addEquivSymbols("?wmemcpy_s@Checked@ATL@@YAXPAGIPBGI@Z", "?memmove_s@Checked@ATL@@YAXPAXIPBXI@Z"); addEquivSymbols("??$AtlMultiply@I@ATL@@YAJPAIII@Z", "??$AtlMultiply@K@ATL@@YAJPAKKK@Z"); addEquivSymbols("__it_wcsncpy", "_wcsncpy"); addEquivSymbols( "??1?$CFixedStringT@V?$CStringT@GV?$StrTraitATL@GV?$ChTraitsCRT@G@ATL@@@ATL@@@ATL@@$0BA@@ATL@@UAE@XZ", "??1?$CFixedStringT@V?$CStringT@DV?$StrTraitMFC@DV?$ChTraitsCRT@D@ATL@@@@@ATL@@$0EA@@ATL@@UAE@XZ"); addEquivSymbols("?StringCbCatA@@YGJPADIPBD@Z", "_StringCchCatA@12"); addEquivSymbols( "??0?$CStringT@GV?$StrTraitATL@GV?$ChTraitsCRT@G@ATL@@@ATL@@@ATL@@QAE@PBG@Z", "??0?$CStringT@DV?$StrTraitMFC@DV?$ChTraitsCRT@D@ATL@@@@@ATL@@QAE@PB_W@Z"); addEquivSymbols("UShortAdd", "RtlUShortAdd"); addEquivSymbols("_StringCchPrintfA", "?StringCbPrintfA@@YAJPADIPBDZZ"); addEquivSymbols("?StringCbCopyA@@YGJPADIPBD@Z", "_StringCchCopyA@12"); // 64-bit addEquivSymbols("??1?$CTempBuffer@G$0BAA@VCCRTAllocator@ATL@@@ATL@@QEAA@XZ", "??1?$CTempBuffer@D$0IA@VCCRTAllocator@ATL@@@ATL@@QEAA@XZ"); addEquivSymbols("?IsEqualGUID@@YAHAEBU_GUID@@0@Z", "IsEqualGUID"); addEquivSymbols( "??1?$CAtlSafeAllocBufferManager@V_CCRTAllocator@_ATL_SAFE_ALLOCA_IMPL@ATL@@@_ATL_SAFE_ALLOCA_IMPL@ATL@@QEAA@XZ", "??1?$CAtlSafeAllocBufferManager@VCCRTAllocator@ATL@@@_ATL_SAFE_ALLOCA_IMPL@ATL@@QEAA@XZ"); addEquivSymbols("??_E_Locimp@locale@std@@MEAAPEAXI@Z", "??_G_Locimp@locale@std@@MEAAPEAXI@Z"); addEquivSymbols("?StringCchCopyW@@YAJPEAG_KPEBG@Z", "StringCchCopyW"); addEquivSymbols("StringCchPrintfA", "?StringCbPrintfA@@YAJPEAD_KPEBDZZ"); addEquivSymbols("?StringCchCatA@@YAJPEAD_KPEBD@Z", "StringCchCatA"); addEquivSymbols("?StringCbCatA@@YAJPEAD_KPEBD@Z", "StringCchCatA"); addEquivSymbols("entry", "mainCRTStartup"); addEquivSymbols("entry", "wmainCRTStartup"); addEquivSymbols("entry", "WinMainCRTStartup"); addEquivSymbols("WPP_SF_ii", "WPP_SF_qq"); addEquivSymbols("WPP_SF_DDDDD", "WPP_SF_ddddd"); addEquivSymbols("?FDIDestroy@@$$J0YAHPEAX@Z", "FDIDestroy"); addEquivSymbols("??1?$CTempBuffer@G$0IA@VCCRTAllocator@ATL@@@ATL@@QEAA@XZ", "??1?$CTempBuffer@D$0IA@VCCRTAllocator@ATL@@@ATL@@QEAA@XZ"); addEquivSymbols("WPP_SF_xx", "WPP_SF_qq"); addEquivSymbols("WPP_SF_iii", "WPP_SF_qqq"); addEquivSymbols("RtlStringCchCopyW", "StringCchCopyW"); addEquivSymbols("_strcmpi", "_stricmp"); addEquivSymbols("WPP_SF_DDDDDDDD", "WPP_SF_dddddddd"); addEquivSymbols("?StringCchPrintfA@@YAJPEAD_KPEBDZZ", "?StringCbPrintfA@@YAJPEAD_KPEBDZZ"); addEquivSymbols("WPP_SF_h", "WPP_SF_H"); addEquivSymbols("WPP_SF_qqDD", "WPP_SF_qqdd"); addEquivSymbols("WPP_SF_DqD", "WPP_SF_dqd"); 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 programs, DomainFolder folder) throws VersionException, CancelledException, IOException { DomainFile[] files = folder.getFiles(); for (DomainFile domainFile : files) { monitor.checkCancelled(); // Do not follow folder-links or consider program links. Using content type // to filter is best way to control this. If program links should be considered // "Program.class.isAssignableFrom(domainFile.getDomainObjectClass())" // should be used. if (domainFile.getContentType().equals(ProgramContentHandler.PROGRAM_CONTENT_TYPE)) { programs.add(domainFile); } } DomainFolder[] folders = folder.getFolders(); for (DomainFolder domainFolder : folders) { monitor.checkCancelled(); findDomainFiles(programs, domainFolder); } } private boolean checkNames(String a, String b) { if (a.equals(b)) { return true; } return equivSymbols.contains(new SymbolPair(a, b)); } private String chooseFunctionName(FidSearchResult result) { Program program = result.function.getProgram(); SymbolIterator it = program.getSymbolTable().getSymbolsAsIterator(result.function.getEntryPoint()); for (Symbol symbol : it) { if (matchAnalysis.containsRawName(symbol.getName())) { return symbol.getName(); } } return result.function.getName(); } private void processFunctionResult(FidSearchResult result) throws CancelledException, IOException { StatRecord record = statRecord; record.totalFunction += 1; if (result.matches == null || result.matches.size() == 0) { record.noMatch += 1; } else { Program program = result.function.getProgram(); matchAnalysis.analyzeNames(result.matches, program, monitor); String finalMatchName = null; boolean matchHappened = false; if (matchAnalysis.getMostOptimisticCount() > 1) { if (matchAnalysis.getOverallScore() >= FidService.MULTINAME_SCORE_THRESHOLD) { record.matchMultiply += 1; matchHappened = true; // FID will put down a multiple match label } } else { record.matchUniquely += 1; matchHappened = true; // FID will put down a single match finalMatchName = matchAnalysis.getNameIterator().next(); } String funcName = chooseFunctionName(result); NameVersions nameVersions = NameVersions.generate(funcName, program); boolean exactNameMatch = false; Iterator iter = matchAnalysis.getRawNameIterator(); while (iter.hasNext()) { String raw = iter.next(); NameVersions matchNames = NameVersions.generate(raw, program); if (matchNames.rawName == null) { continue; } if (checkNames(nameVersions.rawName, matchNames.rawName)) { exactNameMatch = true; break; } if (checkNames(nameVersions.similarName, matchNames.similarName)) { exactNameMatch = true; break; } if (nameVersions.demangledBaseName != null) { 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)) { exactNameMatch = true; break; } if (nameVersions.demangledNoTemplate != null && matchNames.demangledNoTemplate != null) { if (checkNames(nameVersions.demangledNoTemplate, matchNames.demangledNoTemplate)) { exactNameMatch = true; break; } } } if (exactNameMatch) { record.nameMatched += 1; } float score = result.matches.get(0).getOverallScore(); if (score >= scoreThreshold && matchHappened) { record.hitCount += 1; } if (exactNameMatch && ((score < scoreThreshold) || !matchHappened)) { MatchRecord matchRecord = new MatchRecord(result, null, false); StringBuilder buffer = new StringBuilder(); matchRecord.print(buffer); lowTruePositive.append(buffer.toString()); lowTruePositive.append('\n'); } else if ((!exactNameMatch) && (score >= scoreThreshold) && matchHappened) { record.falsePositive += 1; MatchRecord matchRecord = new MatchRecord(result, finalMatchName, true); StringBuilder buffer = new StringBuilder(); matchRecord.print(buffer); highFalsePositive.append(buffer.toString()); highFalsePositive.append('\n'); } } } private void processProgram(Program program, FidQueryService queryService) throws MemoryAccessException, CancelledException, VersionException, IOException { FidProgramSeeker programSeeker = service.getProgramSeeker(program, queryService, 10.0f); monitor.setMessage("Processing " + program.getName()); monitor.initialize(program.getFunctionManager().getFunctionCount()); FunctionIterator iter = program.getFunctionManager().getFunctionsNoStubs(true); while (iter.hasNext()) { Function func = iter.next(); monitor.incrementProgress(1); if (func.getName().startsWith("FUN_") || func.getName().startsWith("Ordinal_")) { continue; } FidSearchResult searchResult = programSeeker.searchFunction(func, monitor); if (searchResult == null) { continue; // Could not hash function } processFunctionResult(searchResult); } } private LinkedList buildDomainFileList() throws CancelledException, VersionException, IOException { ArrayList folders = new ArrayList(); while (true) { monitor.checkCancelled(); try { DomainFolder folder = askProjectFolder("Add a top-level project folder (cancel to quit)"); folders.add(folder); } catch (CancelledException e) { break; } } LinkedList domainFiles = new LinkedList(); monitor.setMessage("Finding domain files..."); for (DomainFolder folder : folders) { monitor.checkCancelled(); findDomainFiles(domainFiles, folder); } return domainFiles; } @Override protected void run() throws Exception { initialize(); LinkedList programList = buildDomainFileList(); File lowFile = askFile("Select file to report true matches", "OK"); File highFile = askFile("Select file to report false positives", "OK"); scoreThreshold = (float) askDouble("Choose score threshold", "OK"); lowTruePositive = new FileWriter(lowFile); highFalsePositive = new FileWriter(highFile); FidQueryService queryService = null; Language lastLanguage = null; int maxPrograms = programList.size(); int counter = 0; try { for (DomainFile domainFile : programList) { Program program = null; try { program = (Program) domainFile.getDomainObject(this, false, false, monitor); if (queryService == null || !lastLanguage.equals(program.getLanguage())) { if (queryService != null) { queryService.close(); } lastLanguage = program.getLanguage(); queryService = service.openFidQueryService(lastLanguage, false); } processProgram(program, queryService); counter += 1; monitor.setMessage("Processing programs ..."); monitor.initialize(maxPrograms); monitor.setProgress(counter); } finally { if (program != null) { program.release(this); } } } } catch (CancelledException ex) { // A cancel in middle of processing still allows results to get printed } queryService.close(); lowTruePositive.close(); highFalsePositive.close(); println(StatRecord.getColumns()); StringBuilder buffer = new StringBuilder(); statRecord.print(buffer); println(buffer.toString()); } }