11 Commits
12 changed files with 501 additions and 112 deletions

No files matched your search

+133 -7
View File
@@ -1,5 +1,8 @@
name: CI
env:
R2V: 6.2.2
on:
push:
branches:
@@ -25,11 +28,13 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Install radare2
id: r2
uses: radareorg/github-actions@v3
with:
version: ${{ env.R2V }}
- name: Build
run: make
@@ -46,11 +51,13 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Install radare2
id: r2
uses: radareorg/github-actions@v3
with:
version: ${{ env.R2V }}
- name: Install deps
run: pip install meson ninja --break-system-packages
@@ -69,7 +76,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Install radare2 from git
id: r2
@@ -89,7 +96,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
@@ -99,6 +106,8 @@ jobs:
- name: Install radare2
id: r2
uses: radareorg/github-actions@v3
with:
version: ${{ env.R2V }}
- name: Build Debian package
run: make -C dist/debian SUDO=
@@ -110,6 +119,107 @@ jobs:
if-no-files-found: error
archive: false
windows:
name: Build Windows package
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Python
uses: actions/setup-python@v7
with:
python-version: 3.12.x
- name: Setup MSVC
uses: TheMrMilchmann/setup-msvc-dev@v4
with:
arch: x64
- name: Install build dependencies
run: python -m pip install meson ninja
- name: Install radare2
id: r2
uses: radareorg/github-actions@v3
with:
version: ${{ env.R2V }}
- name: Configure
run: meson setup build-windows --buildtype=release -Dplugins=enabled
- name: Build
run: meson compile -C build-windows
- name: Test
run: meson test -C build-windows --print-errorlogs
- name: Package Windows build
id: package
shell: pwsh
run: |
$project = meson introspect build-windows --projectinfo | ConvertFrom-Json
$package = "r2unity-$($project.version)-w64"
$files = @(
"build-windows\r2unity.exe",
"build-windows\core_r2unity.dll",
"build-windows\bin_r2unity.dll"
)
New-Item -ItemType Directory -Path $package | Out-Null
foreach ($file in $files) {
if (-not (Test-Path $file)) {
throw "Missing Windows build output: $file"
}
Copy-Item $file -Destination $package
}
$archive = "$package.zip"
Compress-Archive -Path "$package\*" -DestinationPath $archive -Force
"archive=$archive" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
- name: Package r2pm binary
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path bindist\plugins,bindist\bin | Out-Null
Copy-Item build-windows\core_r2unity.dll,build-windows\bin_r2unity.dll bindist\plugins
Copy-Item build-windows\r2unity.exe bindist\bin
Compress-Archive -Path bindist\* -DestinationPath "r2unity-$env:R2V-windows-x86-64.zip" -Force
- name: Upload Windows package artifact
uses: actions/upload-artifact@v7
with:
name: windows-package
path: |
${{ steps.package.outputs.archive }}
r2unity-*-windows-x86-64.zip
if-no-files-found: error
bindist:
name: Build r2pm binary (${{ matrix.os }})
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, ubuntu-24.04-arm, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install radare2
uses: radareorg/github-actions@v3
with:
version: ${{ env.R2V }}
- name: Package r2pm binary
run: make bindist
- name: Upload r2pm binary artifact
uses: actions/upload-artifact@v7
with:
name: bindist-${{ matrix.os }}
path: r2unity-*.zip
if-no-files-found: error
release:
name: Publish release
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}
@@ -117,27 +227,42 @@ jobs:
- build
- meson
- debian
- windows
- bindist
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Download artifacts
- name: Download Debian package artifact
uses: actions/download-artifact@v8
with:
pattern: '*.deb'
path: dist/artifacts
merge-multiple: true
- name: Download Windows package artifact
uses: actions/download-artifact@v8
with:
name: windows-package
path: dist/artifacts
- name: Download r2pm binary artifacts
uses: actions/download-artifact@v8
with:
pattern: bindist-*
path: dist/artifacts
merge-multiple: true
- name: Generate release notes
run: ./release.sh notes > release-notes.md
- name: Create GitHub release
uses: softprops/[email protected].0
uses: softprops/[email protected].3
with:
name: ${{ github.ref_name }}
tag_name: ${{ github.ref_name }}
@@ -147,3 +272,4 @@ jobs:
fail_on_unmatched_files: true
files: |
dist/artifacts/*.deb
dist/artifacts/*.zip
+3
View File
@@ -22,3 +22,6 @@
# Third-party reference checkouts (radare2, il2cpp dumper, etc.)
/third_party/
# r2pm binary packages
/r2unity-*.zip
+9 -1
View File
@@ -66,6 +66,14 @@ user-install: install-plugin
user-uninstall: uninstall-plugin
rm -f "$(R2PM_BINDIR)/$(EXEC)"
# Binary package for r2pm -bi: plugins/ and bin/ for this r2 version and platform
BINDIST_ZIP = r2unity-$(shell r2 -qv)-$(shell r2pm -H R2PM_OS)-$(shell r2pm -H R2PM_ARCH)-$(shell r2pm -H R2PM_BITS).zip
bindist: $(EXEC) $(PLUGINS)
rm -rf build/bindist $(BINDIST_ZIP)
$(MAKE) user-install R2_USER_PLUGINS=$(CURDIR)/build/bindist/plugins R2PM_BINDIR=$(CURDIR)/build/bindist/bin
cd build/bindist && zip -r $(CURDIR)/$(BINDIST_ZIP) plugins bin
$(EXEC): $(OBJS)
$(CC) -o $@ $^ $(LDFLAGS)
@@ -88,4 +96,4 @@ clean:
rm -f $(EXEC) $(OBJS) $(LEGACY_OBJS) $(PLUGINS) $(CONFIG_H)
.PHONY: all clean plugin install-plugin uninstall-plugin fmt
.PHONY: all clean plugin install-plugin uninstall-plugin fmt bindist
+8 -4
View File
@@ -355,10 +355,14 @@ int32_t customAttributeIndex; /* removed at v24.1 */
int32_t typeIndex; /* -> MetadataRegistration.types */
```
Not decoded by r2unity today. Without it, every dumped method
degrades to `Method()` with no parameter types or names. Combined
with `parameterDefaultValues` (§2.4) this is what reconstructs real
C# signatures like `Foo(string name, int count = 0)`.
r2unity decodes this table and exposes parameter tokens, names, and
type indices in `r2unity-sj`; it also emits a canonical signature such
as `Namespace.Type.Foo(this;string:name,int:count):void`. Type indices
that refer directly to a type definition are resolved to source names.
Pointer, array, and constructed-generic indices still require the native
`MetadataRegistration.types` table and use `type_index.N` until that
table is available. `parameterDefaultValues` (§2.4) remains necessary
to reconstruct optional values such as `int count = 0`.
### 2.4 Default values: `fieldDefaultValues`, `parameterDefaultValues`,
`fieldAndParameterDefaultValueData`
+1 -1
View File
@@ -119,7 +119,7 @@ Still missing:
Add or improve decoding for:
- parameters and full method signatures
- generic method/type substitutions in signatures
- default values for fields and parameters
- properties and events
- nested types
+25 -4
View File
@@ -1,7 +1,7 @@
project(
'r2unity',
'c',
version: '1.2.4',
version: '1.2.8',
default_options: [
'c_std=c99',
'warning_level=2',
@@ -17,8 +17,26 @@ add_project_arguments(
language: 'c',
)
r_util_dep = dependency('r_util')
r_bin_dep = dependency('r_bin')
r2 = find_program('r2', required: true)
r2_cflags = run_command(r2, '-H', 'R2_CFLAGS', check: true).stdout().strip().split()
r2_ldflags = run_command(r2, '-H', 'R2_LDFLAGS', check: true).stdout().strip().split()
r2_libs = run_command(r2, '-H', 'R2_LIBS', check: true).stdout().strip().split()
r2_fallback_dep = declare_dependency(
compile_args: r2_cflags,
link_args: r2_ldflags + r2_libs,
)
# Windows release ZIPs are relocatable and are not registered with pkg-config.
# Fall back to the paths reported by r2 when pkg-config cannot find its SDK.
r_util_dep = dependency('r_util', required: false)
if not r_util_dep.found()
r_util_dep = r2_fallback_dep
endif
r_bin_dep = dependency('r_bin', required: false)
if not r_bin_dep.found()
r_bin_dep = r2_fallback_dep
endif
conf = configuration_data()
conf.set_quoted('R2UNITY_VERSION', meson.project_version())
@@ -48,7 +66,10 @@ test('r2unity-help', r2unity, args: ['-h'])
test('r2unity-version', r2unity, args: ['-v'])
plugins_opt = get_option('plugins')
r_core_dep = dependency('r_core', required: plugins_opt)
r_core_dep = dependency('r_core', required: false)
if not r_core_dep.found() and not plugins_opt.disabled()
r_core_dep = r2_fallback_dep
endif
build_plugins = plugins_opt.enabled() or (
plugins_opt.auto() and r_core_dep.found() and r_bin_dep.found()
)
+17 -7
View File
@@ -30,6 +30,10 @@ static void elf_write_word(ut8 *p, ut64 v, bool is64) {
}
}
static bool elf_range_in_file(const ElfImg *e, ut64 off, ut64 size) {
return size <= e->size && off <= e->size - size;
}
static bool elf_load(const char *path, ElfImg *e) {
memset (e, 0, sizeof (*e));
size_t size = 0;
@@ -58,13 +62,16 @@ static bool elf_load(const char *path, ElfImg *e) {
if (type != 1 && type != 2) {
continue;
}
ElfSeg *s = &e->segs[e->nsegs++];
ElfSeg *s = &e->segs[e->nsegs];
s->type = type;
s->flags = r_read_le32 (ph + 4);
s->offset = r_read_le64 (ph + 8);
s->vaddr = r_read_le64 (ph + 16);
s->filesz = r_read_le64 (ph + 32);
s->memsz = r_read_le64 (ph + 40);
if (s->filesz && elf_range_in_file (e, s->offset, s->filesz)) {
e->nsegs++;
}
}
} else {
ut32 phoff = r_read_le32 (e->file + 0x1c);
@@ -80,13 +87,16 @@ static bool elf_load(const char *path, ElfImg *e) {
if (type != 1 && type != 2) {
continue;
}
ElfSeg *s = &e->segs[e->nsegs++];
ElfSeg *s = &e->segs[e->nsegs];
s->type = type;
s->offset = r_read_le32 (ph + 4);
s->vaddr = r_read_le32 (ph + 8);
s->filesz = r_read_le32 (ph + 16);
s->memsz = r_read_le32 (ph + 20);
s->flags = r_read_le32 (ph + 24);
if (s->filesz && elf_range_in_file (e, s->offset, s->filesz)) {
e->nsegs++;
}
}
}
return true;
@@ -104,7 +114,7 @@ static const ut8 *elf_ptr_at_size(ElfImg *e, ut64 va, ut64 size) {
continue;
}
ut64 delta = va - s->vaddr;
if (delta + size <= s->filesz && s->offset + delta + size <= e->size) {
if (size <= s->filesz && delta <= s->filesz - size && elf_range_in_file (e, s->offset + delta, size)) {
return e->file + s->offset + delta;
}
return NULL;
@@ -170,7 +180,7 @@ static void elf_apply_relocs(ElfImg *e, ut64 base) {
break;
}
}
if (!dyn_off || !dyn_sz || dyn_off + dyn_sz > e->size) {
if (!dyn_off || !dyn_sz || !elf_range_in_file (e, dyn_off, dyn_sz)) {
return;
}
ut64 rela_off = 0, rela_sz = 0, rela_ent = e->is64? 24: 12;
@@ -198,7 +208,7 @@ static void elf_apply_relocs(ElfImg *e, ut64 base) {
}
}
const ut64 type_mask = e->is64? 0xffffffffULL: 0xffULL;
for (ut64 i = 0; rela_off && rela_ent && i + rela_ent <= rela_sz; i += rela_ent) {
for (ut64 i = 0; rela_off && rela_ent == (e->is64? 24: 12) && i + rela_ent <= rela_sz; i += rela_ent) {
const ut8 *rp = elf_ptr_at_size (e, rela_off + i, rela_ent);
if (!rp) {
break;
@@ -214,7 +224,7 @@ static void elf_apply_relocs(ElfImg *e, ut64 base) {
}
}
}
for (ut64 i = 0; rel_off && rel_ent && i + rel_ent <= rel_sz; i += rel_ent) {
for (ut64 i = 0; rel_off && rel_ent == (e->is64? 16: 8) && i + rel_ent <= rel_sz; i += rel_ent) {
const ut8 *rp = elf_ptr_at_size (e, rel_off + i, rel_ent);
if (!rp) {
break;
@@ -230,7 +240,7 @@ static void elf_apply_relocs(ElfImg *e, ut64 base) {
}
}
}
if (!e->is64 || !relr_off || !relr_sz || !relr_ent) {
if (!e->is64 || !relr_off || !relr_sz || relr_ent != 8) {
return;
}
ut64 curr = 0;
+125
View File
@@ -295,6 +295,12 @@ static ut64 field_definition_entry_size(R2UnityMetadata *meta) {
return 4 + type_index_size + 4;
}
static ut64 parameter_definition_entry_size(R2UnityMetadata *meta) {
const bool compact_indices = (meta->version >= 35);
const int type_index_size = compact_indices? meta->typeIndexSize: 4;
return 4 + 4 + type_index_size;
}
/* Detect v24.0 vs v24.1+ (both land on disk as version==24).
*
* At v24.1 the ImageDefinition row grew by 8 bytes (added
@@ -507,6 +513,8 @@ R_API ut64 r2unity_metadata_section_entry_size(R2UnityMetadata *meta, R2UMetadat
return method_definition_entry_size (meta);
case R2U_SEC_FIELDS:
return field_definition_entry_size (meta);
case R2U_SEC_PARAMETERS:
return parameter_definition_entry_size (meta);
case R2U_SEC_TYPE_DEFINITIONS:
return type_definition_entry_size (meta);
case R2U_SEC_IMAGES:
@@ -820,6 +828,123 @@ R_API Il2CppFieldDefinition *r2unity_get_field_definitions(R2UnityMetadata *meta
return fields;
}
R_API Il2CppParameterDefinition *r2unity_get_parameter_definitions(R2UnityMetadata *meta, size_t *count) {
R_RETURN_VAL_IF_FAIL (meta && count, NULL);
const bool compact_indices = (meta->version >= 35);
const int type_index_size = compact_indices? meta->typeIndexSize: 4;
const ut64 entry = parameter_definition_entry_size (meta);
ut8 *buf = read_metadata_table (meta, R2U_SEC_PARAMETERS, entry, count);
if (!buf) {
return NULL;
}
Il2CppParameterDefinition *parameters = R_NEWS (Il2CppParameterDefinition, *count);
if (!parameters) {
R_FREE (buf);
return NULL;
}
for (size_t i = 0; i < *count; i++) {
const ut8 *p = buf + i * entry;
parameters[i].nameIndex = read_u32p (&p);
parameters[i].token = read_u32p (&p);
parameters[i].typeIndex = read_indexp (&p, type_index_size);
}
R_FREE (buf);
return parameters;
}
static const char *csharp_type_alias(const char *name) {
static const struct {
const char *fullname;
const char *alias;
} aliases[] = {
{ "System.Void", "void" },
{ "System.Boolean", "bool" },
{ "System.Byte", "byte" },
{ "System.SByte", "sbyte" },
{ "System.Char", "char" },
{ "System.Decimal", "decimal" },
{ "System.Double", "double" },
{ "System.Single", "float" },
{ "System.Int16", "short" },
{ "System.UInt16", "ushort" },
{ "System.Int32", "int" },
{ "System.UInt32", "uint" },
{ "System.Int64", "long" },
{ "System.UInt64", "ulong" },
{ "System.IntPtr", "nint" },
{ "System.UIntPtr", "nuint" },
{ "System.Object", "object" },
{ "System.String", "string" },
};
for (size_t i = 0; i < R_ARRAY_SIZE (aliases); i++) {
if (!strcmp (name, aliases[i].fullname)) {
return aliases[i].alias;
}
}
return NULL;
}
R_API char *r2unity_type_name_from_index(R2UnityMetadata *meta, const Il2CppTypeDefinition *types, size_t type_count, int32_t type_index, bool fallback) {
R_RETURN_VAL_IF_FAIL (meta, NULL);
if (type_index >= 0) {
for (size_t i = 0; types && i < type_count; i++) {
if (types[i].byvalTypeIndex != type_index) {
continue;
}
char *name = r2unity_type_fullname (meta, &types[i], i, R2U_NAME_FALLBACK_TYPE);
if (name) {
const char *alias = csharp_type_alias (name);
if (alias) {
free (name);
return strdup (alias);
}
}
return name;
}
}
return fallback? r_str_newf ("type_index.%d", type_index): NULL;
}
R_API char *r2unity_method_signature(R2UnityMetadata *meta, const Il2CppMethodDefinition *method, const Il2CppTypeDefinition *owner, size_t owner_index, const Il2CppTypeDefinition *types, size_t type_count, const Il2CppParameterDefinition *parameters, size_t parameter_count, bool fallback) {
R_RETURN_VAL_IF_FAIL (meta && method, NULL);
char *return_type = r2unity_type_name_from_index (meta, types, type_count, method->returnType, fallback);
char *method_name = r2unity_method_fullname (meta, method, owner, owner_index,
fallback? R2U_NAME_FALLBACK_TYPE: 0);
if (!method_name) {
free (return_type);
return NULL;
}
RStrBuf *sb = r_strbuf_new (method_name);
r_strbuf_append (sb, "(");
bool is_instance = !(method->flags & 0x0010);
if (is_instance) {
r_strbuf_append (sb, "this;");
}
for (size_t i = 0; i < method->parameterCount; i++) {
st64 pi = (st64)method->parameterStart + (st64)i;
const Il2CppParameterDefinition *parameter = parameters
&& pi >= 0 && (ut64)pi < parameter_count
? &parameters[pi]: NULL;
char *type_name = parameter
? r2unity_type_name_from_index (meta, types, type_count, parameter->typeIndex, fallback)
: NULL;
char *parameter_name = parameter? r2unity_get_string (meta, parameter->nameIndex): NULL;
r_strbuf_appendf (sb, "%s%s", i? ",": "",
type_name? type_name: "unknown");
if (R_STR_ISNOTEMPTY (parameter_name)) {
r_strbuf_appendf (sb, ":%s", parameter_name);
} else {
r_strbuf_appendf (sb, ":arg%zu", i);
}
free (parameter_name);
free (type_name);
}
r_strbuf_appendf (sb, "):%s", return_type? return_type: "unknown");
free (method_name);
free (return_type);
return r_strbuf_drain (sb);
}
R_API int32_t *r2unity_get_type_index_table(R2UnityMetadata *meta, R2UMetadataSectionId id, size_t *count) {
R_RETURN_VAL_IF_FAIL (meta && count, NULL);
const bool compact_indices = (meta->version >= 35);
+9
View File
@@ -130,6 +130,12 @@ typedef struct {
uint32_t token;
} Il2CppFieldDefinition;
typedef struct {
uint32_t nameIndex;
uint32_t token;
int32_t typeIndex;
} Il2CppParameterDefinition;
typedef struct {
uint32_t nameIndex;
int32_t assemblyIndex;
@@ -264,6 +270,9 @@ R_API bool r2unity_read_string_literal(R2UnityMetadata *meta, const Il2CppString
R_API Il2CppTypeDefinition *r2unity_get_type_definitions(R2UnityMetadata *meta, size_t *count);
R_API Il2CppMethodDefinition *r2unity_get_method_definitions(R2UnityMetadata *meta, size_t *count);
R_API Il2CppFieldDefinition *r2unity_get_field_definitions(R2UnityMetadata *meta, size_t *count);
R_API Il2CppParameterDefinition *r2unity_get_parameter_definitions(R2UnityMetadata *meta, size_t *count);
R_API char *r2unity_type_name_from_index(R2UnityMetadata *meta, const Il2CppTypeDefinition *types, size_t type_count, int32_t type_index, bool fallback);
R_API char *r2unity_method_signature(R2UnityMetadata *meta, const Il2CppMethodDefinition *method, const Il2CppTypeDefinition *owner, size_t owner_index, const Il2CppTypeDefinition *types, size_t type_count, const Il2CppParameterDefinition *parameters, size_t parameter_count, bool fallback);
R_API int32_t *r2unity_get_type_index_table(R2UnityMetadata *meta, R2UMetadataSectionId id, size_t *count);
R_API Il2CppImageDefinition *r2unity_get_images(R2UnityMetadata *meta, size_t *count);
R_API int *r2unity_build_type_image_map(const Il2CppImageDefinition *images, size_t image_count, size_t type_count);
-1
View File
@@ -5,7 +5,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <r2unity_config.h>
#include "lib/lib.h"
+126 -60
View File
@@ -189,15 +189,10 @@ static void fill_metadata_sdb(R2UnityBinObj *obj) {
if (!name) {
continue;
}
char key[192];
snprintf (key, sizeof (key), "sections.%s.offset", name);
sdb_num_set (kv, key, sec.offset, 0);
snprintf (key, sizeof (key), "sections.%s.size", name);
sdb_num_set (kv, key, sec.size, 0);
snprintf (key, sizeof (key), "sections.%s.count", name);
sdb_num_set (kv, key, r2unity_metadata_section_count (meta, (R2UMetadataSectionId)i), 0);
snprintf (key, sizeof (key), "sections.%s.entry_size", name);
sdb_num_set (kv, key, r2unity_metadata_section_entry_size (meta, (R2UMetadataSectionId)i), 0);
sdb_num_setf (kv, sec.offset, 0, "sections.%s.offset", name);
sdb_num_setf (kv, sec.size, 0, "sections.%s.size", name);
sdb_num_setf (kv, r2unity_metadata_section_count (meta, (R2UMetadataSectionId)i), 0, "sections.%s.count", name);
sdb_num_setf (kv, r2unity_metadata_section_entry_size (meta, (R2UMetadataSectionId)i), 0, "sections.%s.entry_size", name);
}
sdb_num_set (kv, "counts.types", r2unity_metadata_section_count (meta, R2U_SEC_TYPE_DEFINITIONS), 0);
sdb_num_set (kv, "counts.methods", r2unity_metadata_section_count (meta, R2U_SEC_METHODS), 0);
@@ -225,40 +220,26 @@ static void fill_serialized_file_sdb(R2UnityBinObj *obj) {
sdb_num_set (kv, "counts.scripts", sf->script_count, 0);
sdb_num_set (kv, "counts.externals", sf->external_count, 0);
for (size_t i = 0; i < sf->external_count; i++) {
char key[128];
snprintf (key, sizeof (key), "externals.%zu.path", i);
sdb_set (kv, key, sf->externals[i].path, 0);
sdb_setf (kv, sf->externals[i].path, 0, "externals.%zu.path", i);
}
for (size_t i = 0; i < sf->object_count; i++) {
R2UnitySerializedObject *asset = &sf->objects[i];
char key[128];
snprintf (key, sizeof (key), "objects.%zu.path_id", i);
sdb_num_set (kv, key, (ut64)asset->path_id, 0);
snprintf (key, sizeof (key), "objects.%zu.class_id", i);
sdb_num_set (kv, key, (ut64)(st64)asset->class_id, 0);
snprintf (key, sizeof (key), "objects.%zu.class", i);
sdb_set (kv, key, r2unity_serialized_class_name (asset->class_id), 0);
snprintf (key, sizeof (key), "objects.%zu.offset", i);
sdb_num_set (kv, key, asset->offset, 0);
snprintf (key, sizeof (key), "objects.%zu.size", i);
sdb_num_set (kv, key, asset->size, 0);
sdb_num_setf (kv, (ut64)asset->path_id, 0, "objects.%zu.path_id", i);
sdb_num_setf (kv, (ut64)(st64)asset->class_id, 0, "objects.%zu.class_id", i);
sdb_setf (kv, r2unity_serialized_class_name (asset->class_id), 0, "objects.%zu.class", i);
sdb_num_setf (kv, asset->offset, 0, "objects.%zu.offset", i);
sdb_num_setf (kv, asset->size, 0, "objects.%zu.size", i);
if (asset->name) {
snprintf (key, sizeof (key), "objects.%zu.name", i);
sdb_set (kv, key, asset->name, 0);
sdb_setf (kv, asset->name, 0, "objects.%zu.name", i);
}
if (asset->payload_size) {
snprintf (key, sizeof (key), "objects.%zu.payload.offset", i);
sdb_num_set (kv, key, asset->payload_offset, 0);
snprintf (key, sizeof (key), "objects.%zu.payload.size", i);
sdb_num_set (kv, key, asset->payload_size, 0);
sdb_num_setf (kv, asset->payload_offset, 0, "objects.%zu.payload.offset", i);
sdb_num_setf (kv, asset->payload_size, 0, "objects.%zu.payload.size", i);
}
if (asset->stream_path) {
snprintf (key, sizeof (key), "objects.%zu.stream.path", i);
sdb_set (kv, key, asset->stream_path, 0);
snprintf (key, sizeof (key), "objects.%zu.stream.offset", i);
sdb_num_set (kv, key, asset->stream_offset, 0);
snprintf (key, sizeof (key), "objects.%zu.stream.size", i);
sdb_num_set (kv, key, asset->stream_size, 0);
sdb_setf (kv, asset->stream_path, 0, "objects.%zu.stream.path", i);
sdb_num_setf (kv, asset->stream_offset, 0, "objects.%zu.stream.offset", i);
sdb_num_setf (kv, asset->stream_size, 0, "objects.%zu.stream.size", i);
}
}
}
@@ -278,23 +259,15 @@ static void fill_bgdatabase_sdb(R2UnityBinObj *obj) {
sdb_num_set (kv, "counts.strings", db->string_count, 0);
for (size_t i = 0; i < db->addon_count; i++) {
R2UnityBGDatabaseAddon *addon = &db->addons[i];
char key[128];
snprintf (key, sizeof (key), "addons.%zu.type", i);
sdb_set (kv, key, addon->type, 0);
snprintf (key, sizeof (key), "addons.%zu.payload.offset", i);
sdb_num_set (kv, key, addon->payload_offset, 0);
snprintf (key, sizeof (key), "addons.%zu.payload.size", i);
sdb_num_set (kv, key, addon->payload_size, 0);
sdb_setf (kv, addon->type, 0, "addons.%zu.type", i);
sdb_num_setf (kv, addon->payload_offset, 0, "addons.%zu.payload.offset", i);
sdb_num_setf (kv, addon->payload_size, 0, "addons.%zu.payload.size", i);
}
for (size_t i = 0; i < db->table_count; i++) {
R2UnityBGDatabaseTable *table = &db->tables[i];
char key[128];
snprintf (key, sizeof (key), "tables.%zu.offset", i);
sdb_num_set (kv, key, table->offset, 0);
snprintf (key, sizeof (key), "tables.%zu.size", i);
sdb_num_set (kv, key, table->size, 0);
snprintf (key, sizeof (key), "tables.%zu.fields", i);
sdb_num_set (kv, key, table->field_count, 0);
sdb_num_setf (kv, table->offset, 0, "tables.%zu.offset", i);
sdb_num_setf (kv, table->size, 0, "tables.%zu.size", i);
sdb_num_setf (kv, table->field_count, 0, "tables.%zu.fields", i);
}
}
@@ -308,13 +281,9 @@ static void fill_resource_pack_sdb(R2UnityBinObj *obj) {
sdb_num_set (kv, "counts.resources", pack->entry_count, 0);
for (size_t i = 0; i < pack->entry_count; i++) {
R2UnityResourcePackEntry *entry = &pack->entries[i];
char key[128];
snprintf (key, sizeof (key), "resources.%zu.name", i);
sdb_set (kv, key, entry->name, 0);
snprintf (key, sizeof (key), "resources.%zu.offset", i);
sdb_num_set (kv, key, entry->payload_offset, 0);
snprintf (key, sizeof (key), "resources.%zu.payload_size", i);
sdb_num_set (kv, key, entry->payload_size, 0);
sdb_setf (kv, entry->name, 0, "resources.%zu.name", i);
sdb_num_setf (kv, entry->payload_offset, 0, "resources.%zu.offset", i);
sdb_num_setf (kv, entry->payload_size, 0, "resources.%zu.payload_size", i);
}
}
@@ -835,17 +804,32 @@ static RBinSymbol *new_symbol(const char *name, ut64 paddr, ut64 size, const cha
if (!sym) {
return NULL;
}
#if R2_ABIVERSION >= 138
sym->attr.size = (ut32)R_MIN (size, UT32_MAX);
sym->attr.flags = attr;
sym->attr.lang = R_BIN_LANG_NONE;
#else
sym->size = (ut32)R_MIN (size, UT32_MAX);
sym->type = type;
sym->attr = attr;
sym->ordinal = ordinal;
sym->lang = R_BIN_LANG_NONE;
#endif
sym->type = type;
sym->ordinal = ordinal;
if (classname) {
sym->classname = strdup (classname);
}
return sym;
}
static void set_symbol_signature(RBinSymbol *sym, const char *name, const char *signature) {
if (!sym || !sym->name || !name || !signature) {
return;
}
free (sym->name->name);
sym->name->name = strdup (name);
r_bin_name_update (sym->name, signature);
}
#if R2UNITY_BIN_VEC_ABI
typedef RVecRBinSymbol R2UnitySymbolSink;
@@ -1016,6 +1000,8 @@ static bool symbols_fill(RBinFile *bf, R2UnitySymbolSink *ret) {
size_t method_count = 0;
Il2CppMethodDefinition *methods = r2unity_get_method_definitions (meta, &method_count);
size_t parameter_count = 0;
Il2CppParameterDefinition *parameters = r2unity_get_parameter_definitions (meta, &parameter_count);
ut64 method_entry = r2unity_metadata_section_entry_size (meta, R2U_SEC_METHODS);
Il2CppMetadataSection method_sec;
r2unity_metadata_section (meta, R2U_SEC_METHODS, &method_sec);
@@ -1036,12 +1022,29 @@ static bool symbols_fill(RBinFile *bf, R2UnitySymbolSink *ret) {
classname = r2unity_type_fullname (meta, td, type_idx, R2U_NAME_FALLBACK_TYPE);
}
RBinSymbol *sym = new_symbol (name, method_sec.offset + i * method_entry, method_entry, R_BIN_TYPE_METH_STR, method_attr (methods[i].flags, mn), classname, ordinal++);
if (sym) {
char *signature = r2unity_method_signature (meta, &methods[i], td, type_idx,
types, type_count, parameters, parameter_count, true);
set_symbol_signature (sym, name, signature);
free (signature);
sym->rtype = r2unity_type_name_from_index (meta, types, type_count,
methods[i].returnType, true);
#if R2_ABIVERSION >= 138
sym->attr.lang = R_BIN_LANG_CIL;
sym->arg_count = methods[i].parameterCount
+ ((methods[i].flags & 0x0010)? 0: 1);
sym->cc_arg_count = sym->arg_count;
sym->ret_count = sym->rtype && !strcmp (sym->rtype, "void")? 0: 1;
sym->arg_prefix = "a";
#endif
}
append_symbol (ret, sym);
free (classname);
free (mn);
free (name);
}
R_FREE (parameters);
R_FREE (methods);
R_FREE (types);
R_FREE (asms);
@@ -1087,7 +1090,11 @@ static RList *classes(RBinFile *bf) {
if (klass) {
klass->index = (int)i;
klass->addr = type->offset;
#if R2_ABIVERSION >= 138
klass->attr.lang = R_BIN_LANG_NONE;
#else
klass->lang = R_BIN_LANG_NONE;
#endif
r_list_append (ret, klass);
}
free (name);
@@ -1100,7 +1107,11 @@ static RList *classes(RBinFile *bf) {
RBinClass *klass = r_bin_class_new (name, NULL, R_BIN_ATTR_NONE);
klass->index = (int)i;
klass->addr = obj->bgdb->tables[i].offset;
#if R2_ABIVERSION >= 138
klass->attr.lang = R_BIN_LANG_NONE;
#else
klass->lang = R_BIN_LANG_NONE;
#endif
r_list_append (ret, klass);
free (name);
}
@@ -1115,6 +1126,10 @@ static RList *classes(RBinFile *bf) {
Il2CppTypeDefinition *types = r2unity_get_type_definitions (meta, &type_count);
size_t method_count = 0;
Il2CppMethodDefinition *methods = r2unity_get_method_definitions (meta, &method_count);
size_t parameter_count = 0;
Il2CppParameterDefinition *parameters = r2unity_get_parameter_definitions (meta, &parameter_count);
size_t field_count = 0;
Il2CppFieldDefinition *fields = r2unity_get_field_definitions (meta, &field_count);
Il2CppMetadataSection type_sec;
Il2CppMetadataSection method_sec;
r2unity_metadata_section (meta, R2U_SEC_TYPE_DEFINITIONS, &type_sec);
@@ -1125,16 +1140,48 @@ static RList *classes(RBinFile *bf) {
for (size_t i = 0; types && i < type_count; i++) {
char *ns = get_string (obj, types[i].namespaceIndex);
char *tn = get_string (obj, types[i].nameIndex);
char *base = r2unity_type_name_from_index (meta, types, type_count,
types[i].parentIndex, false);
char *fallback = NULL;
if (!tn || !*tn) {
fallback = r_str_newf ("type.%zu", i);
}
RBinClass *klass = r_bin_class_new ((tn && *tn)? tn: fallback, NULL, type_attr (types[i].flags));
RBinClass *klass = r_bin_class_new ((tn && *tn)? tn: fallback, base, type_attr (types[i].flags));
klass->index = (int)i;
klass->addr = type_sec.offset + i * type_entry;
klass->lang = R_BIN_LANG_NONE;
#if R2_ABIVERSION >= 138
klass->attr.lang = R_BIN_LANG_CIL;
#else
klass->lang = R_BIN_LANG_CIL;
#endif
if (ns && *ns) {
#if R2_ABIVERSION >= 138
klass->attr.ns = strdup (ns);
#else
klass->ns = strdup (ns);
#endif
}
int field_start = types[i].fieldStart;
int fields_in_type = types[i].field_count;
for (int k = 0; fields && k < fields_in_type && field_start >= 0
&& (size_t)(field_start + k) < field_count; k++) {
size_t fi = (size_t)(field_start + k);
char *field_name = get_string (obj, fields[fi].nameIndex);
char *field_type = r2unity_type_name_from_index (meta, types, type_count,
fields[fi].typeIndex, true);
#if R2UNITY_BIN_VEC_ABI
RBinField *field = RVecRBinField_emplace_back (&klass->fields);
if (field) {
field->name = r_bin_name_new (R_STR_ISNOTEMPTY (field_name)? field_name: "field");
field->type = r_bin_name_new (R_STR_ISNOTEMPTY (field_type)? field_type: "unknown");
#if R2_ABIVERSION >= 138
field->attr.kind = R_BIN_FIELD_KIND_FIELD;
field->attr.lang = R_BIN_LANG_CIL;
#endif
}
#endif
free (field_type);
free (field_name);
}
int start = types[i].methodStart;
int count = types[i].method_count;
@@ -1149,16 +1196,35 @@ static RList *classes(RBinFile *bf) {
char *mname = r2unity_method_fullname (meta, &methods[mi], td, type_idx, R2U_NAME_WITH_PARAMS | R2U_NAME_FALLBACK_TYPE);
char *raw = get_string (obj, methods[mi].nameIndex);
RBinSymbol *sym = new_symbol (mname? mname: raw, method_sec.offset + mi * method_entry, method_entry, R_BIN_TYPE_METH_STR, method_attr (methods[mi].flags, raw), NULL, (int)mi);
if (sym) {
char *signature = r2unity_method_signature (meta, &methods[mi], td, type_idx,
types, type_count, parameters, parameter_count, true);
set_symbol_signature (sym, mname? mname: raw, signature);
free (signature);
sym->rtype = r2unity_type_name_from_index (meta, types, type_count,
methods[mi].returnType, true);
#if R2_ABIVERSION >= 138
sym->attr.lang = R_BIN_LANG_CIL;
sym->arg_count = methods[mi].parameterCount
+ ((methods[mi].flags & 0x0010)? 0: 1);
sym->cc_arg_count = sym->arg_count;
sym->ret_count = sym->rtype && !strcmp (sym->rtype, "void")? 0: 1;
sym->arg_prefix = "a";
#endif
}
append_class_method (klass, sym);
free (raw);
free (mname);
}
r_list_append (ret, klass);
free (base);
free (fallback);
free (tn);
free (ns);
}
R_FREE (fields);
R_FREE (parameters);
R_FREE (methods);
R_FREE (types);
return ret;
+45 -27
View File
@@ -441,26 +441,8 @@ static bool enrich_reverse_pinvokes_native(RCore *core, R2UnityMetadata *meta, c
return path && *path && r2unity_enrich_reverse_pinvokes_native (meta, path, &opts, items, count);
}
static int type_definition_for_type_index(const Il2CppTypeDefinition *types, size_t type_count, int32_t type_index) {
if (type_index >= 0) {
for (size_t i = 0; i < type_count; i++) {
if (types[i].byvalTypeIndex == type_index) {
return (int)i;
}
}
}
return -1;
}
static char *type_name_from_index(R2UnityMetadata *meta, const Il2CppTypeDefinition *types, size_t type_count, int32_t type_index, bool fallback) {
int idx = type_definition_for_type_index (types, type_count, type_index);
if (idx >= 0) {
return r2unity_type_fullname (meta, &types[idx], (size_t)idx, R2U_NAME_FALLBACK_TYPE);
}
if (fallback && type_index >= 0) {
return r_str_newf ("type_index.%d", type_index);
}
return NULL;
return r2unity_type_name_from_index (meta, types, type_count, type_index, fallback);
}
static char *field_name_or_fallback(R2UnityMetadata *meta, const Il2CppFieldDefinition *field, size_t index) {
@@ -832,6 +814,8 @@ static int cmd_symbols(RCore *core, char mode) {
Il2CppTypeDefinition *types = r2unity_get_type_definitions (meta, &type_count);
size_t method_count = 0;
Il2CppMethodDefinition *methods = r2unity_get_method_definitions (meta, &method_count);
size_t parameter_count = 0;
Il2CppParameterDefinition *parameters = r2unity_get_parameter_definitions (meta, &parameter_count);
size_t img_count = 0;
Il2CppImageDefinition *images = r2unity_get_images (meta, &img_count);
@@ -876,12 +860,16 @@ static int cmd_symbols(RCore *core, char mode) {
if (!fullname) {
continue;
}
char *signature = r2unity_method_signature (meta, m, td, type_idx,
types, type_count, parameters, parameter_count, true);
char *return_type = r2unity_type_name_from_index (meta, types, type_count,
m->returnType, true);
char *imgname = img? r2unity_get_string (meta, img->nameIndex): NULL;
char flag_buf[1024];
if (imgname && *imgname) {
snprintf (flag_buf, sizeof (flag_buf), "sym.unity.%s.%s", imgname, fullname);
snprintf (flag_buf, sizeof (flag_buf), "sym.unity.%s.%s.%zu", imgname, fullname, j);
} else {
snprintf (flag_buf, sizeof (flag_buf), "sym.unity.%s", fullname);
snprintf (flag_buf, sizeof (flag_buf), "sym.unity.%s.%zu", fullname, j);
}
r_name_filter (flag_buf, -1);
@@ -890,6 +878,33 @@ static int cmd_symbols(RCore *core, char mode) {
if (mode == 'j') {
pj_o (pj);
pj_ks (pj, "name", fullname);
pj_kn (pj, "index", (ut64)j);
pj_hex (pj, "token", m->token, 8);
pj_string_or_null (pj, "signature", signature);
pj_string_or_null (pj, "return_type", return_type);
pj_kb (pj, "static", (m->flags & 0x0010) != 0);
pj_ka (pj, "parameters");
for (size_t k = 0; k < m->parameterCount; k++) {
st64 pi = (st64)m->parameterStart + (st64)k;
const Il2CppParameterDefinition *parameter = pi >= 0 && (ut64)pi < parameter_count
? &parameters[pi]: NULL;
char *parameter_name = parameter? r2unity_get_string (meta, parameter->nameIndex): NULL;
char *parameter_type = parameter
? r2unity_type_name_from_index (meta, types, type_count, parameter->typeIndex, true)
: NULL;
pj_o (pj);
pj_kn (pj, "index", k);
if (parameter) {
pj_ki (pj, "type_index", parameter->typeIndex);
pj_hex (pj, "token", parameter->token, 8);
}
pj_string_or_null (pj, "name", parameter_name);
pj_string_or_null (pj, "type", parameter_type);
pj_end (pj);
free (parameter_type);
free (parameter_name);
}
pj_end (pj);
pj_ks (pj, "flag", flag_buf);
if (imgname) {
pj_ks (pj, "image", imgname);
@@ -903,11 +918,11 @@ static int cmd_symbols(RCore *core, char mode) {
if (addr > 0x1000) {
r_cons_printf (core->cons, "'@0x%" PFMT64x "'f %s\n", addr, flag_buf);
if (imgname && *imgname) {
r_cons_printf (core->cons, "'@0x%" PFMT64x "'CCu Method: [%s]%s%s %s\n", addr, imgname, *attrs? " ": "", attrs, fullname);
r_cons_printf (core->cons, "'@0x%" PFMT64x "'CCu Method: [%s]%s%s %s\n", addr, imgname, *attrs? " ": "", attrs, signature? signature: fullname);
} else if (*attrs) {
r_cons_printf (core->cons, "'@0x%" PFMT64x "'CCu Method: %s %s\n", addr, attrs, fullname);
r_cons_printf (core->cons, "'@0x%" PFMT64x "'CCu Method: %s %s\n", addr, attrs, signature? signature: fullname);
} else {
r_cons_printf (core->cons, "'@0x%" PFMT64x "'CCu Method: %s\n", addr, fullname);
r_cons_printf (core->cons, "'@0x%" PFMT64x "'CCu Method: %s\n", addr, signature? signature: fullname);
}
listed++;
}
@@ -921,11 +936,11 @@ static int cmd_symbols(RCore *core, char mode) {
imgname,
*attrs? " ": "",
attrs,
fullname);
signature? signature: fullname);
} else if (*attrs) {
comment = r_str_newf ("Method: %s %s", attrs, fullname);
comment = r_str_newf ("Method: %s %s", attrs, signature? signature: fullname);
} else {
comment = r_str_newf ("Method: %s", fullname);
comment = r_str_newf ("Method: %s", signature? signature: fullname);
}
if (comment) {
r_meta_set_string (core->anal, R_META_TYPE_COMMENT, addr, comment);
@@ -937,6 +952,8 @@ static int cmd_symbols(RCore *core, char mode) {
free (attrs);
free (imgname);
free (return_type);
free (signature);
free (fullname);
}
@@ -956,6 +973,7 @@ static int cmd_symbols(RCore *core, char mode) {
r2unity_native_result_fini (&native_result);
R_FREE (type2img);
R_FREE (images);
R_FREE (parameters);
R_FREE (methods);
R_FREE (types);
close_metadata (meta, buf);