Skip to content

Commit

Permalink
add(ui), fix(exporter), misc: Add actual UI, fix exporter not knowing…
Browse files Browse the repository at this point in the history
… of overloads, and a buch of other bug fixes and stuff
  • Loading branch information
SpaghettDev committed Sep 5, 2024
1 parent 3bcd7b8 commit 32f6239
Show file tree
Hide file tree
Showing 19 changed files with 1,670 additions and 501 deletions.
134 changes: 76 additions & 58 deletions BromaIDA.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
VERSION = "5.7.0"
# flake8-in-file-ignores: noqa: E402
VERSION = "6.0.0"
__AUTHOR__ = "SpaghettDev"

PLUGIN_NAME = "BromaIDA"
Expand All @@ -8,93 +9,109 @@
from idaapi import (
msg as ida_msg, register_action, unregister_action,
plugin_t as ida_plugin_t, action_desc_t as ida_action_desc_t,
PLUGIN_PROC, PLUGIN_HIDE, PLUGIN_KEEP
PLUGIN_PROC, PLUGIN_KEEP
)
from ida_kernwin import ask_file, ASKBTN_BTN1, ASKBTN_BTN2
from ida_kernwin import ask_file
from idautils import Names

from broma_ida.utils import (
popup, stop, get_platform, get_platform_printable
stop, get_ida_path, get_platform, get_platform_printable, path_exists
)
from broma_ida.broma.importer import BromaImporter
from broma_ida.broma.exporter import BromaExporter
from broma_ida.ida_ctx_entry import IDACtxEntry

from broma_ida.data.data_manager import DataManager

def bida_main():
"""BromaIDA main entrypoint"""
import_export_prompt = popup(
"Import", "Export", "",
"Import or Export Broma file?\n"
)
from broma_ida.ui.simple_popup import SimplePopup
from broma_ida.ui.main_form import MainForm

if import_export_prompt == ASKBTN_BTN1:
filePath: str = ask_file(False, "GeometryDash.bro", "bro")

if filePath is None or (filePath and not filePath.endswith(".bro")):
popup("Ok", "Ok", None, "Please select a valid file!")
stop()
def on_import(form: MainForm, code: int = 0):
form.Close(1)

platform = get_platform()
broma_importer = BromaImporter(platform)
file_path: str = ask_file(False, "GeometryDash.bro", "bro")

try:
with open(filePath, "r") as f:
broma_importer.parse_file_stream(f)
except FileNotFoundError:
popup("Ok", "Ok", None, "File doesn't exist? Please try again.")
stop()
if not path_exists(file_path, ".bro"):
SimplePopup("Please select a valid file!", "Cancel").show()
stop()

broma_importer.import_into_idb()
platform = get_platform()
broma_importer = BromaImporter(platform, file_path)
broma_importer.parse_file()
broma_importer.import_into_idb()

print("[+] BromaIDA: Finished importing bindings from Broma file")
popup(
"Ok", "Ok", None,
"Finished importing "
f"{get_platform_printable(platform)} "
"bindings from Broma file."
)
print("[+] BromaIDA: Finished importing bindings from Broma file")
SimplePopup(
"Finished importing "
f"{get_platform_printable(platform)} "
"bindings from Broma file.",
"OK"
).show()

elif import_export_prompt == ASKBTN_BTN2:
platform = get_platform()
DataManager().close()

if platform.startswith("android"):
popup(
"Ok", "Ok", None,
"Cannot export bindings from Android binary!"
)
stop()

# for_saving is not True because we need to read the file first
# which may not even exist if the saving prompt is used
# (since you can select files that don't exist within said prompt)
filePath = ask_file(False, "GeometryDash.bro", "bro")
def on_export(form: MainForm, code: int = 0):
form.Close(1)

if filePath is None or (filePath and not filePath.endswith(".bro")):
popup("Ok", "Ok", None, "Please select a valid file!")
stop()
platform = get_platform()

broma_exporter = BromaExporter(platform, filePath)
if platform.startswith("android"):
SimplePopup(
"Cannot export bindings from Android binary!", "Cancel"
).show()
stop()

broma_exporter.import_from_idb(Names())
broma_exporter.export()
# for_saving is not True because we need to read the file first
# which may not even exist if the saving prompt is used
# (since you can select files that don't exist within said prompt)
file_path: str = ask_file(False, "GeometryDash.bro", "bro")

print(
"[+] BromaIDA: Finished exporting "
f"{broma_exporter.num_exports} bindings."
)
popup("Ok", "Ok", None, "Finished exporting bindings to Broma file.")
if not path_exists(file_path, ".bro"):
SimplePopup("Please select a valid file!", "Cancel").show()
stop()

broma_exporter = BromaExporter(platform, file_path)

broma_exporter.import_from_idb(Names())
broma_exporter.export()

print(
"[+] BromaIDA: Finished exporting "
f"{broma_exporter.num_exports} bindings, "
f"{broma_exporter.num_ret_exports} return types and "
f"{broma_exporter.num_args_names_exports} argument names."
)
SimplePopup("Finished exporting bindings to Broma file.", "OK").show()

DataManager().close()


def bida_main():
"""BromaIDA main entrypoint"""
DataManager().init(get_ida_path("plugins") / "broma_ida" / "shelf")

form_code = MainForm(
VERSION,
get_platform_printable(get_platform()),
on_import,
on_export
).show()

# cancel
if form_code == 0:
DataManager().close()


class BromaIDAPlugin(ida_plugin_t):
"""BromaIDA Plugin"""
flags = PLUGIN_PROC | PLUGIN_HIDE
flags = PLUGIN_PROC
comment = "Broma support for IDA."
help = f"{PLUGIN_HOTKEY} to start the importing/exporting."
wanted_name = PLUGIN_NAME
wanted_hotkey = PLUGIN_HOTKEY

ACTION_BTIDA = "btida:run_btida"
ACTION_BTIDA = "bida:run_bida"
ACTION_DESC = "Launches the BromaIDA plugin."

def init(self):
Expand All @@ -111,7 +128,8 @@ def term(self):
ida_msg(f"{PLUGIN_NAME} v{VERSION} unloaded\n")

def run(self, arg):
"""Ran on "File -> Script File" (shocker) (broken for me :D)"""
"""Ran on "File -> Script File" (shocker)
(does not work because this plugin has multiple py files)"""
bida_main()

def _register_action(self):
Expand Down
94 changes: 66 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,51 +10,89 @@ Parses a Broma file and exports the bindings into a Broma file/imports the bindi

- IDA 7.0 or higher
- IDAPython
- Python v3.0.0+ (tested with v3.11.9)
- Python v3.10.0+ (tested with v3.11.9)
- PyBroma
- If you want to be able to import types:
- IDAClang
- MSVC STL headers if reversing Windows binary, GCC STL headers for the other platforms
- STL Headers (see [Importing Types Requirements](#importing-types-requirements))

## Features

- Import method names, return type and arguments
- Export method addresses
- Import types (see [Importing Types Requirements](#importing-types-requirements))
- On Android binaries, fixes IDA completely messing up the arguments of functions for no reason
- Importing
- Import function names
- Import types (see [Importing Types Requirements](#importing-types-requirements)). If enabled, will do the following:
- Import Broma classes members, virtual functions, etc...
- Import function return types
- Import function arguments types and names
- On Android binaries, fixes IDA completely messing up the arguments of functions for no reason
- Exporting
- Export function addresses for any platform
- Export function return types (if enabled, see [BromaIDA Settings](#bromaida-settings))
- Export function arguments' names (if enabled, see [BromaIDA Settings](#bromaida-settings))

## Installation

1. Get python, then `git clone https://github.com/CallocGD/PyBroma --recursive`, `cd PyBroma` then finally `python .\setup.py install` to install PyBroma (blame CallocGD for breaking `pip install https://github.com/CallocGD/PyBroma/archive/refs/heads/main.zip`)
1. Download the release/zip file
2. Copy `BromaIDA.py` and the `broma_ida` folder into `IDA_DIRECTORY/plugins`
2. Download the release/zip file
3. Copy `BromaIDA.py` and the `broma_ida` folder into `IDA_DIRECTORY/plugins`

## Usage

1. `Ctrl-Shift-B` to start importing/exporting
2. Browse and select the broma file (must have Extras.bro in the same directory if you want to import types)
1. `Ctrl-Shift-B`, or from the Top Bar (Edit -> Plugins -> BromaIDA) to start importing/exporting
2. Browse and select the Broma file
3. Let the script handle the rest and enjoy free/exported bindings

## Importing Types Requirements

To import types, you must have IDAClang and the headers for the target platform. Currently only tested with Windows and Android.
1. Open the target binary in IDA
2. In the top bar, select Options > Compiler, Source Parser: Clang. And in Include Directories, replace with the location of the header files
1. For Windows binary
1. Get MSVC Headers by installing MSVC using [Visual Studio Installer](https://visualstudio.microsoft.com/downloads)
2. Set the Include Directories to `C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.40.33807\include`
2. For Android binaries (Android 64 and 32 bit)
1. First get gcc-arm-none-linux-gnueabihf (i did so by using scoop; `scoop install extras/gcc-arm-none-linux-gnueabihf`)
2. Then, in the Include Directories, set it to `C:\Users\YOUR_NAME\scoop\apps\gcc-arm-none-linux-gnueabihf\current\arm-none-linux-gnueabihf\include\c++\13.3.1;C:\Users\YOUR_NAME\scoop\apps\gcc-arm-none-linux-gnueabihf\current\arm-none-linux-gnueabihf\include\c++\13.3.1\arm-none-linux-gnueabihf;C:\Users\YOUR_NAME\scoop\apps\gcc-arm-none-linux-gnueabihf\current\arm-none-linux-gnueabihf\libc\usr\include;C:\Users\YOUR_NAME\scoop\apps\gcc-arm-none-linux-gnueabihf\current\lib\gcc\arm-none-linux-gnueabihf\13.3.1\include` (be sure to replace YOUR_NAME with your windows username)
3. Or use MSVC headers, but be sure to click "Yes" when prompted to use Custom GNU STL!
3. For MacOS (Intel and M1 Mac) and iOS binaries
1. First get gcc (i did so by using scoop; `scoop install gcc`)
2. Then, in the Include Directories, set it to `C:\Users\YOUR_NAME\scoop\apps\gcc\current\include\c++\13.2.0;C:\Users\YOUR_NAME\scoop\apps\gcc\current\include\c++\13.2.0\x86_64-w64-mingw32;C:\Users\YOUR_NAME\scoop\apps\gcc\current\x86_64-w64-mingw32\include` (be sure to replace YOUR_NAME with your windows username)
3. Or use MSVC headers, but again, be sure to click "Yes" when prompted to use Custom GNU STL.
3. Click on OK

Start the script and when prompted to import types, click yes, then the types will automatically be imported for you.
- To import types:
- You must have IDAClang.
- You must have the STL headers for the target platform (MSVC headers for Windows binary, GCC headers for the others). You can however use MSVC headers on binaries that aren't Windows (_but not the other way around_).
- Extras.bro **_must_** be in the same directory as the imported Broma file

- Get your STL Headers path (on Windows)
- For Windows binary (or if not using custom GNU STL)
1. Get MSVC Headers by installing MSVC using the [Visual Studio Installer](https://visualstudio.microsoft.com/downloads)
2. Your header path should be `C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.40.33807\include`
- For Android binaries (Android 64 and 32 bit)
1. First get gcc-arm-none-linux-gnueabihf (i did so by using scoop; `scoop install extras/gcc-arm-none-linux-gnueabihf`)
2. Your header path should be `C:\Users\YOUR_NAME\scoop\apps\gcc-arm-none-linux-gnueabihf\current\arm-none-linux-gnueabihf\include\c++\13.3.1;C:\Users\YOUR_NAME\scoop\apps\gcc-arm-none-linux-gnueabihf\current\arm-none-linux-gnueabihf\include\c++\13.3.1\arm-none-linux-gnueabihf;C:\Users\YOUR_NAME\scoop\apps\gcc-arm-none-linux-gnueabihf\current\arm-none-linux-gnueabihf\libc\usr\include;C:\Users\YOUR_NAME\scoop\apps\gcc-arm-none-linux-gnueabihf\current\lib\gcc\arm-none-linux-gnueabihf\13.3.1\include` (be sure to replace YOUR_NAME with your windows username)
- For MacOS (Intel and M1 Mac) and iOS binaries
1. First get gcc (i did so by using scoop; `scoop install gcc`)
2. Your header path should be `C:\Users\YOUR_NAME\scoop\apps\gcc\current\include\c++\13.2.0;C:\Users\YOUR_NAME\scoop\apps\gcc\current\include\c++\13.2.0\x86_64-w64-mingw32;C:\Users\YOUR_NAME\scoop\apps\gcc\current\x86_64-w64-mingw32\include` (be sure to replace YOUR_NAME with your windows username)

1. Launch the BromaIDA plugin using Ctrl-Shift-B, or from the Top Bar (Edit -> Plugins -> BromaIDA)
2. Click on the Settings button
3. Follow the steps above to get and get your STL Headers path (be sure to check "Import Types")
- Once you get your STL Header path, paste it in the correct folder input. ("MSVC STL Directory" for MSVC, ...)
- If you **_aren't_** using custom GNU STL, be sure to **uncheck** "Use Custom [Android/Mac] GNU STL".
- If you **_are_** using custom GNU STL, be sure to **check** "Use Custom [Android/Mac] GNU STL", otherwise you won't be able to select the custom GNU STL path.
4. Exit out of the settings window

Start the script and the plugin will handle everything :)

## BromaIDA Settings

Can be accessed through the main popup by clicking on the "Settings" button.
This replaces the old "ask everything everytime" method.

Here you will find some options you can set, such as importing types, settings default parser parameters, etc...
The options you chose will be saved into a [shelf](https://docs.python.org/3/library/shelve.html) stored in the `IDA_DIRECTORY/plugins/broma_ida` folder.

![BromaIDA Settings](assets/settings.png)

## Utilities

This is section is meant for people who want to contribute.

In the `utils` folder, you can find some utilities that can help in contributing.

- Currently has:
- `tasks.json`: To be put in `/BromaIDA/.vscode`, adds 2 tasks for VSCode. "Install Plugin" will copy `BromaIDA.py` and the `broma_ida` to the `IDA_DIRECTORY/plugins` directory; And "Launch IDA v8.3" which will launch IDA (shocker). Just be sure to replace IDA's directory with your IDA installation directory.

## Thanks

Special thanks to [CallocGD](https://github.com/CallocGD)'s [PyBroma](https://github.com/CallocGD/PyBroma) which is used to import bindings from Broma.
- Special thanks to:
- The [IDAPython API](https://hex-rays.com/products/ida/support/idapython_docs): Used for everything.
- [CallocGD](https://github.com/CallocGD)'s [PyBroma](https://github.com/CallocGD/PyBroma): Used to parse imported Broma files.
- @sleepyut: Issuing 3 trillion bug reports. Also for suggesting a bunch of features. (they also made BromaBJ)
- [AngelDev06](https://github.com/AngelDev06): Contributing features.
Binary file modified assets/bida.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 32f6239

Please sign in to comment.