diff --git a/game_re/.gitignore b/game_re/.gitignore index d8604757..0c7489b0 100644 --- a/game_re/.gitignore +++ b/game_re/.gitignore @@ -1,3 +1,4 @@ gh_auto/* gh_ref/* -*.bak \ No newline at end of file +*.bak +gh_cmake_timestamp \ No newline at end of file diff --git a/game_re/CMakeLists.txt b/game_re/CMakeLists.txt index 5c9cc9bf..e89ef076 100644 --- a/game_re/CMakeLists.txt +++ b/game_re/CMakeLists.txt @@ -37,3 +37,14 @@ target_sources(game_re PRIVATE ${GH_AUTO_SOURCES} ${GH_FIX_SOURCES} ) + +# Ignore -Wformat-security +target_compile_options(game_re PRIVATE -Wno-format-security) + +# Automatically re-run CMake if any gh_*.cxx files change +# due to ghidra script runs +set_property( + DIRECTORY + APPEND + PROPERTY CMAKE_CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/gh_cmake_timestamp +) diff --git a/game_re/binders/gh_base.h b/game_re/binders/gh_base.h index 3951b66a..bfe9279c 100644 --- a/game_re/binders/gh_base.h +++ b/game_re/binders/gh_base.h @@ -10,30 +10,6 @@ #include #include -// struct undefined { -// size_t _0; -// undefined(int i) { -// *this = i; -// } -// undefined(uint32_t i) { -// *this = i; -// } -// undefined(void* i) { -// reinterpret_cast(_0) = i; -// } -// undefined(uint64_t i) { -// *this = i; -// } -// undefined() = default; -// template operator T&() { -// static_assert(sizeof(T) <= sizeof(_0), "Invalid assignment"); -// return reinterpret_cast(_0); -// } -// template T& operator=(const T &other) { -// static_assert(sizeof(T) <= sizeof(_0), "Invalid assignment"); -// return reinterpret_cast(_0) = other; -// } -// }; typedef uint8_t undefined; typedef uint32_t undefined4; typedef uint16_t undefined2; diff --git a/game_re/gh_fix/r3_main.cxx b/game_re/gh_fix/r3_main.cxx index c9fa37a5..2af16c0e 100644 --- a/game_re/gh_fix/r3_main.cxx +++ b/game_re/gh_fix/r3_main.cxx @@ -5,21 +5,22 @@ extern undefined r3_initEngine(void); // 00401220 // r3_initEngine extern undefined r3_module0_init(void); // 00401000 // r3_module0_init -extern uint32_t __stdcall r3_containsCmdLine( +extern uint32_t r3_containsCmdLine( uint *param_1, char *param_2); // 004028e0 // r3_containsCmdLine extern undefined FUN_004010b0(void); // 004010b0 // FUN_004010b0 extern undefined FUN_004464f0(void); // 004464f0 // FUN_004464f0 extern undefined FUN_00503710(void); // 00503710 // FUN_00503710 -extern undefined __stdcall r3_setupWindow( +extern undefined r3_setupWindow( HINSTANCE hInstance, undefined4 param_2, undefined4 param_3); // 00402140 // r3_setupWindow extern undefined FUN_00401320(void); // 00401320 // FUN_00401320 extern undefined spawnThread(void); // 004477d0 // spawnThread extern undefined FUN_005038e0(void); // 005038e0 // FUN_005038e0 extern undefined FUN_004fb300(void); // 004fb300 // FUN_004fb300 -extern void __stdcall g_setInitVar0(void); // 00401310 // g_setInitVar0 -extern void __stdcall r3_noop(void *p_cTxt1, +extern void g_setInitVar0(void); // 00401310 // g_setInitVar0 +extern void r3_noop(void *p_cTxt1, void *p_cTxt2); // 00401100 // r3_noop +extern undefined r3_checkDisc(void); // 004464f0 // r3_checkDisc extern undefined gfx_init2(void); // 00470be0 // gfx_init2 extern undefined4 __cdecl r3_get_gli_width( void); // 0047baf0 // r3_get_gli_width @@ -340,7 +341,7 @@ LAB_004017ce: (acStack_200[0] != '\0')) { /* always true */ hasGLIMode = (uint)(acStack_200[0] != '0'); - FUN_004464f0(); + // r3_checkDisc(); dwOptions = 0; BVar20 = 0; lpTargetHandle = &pvStack_834; diff --git a/game_re/gh_global.cxx b/game_re/gh_global.cxx index 0c89aa78..6268acfe 100644 --- a/game_re/gh_global.cxx +++ b/game_re/gh_global.cxx @@ -19,19 +19,19 @@ char(&s_QUIT)[8] = *reinterpret_cast(GH_MEM(0x005b6624)); const char* s_or_press_ESC_to_quit_Rayman_3__005b662c = "or press ESC to quit Rayman 3."; // 005b662c const char* s__s___Restoring_data____005b664c = "%s - Restoring data..."; // 005b664c const char* s_Daten_Reparatur____005b6664 = "Daten-Reparatur..."; // 005b6664 -undefined s_BEENDIGEN_005b6678= (undefined&) GH_MEM(0x005b6678); -undefined2 DAT_005b6684= (undefined2&) GH_MEM(0x005b6684); +undefined& s_BEENDIGEN_005b6678= (undefined&) GH_MEM(0x005b6678); +undefined2& DAT_005b6684= (undefined2&) GH_MEM(0x005b6684); const char* s__s___Daten_Reparatur____005b66ac = "%s - Daten-Reparatur..."; // 005b66ac const char* s_German_005b66c4 = "German"; // 005b66c4 const char* s_Ripristino_dati____005b66cc = "Ripristino dati..."; // 005b66cc const char* s__s___Pausa_005b66e0 = "%s - Pausa"; // 005b66e0 -undefined s_USCIRE_005b66ec= (undefined&) GH_MEM(0x005b66ec); +undefined& s_USCIRE_005b66ec= (undefined&) GH_MEM(0x005b66ec); const char* s_Premi_ESC_per_uscire_da_Rayman_3_005b66f4 = "Premi ESC per uscire da Rayman 3."; // 005b66f4 const char* s__s___Ripristino_dati____005b6718 = "%s - Ripristino dati..."; // 005b6718 const char* s_Italian_005b6730 = "Italian"; // 005b6730 const char* s_Restablecer_datos____005b6738 = "Restablecer datos..."; // 005b6738 const char* s__s___Rotura_005b6750 = "%s - Rotura"; // 005b6750 -undefined s_SALIR_005b675c= (undefined&) GH_MEM(0x005b675c); +undefined& s_SALIR_005b675c= (undefined&) GH_MEM(0x005b675c); const char* s_Pulsa_ESC_para_salir_Rayman_3__005b6764 = "Pulsa ESC para salir Rayman 3."; // 005b6764 const char* s__s___Restablecer_datos____005b6784 = "%s - Restablecer datos..."; // 005b6784 const char* s_Spanish_005b67a0 = "Spanish"; // 005b67a0 @@ -57,39 +57,51 @@ const char* lpAppName_005b68f0 = "Rayman3"; // 005b68f0 const char* s_Directory_005b68f8 = "Directory"; // 005b68f8 const char* s_None = "None"; // 005b6904 const char* s_UbiSoft_Ubi_ini = "/UbiSoft/Ubi.ini"; // 005b690c +const char* s_UbiSoft_bmp_005bda4c = "UbiSoft.bmp"; // 005bda4c const char* s_R3_DVD_005bdfd8 = "R3_DVD"; // 005bdfd8 const char* s_R3_DVD_005be0ec = "R3_DVD"; // 005be0ec const char* s__s_DVD_missing_005be0f4 = "%s DVD missing "; // 005be0f4 const char* s_Die__s_DVDROM_kann_nicht_gelesen_005be130 = "Die %s DVDROM kann nicht gelesen werden"; // 005be130 const char* s_Impossibile_trovare_il_DVD____s_005be198 = "Impossibile trovare il DVD : %s"; // 005be198 -undefined DAT_005be1ec= (undefined&) GH_MEM(0x005be1ec); +undefined& DAT_005be1ec= (undefined&) GH_MEM(0x005be1ec); const char* s_Impossible_de_trouver_le_DVD_____005be238 = "Impossible de trouver le DVD : %s"; // 005be238 const char* s_Please_insert_the_DVD_in_the_DVD_005be400 = "Please insert the DVD in the DVD-Rom drive."; // 005be400 const char* s_Bitte_legen_Sie_DVD_von_Rayman_3_005be438 = "Bitte legen Sie DVD von Rayman 3 in Ihr DVD-ROM Laufwerk ein."; // 005be438 const char* s_Inserisci_il_DVD_di_Rayman_3_nel_005be484 = "Inserisci il DVD di Rayman 3 nel lettore DVD-ROM."; // 005be484 const char* s_Introduce_el_DVD_de_Rayman_3_en_l_005be4c0 = "Introduce el DVD de Rayman 3 en la unidad de DVD-ROM."; // 005be4c0 -undefined DAT_005be500= (undefined&) GH_MEM(0x005be500); -const char* s__c__s_005be540 = "%c:%s"; // 005be540 -const char* s__program_files_Ubi_Soft_Rayman3_005be548 = "\\program files\\Ubi Soft\\Rayman3"; // 005be548 -undefined* PTR_DAT_005be568 = (undefined*)&GH_MEM(0x005be568); // 005be568 -long lpDefault_005cf96c= (long&) GH_MEM(0x005cf96c); -undefined1 DAT_005d26a8= (undefined1&) GH_MEM(0x005d26a8); -undefined lpVolumeNameBuffer_005d27b0= (undefined&) GH_MEM(0x005d27b0); -r3_main_data r3_main_data_005d28b6= (r3_main_data&) GH_MEM(0x005d28b6); -uint hasGLIMode= (uint&) GH_MEM(0x0077d0a8); -undefined4 g_engineRunning= (undefined4&) GH_MEM(0x0077d0b4); -HANDLE g_drawSemaphore= (HANDLE&) GH_MEM(0x0077d0bc); +undefined& DAT_005be500= (undefined&) GH_MEM(0x005be500); +const char* s_fmt_c_colon_s = "%c:%s"; // 005be540 +const char* s_r3_program_files = "\\program files\\Ubi Soft\\Rayman3"; // 005be548 +undefined *& PTR_DAT_005be568= (undefined *&) GH_MEM(0x005be568); +long& lpDefault_005cf96c= (long&) GH_MEM(0x005cf96c); +undefined4& DAT_005d2660= (undefined4&) GH_MEM(0x005d2660); +undefined1& DAT_005d26a8= (undefined1&) GH_MEM(0x005d26a8); +undefined& lpVolumeNameBuffer_005d27b0= (undefined&) GH_MEM(0x005d27b0); +r3_main_data& r3_main_data_005d28b6= (r3_main_data&) GH_MEM(0x005d28b6); +uint& hasGLIMode= (uint&) GH_MEM(0x0077d0a8); +undefined4& g_engineRunning= (undefined4&) GH_MEM(0x0077d0b4); +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(&lpString_0077d2c0)[256] = *reinterpret_cast(GH_MEM(0x0077d2c0)); char(&s_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); +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)); -undefined2 DAT_007825c0= (undefined2&) GH_MEM(0x007825c0); +undefined2& DAT_007825c0= (undefined2&) GH_MEM(0x007825c0); char(&s_wndStrQuiting)[56] = *reinterpret_cast(GH_MEM(0x00782600)); -uint DAT_007d9cc4= (uint&) GH_MEM(0x007d9cc4); -undefined lpRootPathName_007d9e70= (undefined&) GH_MEM(0x007d9e70); -undefined3 UNK_007d9e71= (undefined3&) GH_MEM(0x007d9e71); +undefined& DAT_007d7d84= (undefined&) GH_MEM(0x007d7d84); +undefined2& DAT_007d7ea8= (undefined2&) GH_MEM(0x007d7ea8); +short& DAT_007d80f8= (short&) GH_MEM(0x007d80f8); +undefined4& DAT_007d83a8= (undefined4&) GH_MEM(0x007d83a8); +r3_TaggedFloatUnk& r3_TaggedFloatUnk_007d83e0= (r3_TaggedFloatUnk&) GH_MEM(0x007d83e0); +r3_TaggedFloatUnk& r3_TaggedFloatUnk_007d8434= (r3_TaggedFloatUnk&) GH_MEM(0x007d8434); +undefined& DAT_007d98fd= (undefined&) GH_MEM(0x007d98fd); +undefined& DAT_007d9928= (undefined&) GH_MEM(0x007d9928); +uint& DAT_007d9cc4= (uint&) GH_MEM(0x007d9cc4); +undefined& lpSystemTime_007d9e40= (undefined&) GH_MEM(0x007d9e40); +undefined4& DAT_007d9e60= (undefined4&) GH_MEM(0x007d9e60); +undefined& lpRootPathName_007d9e70= (undefined&) GH_MEM(0x007d9e70); +undefined3& UNK_007d9e71= (undefined3&) GH_MEM(0x007d9e71); diff --git a/game_re/gh_global.h b/game_re/gh_global.h index 298a0958..31b2cce0 100644 --- a/game_re/gh_global.h +++ b/game_re/gh_global.h @@ -62,6 +62,7 @@ extern const char* lpAppName_005b68f0; // 005b68f0 extern const char* s_Directory_005b68f8; // 005b68f8 extern const char* s_None; // 005b6904 extern const char* s_UbiSoft_Ubi_ini; // 005b690c +extern const char* s_UbiSoft_bmp_005bda4c; // 005bda4c extern const char* s_R3_DVD_005bdfd8; // 005bdfd8 extern const char* s_R3_DVD_005be0ec; // 005be0ec extern const char* s__s_DVD_missing_005be0f4; // 005be0f4 @@ -74,10 +75,11 @@ extern const char* s_Bitte_legen_Sie_DVD_von_Rayman_3_005be438; // 005be438 extern const char* s_Inserisci_il_DVD_di_Rayman_3_nel_005be484; // 005be484 extern const char* s_Introduce_el_DVD_de_Rayman_3_en_l_005be4c0; // 005be4c0 extern undefined& DAT_005be500; // 005be500 -extern const char* s__c__s_005be540; // 005be540 -extern const char* s__program_files_Ubi_Soft_Rayman3_005be548; // 005be548 -extern undefined* PTR_DAT_005be568; // 005be568 +extern const char* s_fmt_c_colon_s; // 005be540 +extern const char* s_r3_program_files; // 005be548 +extern undefined *& PTR_DAT_005be568; // 005be568 extern long& lpDefault_005cf96c; // 005cf96c +extern undefined4& DAT_005d2660; // 005d2660 extern undefined1& DAT_005d26a8; // 005d26a8 extern undefined& lpVolumeNameBuffer_005d27b0; // 005d27b0 extern r3_main_data& r3_main_data_005d28b6; // 005d28b6 @@ -95,7 +97,17 @@ extern char(&g_appCmdLine)[256]; // 0077d4e0 extern char(&s_wndStrRestoring)[256]; // 0077d5e0 extern undefined2& DAT_007825c0; // 007825c0 extern char(&s_wndStrQuiting)[56]; // 00782600 +extern undefined& DAT_007d7d84; // 007d7d84 +extern undefined2& DAT_007d7ea8; // 007d7ea8 +extern short& DAT_007d80f8; // 007d80f8 +extern undefined4& DAT_007d83a8; // 007d83a8 +extern r3_TaggedFloatUnk& r3_TaggedFloatUnk_007d83e0; // 007d83e0 +extern r3_TaggedFloatUnk& r3_TaggedFloatUnk_007d8434; // 007d8434 +extern undefined& DAT_007d98fd; // 007d98fd +extern undefined& DAT_007d9928; // 007d9928 extern uint& DAT_007d9cc4; // 007d9cc4 +extern undefined& lpSystemTime_007d9e40; // 007d9e40 +extern undefined4& DAT_007d9e60; // 007d9e60 extern undefined& lpRootPathName_007d9e70; // 007d9e70 extern undefined3& UNK_007d9e71; // 007d9e71 #endif // GH_GENERATED_GLOBALS_H diff --git a/game_re/globals.txt b/game_re/globals.txt index da722da7..5480c677 100644 --- a/game_re/globals.txt +++ b/game_re/globals.txt @@ -55,22 +55,24 @@ 005b68f8 || s_Directory_005b68f8 || / || string 005b6904 || s_None || / || TerminatedCString 005b690c || s_UbiSoft_Ubi_ini || / || TerminatedCString +005bda4c || s_UbiSoft_bmp_005bda4c || / || string 005bdfd8 || s_R3_DVD_005bdfd8 || / || string 005be0ec || s_R3_DVD_005be0ec || / || string -005be0f4 || s_%s_DVD_missing_005be0f4 || / || string -005be130 || s_Die_%s_DVDROM_kann_nicht_gelesen_005be130 || / || string -005be198 || s_Impossibile_trovare_il_DVD_:_%s_005be198 || / || string +005be0f4 || s__s_DVD_missing_005be0f4 || / || string +005be130 || s_Die__s_DVDROM_kann_nicht_gelesen_005be130 || / || string +005be198 || s_Impossibile_trovare_il_DVD____s_005be198 || / || string 005be1ec || DAT_005be1ec || / || undefined -005be238 || s_Impossible_de_trouver_le_DVD_:_%_005be238 || / || string +005be238 || s_Impossible_de_trouver_le_DVD_____005be238 || / || string 005be400 || s_Please_insert_the_DVD_in_the_DVD_005be400 || / || string 005be438 || s_Bitte_legen_Sie_DVD_von_Rayman_3_005be438 || / || string 005be484 || s_Inserisci_il_DVD_di_Rayman_3_nel_005be484 || / || string 005be4c0 || s_Introduce_el_DVD_de_Rayman_3_en_l_005be4c0 || / || string 005be500 || DAT_005be500 || / || undefined -005be540 || s_%c:%s_005be540 || / || string -005be548 || s_\program_files\Ubi_Soft\Rayman3_005be548 || / || string +005be540 || s_fmt_c_colon_s || / || string +005be548 || s_r3_program_files || / || string 005be568 || PTR_DAT_005be568 || / || undefined * 005cf96c || lpDefault_005cf96c || / || long +005d2660 || DAT_005d2660 || / || undefined4 005d26a8 || DAT_005d26a8 || / || undefined1 005d27b0 || lpVolumeNameBuffer_005d27b0 || / || undefined 005d28b6 || r3_main_data_005d28b6 || / || r3_main_data @@ -88,6 +90,16 @@ 0077d5e0 || s_wndStrRestoring || / || char[256] 007825c0 || DAT_007825c0 || / || undefined2 00782600 || s_wndStrQuiting || / || char[56] +007d7d84 || DAT_007d7d84 || / || undefined +007d7ea8 || DAT_007d7ea8 || / || undefined2 +007d80f8 || DAT_007d80f8 || / || short +007d83a8 || DAT_007d83a8 || / || undefined4 +007d83e0 || r3_TaggedFloatUnk_007d83e0 || /auto_structs || r3_TaggedFloatUnk +007d8434 || r3_TaggedFloatUnk_007d8434 || /auto_structs || r3_TaggedFloatUnk +007d98fd || DAT_007d98fd || / || undefined +007d9928 || DAT_007d9928 || / || undefined 007d9cc4 || DAT_007d9cc4 || / || uint +007d9e40 || lpSystemTime_007d9e40 || / || undefined +007d9e60 || DAT_007d9e60 || / || undefined4 007d9e70 || lpRootPathName_007d9e70 || / || undefined 007d9e71 || UNK_007d9e71 || / || undefined3 diff --git a/scripts/DumpCurrentFunction.java b/scripts/DumpCurrentFunction.java index 0e0b83c4..ae214c4c 100644 --- a/scripts/DumpCurrentFunction.java +++ b/scripts/DumpCurrentFunction.java @@ -25,6 +25,9 @@ public class DumpCurrentFunction extends GhidraScript { println("No function found at the current address."); } + if (functionDumper.createdFile) + RecompileConfig.INSTANCE.touchCMakeTimestamp(); + globalDumper.dumpGlobals(); globalDumper.saveGlobalManifest(); } diff --git a/scripts/SanitizeGlobalSymbols.java b/scripts/SanitizeGlobalSymbols.java index c87d8a03..8f0987b5 100644 --- a/scripts/SanitizeGlobalSymbols.java +++ b/scripts/SanitizeGlobalSymbols.java @@ -1,103 +1,23 @@ // Script to sanitize global symbols in Ghidra // @category _Reman3 +// @menupath Reman3.Sanitize Global Symbols -import java.io.File; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.List; - -import ghidra.app.cmd.label.AddLabelCmd; -import ghidra.app.decompiler.DecompileResults; import ghidra.app.script.GhidraScript; -import ghidra.program.model.address.Address; -import ghidra.program.model.listing.Function; -import ghidra.program.model.listing.VariableStorage; -import ghidra.program.model.pcode.HighSymbol; -import ghidra.program.model.symbol.SourceType; -import ghidra.program.model.symbol.Symbol; +import re3lib.GlobalDumper; import re3lib.RecompileConfig; -import re3lib.Utils; public class SanitizeGlobalSymbols extends GhidraScript { - private static final boolean AUTO_RENAME_SYMBOLS = true; - - HashSet
functionAddrBlackList = new HashSet<>(); - - boolean shouldDecompileFunction(Function function) { - return !functionAddrBlackList.contains(function.getEntryPoint()); - } - - void sanitizeGlobalSymbolsPass(List functions) { - Hashtable globalSymbols = new Hashtable<>(); - - for (Function function : functions) { - println("Processing global symbols for " + function.getName()); - - DecompileResults decompRes = RecompileConfig.INSTANCE.decompCache.getOrInsert(function); - Iterator smyIt = decompRes.getHighFunction().getGlobalSymbolMap().getSymbols(); - - HighSymbol gsym = smyIt.next(); - if (globalSymbols.containsKey(gsym.getName())) - continue; - println("GLOBAL: " + gsym.getName()); - String sanitizedName = sanitizeFunctionName(gsym.getName()); - if (!sanitizedName.equals(gsym.getName())) { - if (AUTO_RENAME_SYMBOLS) { - Symbol symbol = gsym.getSymbol(); - VariableStorage storage = gsym.getStorage(); - Address addr = storage.getMinAddress(); - println("Renaming global symbol: " + gsym.getName() + " (" + addr - + ") -> " + sanitizedName); - if (symbol != null) { - AddLabelCmd cmd = new AddLabelCmd(addr, sanitizedName, symbol.getParentNamespace(), - SourceType.USER_DEFINED); - if (cmd.applyTo(currentProgram)) { - println("Renamed global symbol: " + gsym.getName() + " -> " + sanitizedName); - } else { - println("Error renaming symbol: " + cmd.getStatusMsg()); - } - } else { - println("Symbol is null: " + gsym.getName() + " - " + function.getName()); - } - } else { - println("Invalid global symbol name: " + gsym.getName() + " - " + function.getName()); - } - } - } - } - - private static String sanitizeFunctionName(String name) { - return name.replaceAll("[^a-zA-Z0-9_]", "_"); - } - @Override public void run() throws Exception { - if (currentProgram == null) { - return; - } - RecompileConfig.INSTANCE = new RecompileConfig(this); + RecompileConfig.INSTANCE.createDirectories(); - if (!new File(RecompileConfig.INSTANCE.outputDir).exists()) { - throw new Exception("Output directory does not exist: " + RecompileConfig.INSTANCE.outputDir); - } + GlobalDumper globalDumper = new GlobalDumper(this); + globalDumper.loadGlobalManifest(); - functionAddrBlackList = Utils.loadFunctionBlacklist(RecompileConfig.INSTANCE.functionBlacklistPath); + globalDumper.sanitizeGlobalSymbols(); - List functions = new ArrayList<>(); - - Iterator functionsIt = currentProgram.getFunctionManager().getFunctions(true).iterator(); - while (functionsIt.hasNext()) { - Function function = functionsIt.next(); - if (!shouldDecompileFunction(function)) { - continue; - } - - functions.add(function); - } - - sanitizeGlobalSymbolsPass(functions); + globalDumper.dumpGlobals(); + globalDumper.saveGlobalManifest(); } } diff --git a/scripts/re3lib/FunctionDumper.java b/scripts/re3lib/FunctionDumper.java index 0d1a5cf8..e6894f33 100644 --- a/scripts/re3lib/FunctionDumper.java +++ b/scripts/re3lib/FunctionDumper.java @@ -30,6 +30,8 @@ public class FunctionDumper { GlobalDumper globalDumper; HashSet
functionAddrBlackList = new HashSet<>(); + public boolean createdFile = false; + static final Pattern fieldAccessRegex = Pattern.compile("^_([0-9]+)_([0-9]+)_$"); public FunctionDumper(GhidraScript script, GlobalDumper globalDumper) { @@ -112,11 +114,15 @@ public class FunctionDumper { f0 = new File(RecompileConfig.INSTANCE.dirDecompAuto, fileName); if (f0.exists()) { f0.delete(); + } else { + createdFile = true; } } script.println("Processing " + function.getName() + " => " + f0.toString()); + List externalFunctionCalls = new ArrayList<>(); + DecompileResults decompRes = RecompileConfig.INSTANCE.decompCache.getOrInsert(function); try (PrintWriter writer2 = new PrintWriter(f0, "UTF-8")) { writer2.println("// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!! "); @@ -213,6 +219,7 @@ public class FunctionDumper { headers.add("extern " + proto + "; // " + calledFunction.getEntryPoint() + " // " + calledFunction.getName()); + externalFunctionCalls.add(calledFunction); } } } @@ -236,5 +243,39 @@ public class FunctionDumper { writer2.print(codeWriter.toString()); writer2.println(); } + + // Possibly generate stubs for external functions + for (Function externalFunction : externalFunctionCalls) { + File f2 = new File(RecompileConfig.INSTANCE.dirDecompFix, fileName); + File f3 = new File(RecompileConfig.INSTANCE.dirDecompAuto, fileName); + if (f2.exists() || f3.exists()) { + continue; + } + + File f4 = new File(RecompileConfig.INSTANCE.dirDecompStub, fileName); + script.println("Generating function stub for " + externalFunction.getName() + " => " + f4.toString()); + + try (PrintWriter writer2 = new PrintWriter(f4, "UTF-8")) { + writer2.println("// AUTO-GENERATED FILE!!!!"); + writer2.println("// This function has yet to be decompiled using 'Dump Current Function' in ghidra"); + writer2.println("// with possible manualy fixes"); + writer2.println(); + writer2.println("#include "); + writer2.println("#include \"../gh_global.h\""); + writer2.println("#include "); + writer2.println(); + writer2.println("// " + externalFunction.getEntryPoint()); + writer2.println("// " + externalFunction.getName()); + writer2.println(externalFunction.getSignature().getPrototypeString(false) + " {"); + writer2.println(" // TODO: Implement this function"); + writer2 + .println(" throw std::runtime_error(\"Function not implemented: " + externalFunction.getName() + "\");"); + writer2.println("}"); + } + + if (!f4.exists()) { + createdFile = true; + } + } } } diff --git a/scripts/re3lib/GlobalDumper.java b/scripts/re3lib/GlobalDumper.java index 02c71798..7de4704d 100644 --- a/scripts/re3lib/GlobalDumper.java +++ b/scripts/re3lib/GlobalDumper.java @@ -15,6 +15,7 @@ import java.util.Map; import javax.xml.datatype.DatatypeFactory; +import ghidra.app.cmd.label.AddLabelCmd; import ghidra.app.script.GhidraScript; import ghidra.app.services.DataTypeManagerService; import ghidra.program.model.address.Address; @@ -27,6 +28,8 @@ import ghidra.program.model.data.PointerDataType; import ghidra.program.model.data.Undefined; import ghidra.program.model.listing.Data; import ghidra.program.model.pcode.HighSymbol; +import ghidra.program.model.symbol.SourceType; +import ghidra.program.model.symbol.Symbol; import ghidra.util.data.DataTypeParser; import ghidra.util.data.DataTypeParser.AllowedDataTypes; @@ -181,8 +184,9 @@ public class GlobalDumper { initBlk += "(" + dataType + ")&GH_MEM(0x" + addr + ")"; fullyDefinedType = true; } + String linkagePrefix = "extern "; if (fullyDefinedType) { - hwriter.println("extern " + dataType + " " + name + "; // " + addr); + hwriter.println(linkagePrefix + dataType + " " + name + "; // " + addr); cwriter.println(dataType + " " + name + initBlk + "; // " + addr); } else { if (dt instanceof Array) { @@ -191,14 +195,14 @@ public class GlobalDumper { Array adt = (Array) dt; DataType baseType = adt.getDataType(); hwriter.println( - "extern " + baseType.getDisplayName() + "(&" + name + ")[" + adt.getNumElements() + "]; // " + addr); + linkagePrefix + baseType.getDisplayName() + "(&" + name + ")[" + adt.getNumElements() + "]; // " + addr); cwriter.println( baseType.getDisplayName() + "(&" + name + ")[" + adt.getNumElements() + "] = *reinterpret_cast<" + baseType.getDisplayName() + "(*)[" + adt.getNumElements() + "]>(GH_MEM(0x" + addr + "));"); } else { String refTypeStr = dt.getDisplayName() + "&"; - hwriter.println("extern " + refTypeStr + " " + name + "; // " + addr); - cwriter.println(dataType + " " + name + "= (" + refTypeStr + ") GH_MEM(0x" + addr + ");"); + hwriter.println(linkagePrefix + refTypeStr + " " + name + "; // " + addr); + cwriter.println(refTypeStr + " " + name + "= (" + refTypeStr + ") GH_MEM(0x" + addr + ");"); } } } catch (Exception e) { @@ -233,4 +237,23 @@ public class GlobalDumper { } } } + + public void sanitizeGlobalSymbols() { + for (GlobalRec global : globalAddrs.values()) { + String sanitizedName = Utils.sanitizeIdentifier(global.name); + if (!sanitizedName.equals(global.name)) { + Symbol symbol = script.getSymbolAt(global.address); + if (symbol != null) { + script.println("Renaming global symbol: " + global.name + " -> " + sanitizedName); + AddLabelCmd cmd = new AddLabelCmd(global.address, sanitizedName, + symbol.getParentNamespace(), + SourceType.USER_DEFINED); + if (!cmd.applyTo(script.getCurrentProgram())) { + script.println("Error renaming symbol: " + cmd.getStatusMsg()); + } + global.name = sanitizedName; + } + } + } + } } diff --git a/scripts/re3lib/RecompileConfig.java b/scripts/re3lib/RecompileConfig.java index b5ca7725..a4baf83e 100644 --- a/scripts/re3lib/RecompileConfig.java +++ b/scripts/re3lib/RecompileConfig.java @@ -1,6 +1,7 @@ package re3lib; import java.io.File; +import java.io.IOException; import generic.jar.ResourceFile; import ghidra.app.decompiler.DecompInterface; @@ -27,10 +28,20 @@ public class RecompileConfig { // The manually decompiled files (will not be overwritten by the auto // decompiler) public final File dirDecompFix; - // The automatically generated files get written here in case a gh_fix entry exists + // The automatically generated files get written here in case a gh_fix entry + // exists // usable for referencing the modified function against the auto-decompiled one public final File dirDecompRef; + // The path for generated function stubs, for yet-to-be-compiled functions + // Usefully for testing a part of the recompiled code without linker errors + public final File dirDecompStub; + + // The CMake timestamp file, automatically touched sometimes to trigger a + // reconfigure + // mostly when adding new files to the project + public final File cmakeTimestampFile; + public final Program currentProgram; public final DecompileCache decompCache; @@ -54,6 +65,9 @@ public class RecompileConfig { dirDecompAuto = new File(outputDir, "gh_auto"); dirDecompFix = new File(outputDir, "gh_fix"); dirDecompRef = new File(outputDir, "gh_ref"); + dirDecompStub = new File(outputDir, "gh_stub"); + + cmakeTimestampFile = new File(outputDir, "gh_cmake_timestamp"); currentProgram = script.getCurrentProgram(); @@ -66,5 +80,16 @@ public class RecompileConfig { dirDecompAuto.mkdirs(); dirDecompFix.mkdirs(); dirDecompRef.mkdirs(); + dirDecompStub.mkdirs(); + } + + public void touchCMakeTimestamp() { + try { + if (!cmakeTimestampFile.exists()) { + cmakeTimestampFile.createNewFile(); + } + cmakeTimestampFile.setLastModified(System.currentTimeMillis()); + } catch (IOException e) { + } } }