-
-
Save R3MRUM/f7b1b5ede9876c7e81385c138c871b13 to your computer and use it in GitHub Desktop.
Minimum Yara Search for IDAPYTHON
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
import yara | |
import operator | |
import idautils | |
SEARCH_CASE = 4 | |
SEARCH_REGEX = 8 | |
SEARCH_NOBRK = 16 | |
SEARCH_NOSHOW = 32 | |
SEARCH_UNICODE = 64 | |
SEARCH_IDENT = 128 | |
SEARCH_BRK = 256 | |
class YaraIDASearch(): | |
def __init__(self): | |
self.mem_results = "" | |
self.mem_offsets = [] | |
if not self.mem_results: | |
self._get_memory() | |
def _wowrange(self, start, stop, step=1): | |
# source https://stackoverflow.com/a/1482502 | |
if step == 0: | |
raise ValueError('step must be != 0') | |
elif step < 0: | |
proceed = operator.gt | |
else: | |
proceed = operator.lt | |
while proceed(start, stop): | |
yield start | |
start += step | |
def _get_memory(self): | |
print "Status: Loading memory for Yara." | |
result = "" | |
segments_starts = [ea for ea in idautils.Segments()] | |
offsets = [] | |
start_len = 0 | |
for start in segments_starts: | |
end = idc.get_segm_end(start) | |
for ea in self._wowrange(start, end): | |
result += chr(idc.Byte(ea)) | |
offsets.append((start, start_len, len(result))) | |
start_len = len(result) | |
print "Status: Memory has been loaded." | |
self.mem_results = result | |
self.mem_offsets = offsets | |
def _to_virtual_address(self, offset, segments): | |
va_offset = 0 | |
for seg in segments: | |
if seg[1] <= offset < seg[2]: | |
va_offset = seg[0] + (offset - seg[1]) | |
return va_offset | |
def _init_sig(self, sig_type, pattern, sflag): | |
if SEARCH_REGEX & sflag: | |
signature = "/%s/" % pattern | |
if SEARCH_CASE & sflag: | |
# ida is not case sensitive by default but yara is | |
pass | |
else: | |
signature += " nocase" | |
if SEARCH_UNICODE & sflag: | |
signature += " wide" | |
elif sig_type == "binary": | |
signature = "{ %s }" % pattern | |
elif sig_type == "text" and (SEARCH_REGEX & sflag) == False: | |
signature = '"%s"' % pattern | |
if SEARCH_CASE & sflag: | |
pass | |
else: | |
signature += " nocase" | |
if SEARCH_UNICODE & sflag: | |
signature += " wide" | |
yara_rule = "rule foo : bar { strings: $a = %s condition: $a }" % signature | |
return yara_rule | |
def _compile_rule(self, signature): | |
try: | |
rules = yara.compile(source=signature) | |
except Exception as e: | |
print "ERROR: Cannot compile Yara rule %s" % e | |
return False, None | |
return True, rules | |
def _search(self, signature): | |
status, rules = self._compile_rule(signature) | |
if not status: | |
return False, None | |
values = [] | |
matches = rules.match(data=self.mem_results) | |
if not matches: | |
return False, None | |
for rule_match in matches: | |
for match in rule_match.strings: | |
match_offset = match[0] | |
values.append(self._to_virtual_address(match_offset, self.mem_offsets)) | |
return values | |
def find_binary(self, bin_str, sflag=0): | |
yara_sig = self._init_sig("binary", bin_str, sflag) | |
offset_matches = self._search(yara_sig) | |
return offset_matches | |
def find_text(self, q_str, sflag=0): | |
yara_sig = self._init_sig("text", q_str, sflag) | |
offset_matches = self._search(yara_sig) | |
return offset_matches | |
def find_sig(self, yara_sig): | |
#Uncomment the following line if your existing signatures check for | |
#MZ header so that you dont have to modify all of your signatures: | |
#yara_sig = yara_sig.replace('uint16(0) == 0x5A4D and ', '') | |
offset_matches = self._search(yara_sig) | |
return offset_matches | |
def reload_scan_memory(self): | |
self._get_memory() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Added find_sig function which accepts an existing yara signature as an argument. The original functions, find_binary and find_text, built the yara for you. There was no option to search for a yara rule that you had already built outside of this script. This also allows your yara rule to be more advanced.