Skip to content

Commit

Permalink
Merge pull request #3 from utkonos/refresh
Browse files Browse the repository at this point in the history
Update to Python 3, refresh, migrate from deprecated API components
  • Loading branch information
mrexodia authored Jan 16, 2024
2 parents 599f195 + 81f8d76 commit 287cca4
Show file tree
Hide file tree
Showing 5 changed files with 295 additions and 112 deletions.
161 changes: 160 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,160 @@
*.pyc
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2016 x64dbg
Copyright (c) 2024 x64dbg

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ Clone this repository in your Binary Ninja plugin directory.

Import comments/labels from an uncompressed x64dbg JSON database in Binary Ninja.

Symbols for imported functions and or library functions can be overwritten via the "Overwrite X" entries in Settings.

### Export x64dbg database

Export comments/labels to a JSON database that can be loaded by x64dbg.

To export labels only: uncheck "Export Comments" under "x64dbg Database Export" in Settings.
202 changes: 108 additions & 94 deletions __init__.py
Original file line number Diff line number Diff line change
@@ -1,106 +1,120 @@
from binaryninja import *
import os, sqlite3, traceback


def get_module_name(view):
filename = view.file.filename
if filename.endswith(".bndb"):
try:
conn = sqlite3.connect(filename)
cursor = conn.cursor()
cursor.execute("SELECT * FROM global WHERE name='filename'")
_, rawfilename = cursor.fetchone()
filename = rawfilename[5:-2]
except:
pass
return os.path.basename(filename)


def export_db(view):
db = {}
module = get_module_name(view).lower()
base = view.start
dbext = "dd%d" % (view.arch.default_int_size * 8)

file = get_save_filename_input("Export database", "*.%s" % dbext, "%s.%s" %
(module, dbext))
if not file:
"""Binary Ninja plugin to import and export symbols and comments to x64dbg database format."""
import json
import pathlib

from binaryninja.enums import SymbolType
from binaryninja.interaction import get_save_filename_input, get_open_filename_input
from binaryninja.plugin import PluginCommand
from binaryninja.settings import Settings

s = Settings()
s.register_group('dd', 'x64dbg Database Export')
setting = {
'description': 'Always export comments to the x64dbg database.',
'title': 'Export Comments',
'default': True,
'type': 'boolean'
}
s.register_setting('dd.comments', json.dumps(setting))
setting = {
'description': 'Overwrite LibraryFunctionSymbol name',
'title': 'Overwrite LibraryFunctionSymbol',
'default': False,
'type': 'boolean'
}
s.register_setting('dd.libfs', json.dumps(setting))
setting = {
'description': 'Overwrite ImportedFunctionSymbol name',
'title': 'Overwrite ImportedFunctionSymbol',
'default': False,
'type': 'boolean'
}
s.register_setting('dd.impfs', json.dumps(setting))


def export_db(bv):
"""Export symbols and optionally comments from Binary Ninja to an x64dbg database."""
db = dict()
module = pathlib.Path(bv.file.original_filename)
dbext = 'dd{}'.format(bv.arch.default_int_size * 8)

if not (f := get_save_filename_input('Export database', dbext, f'{module.stem}.{dbext}')):
return
print "Exporting database %s" % file

print "Exporting symbols"
db["labels"] = [{
"text": symbol.name,
"manual": False,
"module": module,
"address": "0x%X" % (symbol.address - base)
} for symbol in view.get_symbols()]
print "%d label(s) exported" % len(db["labels"])

db["comments"] = [{
"text": func.comments[comment].replace("{", "{{").replace("}", "}}"),
"manual": False,
"module": module,
"address": "0x%X" % (comment - base)
} for func in view.functions for comment in func.comments]
print "%d comment(s) exported" % len(db["comments"])

with open(file, "w") as outfile:
json.dump(db, outfile, indent=1)
print "Done!"


def import_db(view):
db = {}
module = get_module_name(view).lower()
base = view.start

file = get_open_filename_input("Import database", "*.dd%d" %
(view.arch.default_int_size * 8))
if not file:
file = pathlib.Path(f)
print(f'Exporting database: {file}')

print('Exporting symbols')
db['labels'] = [
{
'text': symbol.name,
'manual': not symbol.auto,
'module': module.name.lower(),
'address': '0x{:X}'.format(symbol.address - bv.start)
}
for symbol in bv.get_symbols()
]
print('Label(s) exported: {}'.format(len(db['labels'])))

s = Settings()
if s.get_bool('dd.comments'):
db['comments'] = [
{
'text': func.comments[address].replace('{', '{{').replace('}', '}}'),
'manual': True,
'module': module.name.lower(),
'address': '0x{:X}'.format(address - bv.start)
}
for func in bv.functions for address in func.comments
]
print('Comment(s) exported: {}'.format(len(db['comments'])))

file.write_text(json.dumps(db))
print('Done!')


def import_db(bv):
"""Import x64dbg database to Binary Ninja."""
module = pathlib.Path(bv.file.original_filename).name.lower()

if not (f := get_open_filename_input('Import database', '*.dd{}'.format(bv.arch.default_int_size * 8))):
return
print "Importing database %s" % file
file = pathlib.Path(f)
print(f'Importing database: {file}')

with open(file) as dbdata:
db = json.load(dbdata)
db = json.load(file.open())

count = 0
labels = db.get("labels", [])
for label in labels:
try:
if label["module"] != module:
labels = db.get('labels', list())
with bv.bulk_modify_symbols():
for label in labels:
if label['module'] != module:
continue
address = int(label["address"], 16) + base
name = label["text"]
symbol = view.get_symbol_at(address)
if not symbol or symbol.name != name:
view.define_user_symbol(Symbol(FunctionSymbol, address, name))
count += 1
except:
traceback.print_exc()
pass
print "%d/%d label(s) imported" % (count, len(labels))
address = int(label['address'], 16) + bv.start
if not (func := bv.get_function_at(address)):
continue
if func.name == label['text']:
continue
if func.symbol.type is SymbolType.LibraryFunctionSymbol and not s.get_bool('dd.libfs'):
continue
if func.symbol.type is SymbolType.ImportedFunctionSymbol and not s.get_bool('dd.impfs'):
continue
func.name = label['text']
count += 1
print('Label(s) imported: {}/{}'.format(count, len(labels)))

count = 0
comments = db.get("comments", [])
comments = db.get('comments', list())
for comment in comments:
try:
if comment["module"] != module:
continue
address = int(comment["address"], 16) + base
comment = comment["text"]
for func in view.functions:
func.set_comment(address, comment)
count += 1
except:
traceback.print_exc()
pass
print "%d/%d comment(s) imported" % (count, len(comments))
if comment['module'] != module:
continue
address = int(comment['address'], 16) + bv.start
for func in bv.get_functions_containing(address):
func.set_comment_at(address, comment['text'])
count += 1
print('Comment(s) imported: {}/{}'.format(count, len(comments)))

print "Done!"
print('Done!')


PluginCommand.register("Export x64dbg database", "Export x64dbg database",
export_db)
PluginCommand.register("Import x64dbg database", "Import x64dbg database",
import_db)
PluginCommand.register('Export x64dbg database', 'Export x64dbg database', export_db)
PluginCommand.register('Import x64dbg database', 'Import x64dbg database', import_db)
Loading

0 comments on commit 287cca4

Please sign in to comment.