From a0f0588018da10a53313063d8d6345085404ab69 Mon Sep 17 00:00:00 2001 From: Guus Waals <_@guusw.nl> Date: Mon, 23 Sep 2024 21:16:44 +0800 Subject: [PATCH] Improve single file dump script --- game_re/gh_global.cxx | 111 +------ game_re/gh_global.h | 111 +------ scripts/Decompile.java | 466 ++++++----------------------- scripts/DecompileFile.java | 25 -- scripts/DumpCurrentFunction.java | 35 +++ scripts/re3lib/FunctionDumper.java | 239 +++++++++++++++ scripts/re3lib/GlobalDumper.java | 181 +++++++++++ scripts/re3lib/Utils.java | 4 + 8 files changed, 555 insertions(+), 617 deletions(-) delete mode 100644 scripts/DecompileFile.java create mode 100644 scripts/DumpCurrentFunction.java create mode 100644 scripts/re3lib/FunctionDumper.java create mode 100644 scripts/re3lib/GlobalDumper.java diff --git a/game_re/gh_global.cxx b/game_re/gh_global.cxx index 23c0d4d0..2088e0d6 100644 --- a/game_re/gh_global.cxx +++ b/game_re/gh_global.cxx @@ -1,110 +1,5 @@ // AUTO-GENERATED FILE #include -const char* s_R3_DVD_005be0ec = "R3_DVD"; // 005be0ec -undefined s_USCIRE_005b66ec= (undefined&) GH_MEM(0x005b66ec); -undefined4 g_GLI_width1= (undefined4&) GH_MEM(0x007edd54); -int DAT_005bf71c= (int&) GH_MEM(0x005bf71c); -HANDLE g_mainThreadHandle= (HANDLE&) GH_MEM(0x0077d4c8); -char(&g_windowTitle)[256] = *reinterpret_cast(GH_MEM(0x0077d1c0)); -char(&s_windowTitle)[12] = *reinterpret_cast(GH_MEM(0x005b6830)); -const char* s_ou_appuyez_sur_Echap_pour_quitte_005b67d0 = "ou appuyez sur Echap pour quitter Rayman 3."; // 005b67d0 -undefined3 UNK_007d9e71= (undefined3&) GH_MEM(0x007d9e71); -char(&g_mutexName_Rayman3)[256] = *reinterpret_cast(GH_MEM(0x0077d0c0)); -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 -const char* s_SOFTWARE_UBI_SOFT_RAYMAN_3_005b6864 = "SOFTWARE\\UBI SOFT\\RAYMAN 3"; // 005b6864 -undefined2 DAT_007825c0= (undefined2&) GH_MEM(0x007825c0); -R3ModuleId r3_module_id_ff= (R3ModuleId&) GH_MEM(0x005bd58c); -const char* lpText_005b64f0 = "Controlla la tua versione di DirectX. ￈ necessaria la versione 8.1 o superiore."; // 005b64f0 -const char* s_Ripristino_dati____005b66cc = "Ripristino dati..."; // 005b66cc -const char* s__s___Pausa_005b66e0 = "%s - Pausa"; // 005b66e0 -const char* s_CompleteInstall_005b6854 = "CompleteInstall"; // 005b6854 -const char* s_Unable_to_find_R3_Setup_DX8_exe__005b6880 = "Unable to find R3_Setup_DX8.exe. Please reinstall the game."; // 005b6880 -const char* s_or_press_ESC_to_quit_Rayman_3__005b662c = "or press ESC to quit Rayman 3."; // 005b662c -const char* s_UbiSoft_Ubi_ini = "/UbiSoft/Ubi.ini"; // 005b690c -char(&s_QUIT)[8] = *reinterpret_cast(GH_MEM(0x005b6624)); -const char* lpText_005b6540 = "Comprueba tu versi￳n de DirectX. Se necesita la versi￳n 8.1 o superior."; // 005b6540 -const char* s_None = "None"; // 005b6904 -const char* s_Rayman_3_Error_005b68bc = "Rayman 3 Error"; // 005b68bc -const char* fopen_mode_r_binary = "rb"; // 005b68cc -const char* s__program_files_Ubi_Soft_Rayman3_005be548 = "\\program files\\Ubi Soft\\Rayman3"; // 005be548 -const char* s_Adapter_005b68e4 = "Adapter"; // 005b68e4 -const char* s_English_005b684c = "English"; // 005b684c -char(&s_QUITTER)[8] = *reinterpret_cast(GH_MEM(0x005b67fc)); -const char* s_Italian_005b6730 = "Italian"; // 005b6730 -const char* s__s___Restablecer_datos____005b6784 = "%s - Restablecer datos..."; // 005b6784 -const char* s_Restoring_data_____005b6610 = "Restoring data ..."; // 005b6610 -char(&s_wndStrRestoring)[256] = *reinterpret_cast(GH_MEM(0x0077d5e0)); -const char* s_Identifier_005b6420 = "Identifier"; // 005b6420 -const char* s_Die__s_DVDROM_kann_nicht_gelesen_005be130 = "Die %s DVDROM kann nicht gelesen werden"; // 005be130 -const char* s_French_005b6828 = "French"; // 005b6828 -uint hasGLIMode= (uint&) GH_MEM(0x0077d0a8); -const char* lpText_005b6598 = "V←rifiez votre version de DirectX. La version 8.1 minimum est n←cessaire."; // 005b6598 -char g_initVar0= (char&) GH_MEM(0x005cf960); -undefined s_BEENDIGEN_005b6678= (undefined&) GH_MEM(0x005b6678); -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_DRAWSEM_005b6608 = "DRAWSEM"; // 005b6608 -int DAT_005e6c50= (int&) GH_MEM(0x005e6c50); -undefined lpVolumeNameBuffer_005d27b0= (undefined&) GH_MEM(0x005d27b0); -const char* s__s_not_initialized__005b63e0 = "%s not initialized."; // 005b63e0 -undefined4 DAT_007eba20= (undefined4&) GH_MEM(0x007eba20); -const char* s_Restauration_fmt = "%s - Restauration des donn←es..."; // 005b6804 -const char* s__s___Rotura_005b6750 = "%s - Rotura"; // 005b6750 -HANDLE g_drawSemaphore= (HANDLE&) GH_MEM(0x0077d0bc); -undefined DAT_005be500= (undefined&) GH_MEM(0x005be500); -const char* s_Please_run_the__s_setup__005b63f4 = "Please run the %s setup."; // 005b63f4 -const char* s__s___Pause_005b67c4 = "%s - Pause"; // 005b67c4 -char(&s_percents)[4] = *reinterpret_cast(GH_MEM(0x005b683c)); -float FLOAT_005a9fb0= (float&) GH_MEM(0x005a9fb0); -undefined lpRootPathName_007d9e70= (undefined&) GH_MEM(0x007d9e70); -const char* lpAppName_005b68f0 = "Rayman3"; // 005b68f0 -uint DAT_007d9cc4= (uint&) GH_MEM(0x007d9cc4); -const char* s__s_DVD_missing_005be0f4 = "%s DVD missing "; // 005be0f4 -const char* s_Language_005b6840 = "Language"; // 005b6840 -const char* s__c__s_005be540 = "%c:%s"; // 005be540 -const char* fopen_mode_r_text = "rt"; // 005b68ec -char(&s_dashCC)[4] = *reinterpret_cast(GH_MEM(0x005b6410)); -uint DAT_007e5aa4= (uint&) GH_MEM(0x007e5aa4); -undefined g_perfCounterRate= (undefined&) GH_MEM(0x007e5ad8); -HINSTANCE g_hinstance= (HINSTANCE&) GH_MEM(0x0077d4c0); -const char* s_Gli_Mode_005b6414 = "Gli_Mode"; // 005b6414 -r3_main_data r3_main_data_005d28b6= (r3_main_data&) GH_MEM(0x005d28b6); -const char* s_R3_DVD_005bdfd8 = "R3_DVD"; // 005bdfd8 -const char* s_Restauration = "Restauration des donn←es..."; // 005b67a8 -const char* s__s___Daten_Reparatur____005b66ac = "%s - Daten-Reparatur..."; // 005b66ac -undefined s_SALIR_005b675c= (undefined&) GH_MEM(0x005b675c); -undefined4 g_perfCounterRateAdjusted= (undefined4&) GH_MEM(0x005e6b0c); -const char* s_Daten_Reparatur____005b6664 = "Daten-Reparatur..."; // 005b6664 -const char* lpText_005b6478 = "ᅵberprfen Sie, welche DirectX-Version auf Ihrem PC derzeit installiert ist. Sie ben￶tigen DirectX 8.1 oder h￶her."; // 005b6478 -const char* s__s___Restoring_data____005b664c = "%s - Restoring data..."; // 005b664c -const char* s_Pulsa_ESC_para_salir_Rayman_3__005b6764 = "Pulsa ESC para salir Rayman 3."; // 005b6764 -char(&g_appCmdLine)[256] = *reinterpret_cast(GH_MEM(0x0077d4e0)); -char(&s_wndStrQuiting)[56] = *reinterpret_cast(GH_MEM(0x00782600)); -undefined DAT_005be1ec= (undefined&) GH_MEM(0x005be1ec); -undefined1 DAT_005d26a8= (undefined1&) GH_MEM(0x005d26a8); -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__s___Ripristino_dati____005b6718 = "%s - Ripristino dati..."; // 005b6718 -const char* s_dpnhpast_dll_005b65f8 = "dpnhpast.dll"; // 005b65f8 -const char* s_Erreur_Rayman_3_005b65e4 = "Erreur Rayman 3 "; // 005b65e4 -undefined* PTR_DAT_005be568 = (undefined*)&GH_MEM(0x005be568); // 005be568 -const char* s_Rayman_3_005b6588 = "Rayman 3"; // 005b6588 -char(&lpString_0077d2c0)[256] = *reinterpret_cast(GH_MEM(0x0077d2c0)); -R3ModuleId DAT_005bd29c= (R3ModuleId&) GH_MEM(0x005bd29c); -const char* s_German_005b66c4 = "German"; // 005b66c4 -int g_GLI_height1= (int&) GH_MEM(0x007edd58); -const char* s_Impossible_de_trouver_le_DVD_____005be238 = "Impossible de trouver le DVD : %s"; // 005be238 -undefined4 g_engineRunning= (undefined4&) GH_MEM(0x0077d0b4); -const char* s_Spanish_005b67a0 = "Spanish"; // 005b67a0 -const char* s_Impossibile_trovare_il_DVD____s_005be198 = "Impossibile trovare il DVD : %s"; // 005be198 -const char* s__R3_Setup_DX8_exe_005b68d0 = "\\R3_Setup_DX8.exe"; // 005b68d0 -char(&s_windowTitleRestoring)[256] = *reinterpret_cast(GH_MEM(0x0077d3c0)); -float FLOAT_005aa030= (float&) GH_MEM(0x005aa030); -HWND g_gameHWND= (HWND&) GH_MEM(0x0077d4c4); -undefined2 DAT_005b6684= (undefined2&) GH_MEM(0x005b6684); -const char* s_Premi_ESC_per_uscire_da_Rayman_3_005b66f4 = "Premi ESC per uscire da Rayman 3."; // 005b66f4 -long lpDefault_005cf96c= (long&) GH_MEM(0x005cf96c); -int g_engine_= (int&) GH_MEM(0x007eba24); -const char* s_Restablecer_datos____005b6738 = "Restablecer datos..."; // 005b6738 -const char* s_Check_your_version_of_DirectX__V_005b6430 = "Check your version of DirectX. Version 8.1 or higher is required."; // 005b6430 -undefined4 DAT_007eb180= (undefined4&) GH_MEM(0x007eb180); -const char* s_Directory_005b68f8 = "Directory"; // 005b68f8 -const char* s_Please_insert_the_DVD_in_the_DVD_005be400 = "Please insert the DVD in the DVD-Rom drive."; // 005be400 +undefined module0_id= (undefined&) GH_MEM(0x005bf5fc); +int DAT_005bf600= (int&) GH_MEM(0x005bf600); +undefined4 DAT_007edda0= (undefined4&) GH_MEM(0x007edda0); diff --git a/game_re/gh_global.h b/game_re/gh_global.h index 6353c957..8c5af587 100644 --- a/game_re/gh_global.h +++ b/game_re/gh_global.h @@ -5,112 +5,7 @@ #include -extern const char* s_R3_DVD_005be0ec; // 005be0ec -extern undefined& s_USCIRE_005b66ec; // 005b66ec -extern undefined4& g_GLI_width1; // 007edd54 -extern int& DAT_005bf71c; // 005bf71c -extern HANDLE& g_mainThreadHandle; // 0077d4c8 -extern char(&g_windowTitle)[256]; // 0077d1c0 -extern char(&s_windowTitle)[12]; // 005b6830 -extern const char* s_ou_appuyez_sur_Echap_pour_quitte_005b67d0; // 005b67d0 -extern undefined3& UNK_007d9e71; // 007d9e71 -extern char(&g_mutexName_Rayman3)[256]; // 0077d0c0 -extern const char* s_Introduce_el_DVD_de_Rayman_3_en_l_005be4c0; // 005be4c0 -extern const char* s_SOFTWARE_UBI_SOFT_RAYMAN_3_005b6864; // 005b6864 -extern undefined2& DAT_007825c0; // 007825c0 -extern R3ModuleId& r3_module_id_ff; // 005bd58c -extern const char* lpText_005b64f0; // 005b64f0 -extern const char* s_Ripristino_dati____005b66cc; // 005b66cc -extern const char* s__s___Pausa_005b66e0; // 005b66e0 -extern const char* s_CompleteInstall_005b6854; // 005b6854 -extern const char* s_Unable_to_find_R3_Setup_DX8_exe__005b6880; // 005b6880 -extern const char* s_or_press_ESC_to_quit_Rayman_3__005b662c; // 005b662c -extern const char* s_UbiSoft_Ubi_ini; // 005b690c -extern char(&s_QUIT)[8]; // 005b6624 -extern const char* lpText_005b6540; // 005b6540 -extern const char* s_None; // 005b6904 -extern const char* s_Rayman_3_Error_005b68bc; // 005b68bc -extern const char* fopen_mode_r_binary; // 005b68cc -extern const char* s__program_files_Ubi_Soft_Rayman3_005be548; // 005be548 -extern const char* s_Adapter_005b68e4; // 005b68e4 -extern const char* s_English_005b684c; // 005b684c -extern char(&s_QUITTER)[8]; // 005b67fc -extern const char* s_Italian_005b6730; // 005b6730 -extern const char* s__s___Restablecer_datos____005b6784; // 005b6784 -extern const char* s_Restoring_data_____005b6610; // 005b6610 -extern char(&s_wndStrRestoring)[256]; // 0077d5e0 -extern const char* s_Identifier_005b6420; // 005b6420 -extern const char* s_Die__s_DVDROM_kann_nicht_gelesen_005be130; // 005be130 -extern const char* s_French_005b6828; // 005b6828 -extern uint& hasGLIMode; // 0077d0a8 -extern const char* lpText_005b6598; // 005b6598 -extern char& g_initVar0; // 005cf960 -extern undefined& s_BEENDIGEN_005b6678; // 005b6678 -extern const char* s_Inserisci_il_DVD_di_Rayman_3_nel_005be484; // 005be484 -extern const char* s_DRAWSEM_005b6608; // 005b6608 -extern int& DAT_005e6c50; // 005e6c50 -extern undefined& lpVolumeNameBuffer_005d27b0; // 005d27b0 -extern const char* s__s_not_initialized__005b63e0; // 005b63e0 -extern undefined4& DAT_007eba20; // 007eba20 -extern const char* s_Restauration_fmt; // 005b6804 -extern const char* s__s___Rotura_005b6750; // 005b6750 -extern HANDLE& g_drawSemaphore; // 0077d0bc -extern undefined& DAT_005be500; // 005be500 -extern const char* s_Please_run_the__s_setup__005b63f4; // 005b63f4 -extern const char* s__s___Pause_005b67c4; // 005b67c4 -extern char(&s_percents)[4]; // 005b683c -extern float& FLOAT_005a9fb0; // 005a9fb0 -extern undefined& lpRootPathName_007d9e70; // 007d9e70 -extern const char* lpAppName_005b68f0; // 005b68f0 -extern uint& DAT_007d9cc4; // 007d9cc4 -extern const char* s__s_DVD_missing_005be0f4; // 005be0f4 -extern const char* s_Language_005b6840; // 005b6840 -extern const char* s__c__s_005be540; // 005be540 -extern const char* fopen_mode_r_text; // 005b68ec -extern char(&s_dashCC)[4]; // 005b6410 -extern uint& DAT_007e5aa4; // 007e5aa4 -extern undefined& g_perfCounterRate; // 007e5ad8 -extern HINSTANCE& g_hinstance; // 0077d4c0 -extern const char* s_Gli_Mode_005b6414; // 005b6414 -extern r3_main_data& r3_main_data_005d28b6; // 005d28b6 -extern const char* s_R3_DVD_005bdfd8; // 005bdfd8 -extern const char* s_Restauration; // 005b67a8 -extern const char* s__s___Daten_Reparatur____005b66ac; // 005b66ac -extern undefined& s_SALIR_005b675c; // 005b675c -extern undefined4& g_perfCounterRateAdjusted; // 005e6b0c -extern const char* s_Daten_Reparatur____005b6664; // 005b6664 -extern const char* lpText_005b6478; // 005b6478 -extern const char* s__s___Restoring_data____005b664c; // 005b664c -extern const char* s_Pulsa_ESC_para_salir_Rayman_3__005b6764; // 005b6764 -extern char(&g_appCmdLine)[256]; // 0077d4e0 -extern char(&s_wndStrQuiting)[56]; // 00782600 -extern undefined& DAT_005be1ec; // 005be1ec -extern undefined1& DAT_005d26a8; // 005d26a8 -extern const char* s_Bitte_legen_Sie_DVD_von_Rayman_3_005be438; // 005be438 -extern const char* s__s___Ripristino_dati____005b6718; // 005b6718 -extern const char* s_dpnhpast_dll_005b65f8; // 005b65f8 -extern const char* s_Erreur_Rayman_3_005b65e4; // 005b65e4 -extern undefined* PTR_DAT_005be568; // 005be568 -extern const char* s_Rayman_3_005b6588; // 005b6588 -extern char(&lpString_0077d2c0)[256]; // 0077d2c0 -extern R3ModuleId& DAT_005bd29c; // 005bd29c -extern const char* s_German_005b66c4; // 005b66c4 -extern int& g_GLI_height1; // 007edd58 -extern const char* s_Impossible_de_trouver_le_DVD_____005be238; // 005be238 -extern undefined4& g_engineRunning; // 0077d0b4 -extern const char* s_Spanish_005b67a0; // 005b67a0 -extern const char* s_Impossibile_trovare_il_DVD____s_005be198; // 005be198 -extern const char* s__R3_Setup_DX8_exe_005b68d0; // 005b68d0 -extern char(&s_windowTitleRestoring)[256]; // 0077d3c0 -extern float& FLOAT_005aa030; // 005aa030 -extern HWND& g_gameHWND; // 0077d4c4 -extern undefined2& DAT_005b6684; // 005b6684 -extern const char* s_Premi_ESC_per_uscire_da_Rayman_3_005b66f4; // 005b66f4 -extern long& lpDefault_005cf96c; // 005cf96c -extern int& g_engine_; // 007eba24 -extern const char* s_Restablecer_datos____005b6738; // 005b6738 -extern const char* s_Check_your_version_of_DirectX__V_005b6430; // 005b6430 -extern undefined4& DAT_007eb180; // 007eb180 -extern const char* s_Directory_005b68f8; // 005b68f8 -extern const char* s_Please_insert_the_DVD_in_the_DVD_005be400; // 005be400 +extern undefined& module0_id; // 005bf5fc +extern int& DAT_005bf600; // 005bf600 +extern undefined4& DAT_007edda0; // 007edda0 #endif // GH_GENERATED_GLOBALS_H diff --git a/scripts/Decompile.java b/scripts/Decompile.java index 2c953df7..2d801122 100644 --- a/scripts/Decompile.java +++ b/scripts/Decompile.java @@ -46,388 +46,102 @@ import ghidra.util.task.TaskMonitor; import re3lib.*; public class Decompile extends GhidraScript { - // Auto rename invalid symbols - private static final boolean AUTO_RENAME_SYMBOLS = true; + - private static final HashSet ONLY_SYMBOLS = new HashSet<>(Arrays.asList( - "r3_main", - "r3_get_gli_width", - "r3_get_gli_height", - "r3_setup_dx8", - "r3_setup_window", - "r3_contains_cmd_line", - "r3_module0_init", - "r3_noop", - "gfx_init2", - "spawn_thread", - "FUN_004464f0", - "FUN_00401320", - "thunk_FUN_00401410" - )); - // private static final HashSet ONLY_SYMBOLS = null; + // void headerGuardPre(PrintWriter writer, String tag) { + // writer.println("#ifndef GH_GENERATED_" + tag + "_H"); + // writer.println("#define GH_GENERATED_" + tag + "_H"); + // writer.println(); + // } - static final boolean BUILD_BLACKLIST = true; + // void headerGuardPost(PrintWriter writer, String tag) { + // writer.println("#endif // GH_GENERATED_" + tag + "_H"); + // } - HashSet
functionAddrBlackList = new HashSet<>(); + // void dumpGlobals(Hashtable globalSymbols) throws Exception { + // File globalSymbolsListH = new File(RecompileConfig.INSTANCE.outputDir, "gh_global.h"); + // PrintWriter hwriter = new PrintWriter(globalSymbolsListH, "UTF-8"); + // hwriter.println("// AUTO-GENERATED FILE "); + // headerGuardPre(hwriter, "GLOBALS"); + // hwriter.println("#include "); + // hwriter.println(); - boolean shouldDecompileFunction(Function function) { - if (ONLY_SYMBOLS != null && !ONLY_SYMBOLS.contains(function.getName())) { - return false; - } - return !functionAddrBlackList.contains(function.getEntryPoint()); - } + // File globalSymbolsListC = new File(RecompileConfig.INSTANCE.outputDir, "gh_global.cxx"); + // PrintWriter cwriter = new PrintWriter(globalSymbolsListC, "UTF-8"); + // cwriter.println("// AUTO-GENERATED FILE "); + // cwriter.println("#include "); + // hwriter.println(); - void buildFunctionBlacklist() { - functionAddrBlackList = Utils.loadFunctionBlacklist(RecompileConfig.INSTANCE.functionBlacklistPath); + // for (GlobalRec sym : globalSymbols.values()) { + // HighSymbol highSym = sym.highSymbol; + // DataType dt = highSym.getDataType(); + // String dataType = dt.getDisplayName(); + // String sanitizedName = sanitizeFunctionName(highSym.getName()); + // String name = highSym.getName(); + // if (!sanitizedName.equals(name)) { + // println("Invalid global symbol name: " + name); + // name = sanitizedName; + // } + // Address addr = sym.address; + // // println("Symbol: " + symbol + " Addr: " + addr + " Size:" + symSize + " " + + // // storage.getSerializationString()); + // try { + // String initBlk = " = "; + // boolean fullyDefinedType = false; + // if (dt instanceof AbstractStringDataType) { + // AbstractStringDataType sdt = (AbstractStringDataType) dt; + // dataType = "const char*"; + // // String type + // initBlk += "\"" + escapeCString(readCString(addr, 2048)) + "\""; + // fullyDefinedType = true; + // } else if (dt instanceof PointerDataType) { + // PointerDataType pdt = (PointerDataType) dt; + // DataType baseType = pdt.getDataType(); + // dataType = baseType.getDisplayName() + "*"; + // initBlk += "(" + dataType + ")&GH_MEM(0x" + addr + ")"; + // fullyDefinedType = true; + // } + // if (fullyDefinedType) { + // hwriter.println("extern " + dataType + " " + name + "; // " + addr); + // cwriter.println(dataType + " " + name + initBlk + "; // " + addr); + // } else { + // if (dt instanceof Array) { + // // println("Array: " + dt.getDisplayName() + " - " + addr + " - " + + // // dt.getClass().getSimpleName()); + // Array adt = (Array) dt; + // DataType baseType = adt.getDataType(); + // hwriter.println( + // "extern " + 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 + ");"); + // } + // } + // } catch (Exception e) { + // println("Error processing global symbol: " + e); + // println("Symbol: " + highSym.getName() + " - " + addr + " - " + // + highSym.getHighFunction().getFunction().getName()); + // } + // } - if (BUILD_BLACKLIST) { - boolean modified = false; - - Iterator functionsIt = currentProgram.getFunctionManager().getFunctions(true).iterator(); - while (functionsIt.hasNext()) { - Function function = functionsIt.next(); - if (functionAddrBlackList.contains(function.getEntryPoint())) { - continue; - } - - String comment = function.getComment(); - boolean isIgnoredFunction = false; - if (comment != null && comment.contains("Library Function")) { - println("Adding library function " + function.getName() + " to blacklist"); - println("ac:" + functionAddrBlackList.size() + " jj:" - + functionAddrBlackList.contains(function.getEntryPoint()) + " " - + function.getEntryPoint()); - isIgnoredFunction = true; - } - - if (function.getName().startsWith("crt_")) { - println("Adding crt function " + function.getName() + " to blacklist"); - isIgnoredFunction = true; - } - - if (isIgnoredFunction) { - // Decompile and trace - PCallTracer tracer = new PCallTracer(); - tracer.setBlacklist(functionAddrBlackList); - tracer.traceCalls(function); - for (Function f : tracer.out) { - println(" Adding " + f.getName() + " to blacklist"); - functionAddrBlackList.add(f.getEntryPoint()); - modified = true; - } - } - } - - if (modified) { - Utils.saveFunctionBlacklist(functionAddrBlackList, RecompileConfig.INSTANCE.functionBlacklistPath); - } - } - } - - String escapeCString(String str) { - str = str.replace("\\", "\\\\"); - str = str.replace("\"", "\\\""); - return str; - } - - String readCString(Address addr, int maxLen) throws Exception { - StringBuilder sb = new StringBuilder(); - int ofs = 0; - while (true) { - Address read = addr.add(ofs++); - // println("Reading: " + read); - byte b = currentProgram.getMemory().getByte(read); - // println("Read: " + b); - if (b == 0 || ofs >= maxLen) { - break; - } - sb.append((char) b); - } - if (sb.length() > 0) { - // println("STR \"" + sb.toString() + "\""); - } - return sb.toString(); - } - - public class GlobalRec { - public HighSymbol highSymbol; - public Address address; - // public boolean isFullyDefined; - - public GlobalRec(HighSymbol highSymbol, Address address) { - this.highSymbol = highSymbol; - this.address = address; - // this.isFullyDefined = isFullyDefined; - } - }; - - static final Pattern fieldAccessRegex = Pattern.compile("^_([0-9]+)_([0-9]+)_$"); - - void decompileFunction(Hashtable outGlobalSymbols, Function function) - throws Exception { - String fileName = sanitizeFunctionName(function.getName()) + ".cxx"; - - File f0 = new File(RecompileConfig.INSTANCE.dirDecompFix, fileName); - if (f0.exists()) { - println("Func " + function.getName() + " skipped (gh_fix)"); - f0 = new File(RecompileConfig.INSTANCE.dirDecompRef, fileName); - } else { - f0 = new File(RecompileConfig.INSTANCE.dirDecompAuto, fileName); - if (f0.exists()) { - f0.delete(); - } - } - - println("Processing " + function.getName() + " => " + f0.toString()); - - 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!!!!! "); - writer2.println(); - writer2.println("#include "); - writer2.println("#include \"../gh_global.h\""); - writer2.println(); - - // decompRes.get - HighFunction highFunction = decompRes.getHighFunction(); - - // Remap for dynamic symbols - // Dictionary symbolRemap = new Hashtable<>(); - - HashSet headers = new HashSet<>(); - StringWriter codeWriter = new StringWriter(); - - PrettyPrinter pp = new PrettyPrinter(decompRes.getFunction(), decompRes.getCCodeMarkup(), null); - Iterator lines = pp.getLines().iterator(); - while (lines.hasNext()) { - ClangLine line = lines.next(); - for (int i = 0; i < line.getIndent(); i++) { - codeWriter.write(' '); - } - - List tokens = new ArrayList<>(); - // Parse preliminary line tokens - for (int i = 0; i < line.getNumTokens(); i++) { - ClangToken token = line.getToken(i); - if (!token.getText().isEmpty()) - tokens.add(token); - } - - // Preprocess tokens - boolean prevDot = false; - for (int t = 0; t < tokens.size(); t++) { - ClangToken token = tokens.get(t); - - boolean thisDot = false; - // println("Token: " + token.toString()); - if (token.toString().equals(".")) { - // println("Found dot: " + token.toString() + " - " + token.getClass()); - thisDot = true; - } - - if (prevDot) { - // println("Possible field access: " + token.getText()); - if (token instanceof ClangSyntaxToken) { - // Parse _4_4_ sub-access using regex - String text = token.getText(); - Matcher matcher = fieldAccessRegex.matcher(text); - if (matcher.matches()) { - int offset = Integer.parseInt(matcher.group(1)); - int size = Integer.parseInt(matcher.group(2)); - // println("MATCHED: " + token.getText() + " - " + token.getSyntaxType() + " - " - // + token.getVarnode() + " - " - // + token.getPcodeOp()); - - // Replace tokens with + Field - ClangToken replacement = new ClangToken(token.Parent(), " + Field<" + offset + ", " + size + ">()"); - tokens.remove(t); - tokens.remove(t - 1); - tokens.add(t - 1, replacement); - t--; - } - } - } - - // Extract memory references - HighSymbol gsym = token.getHighSymbol(highFunction); - if (gsym != null) { - var symStorage = gsym.getStorage(); - var sym = gsym.getSymbol(); - - Address address; - if (symStorage.isUnassignedStorage()) { - address = sym.getAddress(); - } else { - address = gsym.getStorage().getMinAddress(); - } - - if (address.isMemoryAddress()) { - outGlobalSymbols.put(gsym.getName(), new GlobalRec(gsym, address)); - } - } - - // Extract external function calls - PcodeOp op = token.getPcodeOp(); - if (op != null && op.getOpcode() == PcodeOp.CALL) { - // println("PcodeOp: " + op.toString() + " - " + op.getInput(0).toString()); - Varnode target = op.getInput(0); - if (target.isAddress()) { - Address callAddr = target.getAddress(); - Function calledFunction = getFunctionAt(callAddr); - if (calledFunction != null) { - if (!functionAddrBlackList.contains(calledFunction.getEntryPoint())) { - // println("Adding header: " + calledFunction + " / " + - // calledFunction.getSignature().getPrototypeString(true)); - headers.add("extern " + calledFunction.getSignature().getPrototypeString(true) - + "; // " + calledFunction.getEntryPoint() + " // " - + calledFunction.getName()); - } - } - } - } - prevDot = thisDot; - } - - // Print tokens - for (int t = 0; t < tokens.size(); t++) { - ClangToken token = tokens.get(t); - codeWriter.write(token.toString()); - } - codeWriter.write('\n'); - } - - for (String header : headers) { - writer2.println(header); - } - writer2.println(); - writer2.println("// " + function.getEntryPoint()); - writer2.print(codeWriter.toString()); - writer2.println(); - - // Iterator it = decompRes.getCCodeMarkup().tokenIterator(true); - // int ln = 0; - // while(it.hasNext()) { - // ClangToken token = it.next(); - // ClangLine line = token.getLineParent(); - // while (line != null && ln < line.getLineNumber()) { - // writer2.println(); - // ln++; - // } - // writer2.print(token.toString()); - // } - - // Collect referenced global symbols - // Iterator smyIt = highFunction.getGlobalSymbolMap().getSymbols(); - // while (smyIt.hasNext()) { - // HighSymbol gsym = smyIt.next(); - - // Address addr = gsym.getSymbol().getAddress(); - // println("FunctionSym " + addr + " " + gsym.getName() + " " + - // gsym.getStorage().getMinAddress()); - // println(" IsMem: " + gsym.getStorage().isMemoryStorage() + " " + - // gsym.getStorage().getSerializationString()); - - // if (outGlobalSymbols.containsKey(gsym.getName())) - // continue; - // outGlobalSymbols.put(gsym.getName(), gsym); - // } - } - } - - void headerGuardPre(PrintWriter writer, String tag) { - writer.println("#ifndef GH_GENERATED_" + tag + "_H"); - writer.println("#define GH_GENERATED_" + tag + "_H"); - writer.println(); - } - - void headerGuardPost(PrintWriter writer, String tag) { - writer.println("#endif // GH_GENERATED_" + tag + "_H"); - } - - void dumpGlobals(Hashtable globalSymbols) throws Exception { - File globalSymbolsListH = new File(RecompileConfig.INSTANCE.outputDir, "gh_global.h"); - PrintWriter hwriter = new PrintWriter(globalSymbolsListH, "UTF-8"); - hwriter.println("// AUTO-GENERATED FILE "); - headerGuardPre(hwriter, "GLOBALS"); - hwriter.println("#include "); - hwriter.println(); - - File globalSymbolsListC = new File(RecompileConfig.INSTANCE.outputDir, "gh_global.cxx"); - PrintWriter cwriter = new PrintWriter(globalSymbolsListC, "UTF-8"); - cwriter.println("// AUTO-GENERATED FILE "); - cwriter.println("#include "); - hwriter.println(); - - for (GlobalRec sym : globalSymbols.values()) { - HighSymbol highSym = sym.highSymbol; - DataType dt = highSym.getDataType(); - String dataType = dt.getDisplayName(); - String sanitizedName = sanitizeFunctionName(highSym.getName()); - String name = highSym.getName(); - if (!sanitizedName.equals(name)) { - println("Invalid global symbol name: " + name); - name = sanitizedName; - } - Address addr = sym.address; - // println("Symbol: " + symbol + " Addr: " + addr + " Size:" + symSize + " " + - // storage.getSerializationString()); - try { - String initBlk = " = "; - boolean fullyDefinedType = false; - if (dt instanceof AbstractStringDataType) { - AbstractStringDataType sdt = (AbstractStringDataType) dt; - dataType = "const char*"; - // String type - initBlk += "\"" + escapeCString(readCString(addr, 2048)) + "\""; - fullyDefinedType = true; - } else if (dt instanceof PointerDataType) { - PointerDataType pdt = (PointerDataType) dt; - DataType baseType = pdt.getDataType(); - dataType = baseType.getDisplayName() + "*"; - initBlk += "(" + dataType + ")&GH_MEM(0x" + addr + ")"; - fullyDefinedType = true; - } - if (fullyDefinedType) { - hwriter.println("extern " + dataType + " " + name + "; // " + addr); - cwriter.println(dataType + " " + name + initBlk + "; // " + addr); - } else { - if (dt instanceof Array) { - // println("Array: " + dt.getDisplayName() + " - " + addr + " - " + - // dt.getClass().getSimpleName()); - Array adt = (Array) dt; - DataType baseType = adt.getDataType(); - hwriter.println( - "extern " + 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 + ");"); - } - } - } catch (Exception e) { - println("Error processing global symbol: " + e); - println("Symbol: " + highSym.getName() + " - " + addr + " - " - + highSym.getHighFunction().getFunction().getName()); - } - } - - headerGuardPost(hwriter, "GLOBALS"); - hwriter.close(); - cwriter.close(); - } + // headerGuardPost(hwriter, "GLOBALS"); + // hwriter.close(); + // cwriter.close(); + // } void decompileAll(List functions) throws Exception { - Hashtable globalSymbols = new Hashtable<>(); + // Hashtable globalSymbols = new Hashtable<>(); - for (Function function : functions) { - decompileFunction(globalSymbols, function); - } + // for (Function function : functions) { + // decompileFunction(globalSymbols, function); + // } - dumpStructureTypes(); - dumpGlobals(globalSymbols); + // dumpStructureTypes(); + // dumpGlobals(globalSymbols); } @Override @@ -447,16 +161,16 @@ public class Decompile extends GhidraScript { RecompileConfig.INSTANCE.dirDecompAuto.mkdirs(); RecompileConfig.INSTANCE.dirDecompRef.mkdirs(); - buildFunctionBlacklist(); + // buildFunctionBlacklist(); List functions = new ArrayList<>(); Iterator functionsIt = currentProgram.getFunctionManager().getFunctions(true).iterator(); while (functionsIt.hasNext()) { Function function = functionsIt.next(); - if (!shouldDecompileFunction(function)) { - continue; - } + // if (!shouldDecompileFunction(function)) { + // continue; + // } functions.add(function); } diff --git a/scripts/DecompileFile.java b/scripts/DecompileFile.java deleted file mode 100644 index 4fdba7d2..00000000 --- a/scripts/DecompileFile.java +++ /dev/null @@ -1,25 +0,0 @@ -public class DecompileFile { - - public class MyDecompilerAction extends DecompilerAction { - - public MyDecompilerAction() { - super("My Custom Action"); - setDescription("Description of my custom decompiler action"); - setKeyBindingData(new KeyBindingData(KeyEvent.VK_F5, 0)); - } - - @Override - public void actionPerformed(DecompilerActionContext context) { - // Custom action logic goes here - // You can access decompiler results via: - // DecompileResults results = context.getDecompileResults(); - // HighFunction highFunction = results.getHighFunction(); - - // Implement your custom functionality - } - } - - // Register the action in your plugin's init() method: - // tool.addAction(new MyDecompilerAction()); - -} diff --git a/scripts/DumpCurrentFunction.java b/scripts/DumpCurrentFunction.java new file mode 100644 index 00000000..8aa6a6b8 --- /dev/null +++ b/scripts/DumpCurrentFunction.java @@ -0,0 +1,35 @@ +// Script to export decompiled C code for selected function from Ghidra +// @category _Reman3 +// @menupath Reman3.Dump Current Function + +import ghidra.app.script.GhidraScript; +import ghidra.program.model.listing.Function; +import re3lib.FunctionDumper; +import re3lib.GlobalDumper; +import re3lib.RecompileConfig; + +public class DumpCurrentFunction extends GhidraScript { + @Override + public void run() throws Exception { + RecompileConfig.INSTANCE = new RecompileConfig(this); + RecompileConfig.INSTANCE.createDirectories(); + + GlobalDumper globalDumper = new GlobalDumper(this); + try { + globalDumper.loadGlobalManifest(); + } catch (Exception e) { + println("No global manifest found"); + } + FunctionDumper functionDumper = new FunctionDumper(this, globalDumper); + + Function currentFunction = getFunctionContaining(currentAddress); + if (currentFunction != null) { + functionDumper.dump(currentFunction); + } else { + println("No function found at the current address."); + } + + globalDumper.dumpGlobals(); + globalDumper.saveGlobalManifest(); + } +} diff --git a/scripts/re3lib/FunctionDumper.java b/scripts/re3lib/FunctionDumper.java new file mode 100644 index 00000000..2eb7ef45 --- /dev/null +++ b/scripts/re3lib/FunctionDumper.java @@ -0,0 +1,239 @@ +package re3lib; + +import java.io.File; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import ghidra.app.decompiler.ClangLine; +import ghidra.app.decompiler.ClangSyntaxToken; +import ghidra.app.decompiler.ClangToken; +import ghidra.app.decompiler.DecompileResults; +import ghidra.app.decompiler.PrettyPrinter; +import ghidra.app.script.GhidraScript; +import ghidra.program.model.address.Address; +import ghidra.program.model.listing.Function; +import ghidra.program.model.pcode.HighFunction; +import ghidra.program.model.pcode.HighSymbol; +import ghidra.program.model.pcode.PcodeOp; +import ghidra.program.model.pcode.Varnode; +import re3lib.GlobalDumper.GlobalRec; + +public class FunctionDumper { + GhidraScript script; + GlobalDumper globalDumper; + HashSet
functionAddrBlackList = new HashSet<>(); + + static final Pattern fieldAccessRegex = Pattern.compile("^_([0-9]+)_([0-9]+)_$"); + + public FunctionDumper(GhidraScript script, GlobalDumper globalDumper) { + this.script = script; + this.globalDumper = globalDumper; + initFunctionBlacklist(); + } + + boolean isValidFunction(Function function) { + if (functionAddrBlackList.contains(function.getEntryPoint())) + return false; + if (function.getComment() != null) { + if (function.getComment().startsWith("/i")) + return false; + if (function.getComment().startsWith("library function")) + return false; + } + if (function.getName().startsWith("crt_")) + return false; + return true; + } + + void initFunctionBlacklist() { + functionAddrBlackList = Utils.loadFunctionBlacklist(RecompileConfig.INSTANCE.functionBlacklistPath); + + // Build blacklist if not loaded + if (functionAddrBlackList == null) { + boolean modified = false; + Iterator functionsIt = script.getCurrentProgram().getFunctionManager().getFunctions(true).iterator(); + while (functionsIt.hasNext()) { + Function function = functionsIt.next(); + if (functionAddrBlackList.contains(function.getEntryPoint())) { + continue; + } + + String comment = function.getComment(); + boolean isIgnoredFunction = false; + if (comment != null && comment.contains("Library Function")) { + script.println("Adding library function " + function.getName() + " to blacklist"); + script.println("ac:" + functionAddrBlackList.size() + " jj:" + + functionAddrBlackList.contains(function.getEntryPoint()) + " " + + function.getEntryPoint()); + isIgnoredFunction = true; + } + + if (function.getName().startsWith("crt_")) { + script.println("Adding crt function " + function.getName() + " to blacklist"); + isIgnoredFunction = true; + } + + if (isIgnoredFunction) { + // Decompile and trace + PCallTracer tracer = new PCallTracer(); + tracer.setBlacklist(functionAddrBlackList); + tracer.traceCalls(function); + for (Function f : tracer.out) { + script.println(" Adding " + f.getName() + " to blacklist"); + functionAddrBlackList.add(f.getEntryPoint()); + modified = true; + } + } + } + + if (modified) { + Utils.saveFunctionBlacklist(functionAddrBlackList, RecompileConfig.INSTANCE.functionBlacklistPath); + } + } + } + + public void dump(Function function) + throws Exception { + String sanitizedFunctionName = Utils.sanitizeIdentifier(function.getName()); + String fileName = sanitizedFunctionName + ".cxx"; + + File f0 = new File(RecompileConfig.INSTANCE.dirDecompFix, fileName); + if (f0.exists()) { + script.println("Func " + function.getName() + " skipped (gh_fix)"); + f0 = new File(RecompileConfig.INSTANCE.dirDecompRef, fileName); + } else { + f0 = new File(RecompileConfig.INSTANCE.dirDecompAuto, fileName); + if (f0.exists()) { + f0.delete(); + } + } + + script.println("Processing " + function.getName() + " => " + f0.toString()); + + 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!!!!! "); + writer2.println(); + writer2.println("#include "); + writer2.println("#include \"../gh_global.h\""); + writer2.println(); + + HighFunction highFunction = decompRes.getHighFunction(); + + HashSet headers = new HashSet<>(); + StringWriter codeWriter = new StringWriter(); + + PrettyPrinter pp = new PrettyPrinter(decompRes.getFunction(), decompRes.getCCodeMarkup(), null); + Iterator lines = pp.getLines().iterator(); + while (lines.hasNext()) { + ClangLine line = lines.next(); + for (int i = 0; i < line.getIndent(); i++) { + codeWriter.write(' '); + } + + List tokens = new ArrayList<>(); + // Parse preliminary line tokens + for (int i = 0; i < line.getNumTokens(); i++) { + ClangToken token = line.getToken(i); + if (!token.getText().isEmpty()) + tokens.add(token); + } + + // Preprocess tokens + boolean prevDot = false; + for (int t = 0; t < tokens.size(); t++) { + ClangToken token = tokens.get(t); + + boolean thisDot = false; + // println("Token: " + token.toString()); + if (token.toString().equals(".")) { + // println("Found dot: " + token.toString() + " - " + token.getClass()); + thisDot = true; + } + + if (prevDot) { + // println("Possible field access: " + token.getText()); + if (token instanceof ClangSyntaxToken) { + // Parse _4_4_ sub-access using regex + String text = token.getText(); + Matcher matcher = fieldAccessRegex.matcher(text); + if (matcher.matches()) { + int offset = Integer.parseInt(matcher.group(1)); + int size = Integer.parseInt(matcher.group(2)); + // println("MATCHED: " + token.getText() + " - " + token.getSyntaxType() + " - " + // + token.getVarnode() + " - " + // + token.getPcodeOp()); + + // Replace tokens with + Field + ClangToken replacement = new ClangToken(token.Parent(), " + Field<" + offset + ", " + size + ">()"); + tokens.remove(t); + tokens.remove(t - 1); + tokens.add(t - 1, replacement); + t--; + } + } + } + + // Extract memory references + HighSymbol gsym = token.getHighSymbol(highFunction); + if (gsym != null) { + var symStorage = gsym.getStorage(); + var sym = gsym.getSymbol(); + + Address address; + if (symStorage.isUnassignedStorage()) { + address = sym.getAddress(); + } else { + address = gsym.getStorage().getMinAddress(); + } + + if (address.isMemoryAddress()) { + globalDumper.addGlobal(address, gsym); + } + } + + // Extract external function calls + PcodeOp op = token.getPcodeOp(); + if (op != null && op.getOpcode() == PcodeOp.CALL) { + // println("PcodeOp: " + op.toString() + " - " + op.getInput(0).toString()); + Varnode target = op.getInput(0); + if (target.isAddress()) { + Address callAddr = target.getAddress(); + Function calledFunction = script.getFunctionAt(callAddr); + if (calledFunction != null) { + if (isValidFunction(calledFunction)) { + headers.add("extern " + calledFunction.getSignature().getPrototypeString(true) + + "; // " + calledFunction.getEntryPoint() + " // " + + calledFunction.getName()); + } + } + } + } + prevDot = thisDot; + } + + // Print tokens + for (int t = 0; t < tokens.size(); t++) { + ClangToken token = tokens.get(t); + codeWriter.write(token.toString()); + } + codeWriter.write('\n'); + } + + for (String header : headers) { + writer2.println(header); + } + writer2.println(); + writer2.println("// " + function.getEntryPoint()); + writer2.print(codeWriter.toString()); + writer2.println(); + } + } +} diff --git a/scripts/re3lib/GlobalDumper.java b/scripts/re3lib/GlobalDumper.java new file mode 100644 index 00000000..e5eb4172 --- /dev/null +++ b/scripts/re3lib/GlobalDumper.java @@ -0,0 +1,181 @@ +package re3lib; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Dictionary; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +import ghidra.app.script.GhidraScript; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.AbstractStringDataType; +import ghidra.program.model.data.Array; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.PointerDataType; +import ghidra.program.model.pcode.HighSymbol; + +public class GlobalDumper { + + public class GlobalRec { + public Address address; + public String name; + public DataType type; + + public GlobalRec(Address address, String name, DataType type) { + this.address = address; + this.name = name; + this.type = type; + } + }; + + GhidraScript script; + File manifestFile; + HashMap globalAddrs = new HashMap<>(); + + public GlobalDumper(GhidraScript script) { + this.script = script; + manifestFile = new File(RecompileConfig.INSTANCE.outputDir, "globals.txt"); + } + + public void loadGlobalManifest() throws Exception { + // Globals are stored in the format of + //
|| || + try (BufferedReader reader = new BufferedReader(new FileReader(manifestFile))) { + String line; + while ((line = reader.readLine()) != null) { + String[] parts = line.split(" || "); + if (parts.length == 3) { + String address = parts[0]; + String name = parts[1]; + String typeName = parts[2]; + DataType type = script.getCurrentProgram().getDataTypeManager().getDataType(typeName); + globalAddrs.put(script.parseAddress(address), new GlobalRec(script.parseAddress(address), name, type)); + } + } + } + } + + public void addGlobal(Address addr, HighSymbol sym) { + globalAddrs.put(addr, new GlobalRec(addr, sym.getName(), sym.getDataType())); + } + + String escapeCString(String str) { + str = str.replace("\\", "\\\\"); + str = str.replace("\"", "\\\""); + return str; + } + + String readCString(Address addr, int maxLen) throws Exception { + StringBuilder sb = new StringBuilder(); + int ofs = 0; + while (true) { + Address read = addr.add(ofs++); + // println("Reading: " + read); + byte b = script.getCurrentProgram().getMemory().getByte(read); + // println("Read: " + b); + if (b == 0 || ofs >= maxLen) { + break; + } + sb.append((char) b); + } + if (sb.length() > 0) { + // println("STR \"" + sb.toString() + "\""); + } + return sb.toString(); + } + + public void dumpGlobals() throws Exception { + File globalSymbolsListH = new File(RecompileConfig.INSTANCE.outputDir, "gh_global.h"); + 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(RecompileConfig.INSTANCE.outputDir, "gh_global.cxx"); + PrintWriter cwriter = new PrintWriter(globalSymbolsListC, "UTF-8"); + cwriter.println("// AUTO-GENERATED FILE "); + cwriter.println("#include "); + hwriter.println(); + + List globals = new ArrayList<>(globalAddrs.values()); + globals.sort((o1, o2) -> o1.address.compareTo(o2.address)); + + for (GlobalRec global : globals) { + DataType dt = global.type; + if (dt == null) { + script.println("WARNING: Missing type for global: " + global.name + " at " + global.address); + continue; + } + String dataType = dt.getDisplayName(); + String sanitizedName = Utils.sanitizeIdentifier(global.name); + String name = global.name; + Address addr = global.address; + if (!sanitizedName.equals(name)) { + script.println("WARNING: Invalid global symbol name: " + name); + name = sanitizedName; + } + // println("Symbol: " + symbol + " Addr: " + addr + " Size:" + symSize + " " + + // storage.getSerializationString()); + try { + String initBlk = " = "; + boolean fullyDefinedType = false; + if (dt instanceof AbstractStringDataType) { + AbstractStringDataType sdt = (AbstractStringDataType) dt; + dataType = "const char*"; + // String type + initBlk += "\"" + escapeCString(readCString(addr, 2048)) + "\""; + fullyDefinedType = true; + } else if (dt instanceof PointerDataType) { + PointerDataType pdt = (PointerDataType) dt; + DataType baseType = pdt.getDataType(); + dataType = baseType.getDisplayName() + "*"; + initBlk += "(" + dataType + ")&GH_MEM(0x" + addr + ")"; + fullyDefinedType = true; + } + if (fullyDefinedType) { + hwriter.println("extern " + dataType + " " + name + "; // " + addr); + cwriter.println(dataType + " " + name + initBlk + "; // " + addr); + } else { + if (dt instanceof Array) { + // println("Array: " + dt.getDisplayName() + " - " + addr + " - " + + // dt.getClass().getSimpleName()); + Array adt = (Array) dt; + DataType baseType = adt.getDataType(); + hwriter.println( + "extern " + 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 + ");"); + } + } + } catch (Exception e) { + script.println("Error processing global symbol: " + e); + script.println("Symbol: " + name + " - " + addr); + } + } + + Utils.headerGuardPost(hwriter, "GLOBALS"); + hwriter.close(); + cwriter.close(); + } + + public void saveGlobalManifest() throws Exception { + try (PrintWriter writer = new PrintWriter(manifestFile)) { + script.println("Saving global manifest to " + manifestFile); + for (Map.Entry entry : globalAddrs.entrySet()) { + writer.println(entry.getKey().toString() + " || " + entry.getValue().name + " || " + entry.getValue().type.getDisplayName()); + } + } + } +} diff --git a/scripts/re3lib/Utils.java b/scripts/re3lib/Utils.java index df6d1b5f..27f1143a 100644 --- a/scripts/re3lib/Utils.java +++ b/scripts/re3lib/Utils.java @@ -21,6 +21,10 @@ public class Utils { writer.println("#endif // GH_GENERATED_" + tag + "_H"); } + public static String sanitizeIdentifier(String name) { + return name.replaceAll("[^a-zA-Z0-9_]", "_"); + } + public static HashSet loadStructBlacklist(String path) { File file = new File(path); HashSet structBlacklist = new HashSet<>();