From 2c104648cdd62c01da0d7bc16d781a52b1771c78 Mon Sep 17 00:00:00 2001 From: Guus Waals <_@guusw.nl> Date: Fri, 30 May 2025 02:02:43 +0800 Subject: [PATCH] WIP setup CRT --- game_re/CMakeLists.txt | 18 +++ game_re/gh_datasegment.bin | 4 +- game_re/gh_datasegment.h | 4 +- game_re/gh_fix/entry.cxx | 89 +++++++++++++++ game_re/gh_fix/r3_main.cxx | 28 +++-- game_re/gh_global.cxx | 12 +- game_re/gh_global.h | 12 +- game_re/r3/binders/dbg_mem.cxx | 136 +++++++++++++++++++++-- game_re/r3/binders/stub.h | 2 +- game_re/r3/main.cxx | 6 + java/ghidra/DumpGlobals.java | 28 +++++ java/ghidra/ExportData.java | 2 +- java/ghidra/re3lib/FunctionDatabase.java | 2 +- java/ghidra/re3lib/GlobalDumper.java | 20 +++- java/ghidra/re3lib/RemanConfig.java | 5 +- 15 files changed, 334 insertions(+), 34 deletions(-) create mode 100644 game_re/gh_fix/entry.cxx create mode 100644 java/ghidra/DumpGlobals.java diff --git a/game_re/CMakeLists.txt b/game_re/CMakeLists.txt index 5dc0213e..a891f6df 100644 --- a/game_re/CMakeLists.txt +++ b/game_re/CMakeLists.txt @@ -64,11 +64,29 @@ function(setup_target TARGET DBG_MODE) "$<$:${CMAKE_CURRENT_SOURCE_DIR}/r3/binders/auto_pch.cxx>" ) + # Potentially might want 1/1 translation for code + # For now it has the following values: + # 0 = 100% original (as possible) + # 1 = Runtime QOL (no cd checks, windowed mode, etc.) + target_compile_definitions(${TARGET} PRIVATE + RE_AUTHENTIC=1 + ) + if(DBG_MODE) target_sources(${TARGET} PRIVATE r3/binders/dbg_mem.cxx ) target_compile_definitions(game_dbg PRIVATE RE_DBG_INJECTED=1) + + # We load the original binary at it's original location, so offset the base address + target_link_options(${TARGET} PRIVATE + -Wl,/BASE:0x20000000 + -Wl,/DYNAMICBASE:NO + ) + target_link_libraries(${TARGET} PRIVATE + DbgHelp + ) + else() target_sources(${TARGET} PRIVATE r3/binders/static_mem.cxx diff --git a/game_re/gh_datasegment.bin b/game_re/gh_datasegment.bin index a6af1ada..ec0f30a5 100644 --- a/game_re/gh_datasegment.bin +++ b/game_re/gh_datasegment.bin @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2683e3449586f0084b5a6a01b6e2de45030593764fc06c5acd00ed1d46925c50 -size 2805759 +oid sha256:129e713daef322e9b2dbde50da936d3801770275814bf67d06d5ee294dd0c170 +size 4472831 diff --git a/game_re/gh_datasegment.h b/game_re/gh_datasegment.h index fe83084e..e1112d0a 100644 --- a/game_re/gh_datasegment.h +++ b/game_re/gh_datasegment.h @@ -3,9 +3,9 @@ #pragma once #include -#define GH_DATA_START 0x00597000 +#define GH_DATA_START 0x00400000 #define GH_DATA_END 0x00843fff #define GH_DATA_SIZE (GH_DATA_END - GH_DATA_START) -constexpr size_t gh_data_start = 0x00597000; +constexpr size_t gh_data_start = 0x00400000; constexpr size_t gh_data_end = 0x00843fff; constexpr size_t gh_data_size = gh_data_end - gh_data_start; diff --git a/game_re/gh_fix/entry.cxx b/game_re/gh_fix/entry.cxx new file mode 100644 index 00000000..d2d643f6 --- /dev/null +++ b/game_re/gh_fix/entry.cxx @@ -0,0 +1,89 @@ +// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!! + +#include +#include +#include +#include + +extern "C" { +undefined4 crt_createProgramHeap(undefined4 param_1) { + return gh_stub_impl_cdecl((void *)0x00404902, param_1); +} +undefined4 ioinit(void) { + return gh_stub_impl_cdecl((void *)0x004046bf); +} +void crt_initConsole(void) { + return gh_stub_impl_cdecl((void *)0x00404503); +} +LPSTR crt_setupEnv(void) { + return gh_stub_impl_cdecl((void *)0x004043d1); +} +undefined4 crt_main2(void) { + return gh_stub_impl_cdecl((void *)0x00404184); +} +undefined4 crt_main1(void) { + return gh_stub_impl_cdecl((void *)0x004040cb); +} +void c_static_init(void) { + return gh_stub_impl_cdecl((void *)0x004027be); +} + +char* crt_0(void) { + return gh_stub_impl_cdecl((void *)0x00404073); +} + +void gh_pre_main(void) { + DWORD DVar1; + int iVar2; + LPSTR *cmdline; + uint showCmd; + HMODULE hInstance; + HINSTANCE hPrevInstance; + _STARTUPINFOA local_60; + undefined1 *local_1c; + void *pvStack_14; + undefined1 *puStack_10; + undefined *puStack_c; + undefined4 local_8; + + local_8 = 0xffffffff; + // This sets up the unhandled exception handler i think? + // puStack_c = &DAT_00597ca0; + // puStack_10 = &LAB_00404a58; + // pvStack_14 = ExceptionList; + // local_1c = &stack0xffffff88; + // ExceptionList = &pvStack_14; + DVar1 = GetVersion(); + DWORD_005cf980 = DVar1 >> 8 & 0xff; + DWORD_005cf97c = DVar1 & 0xff; + DWORD_005cf978 = DWORD_005cf97c * 0x100 + DWORD_005cf980; + DWORD_005cf974 = DVar1 >> 0x10; + iVar2 = crt_createProgramHeap(1); + if (iVar2 == 0) { + SPDLOG_ERROR("crt_createProgramHeap failed"); + exit(0); + } + iVar2 = ioinit(); + if (iVar2 == 0) { + SPDLOG_ERROR("_ioinit failed"); + exit(0); + } + local_8 = 0; + crt_initConsole(); + g_crt_cmdLine = GetCommandLineA(); + PTR_005cf9b4 = crt_setupEnv(); + crt_main2(); + crt_main1(); + c_static_init(); + local_60.dwFlags = 0; + GetStartupInfoA(&local_60); + cmdline = (LPSTR *)crt_0(); + if ((local_60.dwFlags & 1) == 0) { + showCmd = 10; + } else { + showCmd = (uint)local_60.wShowWindow; + } + hPrevInstance = (HINSTANCE)0x0; + hInstance = GetModuleHandleA((LPCSTR)0x0); +} +} \ No newline at end of file diff --git a/game_re/gh_fix/r3_main.cxx b/game_re/gh_fix/r3_main.cxx index 06cb12b1..5b4046e8 100644 --- a/game_re/gh_fix/r3_main.cxx +++ b/game_re/gh_fix/r3_main.cxx @@ -82,7 +82,8 @@ int r3_main(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR *cmdline,int showC LPRECT lpRect; LPHANDLE lpTargetHandle; undefined4 uVar22; - + +#if RE_AUTHENTIC == 0 lpBuffer = pathToUbi_ini; uiParam = 0x104; /* Append windows dir / ubi.ini */ @@ -111,17 +112,17 @@ int r3_main(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR *cmdline,int showC pcVar4[(int)(tStack_820 + iVar13)] = cVar1; pcVar4 = pcVar4 + 1; } while (cVar1 != '\0'); - pcVar4 = strrchr(tStack_820,0x5c); + pcVar4 = strrchr(tStack_820,0x5c); // Get the exe path if (pcVar4 == (char *)0x0) { /* Read from ubi.ini */ GetPrivateProfileStringA (lpAppName_005b68f0,s_Directory_005b68f8,s_None,tStack_820,0xff,acStack_61c); iVar13 = strcmpi(tStack_820,s_None); } - else { + else { // We have the .exe path pcVar4 = strrchr(tStack_820,0x5c); - *pcVar4 = '\0'; - iVar13 = chdir(tStack_820); + *pcVar4 = '\0'; // Split into the binary path (strip .exe) + iVar13 = chdir(tStack_820); // Change into the binary path if (iVar13 != -1) goto LAB_00401765; /* Read from ubi.ini */ GetPrivateProfileStringA @@ -244,7 +245,7 @@ LAB_004017ce: /* Setup localized quiting/restoring strings */ iVar13 = strcmpi(aCStack_71c,s_French_005b6828); if (iVar13 == 0) { - sprintf(s_windowTitleRestoring,s_Restauration_fmt,s_windowTitle); + sprintf(g_windowTitleRestoring,s_Restauration_fmt,s_windowTitle); chars = s_QUITTER + Field<4, 4>(); pcVar4 = s_ou_appuyez_sur_Echap_pour_quitte_005b67d0; pcVar17 = s_quitting1; @@ -279,7 +280,7 @@ LAB_004017ce: else { iVar13 = strcmpi(aCStack_71c,s_Spanish_005b67a0); if (iVar13 == 0) { - sprintf(s_windowTitleRestoring,s__s___Restablecer_datos____005b6784,s_windowTitle); + sprintf(g_windowTitleRestoring,s__s___Restablecer_datos____005b6784,s_windowTitle); uVar2 = s_SALIR_005b675c + Field<4, 2>(); pcVar4 = s_Pulsa_ESC_para_salir_Rayman_3__005b6764; pcVar17 = s_quitting1; @@ -319,7 +320,7 @@ LAB_004017ce: else { iVar13 = strcmpi(aCStack_71c,s_Italian_005b6730); if (iVar13 == 0) { - sprintf(s_windowTitleRestoring,s__s___Ripristino_dati____005b6718,s_windowTitle); + sprintf(g_windowTitleRestoring,s__s___Ripristino_dati____005b6718,s_windowTitle); uVar2 = s_USCIRE_005b66ec + Field<4, 2>(); pcVar4 = s_Premi_ESC_per_uscire_da_Rayman_3_005b66f4; pcVar17 = s_quitting1; @@ -360,7 +361,7 @@ LAB_004017ce: else { iVar13 = strcmpi(aCStack_71c,s_German_005b66c4); if (iVar13 == 0) { - sprintf(s_windowTitleRestoring,s__s___Daten_Reparatur____005b66ac,s_windowTitle); + sprintf(g_windowTitleRestoring,s__s___Daten_Reparatur____005b66ac,s_windowTitle); chars = s_BEENDIGEN_005b6678 + Field<0, 4>(); pcVar4 = &CHAR_E_005b6684; pcVar17 = s_quitting1; @@ -420,7 +421,7 @@ LAB_004017ce: s_wndStrRestoring[0x12] = s_Daten_Reparatur____005b6664[0x12]; } else { - sprintf(s_windowTitleRestoring,s__s___Restoring_data____005b664c,s_windowTitle); + sprintf(g_windowTitleRestoring,s__s___Restoring_data____005b664c,s_windowTitle); chars = s_QUIT + Field<0, 4>(); pcVar4 = s_or_press_ESC_to_quit_Rayman_3__005b662c; pcVar17 = s_quitting1; @@ -462,6 +463,13 @@ LAB_004017ce: } } } +#else + strcpy(g_windowTitle, "Reman3"); + strcpy(g_windowTitle1, "Reman3 - Paused"); + strcpy(g_windowTitleRestoring, "Restoring data"); + + +#endif /* Create draw semaphore Initial count = 1 Maximum count = 1 */ diff --git a/game_re/gh_global.cxx b/game_re/gh_global.cxx index 5f3321bc..d49cc3a3 100644 --- a/game_re/gh_global.cxx +++ b/game_re/gh_global.cxx @@ -1,5 +1,7 @@ // AUTO-GENERATED FILE #include +undefined4& crt_unhandled_exception_handler= (undefined4&) GH_MEM(0x00404a58); +undefined4& DAT_00597ca0= (undefined4&) GH_MEM(0x00597ca0); char(&s__s_not_initialized__005b63e0)[20] = reinterpret_cast(GH_MEM(0x005b63e0)); char(&s_Please_run_the__s_setup__005b63f4)[28] = reinterpret_cast(GH_MEM(0x005b63f4)); char(&s_dashCC)[4] = reinterpret_cast(GH_MEM(0x005b6410)); @@ -58,6 +60,11 @@ const char* s_Directory_005b68f8 = "Directory"; // 005b68f8 const char* s_None = "None"; // 005b6904 const char* s_UbiSoft_Ubi_ini = "/UbiSoft/Ubi.ini"; // 005b690c long& lpDefault_005cf96c= (long&) GH_MEM(0x005cf96c); +dword& DWORD_005cf974= (dword&) GH_MEM(0x005cf974); +dword& DWORD_005cf978= (dword&) GH_MEM(0x005cf978); +dword& DWORD_005cf97c= (dword&) GH_MEM(0x005cf97c); +dword& DWORD_005cf980= (dword&) GH_MEM(0x005cf980); +char *& PTR_005cf9b4= (char *&) GH_MEM(0x005cf9b4); r3_main_data& r3_main_data_005d28b6= (r3_main_data&) GH_MEM(0x005d28b6); int& g_runMaximized= (int&) GH_MEM(0x0077d0a8); undefined4& g_engineRunning= (undefined4&) GH_MEM(0x0077d0b4); @@ -65,12 +72,13 @@ HANDLE& g_drawSemaphore= (HANDLE&) GH_MEM(0x0077d0bc); char(&g_mutexName_Rayman3)[256] = reinterpret_cast(GH_MEM(0x0077d0c0)); char(&g_windowTitle)[256] = reinterpret_cast(GH_MEM(0x0077d1c0)); char(&g_windowTitle1)[256] = reinterpret_cast(GH_MEM(0x0077d2c0)); -char(&s_windowTitleRestoring)[256] = reinterpret_cast(GH_MEM(0x0077d3c0)); +char(&g_windowTitleRestoring)[256] = reinterpret_cast(GH_MEM(0x0077d3c0)); HINSTANCE& g_hinstance= (HINSTANCE&) GH_MEM(0x0077d4c0); HWND& g_gameHWND= (HWND&) GH_MEM(0x0077d4c4); HANDLE& g_mainThreadHandle= (HANDLE&) GH_MEM(0x0077d4c8); char(&g_appCmdLine)[256] = reinterpret_cast(GH_MEM(0x0077d4e0)); char(&s_wndStrRestoring)[256] = reinterpret_cast(GH_MEM(0x0077d5e0)); +char *& g_crt_cmdLine= (char *&) GH_MEM(0x0077ea84); char(&s_quitting1)[64] = reinterpret_cast(GH_MEM(0x007825c0)); char(&s_wndStrQuiting)[56] = reinterpret_cast(GH_MEM(0x00782600)); -uint& DAT_007d9cc4= (uint&) GH_MEM(0x007d9cc4); +undefined4& DAT_007d9cc4= (undefined4&) GH_MEM(0x007d9cc4); diff --git a/game_re/gh_global.h b/game_re/gh_global.h index eac15481..abc386f8 100644 --- a/game_re/gh_global.h +++ b/game_re/gh_global.h @@ -5,6 +5,8 @@ #include +extern undefined4& crt_unhandled_exception_handler; // 00404a58 +extern undefined4& DAT_00597ca0; // 00597ca0 extern char(&s__s_not_initialized__005b63e0)[20]; // 005b63e0 extern char(&s_Please_run_the__s_setup__005b63f4)[28]; // 005b63f4 extern char(&s_dashCC)[4]; // 005b6410 @@ -63,6 +65,11 @@ extern const char* s_Directory_005b68f8; // 005b68f8 extern const char* s_None; // 005b6904 extern const char* s_UbiSoft_Ubi_ini; // 005b690c extern long& lpDefault_005cf96c; // 005cf96c +extern dword& DWORD_005cf974; // 005cf974 +extern dword& DWORD_005cf978; // 005cf978 +extern dword& DWORD_005cf97c; // 005cf97c +extern dword& DWORD_005cf980; // 005cf980 +extern char *& PTR_005cf9b4; // 005cf9b4 extern r3_main_data& r3_main_data_005d28b6; // 005d28b6 extern int& g_runMaximized; // 0077d0a8 extern undefined4& g_engineRunning; // 0077d0b4 @@ -70,13 +77,14 @@ extern HANDLE& g_drawSemaphore; // 0077d0bc extern char(&g_mutexName_Rayman3)[256]; // 0077d0c0 extern char(&g_windowTitle)[256]; // 0077d1c0 extern char(&g_windowTitle1)[256]; // 0077d2c0 -extern char(&s_windowTitleRestoring)[256]; // 0077d3c0 +extern char(&g_windowTitleRestoring)[256]; // 0077d3c0 extern HINSTANCE& g_hinstance; // 0077d4c0 extern HWND& g_gameHWND; // 0077d4c4 extern HANDLE& g_mainThreadHandle; // 0077d4c8 extern char(&g_appCmdLine)[256]; // 0077d4e0 extern char(&s_wndStrRestoring)[256]; // 0077d5e0 +extern char *& g_crt_cmdLine; // 0077ea84 extern char(&s_quitting1)[64]; // 007825c0 extern char(&s_wndStrQuiting)[56]; // 00782600 -extern uint& DAT_007d9cc4; // 007d9cc4 +extern undefined4& DAT_007d9cc4; // 007d9cc4 #endif // GH_GENERATED_GLOBALS_H diff --git a/game_re/r3/binders/dbg_mem.cxx b/game_re/r3/binders/dbg_mem.cxx index a049b27d..4fd6046e 100644 --- a/game_re/r3/binders/dbg_mem.cxx +++ b/game_re/r3/binders/dbg_mem.cxx @@ -1,10 +1,134 @@ #include "r3/config/static.hpp" #include +#include +#include + +#define GH_BASE_ADDR 0x00400000 + +static uintptr_t g_gh_translationOffset{}; struct R3Bin { - R3Bin() { SPDLOG_DEBUG("R3Bin constructor"); } + R3Bin() { loadOriginal(); } - static R3Bin& get() { + void loadOriginal() { + SPDLOG_DEBUG("Loading original binary"); + + auto &config = getDefaultConfig(); + std::string path = config.gameRootDir + "/Rayman3.exe"; + module = LoadLibraryA(path.c_str()); + if (!module) + throw std::runtime_error("Failed to load original binary"); + + fixupImports(module); + + g_gh_translationOffset = translationOffset = + uintptr_t(module) - GH_BASE_ADDR; + } + + // Translate address relative from the original image base address + void *translateAddress(void *original) { + uint8_t *runtime_addr = + reinterpret_cast(original) + translationOffset; + return reinterpret_cast(runtime_addr); + } + + void fixupImports(HINSTANCE h) { + // Find the IAT size + DWORD ulsize = 0; + PIMAGE_IMPORT_DESCRIPTOR pImportDesc = + (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData( + h, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulsize); + if (!pImportDesc) + return; + + // Loop names + for (; pImportDesc->Name; pImportDesc++) { + PSTR pszModName = (PSTR)((PBYTE)h + pImportDesc->Name); + if (!pszModName) + break; + + HINSTANCE hImportDLL = LoadLibraryA(pszModName); + if (!hImportDLL) { + // ... (error) + } + + // Get caller's import address table (IAT) for the callee's functions + PIMAGE_THUNK_DATA pThunk = + (PIMAGE_THUNK_DATA)((PBYTE)h + pImportDesc->FirstThunk); + + // Replace current function address with new function address + for (; pThunk->u1.Function; pThunk++) { + FARPROC pfnNew = 0; + size_t rva = 0; +#ifdef _WIN64 + if (pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG64) +#else + if (pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG32) +#endif + { + // Ordinal +#ifdef _WIN64 + size_t ord = IMAGE_ORDINAL64(pThunk->u1.Ordinal); +#else + size_t ord = IMAGE_ORDINAL32(pThunk->u1.Ordinal); +#endif + + PROC *ppfn = (PROC *)&pThunk->u1.Function; + if (!ppfn) { + // ... (error) + } + rva = (size_t)pThunk; + + char fe[100] = {0}; + sprintf_s(fe, 100, "#%u", ord); + pfnNew = GetProcAddress(hImportDLL, (LPCSTR)ord); + if (!pfnNew) { + // ... (error) + } + } else { + // Get the address of the function address + PROC *ppfn = (PROC *)&pThunk->u1.Function; + if (!ppfn) { + // ... (error) + } + rva = (size_t)pThunk; + PSTR fName = (PSTR)h; + fName += pThunk->u1.Function; + fName += 2; + if (!fName) + break; + pfnNew = GetProcAddress(hImportDLL, fName); + if (!pfnNew) { + // ... (error) + } + } + + // Patch it now... + auto hp = GetCurrentProcess(); + if (!WriteProcessMemory(hp, (LPVOID *)rva, &pfnNew, sizeof(pfnNew), + NULL) && + (ERROR_NOACCESS == GetLastError())) { + DWORD dwOldProtect; + if (VirtualProtect((LPVOID)rva, sizeof(pfnNew), PAGE_WRITECOPY, + &dwOldProtect)) { + if (!WriteProcessMemory(GetCurrentProcess(), (LPVOID *)rva, &pfnNew, + sizeof(pfnNew), NULL)) { + // ... (error) + } + if (!VirtualProtect((LPVOID)rva, sizeof(pfnNew), dwOldProtect, + &dwOldProtect)) { + // ... (error) + } + } + } + } + } + } + + HINSTANCE module; + uintptr_t translationOffset; + + static R3Bin &get() { static R3Bin instance; return instance; } @@ -13,13 +137,11 @@ struct R3Bin { uint8_t *gh_map_dbg_mem(size_t addr) { R3Bin::get(); SPDLOG_DEBUG("Mapping debug memory at {}", addr); - return nullptr; + return (uint8_t *)R3Bin::get().translateAddress((void *)addr); } void *gh_stub_impl_ptr(void *ptr) { R3Bin::get(); SPDLOG_DEBUG("Forwarding implementation at {}", ptr); - return nullptr; + return (void *)R3Bin::get().translateAddress((void *)ptr); } -void gh_init_dbg_loader() { - SPDLOG_DEBUG("Initializing debug loader"); -} \ No newline at end of file +void gh_init_dbg_loader() { R3Bin::get(); } \ No newline at end of file diff --git a/game_re/r3/binders/stub.h b/game_re/r3/binders/stub.h index 2e8f347a..5b17c7d8 100644 --- a/game_re/r3/binders/stub.h +++ b/game_re/r3/binders/stub.h @@ -11,7 +11,7 @@ void *gh_stub_impl_ptr(void *ptr); template T gh_stub_impl_cdecl(void *ptr_, Args... args) { -#if RE_DBG_INJECTED +#if RE_DBG_INJECTED using Callable = __cdecl T (*)(Args...); static Callable fn = (Callable)gh_stub_impl_ptr(ptr_); return fn(args...); diff --git a/game_re/r3/main.cxx b/game_re/r3/main.cxx index f8b23682..3d9574e0 100644 --- a/game_re/r3/main.cxx +++ b/game_re/r3/main.cxx @@ -6,6 +6,11 @@ #if RE_DBG_INJECTED #include +extern "C" { +// This is the part of Rayman3.exe main CRT setup that runs before main, but +// doesn't call it +void gh_pre_main(void); +} #else #include #endif @@ -17,6 +22,7 @@ int main(int argc, char **argv) { try { #if RE_DBG_INJECTED gh_init_dbg_loader(); + gh_pre_main(); #else gh_init_data_segment(); #endif diff --git a/java/ghidra/DumpGlobals.java b/java/ghidra/DumpGlobals.java new file mode 100644 index 00000000..7e3c8c87 --- /dev/null +++ b/java/ghidra/DumpGlobals.java @@ -0,0 +1,28 @@ +// Script to refresh all custom globals & types from Ghidra +// @category _Reman3 +// @menupath Reman3.Redump Globals and Types + +import ghidra.app.script.GhidraScript; +import re3lib.GlobalDumper; +import re3lib.RemanConfig; +import re3lib.TypeDumper; +import re3lib.FunctionDatabase; + +public class DumpGlobals extends GhidraScript { + @Override + protected void run() throws Exception { + RemanConfig.INSTANCE = new RemanConfig(this); + RemanConfig.INSTANCE.createDirectories(); + + try (FunctionDatabase functionDatabase = new FunctionDatabase(this)) { + GlobalDumper globalDumper = new GlobalDumper(this, functionDatabase); + globalDumper.loadGlobalManifest(); + + globalDumper.dumpGlobals(); + globalDumper.saveGlobalManifest(); + + TypeDumper dumper = new TypeDumper(this); + dumper.run(); + } + } +} diff --git a/java/ghidra/ExportData.java b/java/ghidra/ExportData.java index d2aff66a..1c622527 100644 --- a/java/ghidra/ExportData.java +++ b/java/ghidra/ExportData.java @@ -1,6 +1,6 @@ // Exports binary read only and data segments to a binary + header file // @category _Reman3 -// @menupath Tools.Reman3.Export Data +// @menupath Reman3.Export Data Segment import java.io.File; import java.io.FileOutputStream; diff --git a/java/ghidra/re3lib/FunctionDatabase.java b/java/ghidra/re3lib/FunctionDatabase.java index 9248f44f..1f3e115a 100644 --- a/java/ghidra/re3lib/FunctionDatabase.java +++ b/java/ghidra/re3lib/FunctionDatabase.java @@ -625,7 +625,7 @@ public class FunctionDatabase implements AutoCloseable { public void addGlobal(Address address, String name, String dataType) throws Exception { ensureConnection(); - String filepath = "globals.h"; // Default filepath for globals + String filepath = RemanConfig.GLOBAL_H_FILE; // Default filepath for globals String addressStr = address.toString(); try { diff --git a/java/ghidra/re3lib/GlobalDumper.java b/java/ghidra/re3lib/GlobalDumper.java index 8b2378d8..573a93e0 100644 --- a/java/ghidra/re3lib/GlobalDumper.java +++ b/java/ghidra/re3lib/GlobalDumper.java @@ -58,7 +58,7 @@ public class GlobalDumper { public void removeGlobalManifest() { // Remove globals from database instead of file try { - functionDatabase.removeGlobalsByFilepath("globals.h"); + functionDatabase.removeGlobalsByFilepath(RemanConfig.INSTANCE.GLOBAL_H_FILE); globalAddrs.clear(); } catch (Exception e) { script.println("Error removing global manifest: " + e.getMessage()); @@ -91,7 +91,13 @@ public class GlobalDumper { if (type == null) { script.println("WARNING: Could not reconstruct type for global: " + entry.name + " at " + entry.address); - continue; + type = dtp.parse("undefined4"); + } + + // Retrieve the name again + Symbol sym = script.getSymbolAt(entry.address); + if (sym != null) { + entry.name = sym.getName(); } globalAddrs.put(entry.address, new GlobalRec(entry.address, entry.name, type)); @@ -130,14 +136,14 @@ public class GlobalDumper { } public void dumpGlobals() throws Exception { - File globalSymbolsListH = new File(RemanConfig.INSTANCE.outputDir, "gh_global.h"); + File globalSymbolsListH = new File(RemanConfig.INSTANCE.outputDir, RemanConfig.GLOBAL_H_FILE); PrintWriter hwriter = new PrintWriter(globalSymbolsListH, "UTF-8"); hwriter.println("// AUTO-GENERATED FILE "); Utils.headerGuardPre(hwriter, "GLOBALS"); hwriter.println("#include "); hwriter.println(); - File globalSymbolsListC = new File(RemanConfig.INSTANCE.outputDir, "gh_global.cxx"); + File globalSymbolsListC = new File(RemanConfig.INSTANCE.outputDir, RemanConfig.GLOBAL_CXX_FILE); PrintWriter cwriter = new PrintWriter(globalSymbolsListC, "UTF-8"); cwriter.println("// AUTO-GENERATED FILE "); cwriter.println("#include "); @@ -216,7 +222,7 @@ public class GlobalDumper { script.println("Saving globals to database"); // Clear existing globals for the default filepath - functionDatabase.removeGlobalsByFilepath("globals.h"); + functionDatabase.removeGlobalsByFilepath(RemanConfig.GLOBAL_H_FILE); // Add all current globals to database for (GlobalRec global : globalAddrs.values()) { @@ -226,6 +232,10 @@ public class GlobalDumper { } public void addGlobal(Address addr, HighSymbol sym) throws Exception { + if (sym.getName().equals("ExceptionList")) { + return; + } + if (addr.compareTo(RemanConfig.INSTANCE.staticMemoryBlockStart) < 0 || addr.compareTo(RemanConfig.INSTANCE.staticMemoryBlockEnd) > 0) { throw new Exception("Global address out of range: " + addr); diff --git a/java/ghidra/re3lib/RemanConfig.java b/java/ghidra/re3lib/RemanConfig.java index 49478fc9..9ad8ca06 100644 --- a/java/ghidra/re3lib/RemanConfig.java +++ b/java/ghidra/re3lib/RemanConfig.java @@ -55,8 +55,11 @@ public class RemanConfig { public static RemanConfig INSTANCE; + public static final String GLOBAL_H_FILE = "gh_global.h"; // Default filepath for globals + public static final String GLOBAL_CXX_FILE = "gh_global.cxx"; // Default filepath for globals + public RemanConfig(GhidraScript script) { - staticMemoryBlockStart = script.getCurrentProgram().getAddressFactory().getAddress("00597000"); + staticMemoryBlockStart = script.getCurrentProgram().getAddressFactory().getAddress("00400000"); staticMemoryBlockEnd = script.getCurrentProgram().getAddressFactory().getAddress("00843fff"); this.script = script;