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

Add Binary Ninja annotation script #306

Merged
merged 1 commit into from
Jan 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion doc/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ handling, among other things. Use the `--no-filter` option to obtain the
raw and unfiltered deobfuscated strings.


### Generate annotation scripts (`-i`, `-r`, and `--x64dbg`)
### Generate annotation scripts (`-i`, `-j`, `-r`, and `--x64dbg`)

FLOSS can generate an IDA Pro Python script that will
annotate the idb database of the malware sample with
Expand All @@ -156,6 +156,11 @@ Provide the option `-i` or `--ida` to instruct FLOSS to
floss.exe -i myscript.py malware.bin
floss.exe --ida=myscript.py malware.bin

To create an annotation script for Binary Ninja, use the `-j`, or `--binja` switch.

floss.exe -j myscript.py malware.bin
floss.exe --binja myscript.py malware.bin

To create an annotation script for radare2, use the `-r`
or `--radare` switch.

Expand Down
101 changes: 101 additions & 0 deletions floss/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ def make_parser():
help="create a x64dbg database/json file to annotate the decoded strings in x64dbg")
output_group.add_option("-r", "--radare", dest="radare2_script_file",
help="create a radare2 script to annotate the decoded strings in an .r2 file")
output_group.add_option("-j", "--binja", dest="binja_script_file",
help="create a Binary Ninja script to annotate the decoded strings in a BNDB file")
parser.add_option_group(output_group)

identification_group = OptionGroup(parser, "Identification Options")
Expand Down Expand Up @@ -657,6 +659,84 @@ def main():
return script_content


def create_binja_script_content(sample_file_path, decoded_strings, stack_strings):
"""
Create Binary Ninja script contents for BNDB file annotations.
:param sample_file_path: input file path
:param decoded_strings: list of decoded strings ([DecodedString])
:param stack_strings: list of stack strings ([StackString])
:return: content of the Binary Ninja script
"""
main_commands = []
for ds in decoded_strings:
if ds.s != "":
sanitized_string = sanitize_string_for_script(ds.s)
if ds.characteristics["location_type"] == LocationType.GLOBAL:
main_commands.append("print \"FLOSS: string \\\"%s\\\" at global VA 0x%X\"" % (sanitized_string, ds.va))
main_commands.append("AppendComment(%d, \"FLOSS: %s\")" % (ds.va, sanitized_string))
else:
main_commands.append("print \"FLOSS: string \\\"%s\\\" decoded at VA 0x%X\"" % (sanitized_string, ds.decoded_at_va))
main_commands.append("AppendComment(%d, \"FLOSS: %s\")" % (ds.decoded_at_va, sanitized_string))
main_commands.append("print \"Imported decoded strings from FLOSS\"")

ss_len = 0
for ss in stack_strings:
if ss.s != "":
sanitized_string = sanitize_string_for_script(ss.s)
main_commands.append("AppendLvarComment(%d, %d, \"FLOSS stackstring: %s\")" % (ss.fva, ss.pc, sanitized_string))
ss_len += 1
main_commands.append("print \"Imported stackstrings from FLOSS\"")

script_content = """import binaryninja as bn


def AppendComment(ea, s):

s = s.encode('ascii')
refAddrs = []
for ref in bv.get_code_refs(ea):
refAddrs.append(ref)

for addr in refAddrs:
fnc = bv.get_functions_containing(addr.address)
fn = fnc[0]

string = fn.get_comment_at(addr.address)

if not string:
string = s # no existing comment
else:
if s in string: # ignore duplicates
return
string = string + "\\n" + s

fn.set_comment_at(addr.address, string)

def AppendLvarComment(fva, pc, s):

# stack var comments are not a thing in Binary Ninja so just add at top of function
# and at location where it's used as an arg
s = s.encode('ascii')
fn = bv.get_function_at(fva)

for addr in [fva, pc]:
string = fn.get_comment_at(addr)

if not string:
string = s
else:
if s in string: # ignore duplicates
return
string = string + "\\n" + s

fn.set_comment(addr, string)

print "Annotating %d strings from FLOSS for %s"
%s

""" % (len(decoded_strings) + ss_len, sample_file_path, "\n".join(main_commands))
return script_content

def create_r2_script_content(sample_file_path, decoded_strings, stack_strings):
"""
Create r2script contents for r2 session annotations.
Expand Down Expand Up @@ -727,6 +807,23 @@ def create_ida_script(sample_file_path, ida_python_file, decoded_strings, stack_
raise e
# TODO return, catch exception in main()

def create_binja_script(sample_file_path, binja_script_file, decoded_strings, stack_strings):
"""
Create a Binary Ninja script to annotate a BNDB file with decoded strings.
:param sample_file_path: input file path
:param binja_script_file: output file path
:param decoded_strings: list of decoded strings ([DecodedString])
:param stack_strings: list of stack strings ([StackString])
"""
script_content = create_binja_script_content(sample_file_path, decoded_strings, stack_strings)
binja_script__file = os.path.abspath(binja_script_file)
with open(binja_script_file, 'wb') as f:
try:
f.write(script_content)
floss_logger.info("Wrote Binary Ninja script file to %s\n" % binja_script_file)
except Exception as e:
raise e
# TODO return, catch exception in main()

def create_r2_script(sample_file_path, r2_script_file, decoded_strings, stack_strings):
"""
Expand Down Expand Up @@ -984,6 +1081,10 @@ def main(argv=None):
floss_logger.info("Creating r2script...")
create_r2_script(sample_file_path, options.radare2_script_file, decoded_strings, stack_strings)

if options.binja_script_file:
floss_logger.info("Creating Binary Ninja script...")
create_binja_script(sample_file_path, options.binja_script_file, decoded_strings, stack_strings)

time1 = time()
if not options.quiet:
print("\nFinished execution after %f seconds" % (time1 - time0))
Expand Down