Skip to content

Commit

Permalink
Fix Android STL having the wrong size and fix exporter again
Browse files Browse the repository at this point in the history
  • Loading branch information
SpaghettDev committed Jul 19, 2024
1 parent 1d59efe commit db12d76
Show file tree
Hide file tree
Showing 11 changed files with 506 additions and 362 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/.vscode
/.mypy_cache
/**/__pycache__
/codegen.txt
/jupyter
Expand Down
2 changes: 1 addition & 1 deletion BromaIDA.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION = "5.0.0"
VERSION = "5.1.0"
__AUTHOR__ = "SpaghettDev"

PLUGIN_NAME = "BromaIDA"
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ Parses a Broma file and exports the bindings into a Broma file/imports the bindi
## Requirements

- IDA 7.0 or higher
- IDAPython Python v3.0.0 support
- IDAPython
- Python v3.0.0+ (tested with v3.11.9)
- PyBroma
- If you want to be able to import types:
- IDAClang
- MSVC if on Windows, GCC if on Linux or MacOS (untested)
- MSVC STL headers if reversing Windows binary, GCC STL headers for the other platforms

## Features

- Import method names
- 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
Expand All @@ -44,6 +45,7 @@ To import types, you must have IDAClang and the headers for the target platform.
2. For GCC (Android binary)
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, i think it works fine?
3. For GCC (MacOS and iOS), i have no clue
3. Click on OK

Expand Down
50 changes: 38 additions & 12 deletions broma_ida/broma/codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@

class BromaCodegen:
"""Codegen for Broma"""
FILE_HEADER = """// Generated by BromaIDA, do not modify
FILE_HEADER = f"""// Generated by BromaIDA, do not modify
#include <array>
#define BROMAIDA_PLATFORM_MACRO_NAME
#define STR_CONCAT_WRAPPER(a, b) a ## b
#define STR_CONCAT(a, b) STR_CONCAT_WRAPPER(a, b)
#define PAD(size) unsigned char STR_CONCAT(__pad, __LINE__)[size]\n\n"""
Expand All @@ -34,53 +36,64 @@ def __init__(
self._path = path
self._broma_path = broma_path

Path(self._path / "codegen").mkdir(parents=True, exist_ok=True)
(self._path / "codegen").mkdir(parents=True, exist_ok=True)

def write(self):
"""Dumps codegenned classes, structs and enums
to the path supplied in __init__
Args:
path (Path): _description_
path (Path)
"""
with open(
self._path / "codegen" / f"{self._target_platform}.hpp",
"w",
buffering=10*1024*1024
) as f:
f.write(self.FILE_HEADER)
f.write(
self.FILE_HEADER.replace(
"BROMAIDA_PLATFORM_MACRO_NAME",
self._get_bromaida_platform_macro()
)
)

with open(self._path / "enums.hpp") as enums:
f.write("// enums.hpp\n")
for line in enums.readlines():
f.write(line)
f.writelines(enums.readlines())
f.write("\n\n")

if self._target_platform.startswith("android"):
with open(self._path / "gnustl.hpp") as gnustl:
f.write("// gnustl.hpp\n")
f.writelines(gnustl.readlines())
f.write("\n\n")

with open(self._path / "cocos2d.hpp") as cocos:
f.write("// cocos2d.hpp\n")
for line in cocos.readlines():
if line.startswith("#include \""):
line = f"// {line}"

f.write(line)
f.write("\n\n")

with open(self._path / "fmod.hpp") as fmod:
f.write("// fmod.hpp\n")
for line in fmod.readlines():
f.write(line)
f.writelines(fmod.readlines())
f.write("\n\n")

with open(self._path / "stl_types.hpp") as stl_types:
f.write("// stl_types.hpp\n")
for line in stl_types.readlines():
if line == """#include "enums.hpp"\n""":
continue
if line.startswith("#include \""):
line = f"// {line}"

f.write(line)
f.write("\n\n")

with open(self._path / "helpers.hpp") as helpers:
f.write("// helpers.hpp\n")
for line in helpers.readlines():
f.write(line)
f.writelines(helpers.readlines())
f.write("\n\n")

f.flush()
Expand Down Expand Up @@ -142,3 +155,16 @@ def write(self):
f.write(
ClassBuilder(self._target_platform, broma_class).get_str()
)

def _get_bromaida_platform_macro(self) -> str:
"""Gets the BromaIDA platform macro name (shocker)"""
plat_to_macro_suffix: dict[BROMA_PLATFORMS, str] = {
"win": "WINDOWS",
"imac": "INTEL_MACOS",
"m1": "M1_MACOS",
"ios": "IOS",
"android32": "ANDROID32",
"android64": "ANDROID64"
}

return f"""BROMAIDA_PLATFORM_{plat_to_macro_suffix[self._target_platform]}"""
10 changes: 6 additions & 4 deletions broma_ida/broma/exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class BromaExporter:
group 5: comma-separated platform address(es)
"""
RX_METHOD = \
r"""^(?:\t| {4})(?:\/\/ )?(virtual|callback|static|)(?: )?(?:(\S+) )?(\S+)\((.*)\)(?: const|)(?: = (?(?=inline).* \{|((?:(?:win|imac|m1|ios) (?:0[xX][0-9a-fA-F]+|inline)(?:, )?)+)))?""" # noqa: E501
r"""^(?:\t| {4})(?:\/\/ )?(virtual|callback|static|)(?: )?(?:(\S+) )?(\S+)\((.*)\)(?: const|)(?: = ((?=inline).* \{|(?!inline)((?:(?:win|imac|m1|ios) (?:0[xX][0-9a-fA-F]+|inline)(?:, )?)+)))?""" # noqa: E501
RX_METHOD_PLAT_ADDR_BASE = r"""{platform} (0[xX][0-9a-fA-F]+|inline)"""

_filepath: str = ""
Expand Down Expand Up @@ -63,9 +63,11 @@ def _parse_method_platforms(
"""
if platforms is None:
return {}

platforms_list = platforms.split(", ")
platforms_list = [f"""{plat.split(" ")[0]} 0x0""" if plat.endswith("inline") else plat for plat in platforms_list]

platforms_list = [
f"""{plat.split(" ")[0]} 0x0""" if plat.endswith("inline") else plat
for plat in platforms.split(", ")
]

return {
cast(BROMA_PLATFORMS, plat_inf[0]): int(plat_inf[1], 16)
Expand Down
77 changes: 49 additions & 28 deletions broma_ida/broma/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from re import sub
from pathlib import Path

from pybroma import Root, FunctionBindField, Type, Class
from pybroma import Root, Type, Class

from broma_ida.broma.constants import BROMA_PLATFORMS
from broma_ida.broma.binding import Binding
Expand Down Expand Up @@ -125,6 +125,28 @@ def verify_type(t: Optional[ida_tinfo_t]) -> bool:
return True

return False

@staticmethod
def get_holy_shit_struct_size(platform: BROMA_PLATFORMS) -> int:
"""Gets the size of the STL struct for the supplied platform
Args:
platform (BROMA_PLATFORMS)
Returns:
int: size in bytes
"""
# TODO: yea wth update this!!
plat_to_hss_size: dict[BROMA_PLATFORMS, int] = {
"win": 0x808,
"imac": 0x1, # need them headers
"m1": 0x1,
"ios": 0x1, # this probably will never exist
"android32": 0x45C,
"android64": 0x828
}

return plat_to_hss_size[platform]


class BromaImporter:
Expand Down Expand Up @@ -297,41 +319,40 @@ def parse_file_stream(self, file: TextIOWrapper):
)

self._has_types = True
else:
holy_shit_struct = BIUtils.get_type_info("holy_shit")
else:
holy_shit_struct = BIUtils.get_type_info("holy_shit")

if holy_shit_struct:
self._has_types = holy_shit_struct.get_size() == BIUtils.get_holy_shit_strut_size(self._target_platform)

if not self._has_types:
popup(
"Ok", "Ok", None,
"Mismatch in STL types! "
"Function types will not be changed! "
"To fix this, go to the local types window "
"and delete all Cocos and GD types "
"(as well as holy_shit struct)"
)

if holy_shit_struct:
if self._target_platform != "android32":
self._has_types = holy_shit_struct.get_size() == 0x808
else:
self._has_types = holy_shit_struct.get_size() == 1
if any([
BIUtils.verify_type(BIUtils.get_type_info(t))
for t in (
"cocos2d::CCObject", "cocos2d::CCImage",
"cocos2d::CCApplication", "cocos2d::CCDirector"
)
]):
self._has_types = False

if not self._has_types:
popup(
"Ok", "Ok", None,
"Mismatch in STL types! "
"Mismatch in cocos2d types! "
"Function types will not be changed! "
"To fix this, go to the local types window "
"and delete all Cocos and GD types"
"and delete all Cocos and GD types "
"(as well as holy_shit struct)"
)

if any([
BIUtils.verify_type(BIUtils.get_type_info(t))
for t in (
"cocos2d::CCObject", "cocos2d::CCImage",
"cocos2d::CCApplication", "cocos2d::CCDirector"
)
]):
self._has_types = False

popup(
"Ok", "Ok", None,
"Mismatch in cocos2d types! "
"Function types will not be changed! "
"To fix this, go to the local types window "
"and delete all Cocos and GD types"
)

if self._target_platform.startswith("android"):
for class_name, broma_class in root.classesAsDict().items():
for field in broma_class.fields:
Expand Down
Loading

0 comments on commit db12d76

Please sign in to comment.