mirror of
https://github.com/radareorg/r2unity.git
synced 2026-11-07 06:36:00 -10:00
Initial commit
This commit is contained in:
commit
25ca0a9a6a
5 files changed
+595
No files matched your search
@@ -0,0 +1,31 @@
|
||||
# Simple Makefile for the r2unity project
|
||||
|
||||
# Compiler and flags
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -g -I./third_party/radare2/libr/include $(shell pkg-config --cflags r_core r_util 2>/dev/null || echo "")
|
||||
LDFLAGS = $(shell pkg-config --libs r_core r_util 2>/dev/null || echo "")
|
||||
|
||||
# Project name
|
||||
EXEC = r2unity
|
||||
|
||||
# Source files and object files
|
||||
SRCS = $(wildcard src/*.c) $(wildcard src/lib/*.c)
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
|
||||
# Default target
|
||||
all: $(EXEC)
|
||||
|
||||
# Linking the executable
|
||||
$(EXEC): $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^
|
||||
|
||||
# Compiling source files into object files
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
# Clean up build artifacts
|
||||
clean:
|
||||
rm -f $(EXEC) $(OBJS)
|
||||
|
||||
# Phony targets
|
||||
.PHONY: all clean
|
||||
@@ -0,0 +1,96 @@
|
||||
# r2unity
|
||||
|
||||
A lightweight, dependency-free C tool to parse Unity's `global-metadata.dat` and generate [radare2](https://github.com/radareorg/radare2) scripts for analyzing `libil2cpp.so` binaries.
|
||||
|
||||
## Motivation
|
||||
|
||||
The Unity engine, when using its IL2CPP backend, compiles C# code into C++ and then into a native library (`libil2cpp.so` on Android/Linux, `GameAssembly.dll` on Windows, etc.). To understand the original code structure, reverse engineers need to parse the `global-metadata.dat` file, which contains all the type information, method names, and pointers into the native library.
|
||||
|
||||
While powerful tools like [Il2CppDumper](https://github.com/Perfare/Il2CppDumper) exist, they are often written in higher-level languages (like C#) and produce generic outputs (like C++ headers or JSON files).
|
||||
|
||||
**r2unity** takes a different approach by focusing on a single goal: **deep integration with radare2**. It is written in plain C for maximum performance, portability, and zero runtime dependencies. The output is a ready-to-use `.r2` script, allowing analysts to immediately apply this metadata within their radare2 sessions.
|
||||
|
||||
This project is inspired by the functionality of Il2CppDumper and the metadata parsing concepts from projects like [lib-global-metadata](https://github.com/axstin/lib-global-metadata).
|
||||
|
||||
## Features
|
||||
|
||||
- **Parses `global-metadata.dat`:** Extracts classes, methods, and their relative addresses.
|
||||
- **Generates Radare2 Scripts:** Creates `.r2` files to name functions and add comments in your analysis session.
|
||||
- **Written in Plain C:** No dependencies beyond a standard C compiler (like `gcc` or `clang`).
|
||||
- **Lightweight and Fast:** Designed for speed and minimal memory footprint.
|
||||
- **Cross-Platform:** Aims to be easily compilable on Linux, macOS, and Windows.
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- A C compiler (e.g., `gcc`, `clang`)
|
||||
- `make`
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
git clone https://github.com/your-username/r2unity.git
|
||||
cd r2unity
|
||||
make
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
The primary goal is to generate a script that radare2 can use to annotate the `libil2cpp.so` binary.
|
||||
|
||||
1. **Extract Files:** Obtain the `global-metadata.dat` file and the main binary (e.g., `libil2cpp.so`) from your target application.
|
||||
|
||||
2. **Run r2unity:** Execute `r2unity` with the metadata file and the base address where the binary is loaded. The output will be an `.r2` script.
|
||||
|
||||
```bash
|
||||
./r2unity /path/to/global-metadata.dat > symbols.r2
|
||||
```
|
||||
|
||||
3. **Launch Radare2:** Open the binary in radare2, sourcing the generated script with the `-i` flag.
|
||||
|
||||
```bash
|
||||
r2 -i symbols.r2 /path/to/libil2cpp.so
|
||||
```
|
||||
|
||||
Radare2 will execute the script, defining flags (function names) for all the methods found in the metadata.
|
||||
|
||||
### Example Output (`symbols.r2`)
|
||||
|
||||
The generated script will contain a series of radare2 commands:
|
||||
|
||||
```
|
||||
# r2 script generated by r2unity
|
||||
# Found 50,000+ methods in global-metadata.dat
|
||||
|
||||
f Some.Namespace.ClassName.MethodName @ 0x1a2b3c
|
||||
CCu Method: Some.Namespace.ClassName.MethodName @ 0x1a2b3c
|
||||
|
||||
f Another.Class.Update @ 0x2b3c4d
|
||||
CCu Method: Another.Class.Update @ 0x2b3c4d
|
||||
|
||||
f Player.Stats.GetHealth @ 0x3c4d5e
|
||||
CCu Method: Player.Stats.GetHealth @ 0x3c4d5e
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
## Philosophy
|
||||
|
||||
- **Do One Thing Well:** Focus solely on creating `r2` scripts from Unity metadata.
|
||||
- **Native and Dependency-Free:** Avoid the complexity of runtimes like .NET or Python. A single, static binary is the goal.
|
||||
- **Integrate, Don't Just Convert:** The output should be directly consumable by the target tool (`radare2`) to provide immediate value.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Please feel free to open an issue or submit a pull request. As this is a C project, please adhere to a clean and readable coding style.
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
- The [Il2CppDumper](https://github.com/Perfare/Il2CppDumper) project for being the gold standard in Unity IL2CPP reversing.
|
||||
- The [lib-global-metadata](https://github.com/axstin/lib-global-metadata) project for its clear implementation of metadata parsing.
|
||||
- The [radare2](https://github.com/radareorg/radare2) community.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
#include "lib.h"
|
||||
#include <r_util.h>
|
||||
#include <r_util/r_buf.h>
|
||||
|
||||
R_API R2UnityMetadata *r2unity_parse_metadata (RBuffer *buf) {
|
||||
if (!buf) {
|
||||
return NULL;
|
||||
}
|
||||
R2UnityMetadata *meta = R_NEW0 (R2UnityMetadata);
|
||||
if (!meta) {
|
||||
return NULL;
|
||||
}
|
||||
r_buf_seek (buf, 0, R_BUF_SET);
|
||||
uint32_t magic = r_buf_read_le32 (buf);
|
||||
if (magic != IL2CPP_MAGIC) {
|
||||
R_FREE (meta);
|
||||
return NULL;
|
||||
}
|
||||
r_buf_seek (buf, 4, R_BUF_SET);
|
||||
size_t header_size = 0;
|
||||
// First read a small part to get the version
|
||||
uint32_t sanity;
|
||||
int32_t version;
|
||||
if (r_buf_read (buf, (ut8 *)&sanity, 4) != 4) {
|
||||
R_FREE (meta);
|
||||
return NULL;
|
||||
}
|
||||
if (r_buf_read (buf, (ut8 *)&version, 4) != 4) {
|
||||
R_FREE (meta);
|
||||
return NULL;
|
||||
}
|
||||
if (sanity != IL2CPP_MAGIC) {
|
||||
R_FREE (meta);
|
||||
return NULL;
|
||||
}
|
||||
meta->version = version;
|
||||
switch (version) {
|
||||
case 24:
|
||||
header_size = sizeof (Il2CppGlobalMetadataHeader_v24) - 8; // subtract sanity and version already read
|
||||
break;
|
||||
case 27:
|
||||
header_size = sizeof (Il2CppGlobalMetadataHeader_v27) - 8;
|
||||
break;
|
||||
case 29:
|
||||
header_size = sizeof (Il2CppGlobalMetadataHeader_v29) - 8;
|
||||
break;
|
||||
default:
|
||||
R_FREE (meta);
|
||||
return NULL;
|
||||
}
|
||||
if (r_buf_read (buf, (ut8 *)&meta->header.v24.stringLiteralOffset, header_size) != (st64)header_size) {
|
||||
R_FREE (meta);
|
||||
return NULL;
|
||||
}
|
||||
meta->strings = r_buf_new_slice (buf, meta->header.v24.stringOffset, meta->header.v24.stringSize);
|
||||
meta->string_literals = r_buf_new_slice (buf, meta->header.v24.stringLiteralOffset, meta->header.v24.stringLiteralSize);
|
||||
return meta;
|
||||
}
|
||||
|
||||
R_API void r2unity_free_metadata (R2UnityMetadata *meta) {
|
||||
if (!meta) {
|
||||
return;
|
||||
}
|
||||
r_buf_free (meta->strings);
|
||||
r_buf_free (meta->string_literals);
|
||||
R_FREE (meta);
|
||||
}
|
||||
|
||||
R_API const char *r2unity_get_string (R2UnityMetadata *meta, uint32_t index) {
|
||||
if (!meta || !meta->strings || index >= r_buf_size (meta->strings)) {
|
||||
return NULL;
|
||||
}
|
||||
// Read until null terminator
|
||||
char *str = NULL;
|
||||
ut64 len = 0;
|
||||
ut8 byte;
|
||||
while (r_buf_read_at (meta->strings, index + len, &byte, 1) == 1 && byte != 0) {
|
||||
len++;
|
||||
}
|
||||
if (len > 0) {
|
||||
str = R_NEWS (char, len + 1);
|
||||
if (str) {
|
||||
r_buf_read_at (meta->strings, index, (ut8 *)str, len);
|
||||
str[len] = 0;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
R_API Il2CppTypeDefinition *r2unity_get_type_definitions (R2UnityMetadata *meta, size_t *count) {
|
||||
if (!meta || !count) {
|
||||
return NULL;
|
||||
}
|
||||
*count = meta->header.v24.typeDefinitionsSize / sizeof (Il2CppTypeDefinition);
|
||||
if (*count == 0) {
|
||||
return NULL;
|
||||
}
|
||||
Il2CppTypeDefinition *types = R_NEWS (Il2CppTypeDefinition, *count);
|
||||
if (!types) {
|
||||
return NULL;
|
||||
}
|
||||
r_buf_seek (meta->strings, meta->header.v24.typeDefinitionsOffset, R_BUF_SET);
|
||||
if (r_buf_read (meta->strings, (ut8 *)types, meta->header.v24.typeDefinitionsSize) != meta->header.v24.typeDefinitionsSize) {
|
||||
R_FREE (types);
|
||||
return NULL;
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
R_API Il2CppMethodDefinition *r2unity_get_method_definitions (R2UnityMetadata *meta, size_t *count) {
|
||||
if (!meta || !count) {
|
||||
return NULL;
|
||||
}
|
||||
*count = meta->header.v24.methodsSize / sizeof (Il2CppMethodDefinition);
|
||||
if (*count == 0) {
|
||||
return NULL;
|
||||
}
|
||||
Il2CppMethodDefinition *methods = R_NEWS (Il2CppMethodDefinition, *count);
|
||||
if (!methods) {
|
||||
return NULL;
|
||||
}
|
||||
r_buf_seek (meta->strings, meta->header.v24.methodsOffset, R_BUF_SET);
|
||||
if (r_buf_read (meta->strings, (ut8 *)methods, meta->header.v24.methodsSize) != meta->header.v24.methodsSize) {
|
||||
R_FREE (methods);
|
||||
return NULL;
|
||||
}
|
||||
return methods;
|
||||
}
|
||||
+276
@@ -0,0 +1,276 @@
|
||||
#ifndef R2UNITY_LIB_H
|
||||
#define R2UNITY_LIB_H
|
||||
|
||||
#include <r_util.h>
|
||||
|
||||
#define IL2CPP_MAGIC 0xFAB11BAF
|
||||
|
||||
typedef struct {
|
||||
uint32_t sanity;
|
||||
int32_t version;
|
||||
uint32_t stringLiteralOffset;
|
||||
int32_t stringLiteralSize;
|
||||
uint32_t stringLiteralDataOffset;
|
||||
int32_t stringLiteralDataSize;
|
||||
uint32_t stringOffset;
|
||||
int32_t stringSize;
|
||||
uint32_t eventsOffset;
|
||||
int32_t eventsSize;
|
||||
uint32_t propertiesOffset;
|
||||
int32_t propertiesSize;
|
||||
uint32_t methodsOffset;
|
||||
int32_t methodsSize;
|
||||
uint32_t parameterDefaultValuesOffset;
|
||||
int32_t parameterDefaultValuesSize;
|
||||
uint32_t fieldDefaultValuesOffset;
|
||||
int32_t fieldDefaultValuesSize;
|
||||
uint32_t fieldAndParameterDefaultValueDataOffset;
|
||||
int32_t fieldAndParameterDefaultValueDataSize;
|
||||
uint32_t fieldMarshaledSizesOffset;
|
||||
int32_t fieldMarshaledSizesSize;
|
||||
uint32_t parametersOffset;
|
||||
int32_t parametersSize;
|
||||
uint32_t fieldsOffset;
|
||||
int32_t fieldsSize;
|
||||
uint32_t genericParametersOffset;
|
||||
int32_t genericParametersSize;
|
||||
uint32_t genericParameterConstraintsOffset;
|
||||
int32_t genericParameterConstraintsSize;
|
||||
uint32_t genericContainersOffset;
|
||||
int32_t genericContainersSize;
|
||||
uint32_t nestedTypesOffset;
|
||||
int32_t nestedTypesSize;
|
||||
uint32_t interfacesOffset;
|
||||
int32_t interfacesSize;
|
||||
uint32_t vtableMethodsOffset;
|
||||
int32_t vtableMethodsSize;
|
||||
uint32_t interfaceOffsetsOffset;
|
||||
int32_t interfaceOffsetsSize;
|
||||
uint32_t typeDefinitionsOffset;
|
||||
int32_t typeDefinitionsSize;
|
||||
uint32_t imagesOffset;
|
||||
int32_t imagesSize;
|
||||
uint32_t assembliesOffset;
|
||||
int32_t assembliesSize;
|
||||
uint32_t fieldRefsOffset;
|
||||
int32_t fieldRefsSize;
|
||||
uint32_t referencedAssembliesOffset;
|
||||
int32_t referencedAssembliesSize;
|
||||
uint32_t attributesInfoOffset;
|
||||
int32_t attributesInfoSize;
|
||||
uint32_t attributeTypesOffset;
|
||||
int32_t attributeTypesSize;
|
||||
uint32_t unresolvedVirtualCallParameterTypesOffset;
|
||||
int32_t unresolvedVirtualCallParameterTypesSize;
|
||||
uint32_t unresolvedVirtualCallParameterRangesOffset;
|
||||
int32_t unresolvedVirtualCallParameterRangesSize;
|
||||
uint32_t windowsRuntimeTypeNamesOffset;
|
||||
int32_t windowsRuntimeTypeNamesSize;
|
||||
uint32_t windowsRuntimeStringsOffset;
|
||||
int32_t windowsRuntimeStringsSize;
|
||||
uint32_t exportedTypeDefinitionsOffset;
|
||||
int32_t exportedTypeDefinitionsSize;
|
||||
} Il2CppGlobalMetadataHeader_v24;
|
||||
|
||||
typedef struct {
|
||||
uint32_t sanity;
|
||||
int32_t version;
|
||||
uint32_t stringLiteralOffset;
|
||||
int32_t stringLiteralSize;
|
||||
uint32_t stringLiteralDataOffset;
|
||||
int32_t stringLiteralDataSize;
|
||||
uint32_t stringOffset;
|
||||
int32_t stringSize;
|
||||
uint32_t eventsOffset;
|
||||
int32_t eventsSize;
|
||||
uint32_t propertiesOffset;
|
||||
int32_t propertiesSize;
|
||||
uint32_t methodsOffset;
|
||||
int32_t methodsSize;
|
||||
uint32_t parameterDefaultValuesOffset;
|
||||
int32_t parameterDefaultValuesSize;
|
||||
uint32_t fieldDefaultValuesOffset;
|
||||
int32_t fieldDefaultValuesSize;
|
||||
uint32_t fieldAndParameterDefaultValueDataOffset;
|
||||
int32_t fieldAndParameterDefaultValueDataSize;
|
||||
uint32_t fieldMarshaledSizesOffset;
|
||||
int32_t fieldMarshaledSizesSize;
|
||||
uint32_t parametersOffset;
|
||||
int32_t parametersSize;
|
||||
uint32_t fieldsOffset;
|
||||
int32_t fieldsSize;
|
||||
uint32_t genericParametersOffset;
|
||||
int32_t genericParametersSize;
|
||||
uint32_t genericParameterConstraintsOffset;
|
||||
int32_t genericParameterConstraintsSize;
|
||||
uint32_t genericContainersOffset;
|
||||
int32_t genericContainersSize;
|
||||
uint32_t nestedTypesOffset;
|
||||
int32_t nestedTypesSize;
|
||||
uint32_t interfacesOffset;
|
||||
int32_t interfacesSize;
|
||||
uint32_t vtableMethodsOffset;
|
||||
int32_t vtableMethodsSize;
|
||||
uint32_t interfaceOffsetsOffset;
|
||||
int32_t interfaceOffsetsSize;
|
||||
uint32_t typeDefinitionsOffset;
|
||||
int32_t typeDefinitionsSize;
|
||||
uint32_t imagesOffset;
|
||||
int32_t imagesSize;
|
||||
uint32_t assembliesOffset;
|
||||
int32_t assembliesSize;
|
||||
uint32_t fieldRefsOffset;
|
||||
int32_t fieldRefsSize;
|
||||
uint32_t referencedAssembliesOffset;
|
||||
int32_t referencedAssembliesSize;
|
||||
uint32_t attributesInfoOffset;
|
||||
int32_t attributesInfoSize;
|
||||
uint32_t attributeTypesOffset;
|
||||
int32_t attributeTypesSize;
|
||||
uint32_t unresolvedVirtualCallParameterTypesOffset;
|
||||
int32_t unresolvedVirtualCallParameterTypesSize;
|
||||
uint32_t unresolvedVirtualCallParameterRangesOffset;
|
||||
int32_t unresolvedVirtualCallParameterRangesSize;
|
||||
uint32_t windowsRuntimeTypeNamesOffset;
|
||||
int32_t windowsRuntimeTypeNamesSize;
|
||||
uint32_t windowsRuntimeStringsOffset;
|
||||
int32_t windowsRuntimeStringsSize;
|
||||
uint32_t exportedTypeDefinitionsOffset;
|
||||
int32_t exportedTypeDefinitionsSize;
|
||||
uint32_t rgctxEntriesOffset;
|
||||
int32_t rgctxEntriesSize;
|
||||
} Il2CppGlobalMetadataHeader_v27;
|
||||
|
||||
typedef struct {
|
||||
uint32_t sanity;
|
||||
int32_t version;
|
||||
uint32_t stringLiteralOffset;
|
||||
int32_t stringLiteralSize;
|
||||
uint32_t stringLiteralDataOffset;
|
||||
int32_t stringLiteralDataSize;
|
||||
uint32_t stringOffset;
|
||||
int32_t stringSize;
|
||||
uint32_t eventsOffset;
|
||||
int32_t eventsSize;
|
||||
uint32_t propertiesOffset;
|
||||
int32_t propertiesSize;
|
||||
uint32_t methodsOffset;
|
||||
int32_t methodsSize;
|
||||
uint32_t parameterDefaultValuesOffset;
|
||||
int32_t parameterDefaultValuesSize;
|
||||
uint32_t fieldDefaultValuesOffset;
|
||||
int32_t fieldDefaultValuesSize;
|
||||
uint32_t fieldAndParameterDefaultValueDataOffset;
|
||||
int32_t fieldAndParameterDefaultValueDataSize;
|
||||
uint32_t fieldMarshaledSizesOffset;
|
||||
int32_t fieldMarshaledSizesSize;
|
||||
uint32_t parametersOffset;
|
||||
int32_t parametersSize;
|
||||
uint32_t fieldsOffset;
|
||||
int32_t fieldsSize;
|
||||
uint32_t genericParametersOffset;
|
||||
int32_t genericParametersSize;
|
||||
uint32_t genericParameterConstraintsOffset;
|
||||
int32_t genericParameterConstraintsSize;
|
||||
uint32_t genericContainersOffset;
|
||||
int32_t genericContainersSize;
|
||||
uint32_t nestedTypesOffset;
|
||||
int32_t nestedTypesSize;
|
||||
uint32_t interfacesOffset;
|
||||
int32_t interfacesSize;
|
||||
uint32_t vtableMethodsOffset;
|
||||
int32_t vtableMethodsSize;
|
||||
uint32_t interfaceOffsetsOffset;
|
||||
int32_t interfaceOffsetsSize;
|
||||
uint32_t typeDefinitionsOffset;
|
||||
int32_t typeDefinitionsSize;
|
||||
uint32_t imagesOffset;
|
||||
int32_t imagesSize;
|
||||
uint32_t assembliesOffset;
|
||||
int32_t assembliesSize;
|
||||
uint32_t fieldRefsOffset;
|
||||
int32_t fieldRefsSize;
|
||||
uint32_t referencedAssembliesOffset;
|
||||
int32_t referencedAssembliesSize;
|
||||
uint32_t attributesInfoOffset;
|
||||
int32_t attributesInfoSize;
|
||||
uint32_t attributeTypesOffset;
|
||||
int32_t attributeTypesSize;
|
||||
uint32_t unresolvedVirtualCallParameterTypesOffset;
|
||||
int32_t unresolvedVirtualCallParameterTypesSize;
|
||||
uint32_t unresolvedVirtualCallParameterRangesOffset;
|
||||
int32_t unresolvedVirtualCallParameterRangesSize;
|
||||
uint32_t windowsRuntimeTypeNamesOffset;
|
||||
int32_t windowsRuntimeTypeNamesSize;
|
||||
uint32_t windowsRuntimeStringsOffset;
|
||||
int32_t windowsRuntimeStringsSize;
|
||||
uint32_t exportedTypeDefinitionsOffset;
|
||||
int32_t exportedTypeDefinitionsSize;
|
||||
uint32_t rgctxEntriesOffset;
|
||||
int32_t rgctxEntriesSize;
|
||||
uint32_t rgctxEntriesDataOffset;
|
||||
int32_t rgctxEntriesDataSize;
|
||||
} Il2CppGlobalMetadataHeader_v29;
|
||||
|
||||
typedef union {
|
||||
Il2CppGlobalMetadataHeader_v24 v24;
|
||||
Il2CppGlobalMetadataHeader_v27 v27;
|
||||
Il2CppGlobalMetadataHeader_v29 v29;
|
||||
} Il2CppGlobalMetadataHeader;
|
||||
|
||||
typedef struct {
|
||||
int32_t version;
|
||||
Il2CppGlobalMetadataHeader header;
|
||||
RBuffer *strings;
|
||||
RBuffer *string_literals;
|
||||
} R2UnityMetadata;
|
||||
|
||||
typedef struct {
|
||||
uint32_t nameIndex;
|
||||
uint32_t namespaceIndex;
|
||||
int32_t byvalTypeIndex;
|
||||
int32_t declaringTypeIndex;
|
||||
int32_t parentIndex;
|
||||
int32_t elementTypeIndex;
|
||||
int32_t genericContainerIndex;
|
||||
uint32_t flags;
|
||||
int32_t fieldStart;
|
||||
int32_t methodStart;
|
||||
int32_t eventStart;
|
||||
int32_t propertyStart;
|
||||
int32_t nestedTypesStart;
|
||||
int32_t interfacesStart;
|
||||
int32_t vtableStart;
|
||||
int32_t interfaceOffsetsStart;
|
||||
uint16_t method_count;
|
||||
uint16_t property_count;
|
||||
uint16_t field_count;
|
||||
uint16_t event_count;
|
||||
uint16_t nested_type_count;
|
||||
uint16_t vtable_count;
|
||||
uint16_t interfaces_count;
|
||||
uint16_t interface_offsets_count;
|
||||
uint32_t bitfield;
|
||||
uint32_t token;
|
||||
} Il2CppTypeDefinition;
|
||||
|
||||
typedef struct {
|
||||
uint32_t nameIndex;
|
||||
int32_t declaringType;
|
||||
int32_t returnType;
|
||||
int32_t parameterStart;
|
||||
int32_t genericContainerIndex;
|
||||
uint32_t token;
|
||||
uint16_t flags;
|
||||
uint16_t iflags;
|
||||
uint16_t slot;
|
||||
uint16_t parameterCount;
|
||||
} Il2CppMethodDefinition;
|
||||
|
||||
R_API R2UnityMetadata *r2unity_parse_metadata (RBuffer *buf);
|
||||
R_API void r2unity_free_metadata (R2UnityMetadata *meta);
|
||||
R_API const char *r2unity_get_string (R2UnityMetadata *meta, uint32_t index);
|
||||
R_API Il2CppTypeDefinition *r2unity_get_type_definitions (R2UnityMetadata *meta, size_t *count);
|
||||
R_API Il2CppMethodDefinition *r2unity_get_method_definitions (R2UnityMetadata *meta, size_t *count);
|
||||
|
||||
#endif
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "lib/lib.h"
|
||||
|
||||
void print_usage(const char *prog_name) {
|
||||
fprintf(stderr, "Usage: %s <executable> <path/to/global-metadata.dat>\n", prog_name);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 3) {
|
||||
print_usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *exe_path = argv[1];
|
||||
const char *metadata_path = argv[2];
|
||||
|
||||
RBuffer *buf = r_buf_new_file (metadata_path, O_RDONLY, 0);
|
||||
if (!buf) {
|
||||
perror("Error opening file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("# r2 script generated by r2unity\n");
|
||||
printf("# Input file: %s\n\n", metadata_path);
|
||||
|
||||
R2UnityMetadata *meta = r2unity_parse_metadata (buf);
|
||||
if (!meta) {
|
||||
fprintf(stderr, "Failed to parse metadata\n");
|
||||
r_buf_free (buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t type_count;
|
||||
Il2CppTypeDefinition *types = r2unity_get_type_definitions (meta, &type_count);
|
||||
if (types) {
|
||||
for (size_t i = 0; i < type_count; i++) {
|
||||
const char *type_name = r2unity_get_string (meta, types[i].nameIndex);
|
||||
const char *namespace_name = r2unity_get_string (meta, types[i].namespaceIndex);
|
||||
if (type_name) {
|
||||
printf("f %s.%s @ 0x0\n", namespace_name ? namespace_name : "", type_name);
|
||||
}
|
||||
}
|
||||
R_FREE (types);
|
||||
}
|
||||
|
||||
size_t method_count;
|
||||
Il2CppMethodDefinition *methods = r2unity_get_method_definitions (meta, &method_count);
|
||||
if (methods) {
|
||||
for (size_t i = 0; i < method_count; i++) {
|
||||
const char *method_name = r2unity_get_string (meta, methods[i].nameIndex);
|
||||
if (method_name) {
|
||||
printf("f %s @ 0x0\n", method_name);
|
||||
printf("CCu Method: %s @ 0x0\n", method_name);
|
||||
}
|
||||
}
|
||||
R_FREE (methods);
|
||||
}
|
||||
|
||||
r2unity_free_metadata (meta);
|
||||
r_buf_free (buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user