Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

show function names, label instructions not tails, do not require run-as-plugin #39

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 99 additions & 7 deletions findcrypt3.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ def __init__(self, title, items, flags=0, width=None, height=None, embedded=Fals
title,
[
["Address", idaapi.Choose.CHCOL_HEX|10],
["Function", idaapi.Choose.CHCOL_PLAIN|10],
["Rules file", idaapi.Choose.CHCOL_PLAIN|12],
["Name", idaapi.Choose.CHCOL_PLAIN|25],
["String", idaapi.Choose.CHCOL_PLAIN|25],
Expand Down Expand Up @@ -181,29 +182,101 @@ def search(self):
c = YaraSearchResultChooser("Findcrypt results", values)
r = c.show()

def has_user_name(ea): return (idc.get_full_flags(ea) & idc.FF_ANYNAME) == idc.FF_NAME

def label_address(self, ea, name, predicate=None, force=False, throw=False):
"""
Label an address with a given name or renaming the previous owner of that name.
:param ea: address
:param name: desired name [str, callable(address, exiting_name)]
:param predicate: optional callback
:param force: force name (displace existing name)
:param throw: raise exception on error
:return: success as bool

label_address(ea, 'philbert', lambda x, *a: not HasUserName(x))

`predicate` can also return an int instead of True to specify an
alternate address, e.g.

label_address(ea, 'philbert', lambda x, *a: idc.get_item_head(x))
"""
def ThrowOnFailure(result):
if not result and throw:
raise RuntimeError("Couldn't label address {:x} with \"{}\"".format(ea, name))
return not not result

def MakeUniqueLabel(name, ea = BADADDR):
fnLoc = idc.get_name_ea_simple(name)
if fnLoc == BADADDR or fnLoc == ea:
return name
fmt = "%s_%%i" % name
for i in range(1, 99999):
tmpName = fmt % i
fnLoc = idc.get_name_ea_simple(tmpName)
if fnLoc == BADADDR or fnLoc == ea:
return tmpName
return ""


if ea < BADADDR:
tmp = ea
if callable(predicate):
tmp = predicate(ea, idc.get_name(ea, 0))
if not tmp:
return True
# check if name already exists
fnLoc = idc.get_name_ea_simple(name)
if fnLoc == BADADDR:
return ThrowOnFailure(idc.set_name(ea, name, idc.SN_NOWARN))
elif fnLoc == ea:
return ThrowOnFailure(True)
else:
if force:
idc.set_name(fnLoc, "", idc.SN_AUTO | idc.SN_NOWARN)
idc.auto_wait()
return ThrowOnFailure(idc.set_name(ea, name, idc.SN_NOWARN))
else:
name = MakeUniqueLabel(name, ea)
return ThrowOnFailure(idc.set_name(ea, name, idc.SN_NOWARN))

else:
print("0x0%0x: Couldn't label %s, BADADDR" % (ea, name))
return False


def yarasearch(self, memory, offsets, rules):
def pred(ea, name):
head = idc.get_item_head(ea)
if IsCode_(head):
return head
if IsData(head):
return head
if IsUnknown(head):
return False
return False
print(">>> start yara search")
values = list()
matches = rules.match(data=memory)
for match in matches:
for string in match.strings:
ea = self.toVirtualAddress(string[0], offsets)
name = match.rule
if name.endswith("_API"):
try:
name = name + "_" + idc.GetString(self.toVirtualAddress(string[0], offsets))
name = name + "_" + idc.GetString(ea)
except:
pass
value = [
self.toVirtualAddress(string[0], offsets),
ea,
GetFuncName(ea),
match.namespace,
name + "_" + hex(self.toVirtualAddress(string[0], offsets)).lstrip("0x").rstrip("L").upper(),
name + "_" + hex(ea).lstrip("0x").rstrip("L").upper(),
string[1],
repr(string[2]),
]
idaapi.set_name(value[0], name
+ "_"
+ hex(self.toVirtualAddress(string[0], offsets)).lstrip("0x").rstrip("L").upper()
, 0)
label = name + "_" + hex(ea).lstrip("0x").rstrip("L").upper()
self.label_address(value[0], label, predicate=pred)
values.append(value)
print("<<< end yara search")
return values
Expand All @@ -227,3 +300,22 @@ def run(self, arg):
# register IDA plugin
def PLUGIN_ENTRY():
return Findcrypt_Plugin_t()

_load_method = None
if __name__ == "__main__":
# loaded directly
_load_method = 'direct'
elif __name__.startswith("__plugins__"):
_load_method = 'plugin'
# loaded as a plugin
elif __name__ == "findcrypt3":
_load_method = 'module'
else:
# unknown load method (filename could be changed?)
_load_method = 'unknown'
print("[findcrypt3]: unknown load method '{}'".format(__name__))

if _load_method == 'direct':
fcp = Findcrypt_Plugin_t()
fcp.init()
fcp.run(0)