Created
January 30, 2015 19:41
-
-
Save handsomematt/338d8cd96dc5f602c843 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
// | |
// This will take all cross references to strings containing '.cpp', and pre-pend the name of the .cpp file | |
// to any IDA-recognized subs that xref that string. For example, if sub_b0aafd references a string that | |
// looks like '..\dev\src\game\client\main\file.cpp', this script will re-name sub_b0aafd to file.cpp_sub_b0aafd. | |
// | |
// To use: | |
// Run this as an idaPython script. I don't know IDA very well, so I usually just copy it, in its entirety, into the | |
// Python command window. | |
// | |
""" | |
from idautils import * | |
from idaapi import * | |
from idc import * | |
prefixToStringMappings = dict() | |
stringToPrefixMapping = dict() | |
prefixToSI = dict() | |
def contains(s, xdict): | |
if(xdict.get(s) is not None): | |
return True | |
return False | |
def deconflictPrefix(origPrefix, conflictString): | |
conflictPrefix = origPrefix | |
origString = prefixToStringMappings[origPrefix] | |
origList = origString.split("\\") | |
conflictList = conflictString.split("\\") | |
if(len(origList)!=len(conflictList)): | |
# iterate backwards, because they are likely in totally different paths | |
origList=reversed(origList) | |
conflictList = reversed(conflictList) | |
# iterate through in the chosen directory to find | |
for x,y in zip(origList, conflictList): | |
if(x.find('.')>-1): continue | |
if(y.find('.')>-1): continue | |
if x != y: | |
origNewCandidate = x+"_"+origPrefix | |
conflictNewCandidate = y+"_"+conflictPrefix | |
if((contains(origNewCandidate, prefixToStringMappings) is False) and (contains(conflictNewCandidate, prefixToStringMappings)) is False ): | |
# both prefixes are good. Make the change. | |
# add a new entry for origNewCandidate | |
prefixToStringMappings[origNewCandidate]=origString | |
stringToPrefixMapping[origString]=origNewCandidate | |
# Update the overall SI to prefix/string mapping for originalstring. Remove the original prefix, add the new one. | |
# DO NOT update the prefixToStringsMapping to remove the original prefix. If there are more than 2 conflicts, we want to make sure we get them all. | |
tempSI = prefixToSI[origPrefix] | |
# this will be None if we have previously had a conflict on this prefix | |
if(tempSI is not None): | |
prefixToSI[origNewCandidate] = tempSI | |
del prefixToSI[origPrefix] | |
return checkPrefix(conflictNewCandidate, conflictString) | |
# this should NEVER get hit. If it does, there's some major flaw in my logic | |
filenameLoc = chkstr.rfind("\\") | |
prevDir = conflictString.rfind("\\", 0, filenameLoc) | |
prevDir = prevDir+1 #don't include \ | |
prefix = conflictString[prevDir:filenameLoc] +"_"+ prefix | |
return checkPrefix(prefix, chkstr) | |
def checkPrefix(prefix, chkstr): | |
filenameLoc = chkstr.rfind("\\") | |
# Easy check to see if we've ever seen this prefix before | |
if(contains(prefix, prefixToStringMappings)): | |
# If we've seen this prefix before, see if the chkstr is a duplicate | |
originalPrefix = prefix # save the duplicate prefix so we can go back and fix the other reference | |
if(prefixToStringMappings[prefix] == chkstr): | |
return prefix | |
else: | |
# Then we need to update the old string, too, since it is probably not descriptive enough | |
newprefix = deconflictPrefix(originalPrefix, chkstr) | |
return newprefix | |
else: | |
prefixToStringMappings[prefix]=chkstr | |
stringToPrefixMapping[chkstr]=prefix | |
return prefix | |
def makePrefix(chkstr): | |
filenameLoc = chkstr.rfind("\\") | |
prefix = chkstr[filenameLoc+1:] | |
return checkPrefix(prefix, chkstr) | |
def getStringItemsByContent(filter): | |
foundStringItems = dict() | |
s = Strings(False) | |
s.setup(strtypes=Strings.STR_UNICODE | Strings.STR_C) | |
for si in s: | |
chkstr = GetString(si.ea, si.length, si.type) | |
if chkstr != None: | |
if ((chkstr.find(filter) > -1) and (chkstr.find('\\') > -1)): | |
foundPrefix = makePrefix(chkstr) | |
prefixToSI[foundPrefix]=si | |
return foundStringItems | |
def renameXrefFuncs(si, prefix): | |
if (prefix is None): return; | |
flag = 1 | |
sourceAddr = si.ea | |
length = len(prefix); | |
lastChar = prefix[length-1:length]; | |
if(lastChar!="_"): | |
newPrefix = prefix + "_" | |
xrefs = XrefsTo(sourceAddr, 0) | |
for xref in xrefs: | |
ea = xref.frm | |
if(xref.to is not None): | |
originalName = GetFunctionName(ea); | |
if(originalName is not None): | |
functionOffset = GetFunctionAttr(ea,FUNCATTR_START); | |
contains = originalName.find(newPrefix); | |
if(contains <= -1): | |
newName = newPrefix + originalName; | |
MakeNameEx(functionOffset,newName,SN_NOCHECK); | |
else: | |
i = 1+1 | |
def renameXrefFunc(): | |
renameXrefFuncs(get_screen_ea()); | |
print "Starting..." | |
string = getStringItemsByContent('.cpp') | |
for prefix in prefixToSI: | |
si = prefixToSI[prefix] | |
path = GetString(si.ea, si.length, si.type) | |
print "Pre-pending "+prefix+" to all subs that xref "+path+"." | |
renameXrefFuncs(si, prefix) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment