mirror of
https://github.com/JogmansonReal/Radicade.git
synced 2026-10-25 15:09:26 -07:00
125 lines
6.1 KiB
C
125 lines
6.1 KiB
C
// Read-only runtime metadata inspection; no account values or method calls.
|
|
#include <android/log.h>
|
|
#include <dlfcn.h>
|
|
#include <jni.h>
|
|
#include <pthread.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#define LOG(...) __android_log_print(ANDROID_LOG_INFO, "RadicadePlatform", __VA_ARGS__)
|
|
#define API(name, ret, args) ret (*name) args = (ret (*) args)dlsym(lib, #name); if (!name) { LOG("Missing API: %s", #name); return 0; }
|
|
static void *inspect(void *unused) {
|
|
(void)unused;
|
|
// Let Unity finish its single-threaded runtime initialization first.
|
|
sleep(30);
|
|
void *lib = 0;
|
|
for (int i = 0; i < 120 && !lib; ++i) {
|
|
lib = dlopen("libil2cpp.so", RTLD_NOW | RTLD_NOLOAD);
|
|
if (!lib) sleep(1);
|
|
}
|
|
if (!lib) { LOG("IL2CPP not loaded within 120 seconds"); return 0; }
|
|
API(il2cpp_domain_get, void *, (void));
|
|
API(il2cpp_domain_get_assemblies, const void **, (void *, size_t *));
|
|
API(il2cpp_thread_attach, void *, (void *));
|
|
API(il2cpp_thread_detach, void, (void *));
|
|
API(il2cpp_assembly_get_image, void *, (const void *));
|
|
API(il2cpp_image_get_name, const char *, (void *));
|
|
API(il2cpp_image_get_class_count, size_t, (void *));
|
|
API(il2cpp_image_get_class, void *, (void *, size_t));
|
|
API(il2cpp_class_get_name, const char *, (void *));
|
|
API(il2cpp_class_get_namespace, const char *, (void *));
|
|
API(il2cpp_class_from_name, void *, (void *, const char *, const char *));
|
|
API(il2cpp_class_get_methods, const void *, (void *, void **));
|
|
API(il2cpp_method_get_name, const char *, (const void *));
|
|
API(il2cpp_method_get_param_count, uint32_t, (const void *));
|
|
API(il2cpp_class_get_fields, void *, (void *, void **));
|
|
API(il2cpp_field_get_name, const char *, (void *));
|
|
API(il2cpp_field_get_offset, size_t, (void *));
|
|
API(il2cpp_field_get_type, void *, (void *));
|
|
API(il2cpp_type_get_name, char *, (void *));
|
|
API(il2cpp_free, void, (void *));
|
|
void *domain = 0;
|
|
size_t count = 0;
|
|
const void **assemblies = 0;
|
|
for (int i = 0; i < 120; ++i) {
|
|
domain = il2cpp_domain_get();
|
|
if (domain) assemblies = il2cpp_domain_get_assemblies(domain, &count);
|
|
if (count) break;
|
|
sleep(1);
|
|
}
|
|
if (!domain || !count) { LOG("IL2CPP domain unavailable"); return 0; }
|
|
void *thread = il2cpp_thread_attach(domain);
|
|
if (!thread) { LOG("Thread attach failed"); return 0; }
|
|
char fields_path[192], map_path[192];
|
|
unsigned user = (unsigned)getuid() / 100000;
|
|
snprintf(fields_path, sizeof(fields_path), "/data/user/%u/com.radicade.questtls/files/quest-recnet-fields.tsv", user);
|
|
snprintf(map_path, sizeof(map_path), "/data/user/%u/com.radicade.questtls/files/quest-method-map.tsv", user);
|
|
FILE *fields = fopen(fields_path, "w");
|
|
FILE *map = fopen(map_path, "w");
|
|
if (map) {
|
|
for (size_t a = 0; a < count; ++a) {
|
|
void *img = il2cpp_assembly_get_image(assemblies[a]);
|
|
size_t classes = il2cpp_image_get_class_count(img);
|
|
for (size_t c = 0; c < classes; ++c) {
|
|
void *klass = il2cpp_image_get_class(img, c);
|
|
if (!klass) continue;
|
|
if (fields && !strncmp(il2cpp_image_get_name(img), "RecNet.", 7)) {
|
|
void *fi = 0, *f;
|
|
while ((f = il2cpp_class_get_fields(klass, &fi))) {
|
|
char *tn = il2cpp_type_get_name(il2cpp_field_get_type(f));
|
|
fprintf(fields, "%s\t%s\t%zx\t%s\n", il2cpp_class_get_name(klass), il2cpp_field_get_name(f), il2cpp_field_get_offset(f), tn ? tn : "?");
|
|
if (tn) il2cpp_free(tn);
|
|
}
|
|
}
|
|
void *iter = 0;
|
|
const void *method;
|
|
while ((method = il2cpp_class_get_methods(klass, &iter))) {
|
|
void *code = *(void *const *)method;
|
|
Dl_info info = {0};
|
|
if (code && dladdr(code, &info))
|
|
fprintf(map, "%lx\t%s\t%s\t%s\t%s\t%u\n",
|
|
(unsigned long)((uintptr_t)code - (uintptr_t)info.dli_fbase),
|
|
il2cpp_image_get_name(img), il2cpp_class_get_namespace(klass),
|
|
il2cpp_class_get_name(klass), il2cpp_method_get_name(method),
|
|
il2cpp_method_get_param_count(method));
|
|
}
|
|
}
|
|
}
|
|
fclose(map);
|
|
LOG("Full method map saved (metadata only)");
|
|
} else LOG("Cannot open method map output");
|
|
const char *names[] = {"PlatformManager", "PlatformManagerBootstrapper", "OculusPlatformManager", "StandalonePlatformManager", "GooglePlayPlatformManager", "BootSequence"};
|
|
for (size_t a = 0; a < count; ++a) {
|
|
void *img = il2cpp_assembly_get_image(assemblies[a]);
|
|
if (strcmp(il2cpp_image_get_name(img), "Assembly-CSharp.dll")) continue;
|
|
for (size_t n = 0; n < sizeof(names)/sizeof(names[0]); ++n) {
|
|
void *klass = il2cpp_class_from_name(img, "", names[n]);
|
|
LOG("Class %s found=%d", names[n], klass != 0);
|
|
if (!klass) continue;
|
|
void *iter = 0;
|
|
const void *method;
|
|
while ((method = il2cpp_class_get_methods(klass, &iter))) {
|
|
void *code = *(void *const *)method;
|
|
Dl_info info = {0};
|
|
uintptr_t rva = dladdr(code, &info) ? (uintptr_t)code - (uintptr_t)info.dli_fbase : 0;
|
|
LOG("Method %s.%s argc=%u rva=0x%lx", names[n], il2cpp_method_get_name(method), il2cpp_method_get_param_count(method), (unsigned long)rva);
|
|
}
|
|
iter = 0;
|
|
void *field;
|
|
while ((field = il2cpp_class_get_fields(klass, &iter)))
|
|
LOG("Field %s.%s offset=0x%lx", names[n], il2cpp_field_get_name(field), (unsigned long)il2cpp_field_get_offset(field));
|
|
}
|
|
}
|
|
if (fields) fclose(fields);
|
|
il2cpp_thread_detach(thread);
|
|
LOG("Inspection complete");
|
|
return 0;
|
|
}
|
|
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
|
|
(void)vm; (void)reserved;
|
|
pthread_t thread;
|
|
if (!pthread_create(&thread, 0, inspect, 0)) pthread_detach(thread);
|
|
return JNI_VERSION_1_6;
|
|
}
|