Compare commits

...

125 Commits

Author SHA1 Message Date
5638734828 WIP Ghidra plugin 2025-06-09 00:20:53 +08:00
b5805d39d4 WIP 2025-06-09 00:20:52 +08:00
7e68709aec chmod 2025-06-07 16:30:40 +08:00
0d35e5af6d WIP Stuff 2025-06-07 02:18:05 +08:00
b6be9b7c09 Fix wrongly marked functions as stdcall 2025-06-07 01:30:24 +08:00
e6c8d527bc Remove binkw 2025-06-07 01:05:41 +08:00
a8143e6ac0 Patcher 2025-06-06 20:34:31 +08:00
3537c91324 WIP Patch 2025-06-06 20:18:52 +08:00
360df2dfda WIP Patch 2025-06-06 20:15:06 +08:00
8b73364db9 WIP Patch 2025-06-06 20:09:23 +08:00
72c6656e01 WIP Patch 2025-06-06 19:46:03 +08:00
c854b78e02 Restore binary and such 2025-06-06 18:49:08 +08:00
6104238552 WIP Patch 2025-06-06 18:18:50 +08:00
892aa30091 WIP Patch 2025-06-06 18:11:44 +08:00
b19de8b1b7 WIP 2025-06-06 17:54:05 +08:00
b1dc3a13c2 Code Patcher 2025-06-06 17:49:59 +08:00
fb30afded9 WIP Patcher 2025-06-06 17:41:15 +08:00
38b62c4d50 WIP 2025-06-06 02:56:59 +08:00
919430c923 WIP 2025-06-06 02:50:20 +08:00
599c2f746b Better relocations 2025-06-06 02:27:28 +08:00
7d095623ba WIP 2025-06-06 02:06:59 +08:00
080b9f7b8c WIP 2025-06-06 01:14:59 +08:00
ab0c1473ec WIP 2025-06-06 01:04:31 +08:00
a559f68de2 WIP Program plugin 2025-06-02 18:39:23 +08:00
010e3825da Fix function pointer types in globals 2025-06-02 15:04:53 +08:00
8c53aa61be WIP 2025-06-02 12:43:35 +08:00
0d488e24e3 Fix global uniqueness 2025-06-02 12:43:30 +08:00
4dc6fb2176 Annotations & fix DumpCurrentFunctionRecursive script 2025-06-02 12:22:23 +08:00
836c856258 Remove global load/save functions 2025-06-02 12:12:39 +08:00
027829659c Move eclipse project completely outside of vscode folder
create your own
2025-06-02 11:37:18 +08:00
1bbe4bf3c7 Separate Eclipse folder cause otherwise vscode fucks up 2025-06-02 11:28:31 +08:00
1835eecb49 Clean classpath 2025-06-02 11:07:11 +08:00
7186b95de4 Add ignore 2025-06-02 10:56:02 +08:00
3c6c7a6f65 Move java src 2025-06-02 10:53:30 +08:00
ac9879a4aa WIP Dump required function pointer types for globals 2025-06-02 00:05:18 +08:00
2423d68e0a Add fix 2025-06-01 23:30:20 +08:00
66565671b5 Dump 2025-06-01 23:30:10 +08:00
bd98761921 Update java code to include parameter names and types 2025-06-01 23:29:51 +08:00
cfb41094d5 Add parameter names and types 2025-06-01 23:18:47 +08:00
743d5aa015 Fix calling convention 2025-06-01 23:18:29 +08:00
947165067c Ok hook types 2025-06-01 23:01:05 +08:00
cde5c7c313 Remove type from java db 2025-06-01 22:55:11 +08:00
f6d2ec6efb Upgrade function dumper for cc 2025-06-01 22:46:30 +08:00
ac92d40671 Fix window proc calling convention 2025-06-01 22:40:26 +08:00
f2606cd72f Fix parsing of cc 2025-06-01 22:27:11 +08:00
15ec7bd1f1 Add call_conv to tool 2025-06-01 22:24:56 +08:00
3ad0cb5bd1 Upgrade stub 2025-06-01 22:13:09 +08:00
7a7c907abb Tool verify 2025-06-01 21:59:37 +08:00
6bce41bd2d WIP 2025-06-01 21:13:47 +08:00
35b2c67e73 CODE 2025-06-01 18:02:08 +08:00
4092af3513 Hotpatching 2025-06-01 16:22:06 +08:00
e3c19e890f Add hooker and upgrade it 2025-06-01 16:13:43 +08:00
8328a6e8e8 Cleanup database script 2025-06-01 00:13:12 +08:00
1d305a44c6 Convert to fix dump script 2025-05-31 23:57:56 +08:00
36b700f66e Cleanup 2025-05-31 23:50:32 +08:00
a723dbd2f9 Hook setup in cmake 2025-05-31 23:46:23 +08:00
76915ede69 Hooks tool 2025-05-31 23:38:21 +08:00
2c305c7a03 New tool split up 2025-05-31 23:34:29 +08:00
af2c8c1384 Pdb dumpickery 2025-05-31 00:17:41 +08:00
0187b3943c Debug data generator 2025-05-30 23:06:14 +08:00
209d82c172 We are relocated 2025-05-30 15:26:50 +08:00
325219104a Remove dll link stub 2025-05-30 15:05:37 +08:00
891277f15d Remove dllhack 2025-05-30 15:04:00 +08:00
532c1653c0 DLLHack wip 2025-05-30 15:03:10 +08:00
1e91d93470 RELO 2025-05-30 14:53:24 +08:00
f1b346fb0e W 2025-05-30 14:36:39 +08:00
faf2e134f2 Wip relo finder 2025-05-30 14:34:14 +08:00
7613e37444 Pcode finder 2025-05-30 14:19:03 +08:00
0edba96773 Reloc script WIP 2025-05-30 14:17:21 +08:00
556f8339c0 Try to relocate r3 exe 2025-05-30 03:23:12 +08:00
2c104648cd WIP setup CRT 2025-05-30 02:02:43 +08:00
acb9d47e0e Ray3 main debug stub 2025-05-30 00:18:17 +08:00
ea677e6de7 WIP 2025-05-29 23:59:16 +08:00
4a669d86b7 Cleanup 2025-05-29 23:59:05 +08:00
35a220de3f WIP 2025-05-29 22:18:55 +08:00
b0b4683f7d WIP 2025-05-29 20:36:01 +08:00
e7417745fd WIP 2025-05-29 20:09:23 +08:00
31ee70e8c0 Wip new dtw 2025-05-29 19:44:08 +08:00
55438d7380 WIP 2025-05-29 19:16:33 +08:00
edf6cc5a67 Add ghidra eclipse project 2025-05-29 19:16:20 +08:00
ebfc4bf4f4 WIP 2025-05-29 19:15:52 +08:00
5ce1a399b1 Update stub dumping routines 2025-05-29 18:05:55 +08:00
e19a123b94 WIP 2025-05-29 18:03:37 +08:00
16e5456079 WIP 2025-05-29 17:36:15 +08:00
2791a66b1f Ignore logs 2025-05-29 17:32:17 +08:00
45344e2e52 Ignore db 2025-05-29 17:31:54 +08:00
647e3668a0 Update readme and rename config java 2025-05-29 17:31:42 +08:00
d7de3deb59 Update tooling ignores 2025-05-29 15:57:35 +08:00
7c18d04724 Add notes 2025-05-29 15:57:22 +08:00
3d40dc7e80 Update ignores 2025-05-29 15:57:01 +08:00
0383ef8f13 WIP 2025-05-29 15:56:11 +08:00
58397127e7 Fix setup script 2025-05-29 15:52:26 +08:00
560fbe70ce Ignore refs from tooling duplicate check 2025-05-29 15:46:15 +08:00
db228e64ec Fix tool file categorization 2025-05-29 15:29:07 +08:00
836e281b80 Return in findGlobals 2025-05-28 14:40:05 +08:00
8ac8951d8d Fix duplicates check 2025-05-28 14:37:12 +08:00
a958b0268e WIP Duplicate detection mode 2025-05-28 01:29:10 +08:00
ec5d40be0c WIP 2025-05-28 01:16:13 +08:00
99aaebba82 Try to fix gloal tool stuff 2025-05-28 01:00:52 +08:00
c9c9e9c6e6 Cleanup tool 2025-05-28 00:50:59 +08:00
c7309d1b29 Test with globals and stuff 2025-05-28 00:32:14 +08:00
4070a99bf8 WIP Global scan 2025-05-28 00:14:59 +08:00
04b92cbd08 Add scan script 2025-05-27 23:19:14 +08:00
f2ca59b3b1 ignores 2025-05-27 23:19:07 +08:00
84ebde858e Move tooling 2025-05-27 00:31:02 +08:00
c2397e8e24 Remove old tooling 2025-05-27 00:29:47 +08:00
c20f540b47 Tooling setup script 2025-05-27 00:29:22 +08:00
fd4546c1f0 Add editor config 2025-05-27 00:20:35 +08:00
e4325de092 Fix spacing 2025-05-27 00:19:30 +08:00
dfe339bcd3 Simplify tool 2025-05-27 00:18:17 +08:00
cc7964f03e Updated 2025-05-27 00:12:40 +08:00
fd90916a1f Test script 2025-05-27 00:06:51 +08:00
54476f89f0 CLI and list file support 2025-05-27 00:06:41 +08:00
5223f1c7c1 Add CLI11 2025-05-27 00:04:32 +08:00
468866b833 New tool version 2025-05-26 23:56:11 +08:00
86fb5c8973 Parser tool draft 2025-05-26 23:50:57 +08:00
1b2694d2e4 Tool wip 2025-05-26 23:46:44 +08:00
376c86051a WIP Tooling 2025-05-26 23:21:16 +08:00
cf51259899 Cleanup & WIP tooling 2025-05-26 23:21:07 +08:00
9e52c0147d Cleanup and move deps 2025-05-26 22:41:27 +08:00
55aa93eee2 Move tooling to subproject 2025-05-25 16:10:17 +08:00
5b8a014013 Creating file test.cpp 2025-05-25 15:47:35 +08:00
aa93dba62f Add tooling 2025-05-25 15:47:27 +08:00
6e748b6c94 WIP 2025-05-25 15:47:21 +08:00
494038ebde Editing file CMakeLists.txt 2025-05-25 15:46:51 +08:00
649 changed files with 436228 additions and 12012 deletions

6
.gitignore vendored
View File

@@ -19,5 +19,11 @@ headers
ACP_Ray2/
build/
build_msvc/
# game_re/
windows_libs/
tooling/build/
*.code-workspace
*.log
.edits_backup/

12
.gitmodules vendored
View File

@@ -1,3 +1,15 @@
[submodule "game_re/third_party/spdlog"]
path = game_re/third_party/spdlog
url = https://github.com/gabime/spdlog.git
[submodule "tooling2/third_party/tree-sitter"]
path = tooling/third_party/tree-sitter
url = https://github.com/guusw/tree-sitter.git
[submodule "tooling2/third_party/tree-sitter-cpp"]
path = tooling/third_party/tree-sitter-cpp
url = https://github.com/guusw/tree-sitter-cpp.git
[submodule "third_party/hooker"]
path = third_party/hooker
url = https://github.com/guusw/hooker.git
[submodule "third_party/magic_enum"]
path = third_party/magic_enum
url = https://github.com/Neargye/magic_enum.git

View File

@@ -1,9 +1,23 @@
cmake_minimum_required(VERSION 3.26.4)
project(reman3)
# Build for 32-bit compatibility, until code is binary compatible with 64-bit
option(R3_32BIT "Build for 32-bit compatibility" ON)
if(R3_32BIT)
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
add_link_options(/machine:x86)
else()
add_compile_options(-m32)
add_link_options(-m32)
endif()
endif()
set(GAME_DATA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/game)
add_subdirectory(third_party)
add_subdirectory(game_re)
add_subdirectory(patcher)
# Use highest possible C standard
set_target_properties(game_re PROPERTIES C_STANDARD 23)

741
GhidraPlugin/.classpath Normal file
View File

@@ -0,0 +1,741 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="bin/scripts" path="ghidra_scripts"/>
<classpathentry kind="src" output="bin/main" path="src/main/help"/>
<classpathentry kind="src" output="bin/main" path="src/main/resources"/>
<classpathentry kind="src" output="bin/test" path="src/test/java"/>
<classpathentry kind="src" output="bin/main" path="src/main/java"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk-21.0.7.6-hotspot"/>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/68000/lib/68000.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/68000/lib/68000-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/8051/lib/8051.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/AARCH64/lib/AARCH64.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/AARCH64/lib/AARCH64-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/ARM/lib/ARM.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/ARM/lib/ARM-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Debug/AnnotationValidator/lib/AnnotationValidator.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Debug/AnnotationValidator/lib/AnnotationValidator-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/Atmel/lib/Atmel.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/Atmel/lib/Atmel-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/BSim/lib/BSim.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/BSim/lib/BSim-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/BSim/lib/commons-dbcp2-2.9.0.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/BSim/lib/commons-logging-1.2.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/BSim/lib/commons-pool2-2.11.1.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/BSim/lib/h2-2.2.220.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/BSim/lib/postgresql-42.7.3.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/BSimFeatureVisualizer/lib/BSimFeatureVisualizer.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/BSimFeatureVisualizer/lib/BSimFeatureVisualizer-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/Base/lib/Base.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/Base/lib/Base-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/Base/lib/biz.aQute.bnd.util-7.0.0.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/Base/lib/biz.aQute.bndlib-7.0.0.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/Base/lib/org.apache.felix.framework-7.0.5.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/Base/lib/org.osgi.util.promise-1.3.0.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/Base/lib/phidias-0.3.7.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/Base/lib/slf4j-api-1.7.25.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/Base/lib/slf4j-nop-1.7.25.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/BytePatterns/lib/BytePatterns.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/BytePatterns/lib/BytePatterns-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/ByteViewer/lib/ByteViewer.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/ByteViewer/lib/ByteViewer-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/CodeCompare/lib/CodeCompare.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/CodeCompare/lib/CodeCompare-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/DATA/lib/DATA.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/DATA/lib/DATA-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/DB/lib/DB.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/DB/lib/DB-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/Dalvik/lib/Dalvik.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/Dalvik/lib/Dalvik-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/DebugUtils/lib/DebugUtils.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/DebugUtils/lib/DebugUtils-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Debug/Debugger/lib/Debugger.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Debug/Debugger/lib/Debugger-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Debug/Debugger-api/lib/Debugger-api.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Debug/Debugger-api/lib/Debugger-api-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Debug/Debugger-isf/lib/Debugger-isf.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Debug/Debugger-isf/lib/Debugger-isf-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Debug/Debugger-jpda/lib/Debugger-jpda.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Debug/Debugger-jpda/lib/Debugger-jpda-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Debug/Debugger-rmi-trace/lib/Debugger-rmi-trace.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Debug/Debugger-rmi-trace/lib/Debugger-rmi-trace-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/Decompiler/lib/Decompiler.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/Decompiler/lib/Decompiler-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/DecompilerDependent/lib/DecompilerDependent.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/DecompilerDependent/lib/DecompilerDependent-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Docking/lib/Docking.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Docking/lib/Docking-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Emulation/lib/asm-9.7.1.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Emulation/lib/asm-analysis-9.7.1.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Emulation/lib/asm-commons-9.7.1.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Emulation/lib/asm-tree-9.7.1.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Emulation/lib/asm-util-9.7.1.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Emulation/lib/Emulation.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Emulation/lib/Emulation-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/FileFormats/lib/AXMLPrinter2.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/FileFormats/lib/baksmali-2.5.2.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/FileFormats/lib/dex-ir-2.4.24.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/FileFormats/lib/dex-reader-2.4.24.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/FileFormats/lib/dex-reader-api-2.4.24.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/FileFormats/lib/dex-translator-2.4.24.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/FileFormats/lib/dexlib2-2.5.2.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/FileFormats/lib/FileFormats.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/FileFormats/lib/FileFormats-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/FileFormats/lib/sevenzipjbinding-16.02-2.01.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/FileFormats/lib/sevenzipjbinding-all-platforms-16.02-2.01.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/FileFormats/lib/util-2.5.2.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/FileSystem/lib/FileSystem.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/FileSystem/lib/FileSystem-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Debug/Framework-AsyncComm/lib/Framework-AsyncComm.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Debug/Framework-AsyncComm/lib/Framework-AsyncComm-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Debug/Framework-AsyncComm/lib/protobuf-java-3.21.8.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Debug/Framework-TraceModeling/lib/Framework-TraceModeling.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Debug/Framework-TraceModeling/lib/Framework-TraceModeling-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/FunctionGraph/lib/FunctionGraph.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/FunctionGraph/lib/FunctionGraph-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/FunctionGraphDecompilerExtension/lib/FunctionGraphDecompilerExtension.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/FunctionGraphDecompilerExtension/lib/FunctionGraphDecompilerExtension-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/FunctionID/lib/FunctionID.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/FunctionID/lib/FunctionID-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Generic/lib/bcpkix-jdk15on-1.69.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Generic/lib/bcprov-jdk15on-1.69.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Generic/lib/bcutil-jdk15on-1.69.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Generic/lib/commons-collections4-4.1.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Generic/lib/commons-compress-1.21.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Generic/lib/commons-io-2.11.0.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Generic/lib/commons-lang3-3.12.0.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Generic/lib/commons-text-1.10.0.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Generic/lib/failureaccess-1.0.1.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Generic/lib/Generic.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Generic/lib/Generic-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Generic/lib/gson-2.9.0.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Generic/lib/guava-32.1.3-jre.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Generic/lib/jdom-legacy-1.1.3.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Generic/lib/log4j-api-2.17.1.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Generic/lib/log4j-core-2.17.1.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/GhidraGo/lib/GhidraGo.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/GhidraGo/lib/GhidraGo-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/GhidraServer/lib/GhidraServer.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/GhidraServer/lib/GhidraServer-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/GnuDemangler/lib/GnuDemangler.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/GnuDemangler/lib/GnuDemangler-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Graph/lib/Graph.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Graph/lib/Graph-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Graph/lib/jgrapht-core-1.5.1.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Graph/lib/jgrapht-io-1.5.1.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Graph/lib/jung-algorithms-2.1.1.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Graph/lib/jung-api-2.1.1.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Graph/lib/jung-graph-impl-2.1.1.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Graph/lib/jung-visualization-2.1.1.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/GraphFunctionCalls/lib/GraphFunctionCalls.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/GraphFunctionCalls/lib/GraphFunctionCalls-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/GraphServices/lib/GraphServices.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/GraphServices/lib/GraphServices-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/GraphServices/lib/jgrapht-core-1.5.1.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/GraphServices/lib/jgrapht-io-1.5.1.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/GraphServices/lib/jheaps-0.13.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/GraphServices/lib/jungrapht-layout-1.4.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/GraphServices/lib/jungrapht-visualization-1.4.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Gui/lib/flatlaf-3.5.4.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Gui/lib/Gui.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Gui/lib/Gui-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/HCS12/lib/HCS12.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/HCS12/lib/HCS12-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Help/lib/Help.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Help/lib/Help-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Help/lib/javahelp-2.0.05.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Help/lib/timingframework-1.0.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/JVM/lib/JVM.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/JVM/lib/JVM-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/Jython/lib/jython-standalone-2.7.4.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/Jython/lib/Jython.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/Jython/lib/Jython-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/Loongarch/lib/Loongarch.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/Loongarch/lib/Loongarch-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/MIPS/lib/MIPS.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/MIPS/lib/MIPS-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/MicrosoftCodeAnalyzer/lib/MicrosoftCodeAnalyzer.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/MicrosoftCodeAnalyzer/lib/MicrosoftCodeAnalyzer-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/MicrosoftDemangler/lib/MicrosoftDemangler.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/MicrosoftDemangler/lib/MicrosoftDemangler-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/MicrosoftDmang/lib/MicrosoftDmang.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/MicrosoftDmang/lib/MicrosoftDmang-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/PDB/lib/PDB.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/PDB/lib/PDB-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/PIC/lib/PIC.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/PIC/lib/PIC-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/PowerPC/lib/PowerPC.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/PowerPC/lib/PowerPC-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/ProgramDiff/lib/ProgramDiff.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/ProgramDiff/lib/ProgramDiff-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/ProgramGraph/lib/ProgramGraph.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/ProgramGraph/lib/ProgramGraph-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Project/lib/Project.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Project/lib/Project-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Project/lib/xz-1.9.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Debug/ProposedUtils/lib/ProposedUtils.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Debug/ProposedUtils/lib/ProposedUtils-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Pty/lib/jna-5.14.0.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Pty/lib/jna-platform-5.14.0.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Pty/lib/Pty.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Pty/lib/Pty-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Configurations/Public_Release/lib/Public_Release.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/PyGhidra/lib/PyGhidra.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/PyGhidra/lib/PyGhidra-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/RISCV/lib/RISCV.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/RISCV/lib/RISCV-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/Recognizers/lib/Recognizers.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/Recognizers/lib/Recognizers-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/Sarif/lib/java-sarif-2.1-modified.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/Sarif/lib/Sarif.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/Sarif/lib/Sarif-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/SoftwareModeling/lib/antlr-runtime-3.5.2.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/SoftwareModeling/lib/isorelax-20050913.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/SoftwareModeling/lib/msv-20050913.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/SoftwareModeling/lib/relaxngDatatype-20050913.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/SoftwareModeling/lib/SoftwareModeling.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/SoftwareModeling/lib/SoftwareModeling-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/SoftwareModeling/lib/xsdlib-20050913.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/SourceCodeLookup/lib/SourceCodeLookup.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/SourceCodeLookup/lib/SourceCodeLookup-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/Sparc/lib/Sparc.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/Sparc/lib/Sparc-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/SuperH4/lib/SuperH4.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/SuperH4/lib/SuperH4-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/SwiftDemangler/lib/SwiftDemangler.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/SwiftDemangler/lib/SwiftDemangler-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/SystemEmulation/lib/SystemEmulation.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/SystemEmulation/lib/SystemEmulation-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/TI_MSP430/lib/TI_MSP430.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/TI_MSP430/lib/TI_MSP430-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Debug/TaintAnalysis/lib/TaintAnalysis.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Debug/TaintAnalysis/lib/TaintAnalysis-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Utility/lib/Utility.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Framework/Utility/lib/Utility-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/V850/lib/V850.jar">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/VersionTracking/lib/VersionTracking.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/VersionTracking/lib/VersionTracking-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/VersionTrackingBSim/lib/VersionTrackingBSim.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/VersionTrackingBSim/lib/VersionTrackingBSim-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/WildcardAssembler/lib/WildcardAssembler.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Features/WildcardAssembler/lib/WildcardAssembler-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Users/Guus/AppData/Roaming/ghidra/ghidra_11.3.2_PUBLIC/Extensions/XEXLoaderWV/lib/XEXLoaderWV.jar" sourcepath="C:/Users/Guus/AppData/Roaming/ghidra/ghidra_11.3.2_PUBLIC/Extensions/XEXLoaderWV/lib/XEXLoaderWV-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/Xtensa/lib/Xtensa.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/Xtensa/lib/Xtensa-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/eBPF/lib/eBPF.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/eBPF/lib/eBPF-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/tricore/lib/tricore.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/tricore/lib/tricore-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/x86/lib/x86.jar" sourcepath="C:/Projects/ghidra_11.3.2_PUBLIC/Ghidra/Processors/x86/lib/x86-src.zip">
<attributes>
<attribute name="javadoc_location" value="jar:file:/C:\Projects\ghidra_11.3.2_PUBLIC\docs\GhidraAPI_javadoc.zip!/api/"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="bin/main"/>
</classpath>

24
GhidraPlugin/.project Normal file
View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>GhidraPlugin</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
<linkedResources>
<link>
<name>Ghidra</name>
<type>2</type>
<location>C:/Projects/ghidra_11.3.2_PUBLIC</location>
</link>
</linkedResources>
</projectDescription>

View File

@@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8

View File

@@ -0,0 +1,47 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=21
org.eclipse.jdt.core.compiler.compliance=21
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=error
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
org.eclipse.jdt.core.compiler.problem.deprecation=warning
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=error
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=error
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning
org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
org.eclipse.jdt.core.compiler.problem.nullReference=warning
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.source=21

View File

1
GhidraPlugin/README.md Normal file
View File

@@ -0,0 +1 @@
# GhidraPlugin

View File

@@ -0,0 +1,57 @@
<?xml version='1.0' encoding='ISO-8859-1' ?>
<!--
This is an XML file intended to be parsed by the Ghidra help system. It is loosely based
upon the JavaHelp table of contents document format. The Ghidra help system uses a
TOC_Source.xml file to allow a module with help to define how its contents appear in the
Ghidra help viewer's table of contents. The main document (in the Base module)
defines a basic structure for the
Ghidra table of contents system. Other TOC_Source.xml files may use this structure to insert
their files directly into this structure (and optionally define a substructure).
In this document, a tag can be either a <tocdef> or a <tocref>. The former is a definition
of an XML item that may have a link and may contain other <tocdef> and <tocref> children.
<tocdef> items may be referred to in other documents by using a <tocref> tag with the
appropriate id attribute value. Using these two tags allows any module to define a place
in the table of contents system (<tocdef>), which also provides a place for
other TOC_Source.xml files to insert content (<tocref>).
During the help build time, all TOC_Source.xml files will be parsed and validated to ensure
that all <tocref> tags point to valid <tocdef> tags. From these files will be generated
<module name>_TOC.xml files, which are table of contents files written in the format
desired by the JavaHelp system. Additionally, the genated files will be merged together
as they are loaded by the JavaHelp system. In the end, when displaying help in the Ghidra
help GUI, there will be on table of contents that has been created from the definitions in
all of the modules' TOC_Source.xml files.
Tags and Attributes
<tocdef>
-id - the name of the definition (this must be unique across all TOC_Source.xml files)
-text - the display text of the node, as seen in the help GUI
-target** - the file to display when the node is clicked in the GUI
-sortgroup - this is a string that defines where a given node should appear under a given
parent. The string values will be sorted by the JavaHelp system using
a javax.text.RulesBasedCollator. If this attribute is not specified, then
the text of attribute will be used.
<tocref>
-id - The id of the <tocdef> that this reference points to
**The URL for the target is relative and should start with 'help/topics'. This text is
used by the Ghidra help system to provide a universal starting point for all links so that
they can be resolved at runtime, across modules.
-->
<tocroot>
<!-- Uncomment and adjust fields to add help topic to help system's Table of Contents
<tocref id="Ghidra Functionality">
<tocdef id="HelpAnchor" text="My Feature" target="help/topics/my_topic/help.html" />
</tocref>
-->
</tocroot>

View File

@@ -0,0 +1,23 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<META name="generator" content=
"HTML Tidy for Java (vers. 2009-12-01), see jtidy.sourceforge.net">
<META http-equiv="Content-Language" content="en-us">
<META http-equiv="Content-Type" content="text/html; charset=windows-1252">
<META name="GENERATOR" content="Microsoft FrontPage 4.0">
<META name="ProgId" content="FrontPage.Editor.Document">
<TITLE>Skeleton Help File for a Module</TITLE>
<LINK rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
</HEAD>
<BODY>
<H1><a name="HelpAnchor"></a>Skeleton Help File for a Module</H1>
<P>This is a simple skeleton help topic. For a better description of what should and should not
go in here, see the "sample" Ghidra extension in the Extensions/Ghidra directory, or see your
favorite help topic. In general, language modules do not have their own help topics.</P>
</BODY>
</HTML>

View File

@@ -0,0 +1,2 @@
The "src/resources/images" directory is intended to hold all image/icon files used by
this module.

View File

@@ -0,0 +1 @@
Java source directory to hold module-specific Ghidra scripts.

66
GhidraPlugin/build.gradle Normal file
View File

@@ -0,0 +1,66 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Builds a Ghidra Extension for a given Ghidra installation.
//
// An absolute path to the Ghidra installation directory must be supplied either by setting the
// GHIDRA_INSTALL_DIR environment variable or Gradle project property:
//
// > export GHIDRA_INSTALL_DIR=<Absolute path to Ghidra>
// > gradle
//
// or
//
// > gradle -PGHIDRA_INSTALL_DIR=<Absolute path to Ghidra>
//
// Gradle should be invoked from the directory of the project to build. Please see the
// application.gradle.version property in <GHIDRA_INSTALL_DIR>/Ghidra/application.properties
// for the correction version of Gradle to use for the Ghidra installation you specify.
//----------------------START "DO NOT MODIFY" SECTION------------------------------
def ghidraInstallDir
if (System.env.GHIDRA_INSTALL_DIR) {
ghidraInstallDir = System.env.GHIDRA_INSTALL_DIR
}
else if (project.hasProperty("GHIDRA_INSTALL_DIR")) {
ghidraInstallDir = project.getProperty("GHIDRA_INSTALL_DIR")
}
else {
ghidraInstallDir = "<REPLACE>"
}
task distributeExtension {
group "Ghidra"
apply from: new File(ghidraInstallDir).getCanonicalPath() + "/support/buildExtension.gradle"
dependsOn ':buildExtension'
}
//----------------------END "DO NOT MODIFY" SECTION-------------------------------
repositories {
// Declare dependency repositories here. This is not needed if dependencies are manually
// dropped into the lib/ directory.
// See https://docs.gradle.org/current/userguide/declaring_repositories.html for more info.
// Ex: mavenCentral()
}
dependencies {
// Any external dependencies added here will automatically be copied to the lib/ directory when
// this extension is built.
}
// Exclude additional files from the built extension
// Ex: buildExtension.exclude '.idea/**'

View File

@@ -0,0 +1,15 @@
The "data" directory is intended to hold data files that will be used by this module and will
not end up in the .jar file, but will be present in the zip or tar file. Typically, data
files are placed here rather than in the resources directory if the user may need to edit them.
An optional data/languages directory can exist for the purpose of containing various Sleigh language
specification files and importer opinion files.
The data/buildLanguage.xml is used for building the contents of the data/languages directory.
The skel language definition has been commented-out within the skel.ldefs file so that the
skeleton language does not show-up within Ghidra.
See the Sleigh language documentation (docs/languages/index.html) for details Sleigh language
specification syntax.

View File

@@ -0,0 +1,5 @@
name=@extname@
description=The extension description can be customized by editing the extension.properties file.
author=
createdOn=
version=@extversion@

View File

@@ -0,0 +1 @@
Java source directory to hold module-specific Ghidra scripts.

View File

@@ -0,0 +1,3 @@
The "lib" directory is intended to hold Jar files which this module is dependent upon. Jar files
may be placed in this directory manually, or automatically by maven via the dependencies block
of this module's build.gradle file.

View File

@@ -0,0 +1,3 @@
The "os/linux_x86_64" directory is intended to hold Linux native binaries
which this module is dependent upon. This directory may be eliminated for a specific
module if native binaries are not provided for the corresponding platform.

View File

@@ -0,0 +1,3 @@
The "os/mac_x86_64" directory is intended to hold macOS (OS X) native binaries
which this module is dependent upon. This directory may be eliminated for a specific
module if native binaries are not provided for the corresponding platform.

View File

@@ -0,0 +1,3 @@
The "os/win_x86_64" directory is intended to hold MS Windows native binaries (.exe)
which this module is dependent upon. This directory may be eliminated for a specific
module if native binaries are not provided for the corresponding platform.

View File

@@ -0,0 +1,57 @@
<?xml version='1.0' encoding='ISO-8859-1' ?>
<!--
This is an XML file intended to be parsed by the Ghidra help system. It is loosely based
upon the JavaHelp table of contents document format. The Ghidra help system uses a
TOC_Source.xml file to allow a module with help to define how its contents appear in the
Ghidra help viewer's table of contents. The main document (in the Base module)
defines a basic structure for the
Ghidra table of contents system. Other TOC_Source.xml files may use this structure to insert
their files directly into this structure (and optionally define a substructure).
In this document, a tag can be either a <tocdef> or a <tocref>. The former is a definition
of an XML item that may have a link and may contain other <tocdef> and <tocref> children.
<tocdef> items may be referred to in other documents by using a <tocref> tag with the
appropriate id attribute value. Using these two tags allows any module to define a place
in the table of contents system (<tocdef>), which also provides a place for
other TOC_Source.xml files to insert content (<tocref>).
During the help build time, all TOC_Source.xml files will be parsed and validated to ensure
that all <tocref> tags point to valid <tocdef> tags. From these files will be generated
<module name>_TOC.xml files, which are table of contents files written in the format
desired by the JavaHelp system. Additionally, the genated files will be merged together
as they are loaded by the JavaHelp system. In the end, when displaying help in the Ghidra
help GUI, there will be on table of contents that has been created from the definitions in
all of the modules' TOC_Source.xml files.
Tags and Attributes
<tocdef>
-id - the name of the definition (this must be unique across all TOC_Source.xml files)
-text - the display text of the node, as seen in the help GUI
-target** - the file to display when the node is clicked in the GUI
-sortgroup - this is a string that defines where a given node should appear under a given
parent. The string values will be sorted by the JavaHelp system using
a javax.text.RulesBasedCollator. If this attribute is not specified, then
the text of attribute will be used.
<tocref>
-id - The id of the <tocdef> that this reference points to
**The URL for the target is relative and should start with 'help/topics'. This text is
used by the Ghidra help system to provide a universal starting point for all links so that
they can be resolved at runtime, across modules.
-->
<tocroot>
<!-- Uncomment and adjust fields to add help topic to help system's Table of Contents
<tocref id="Ghidra Functionality">
<tocdef id="HelpAnchor" text="My Feature" target="help/topics/my_topic/help.html" />
</tocref>
-->
</tocroot>

View File

@@ -0,0 +1,23 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<META name="generator" content=
"HTML Tidy for Java (vers. 2009-12-01), see jtidy.sourceforge.net">
<META http-equiv="Content-Language" content="en-us">
<META http-equiv="Content-Type" content="text/html; charset=windows-1252">
<META name="GENERATOR" content="Microsoft FrontPage 4.0">
<META name="ProgId" content="FrontPage.Editor.Document">
<TITLE>Skeleton Help File for a Module</TITLE>
<LINK rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
</HEAD>
<BODY>
<H1><a name="HelpAnchor"></a>Skeleton Help File for a Module</H1>
<P>This is a simple skeleton help topic. For a better description of what should and should not
go in here, see the "sample" Ghidra extension in the Extensions/Ghidra directory, or see your
favorite help topic. In general, language modules do not have their own help topics.</P>
</BODY>
</HTML>

View File

@@ -0,0 +1,74 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidraplugin;
import ghidra.app.services.AbstractAnalyzer;
import ghidra.app.services.AnalyzerType;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.Program;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* Provide class-level documentation that describes what this analyzer does.
*/
public class GhidraPluginAnalyzer extends AbstractAnalyzer {
public GhidraPluginAnalyzer() {
// Name the analyzer and give it a description.
super("My Analyzer", "Analyzer description goes here", AnalyzerType.BYTE_ANALYZER);
}
@Override
public boolean getDefaultEnablement(Program program) {
// Return true if analyzer should be enabled by default
return true;
}
@Override
public boolean canAnalyze(Program program) {
// Examine 'program' to determine of this analyzer should analyze it. Return true
// if it can.
return true;
}
@Override
public void registerOptions(Options options, Program program) {
// If this analyzer has custom options, register them here
options.registerOption("Option name goes here", false, null,
"Option description goes here");
}
@Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
// Perform analysis when things get added to the 'program'. Return true if the
// analysis succeeded.
return false;
}
}

View File

@@ -0,0 +1,116 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidraplugin;
import java.awt.BorderLayout;
import javax.swing.*;
import docking.ActionContext;
import docking.ComponentProvider;
import docking.action.DockingAction;
import docking.action.ToolBarData;
import ghidra.app.ExamplesPluginPackage;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.ProgramPlugin;
import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.util.HelpLocation;
import ghidra.util.Msg;
import resources.Icons;
/**
* Provide class-level documentation that describes what this plugin does.
*/
//@formatter:off
@PluginInfo(
status = PluginStatus.STABLE,
packageName = ExamplesPluginPackage.NAME,
category = PluginCategoryNames.EXAMPLES,
shortDescription = "Plugin short description goes here.",
description = "Plugin long description goes here."
)
//@formatter:on
public class GhidraPluginPlugin extends ProgramPlugin {
MyProvider provider;
/**
* Plugin constructor.
*
* @param tool The plugin tool that this plugin is added to.
*/
public GhidraPluginPlugin(PluginTool tool) {
super(tool);
// Customize provider (or remove if a provider is not desired)
String pluginName = getName();
provider = new MyProvider(this, pluginName);
// Customize help (or remove if help is not desired)
String topicName = this.getClass().getPackage().getName();
String anchorName = "HelpAnchor";
provider.setHelpLocation(new HelpLocation(topicName, anchorName));
}
@Override
public void init() {
super.init();
// Acquire services if necessary
}
// If provider is desired, it is recommended to move it to its own file
private static class MyProvider extends ComponentProvider {
private JPanel panel;
private DockingAction action;
public MyProvider(Plugin plugin, String owner) {
super(plugin.getTool(), "Skeleton Provider", owner);
buildPanel();
createActions();
}
// Customize GUI
private void buildPanel() {
panel = new JPanel(new BorderLayout());
JTextArea textArea = new JTextArea(5, 25);
textArea.setEditable(false);
panel.add(new JScrollPane(textArea));
setVisible(true);
}
// Customize actions
private void createActions() {
action = new DockingAction("My Action", getOwner()) {
@Override
public void actionPerformed(ActionContext context) {
Msg.showInfo(getClass(), panel, "Custom Action", "Hello!");
}
};
action.setToolBarData(new ToolBarData(Icons.ADD_ICON, null));
action.setEnabled(true);
action.markHelpUnnecessary();
dockingTool.addLocalAction(this, action);
}
@Override
public JComponent getComponent() {
return panel;
}
}
}

View File

@@ -0,0 +1,409 @@
package ghidraplugin;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.ProgramPlugin;
import ghidra.framework.plugintool.PluginInfo;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramChangeRecord;
import ghidra.program.util.ProgramEvent;
import ghidra.util.Msg;
import ghidra.framework.model.*;
import ghidra.program.model.symbol.*;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Function;
import ghidra.program.util.*;
import ghidra.framework.cmd.Command;
import ghidra.framework.model.TransactionInfo;
@PluginInfo(
status = PluginStatus.STABLE,
packageName = "SymbolLogger",
category = PluginCategoryNames.COMMON,
shortDescription = "Logs symbol and function renames",
description = "A plugin that monitors and logs all symbol and function rename events to the console, including undo/redo context",
servicesRequired = {},
servicesProvided = {}
)
public class SymbolRenameLoggerPlugin extends ProgramPlugin implements DomainObjectListener {
public SymbolRenameLoggerPlugin(PluginTool tool) {
super(tool);
}
@Override
protected void init() {
super.init();
Msg.info(this, "SymbolRenameLoggerPlugin initialized");
}
@Override
protected void programActivated(Program program) {
super.programActivated(program);
if (program != null) {
program.addListener(this);
Msg.info(this, "Started listening for rename events in program: " + program.getName());
}
}
@Override
protected void programDeactivated(Program program) {
if (program != null) {
program.removeListener(this);
Msg.info(this, "Stopped listening for rename events in program: " + program.getName());
}
super.programDeactivated(program);
}
@Override
public void domainObjectChanged(DomainObjectChangedEvent ev) {
for (DomainObjectChangeRecord record : ev) {
if (record instanceof ProgramChangeRecord) {
ProgramChangeRecord progRecord = (ProgramChangeRecord) record;
handleProgramChange(progRecord);
}
}
}
/**
* Determines the context of the current operation (direct action, undo, or redo)
*/
private String getOperationContext() {
try {
Program program = getCurrentProgram();
if (program != null) {
TransactionInfo currentTransaction = program.getCurrentTransactionInfo();
if (currentTransaction != null) {
String description = currentTransaction.getDescription();
if (description != null) {
if (description.startsWith("Undo")) {
return "[UNDO] ";
} else if (description.startsWith("Redo")) {
return "[REDO] ";
}
}
}
}
} catch (Exception e) {
// Silently handle any exceptions in context detection
}
return ""; // Direct user action (no prefix)
}
/**
* Enhanced logging method that includes undo/redo context
*/
private void logWithContext(String message) {
String context = getOperationContext();
Msg.info(this, context + message);
}
private void handleProgramChange(ProgramChangeRecord record) {
ProgramEvent eventType = (ProgramEvent)record.getEventType();
Msg.info(this, "Event: " + record.toString());
// Handle symbol rename events
if (eventType == ProgramEvent.SYMBOL_RENAMED) {
handleSymbolRenamed(record);
}
// Handle function rename events (functions are also symbols, but we can be more specific)
else if (eventType == ProgramEvent.FUNCTION_CHANGED) {
handleFunctionChanged(record);
}
// Handle symbol added events (in case we want to track new symbols)
else if (eventType == ProgramEvent.SYMBOL_ADDED) {
handleSymbolAdded(record);
}
// Handle symbol removed events
else if (eventType == ProgramEvent.SYMBOL_REMOVED) {
handleSymbolRemoved(record);
}
// Handle data type changes (includes global type definitions, structures, etc.)
else if (eventType == ProgramEvent.DATA_TYPE_CHANGED) {
handleDataTypeChanged(record);
}
// Handle data type added events
else if (eventType == ProgramEvent.DATA_TYPE_ADDED) {
handleDataTypeAdded(record);
}
// Handle data type removed events
else if (eventType == ProgramEvent.DATA_TYPE_REMOVED) {
handleDataTypeRemoved(record);
}
// Handle data type renamed events
else if (eventType == ProgramEvent.DATA_TYPE_RENAMED) {
handleDataTypeRenamed(record);
}
// Handle function signature changes (parameters, return types, etc.)
else if (eventType == ProgramEvent.FUNCTION_CHANGED) {
handleFunctionSignatureChanged(record);
}
// Handle transaction events for better undo/redo tracking
// else if (eventType == ProgramEvent..TRANSACTION_STARTED) {
// handleTransactionStarted(record);
// }
// else if (eventType == ProgramEvent.TRANSACTION_ENDED) {
// handleTransactionEnded(record);
// }
}
private void handleTransactionStarted(ProgramChangeRecord record) {
String context = getOperationContext();
if (!context.isEmpty()) {
logWithContext("TRANSACTION STARTED");
}
}
private void handleTransactionEnded(ProgramChangeRecord record) {
String context = getOperationContext();
if (!context.isEmpty()) {
logWithContext("TRANSACTION ENDED");
}
}
private void handleSymbolRenamed(ProgramChangeRecord record) {
Object newValue = record.getNewValue();
Object oldValue = record.getOldValue();
String newName = (newValue != null) ? newValue.toString() : "null";
String oldName = (oldValue != null) ? oldValue.toString() : "null";
logWithContext(String.format("SYMBOL RENAMED: '%s' -> '%s' at address %s",
oldName, newName, record.getStart()));
// Try to get additional information about the symbol
try {
Program program = getCurrentProgram();
if (program != null) {
SymbolTable symbolTable = program.getSymbolTable();
Symbol[] symbols = symbolTable.getSymbols(record.getStart());
for (Symbol symbol : symbols) {
if (symbol.getName().equals(newName)) {
String symbolType = getSymbolTypeDescription(symbol);
logWithContext(String.format(" Symbol type: %s, Namespace: %s",
symbolType, symbol.getParentNamespace().getName()));
// If it's a function, log additional function details
if (symbol.getSymbolType() == SymbolType.FUNCTION) {
Function function = (Function) symbol.getObject();
if (function != null) {
logWithContext(String.format(" Function signature: %s",
function.getPrototypeString(false, false)));
}
}
break;
}
}
}
} catch (Exception e) {
Msg.error(this, "Error getting symbol details: " + e.getMessage());
}
}
private void handleFunctionChanged(ProgramChangeRecord record) {
// This handles function-specific changes including renames and signature changes
Object newValue = record.getNewValue();
Object oldValue = record.getOldValue();
if (newValue instanceof Function && oldValue instanceof Function) {
Function newFunc = (Function) newValue;
Function oldFunc = (Function) oldValue;
// Check for name changes
if (!newFunc.getName().equals(oldFunc.getName())) {
logWithContext(String.format("FUNCTION RENAMED: '%s' -> '%s' at address %s",
oldFunc.getName(), newFunc.getName(), newFunc.getEntryPoint()));
}
// Check for signature changes
String oldSignature = oldFunc.getPrototypeString(false, false);
String newSignature = newFunc.getPrototypeString(false, false);
if (!oldSignature.equals(newSignature)) {
logWithContext(String.format("FUNCTION SIGNATURE CHANGED at address %s:", newFunc.getEntryPoint()));
logWithContext(String.format(" Old: %s", oldSignature));
logWithContext(String.format(" New: %s", newSignature));
// Log specific changes
logFunctionSignatureDetails(oldFunc, newFunc);
}
} else if (newValue instanceof Function) {
Function function = (Function) newValue;
logWithContext(String.format("FUNCTION MODIFIED: %s at address %s",
function.getName(), function.getEntryPoint()));
logWithContext(String.format(" Signature: %s", function.getPrototypeString(false, false)));
}
}
private void handleFunctionSignatureChanged(ProgramChangeRecord record) {
// Handle detailed function signature changes
handleFunctionChanged(record); // Reuse the existing logic
}
private void handleDataTypeChanged(ProgramChangeRecord record) {
Object newValue = record.getNewValue();
Object oldValue = record.getOldValue();
logWithContext(String.format("DATA TYPE CHANGED at address %s", record.getStart()));
if (oldValue != null && newValue != null) {
logWithContext(String.format(" Old type: %s", oldValue.toString()));
logWithContext(String.format(" New type: %s", newValue.toString()));
} else if (newValue != null) {
logWithContext(String.format(" Type set to: %s", newValue.toString()));
}
// Try to get more context about the data type change
try {
Program program = getCurrentProgram();
if (program != null && record.getStart() != null) {
Data data = program.getListing().getDataAt(record.getStart());
if (data != null) {
logWithContext(String.format(" Data label: %s", data.getLabel()));
logWithContext(String.format(" Data type: %s", data.getDataType().getName()));
}
}
} catch (Exception e) {
Msg.error(this, "Error getting data type details: " + e.getMessage());
}
}
private void handleDataTypeAdded(ProgramChangeRecord record) {
Object newValue = record.getNewValue();
logWithContext(String.format("DATA TYPE ADDED at address %s", record.getStart()));
if (newValue != null) {
logWithContext(String.format(" Type: %s", newValue.toString()));
}
}
private void handleDataTypeRemoved(ProgramChangeRecord record) {
Object oldValue = record.getOldValue();
logWithContext(String.format("DATA TYPE REMOVED at address %s", record.getStart()));
if (oldValue != null) {
logWithContext(String.format(" Removed type: %s", oldValue.toString()));
}
}
private void handleDataTypeRenamed(ProgramChangeRecord record) {
Object newValue = record.getNewValue();
Object oldValue = record.getOldValue();
String newName = (newValue != null) ? newValue.toString() : "null";
String oldName = (oldValue != null) ? oldValue.toString() : "null";
logWithContext(String.format("DATA TYPE RENAMED: '%s' -> '%s' at address %s",
oldName, newName, record.getStart()));
}
private void logFunctionSignatureDetails(Function oldFunc, Function newFunc) {
try {
// Check return type changes
if (!oldFunc.getReturnType().equals(newFunc.getReturnType())) {
logWithContext(String.format(" Return type changed: %s -> %s",
oldFunc.getReturnType().getName(), newFunc.getReturnType().getName()));
}
// Check parameter count changes
int oldParamCount = oldFunc.getParameterCount();
int newParamCount = newFunc.getParameterCount();
if (oldParamCount != newParamCount) {
logWithContext(String.format(" Parameter count changed: %d -> %d",
oldParamCount, newParamCount));
}
// Check individual parameter changes
int maxParams = Math.max(oldParamCount, newParamCount);
for (int i = 0; i < maxParams; i++) {
if (i < oldParamCount && i < newParamCount) {
ghidra.program.model.listing.Parameter oldParam = oldFunc.getParameter(i);
ghidra.program.model.listing.Parameter newParam = newFunc.getParameter(i);
if (!oldParam.getDataType().equals(newParam.getDataType())) {
logWithContext(String.format(" Parameter %d type changed: %s -> %s",
i, oldParam.getDataType().getName(), newParam.getDataType().getName()));
}
if (!oldParam.getName().equals(newParam.getName())) {
logWithContext(String.format(" Parameter %d name changed: %s -> %s",
i, oldParam.getName(), newParam.getName()));
}
} else if (i < newParamCount) {
ghidra.program.model.listing.Parameter newParam = newFunc.getParameter(i);
logWithContext(String.format(" Parameter %d added: %s %s",
i, newParam.getDataType().getName(), newParam.getName()));
} else {
ghidra.program.model.listing.Parameter oldParam = oldFunc.getParameter(i);
logWithContext(String.format(" Parameter %d removed: %s %s",
i, oldParam.getDataType().getName(), oldParam.getName()));
}
}
// Check calling convention changes
if (!oldFunc.getCallingConventionName().equals(newFunc.getCallingConventionName())) {
logWithContext(String.format(" Calling convention changed: %s -> %s",
oldFunc.getCallingConventionName(), newFunc.getCallingConventionName()));
}
} catch (Exception e) {
Msg.error(this, "Error logging function signature details: " + e.getMessage());
}
}
private void handleSymbolAdded(ProgramChangeRecord record) {
Object newValue = record.getNewValue();
if (newValue instanceof Symbol) {
Symbol symbol = (Symbol) newValue;
String symbolType = getSymbolTypeDescription(symbol);
logWithContext(String.format("SYMBOL ADDED: '%s' (%s) at address %s",
symbol.getName(), symbolType, symbol.getAddress()));
}
}
private void handleSymbolRemoved(ProgramChangeRecord record) {
Object oldValue = record.getOldValue();
if (oldValue instanceof Symbol) {
Symbol symbol = (Symbol) oldValue;
String symbolType = getSymbolTypeDescription(symbol);
logWithContext(String.format("SYMBOL REMOVED: '%s' (%s) at address %s",
symbol.getName(), symbolType, symbol.getAddress()));
}
}
private String getSymbolTypeDescription(Symbol symbol) {
SymbolType type = symbol.getSymbolType();
if (type == SymbolType.FUNCTION) {
return "Function";
} else if (type == SymbolType.LABEL) {
return "Label";
} else if (type == SymbolType.CLASS) {
return "Class";
} else if (type == SymbolType.NAMESPACE) {
return "Namespace";
} else if (type == SymbolType.PARAMETER) {
return "Parameter";
} else if (type == SymbolType.LOCAL_VAR) {
return "Local Variable";
} else if (type == SymbolType.GLOBAL_VAR) {
return "Global Variable";
} else if (type == SymbolType.LIBRARY) {
return "Library";
} else {
return type.toString();
}
}
@Override
protected void dispose() {
Program program = getCurrentProgram();
if (program != null) {
program.removeListener(this);
}
super.dispose();
Msg.info(this, "SymbolRenameLoggerPlugin disposed");
}
}

View File

@@ -0,0 +1,2 @@
The "src/resources/images" directory is intended to hold all image/icon files used by
this module.

View File

@@ -0,0 +1,150 @@
// Cleanup the database of all missing files, and report duplicates
// @category _Reman3
// @menupath Reman3.Cleanup Database
// @importpackage org.sqlite
import ghidra.app.script.GhidraScript;
import ghidra.program.model.listing.Function;
import re3lib.FunctionDumper;
import re3lib.GlobalDumper;
import re3lib.RemanConfig;
import re3lib.FunctionDatabase;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;
import ghidra.program.model.address.Address;
public class CleanupDatabase extends GhidraScript {
@Override
public void run() throws Exception {
RemanConfig.INSTANCE = new RemanConfig(this);
RemanConfig.INSTANCE.createDirectories();
boolean anyChanges = false;
try (FunctionDatabase functionDatabase = new FunctionDatabase(this)) {
functionDatabase.connect();
// Step 1: Check for missing files and remove entries
anyChanges |= cleanupMissingFiles(functionDatabase);
// Step 2: Check for duplicate addresses
anyChanges |= reportDuplicateAddresses(functionDatabase);
// Step 3: Check if database names match function names
anyChanges |= validateFunctionNames(functionDatabase);
if (anyChanges) {
println("Database cleanup completed with changes - touching CMake timestamp");
RemanConfig.INSTANCE.touchCMakeTimestamp();
} else {
println("Database cleanup completed - no changes needed");
}
}
}
private boolean cleanupMissingFiles(FunctionDatabase functionDatabase) throws Exception {
println("=== Step 1: Checking for missing files ===");
boolean madeChanges = false;
List<FunctionDatabase.FunctionEntry> entries = functionDatabase.loadAllEntries();
List<FunctionDatabase.FunctionEntry> entriesToRemove = new ArrayList<>();
for (FunctionDatabase.FunctionEntry entry : entries) {
if (!entry.file.exists()) {
println("Missing file: " + entry.file.getAbsolutePath() + " for function " + entry.name);
entriesToRemove.add(entry);
}
}
for (FunctionDatabase.FunctionEntry entry : entriesToRemove) {
println("Removing database entry for missing file: " + entry.file.getAbsolutePath());
functionDatabase.removeEntryAt(entry.file.getAbsolutePath());
madeChanges = true;
}
println("Removed " + entriesToRemove.size() + " entries for missing files");
return madeChanges;
}
private boolean reportDuplicateAddresses(FunctionDatabase functionDatabase) throws Exception {
println("=== Step 2: Checking for duplicate addresses ===");
boolean madeChanges = false;
List<FunctionDatabase.FunctionEntry> entries = functionDatabase.loadAllEntries();
Map<Address, List<FunctionDatabase.FunctionEntry>> addressMap = new HashMap<>();
// Group entries by address
for (FunctionDatabase.FunctionEntry entry : entries) {
if (entry.type == FunctionDatabase.Type.Ref)
continue;
if (!addressMap.containsKey(entry.address)) {
addressMap.put(entry.address, new ArrayList<>());
}
addressMap.get(entry.address).add(entry);
}
// Check for duplicates
for (Map.Entry<Address, List<FunctionDatabase.FunctionEntry>> mapEntry : addressMap.entrySet()) {
List<FunctionDatabase.FunctionEntry> duplicates = mapEntry.getValue();
if (duplicates.size() > 1) {
println("Found " + duplicates.size() + " entries for address " + mapEntry.getKey() + ":");
// Report all entries
for (FunctionDatabase.FunctionEntry entry : duplicates) {
println(" - " + entry.type + ": " + entry.file.getAbsolutePath() + " (name: " + entry.name + ")");
}
}
}
return madeChanges;
}
private boolean validateFunctionNames(FunctionDatabase functionDatabase) throws Exception {
println("=== Step 3: Validating function names ===");
boolean madeChanges = false;
List<FunctionDatabase.FunctionEntry> entries = functionDatabase.loadAllEntries();
List<FunctionDatabase.FunctionEntry> entriesToUpdate = new ArrayList<>();
List<FunctionDatabase.FunctionEntry> entriesToRemove = new ArrayList<>();
for (FunctionDatabase.FunctionEntry entry : entries) {
Function function = getFunctionAt(entry.address);
if (function == null) {
println("No function found at address " + entry.address + " for database entry: " + entry.name);
println(" Removing orphaned database entry");
entriesToRemove.add(entry);
} else {
String actualName = function.getName();
if (!actualName.equals(entry.name)) {
println("Name mismatch at " + entry.address + ":");
println(" Database name: " + entry.name);
println(" Actual name: " + actualName);
// Update the entry with the correct name
entry.name = actualName;
entriesToUpdate.add(entry);
}
}
}
// Report orphaned entries
for (FunctionDatabase.FunctionEntry entry : entriesToRemove) {
println("Found orphaned entry: " + entry.file.getAbsolutePath() + " for function " + entry.name + " at address "
+ entry.address);
}
// Update entries with corrected names
for (FunctionDatabase.FunctionEntry entry : entriesToUpdate) {
println("Updating database entry for " + entry.address + " with correct name: " + entry.name);
functionDatabase.addEntryAt(entry);
madeChanges = true;
}
println("Removed " + entriesToRemove.size() + " orphaned entries");
println("Updated " + entriesToUpdate.size() + " entries with corrected names");
return madeChanges;
}
}

View File

@@ -0,0 +1,36 @@
// Script to export decompiled C code for selected function from Ghidra
// @category _Reman3
// @menupath Reman3.Dump Current Function
// @importpackage org.sqlite
import ghidra.app.script.GhidraScript;
import ghidra.program.model.listing.Function;
import re3lib.FunctionDumper;
import re3lib.GlobalDumper;
import re3lib.RemanConfig;
import re3lib.FunctionDatabase;
public class DumpCurrentFunction extends GhidraScript {
@Override
public void run() throws Exception {
RemanConfig.INSTANCE = new RemanConfig(this);
RemanConfig.INSTANCE.createDirectories();
try (FunctionDatabase functionDatabase = new FunctionDatabase(this)) {
GlobalDumper globalDumper = new GlobalDumper(this, functionDatabase);
FunctionDumper functionDumper = new FunctionDumper(this, functionDatabase, globalDumper);
Function currentFunction = getFunctionContaining(currentAddress);
if (currentFunction != null) {
functionDumper.dump(currentFunction);
} else {
println("No function found at the current address.");
}
if (functionDumper.createdFile)
RemanConfig.INSTANCE.touchCMakeTimestamp();
globalDumper.dumpGlobals();
}
}
}

View File

@@ -0,0 +1,39 @@
// Script to export decompiled C code for selected function from Ghidra as Fix type
// @category _Reman3
// @menupath Reman3.Dump Current Function (Fix)
// @importpackage org.sqlite
import ghidra.app.script.GhidraScript;
import ghidra.program.model.listing.Function;
import re3lib.FunctionDumper;
import re3lib.GlobalDumper;
import re3lib.RemanConfig;
import re3lib.FunctionDatabase;
public class DumpCurrentFunctionFix extends GhidraScript {
@Override
public void run() throws Exception {
RemanConfig.INSTANCE = new RemanConfig(this);
RemanConfig.INSTANCE.createDirectories();
try (FunctionDatabase functionDatabase = new FunctionDatabase(this)) {
GlobalDumper globalDumper = new GlobalDumper(this, functionDatabase);
FunctionDumper functionDumper = new FunctionDumper(this, functionDatabase, globalDumper);
// Force Fix type instead of Auto
functionDumper.forceFixType = true;
Function currentFunction = getFunctionContaining(currentAddress);
if (currentFunction != null) {
functionDumper.dump(currentFunction);
} else {
println("No function found at the current address.");
}
if (functionDumper.createdFile)
RemanConfig.INSTANCE.touchCMakeTimestamp();
globalDumper.dumpGlobals();
}
}
}

View File

@@ -0,0 +1,112 @@
// Decompile selected function recursively (until a given number of new functions is reached)
// @category _Reman3
// @menupath Reman3.Dump N Functions
// @importpackage org.sqlite
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import ghidra.app.script.GhidraScript;
import ghidra.pcodeCPort.address.Address;
import ghidra.program.model.listing.Function;
import re3lib.FunctionDatabase;
import re3lib.FunctionDumper;
import re3lib.GlobalDumper;
import re3lib.PCallTracer;
import re3lib.RemanConfig;
import re3lib.TypeDumper;
public class DumpCurrentFunctionN extends GhidraScript {
final int NumFunctions = 8;
// class Entry {
// Function function;
// }
// class QueueEntry {
// Function function;
// List<Function> callees;
// }
// HashSet<Address> visited = new HashSet<>();
// QueueEntry enter(Function function) {
// if (visited.contains(function.getEntryPoint()))
// return null;
// visited.add(function.getEntryPoint());
// QueueEntry entry = new QueueEntry();
// entry.function = function;
// function.getCalledFunctions(monitor);
// }
@Override
public void run() throws Exception {
RemanConfig.INSTANCE = new RemanConfig(this);
RemanConfig.INSTANCE.createDirectories();
try (FunctionDatabase functionDatabase = new FunctionDatabase(this)) {
GlobalDumper globalDumper = new GlobalDumper(this, functionDatabase);
FunctionDumper functionDumper = new FunctionDumper(this, functionDatabase, globalDumper);
PCallTracer tracer = new PCallTracer();
tracer.setBlacklist(functionDumper.functionAddrBlackList);
tracer.traceCalls(getFunctionContaining(currentAddress));
List<Address> queue = new ArrayList<>();
// List<Function> functionsToDump = new ArrayList<>();
// List<Function> functionsToDumpNew = new ArrayList<>();
// for (Function func : tracer.out) {
// if (FunctionDumper.isDumpedFix(func))
// continue;
// println("Dump: " + func.getName());
// functionsToDump.add(func);
// if (!FunctionDumper.isDumpedAuto(func))
// functionsToDumpNew.add(func);
// }
// if (!functionsToDump.isEmpty()) {
// String newOpt = "Only new (" + functionsToDumpNew.size() + ")";
// String okOpt = "Yes (" + functionsToDump.size() + ")";
// String choice = askChoice("Confirmation", "About to generate " +
// functionsToDump.size() + " functions ("
// + functionsToDumpNew.size() + " new), continue?",
// new ArrayList<String>() {
// {
// add(okOpt);
// add(newOpt);
// add("No");
// }
// }, okOpt);
// if (choice == okOpt) {
// } else if (choice == newOpt) {
// functionsToDump = functionsToDumpNew;
// } else {
// return;
// }
// for (Function func : functionsToDump) {
// functionDumper.dump(func);
// }
// if (functionDumper.createdFile)
// RecompileConfig.INSTANCE.touchCMakeTimestamp();
// globalDumper.dumpGlobals();
// globalDumper.saveGlobalManifest();
// }
// // Dump types
// TypeDumper dumper = new TypeDumper(this);
// dumper.run();
}
}
}

View File

@@ -0,0 +1,91 @@
// Decompile selected function recursively
// @category _Reman3
// @menupath Reman3.Dump Current Function (recursive)
// @importpackage org.sqlite
import java.util.ArrayList;
import java.util.List;
import ghidra.app.script.GhidraScript;
import ghidra.program.model.listing.Function;
import re3lib.FunctionDatabase;
import re3lib.FunctionDumper;
import re3lib.GlobalDumper;
import re3lib.PCallTracer;
import re3lib.RemanConfig;
import re3lib.TypeDumper;
public class DumpCurrentFunctionRecursive extends GhidraScript {
@Override
public void run() throws Exception {
RemanConfig.INSTANCE = new RemanConfig(this);
RemanConfig.INSTANCE.createDirectories();
try (FunctionDatabase functionDatabase = new FunctionDatabase(this)) {
GlobalDumper globalDumper = new GlobalDumper(this, functionDatabase);
FunctionDumper functionDumper = new FunctionDumper(this, functionDatabase, globalDumper);
PCallTracer tracer = new PCallTracer();
tracer.setBlacklist(functionDumper.functionAddrBlackList);
tracer.traceCalls(getFunctionContaining(currentAddress));
List<Function> functionsToDump = new ArrayList<>();
List<Function> functionsToDumpNew = new ArrayList<>();
for (Function func : tracer.out) {
List<FunctionDatabase.FunctionEntry> entries = functionDatabase.findEntriesByAddress(func.getEntryPoint());
boolean shouldDump = true;
boolean isNew = true;
for (FunctionDatabase.FunctionEntry entry : entries) {
if (entry.type == FunctionDatabase.Type.Fix) {
shouldDump = false;
}
if (entry.type == FunctionDatabase.Type.Fix || entry.type == FunctionDatabase.Type.Auto) {
isNew = false;
}
}
if (!shouldDump)
continue;
println("Dump: " + func.getName());
functionsToDump.add(func);
if (isNew)
functionsToDumpNew.add(func);
}
if (!functionsToDump.isEmpty()) {
String newOpt = "Only new (" + functionsToDumpNew.size() + ")";
String okOpt = "Yes (" + functionsToDump.size() + ")";
String choice = askChoice("Confirmation", "About to generate " + functionsToDump.size() + " functions ("
+ functionsToDumpNew.size() + " new), continue?",
new ArrayList<String>() {
{
add(okOpt);
add(newOpt);
add("No");
}
}, okOpt);
if (choice == okOpt) {
} else if (choice == newOpt) {
functionsToDump = functionsToDumpNew;
} else {
return;
}
for (Function func : functionsToDump) {
functionDumper.dump(func);
}
if (functionDumper.createdFile)
RemanConfig.INSTANCE.touchCMakeTimestamp();
globalDumper.dumpGlobals();
}
// Dump types
TypeDumper dumper = new TypeDumper(this);
dumper.run();
}
}
}

View File

@@ -0,0 +1,26 @@
// Script to refresh all custom globals & types from Ghidra
// @category _Reman3
// @menupath Reman3.Redump Globals and Types
// @importpackage org.sqlite
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.dumpGlobals();
TypeDumper dumper = new TypeDumper(this);
dumper.run();
}
}
}

View File

@@ -1,6 +1,7 @@
// Script to dump all custom types from Ghidra
// @category _Reman3
// @menupath Reman3.Dump Types
// @importpackage org.sqlite
import ghidra.app.script.GhidraScript;
import ghidra.program.model.data.DataType;

View File

@@ -1,13 +1,14 @@
// Exports binary read only and data segments to a binary + header file
// @category _Reman3
// @menupath Tools.Reman3.Export Data
// @menupath Reman3.Export Data Segment
// @importpackage org.sqlite
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.Address;
import re3lib.RecompileConfig;
import re3lib.RemanConfig;
public class ExportData extends GhidraScript {
@@ -16,16 +17,16 @@ public class ExportData extends GhidraScript {
if (currentProgram == null) {
return;
}
RecompileConfig.INSTANCE = new RecompileConfig(this);
RemanConfig.INSTANCE = new RemanConfig(this);
String dataFile = new File(RecompileConfig.INSTANCE.outputDir, "gh_datasegment.bin").toString();
String headerFile = new File(RecompileConfig.INSTANCE.outputDir, "gh_datasegment.h").toString();
String dataFile = new File(RemanConfig.INSTANCE.outputDir, "gh_datasegment.bin").toString();
String headerFile = new File(RemanConfig.INSTANCE.outputDir, "gh_datasegment.h").toString();
FileOutputStream dataOutputStream = new FileOutputStream(dataFile);
PrintWriter headerWriter = new PrintWriter(headerFile, "UTF-8");
Address startAddr = RecompileConfig.INSTANCE.staticMemoryBlockStart;
Address endAddr = RecompileConfig.INSTANCE.staticMemoryBlockEnd;
Address startAddr = RemanConfig.INSTANCE.staticMemoryBlockStart;
Address endAddr = RemanConfig.INSTANCE.staticMemoryBlockEnd;
// Dump all the memory to the bin file
int numBytes = (int) endAddr.subtract(startAddr);

View File

@@ -0,0 +1,448 @@
// Script to find hardcoded addresses in the binary that need to be relocated
// @category _Reman3
// @menupath Reman3.Find and dump Relocations
// @importpackage org.sqlite
import ghidra.app.script.GhidraScript;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.address.*;
import ghidra.program.model.scalar.Scalar;
import ghidra.program.model.symbol.Reference;
import ghidra.program.model.pcode.*;
import java.util.*;
import java.io.*;
import re3lib.RemanConfig;
public class FindRelocations extends GhidraScript {
private Set<String> foundRelocations = new HashSet<>();
private PrintWriter outputFile;
long addrMin, addrMax;
private void analyzeInstruction(Instruction instruction) {
String mnemonic = instruction.getMnemonicString().toLowerCase();
boolean trace = instruction.getAddress().getOffset() == 0x004ac0f0;
if (trace) {
println("DEBUG: " + mnemonic + " at " + instruction.getAddress());
}
// Check for instructions that commonly use absolute addresses
if (isRelocatableInstruction(mnemonic)) {
// Always run both analyses to catch all cases
// Pcode analysis is better for complex addressing, reference analysis catches
// simple cases
Set<String> foundAddresses = new HashSet<>();
analyzePcodeForConstants(instruction, trace, foundAddresses);
analyzeReferences(instruction, trace, foundAddresses);
}
}
@Override
public void run() throws Exception {
RemanConfig.INSTANCE = new RemanConfig(this);
RemanConfig.INSTANCE.createDirectories();
addrMin = RemanConfig.INSTANCE.staticMemoryBlockStart.getOffset();
addrMax = RemanConfig.INSTANCE.staticMemoryBlockEnd.getOffset();
// Create output file for relocations
File relocFile = new File(RemanConfig.INSTANCE.outputDir, "relocations.def");
outputFile = new PrintWriter(new FileWriter(relocFile));
try {
println("Counting instructions and data for progress tracking...");
// Count total work for progress monitoring
long totalInstructions = currentProgram.getListing().getNumInstructions();
long totalDataBytes = currentProgram.getMemory().getLoadedAndInitializedAddressSet().getNumAddresses();
long totalWork = totalInstructions + (totalDataBytes / currentProgram.getDefaultPointerSize());
monitor.initialize(totalWork);
monitor.setMessage("Scanning for relocations...");
println("Scanning " + totalInstructions + " instructions and " + totalDataBytes + " data bytes...");
// Get all instructions in the program
InstructionIterator instructions = currentProgram.getListing().getInstructions(true);
long processedInstructions = 0;
while (instructions.hasNext()) {
if (monitor.isCancelled()) {
println("Operation cancelled by user");
return;
}
Instruction instruction = instructions.next();
analyzeInstruction(instruction);
// Check if we've gone past the end address
if (instruction.getAddress().getOffset() >= 0x00844190) {
break;
}
processedInstructions++;
if (processedInstructions % 1000 == 0) {
monitor.setProgress(processedInstructions);
monitor.setMessage("Processed " + processedInstructions + "/" + totalInstructions + " instructions...");
}
}
monitor.setProgress(totalInstructions);
monitor.setMessage("Analyzing data sections...");
// Also check data references
analyzeDataReferences(totalInstructions, totalWork);
monitor.setMessage("Scan complete");
println("Found " + foundRelocations.size() + " potential relocations");
println("Results saved to: " + relocFile.getAbsolutePath());
} finally {
if (outputFile != null) {
outputFile.close();
}
}
}
private void analyzePcodeForConstants(Instruction instruction, boolean trace, Set<String> foundAddresses) {
try {
// Get the pcode operations for this instruction
PcodeOp[] pcodeOps = instruction.getPcode();
if (trace) {
println("DEBUG: Analyzing pcode for " + instruction.getAddress());
for (PcodeOp op : pcodeOps) {
println("DEBUG: PcodeOp: " + op.toString());
}
}
for (PcodeOp op : pcodeOps) {
// Look for constants in the pcode that look like addresses
Varnode[] inputs = op.getInputs();
for (Varnode input : inputs) {
if (input.isConstant()) {
long constantValue = input.getOffset();
// Check if this constant looks like an address in our target range
if (looksLikeAddress(constantValue)) {
if (trace) {
println("DEBUG: Found constant: 0x" + Long.toHexString(constantValue) + " that looks like an address");
}
try {
Address targetAddr = currentProgram.getAddressFactory().getDefaultAddressSpace()
.getAddress(constantValue);
if (isInMainMemorySpace(targetAddr)) {
String addrKey = targetAddr.toString();
if (!foundAddresses.contains(addrKey)) {
// Find where this constant appears in the instruction bytes
int operandOffset = findAbsoluteAddressOffset(instruction, targetAddr, trace);
if (operandOffset >= 0) {
recordRelocation(instruction.getAddress(), targetAddr, instruction.getMnemonicString(),
"pcode_constant", operandOffset);
foundAddresses.add(addrKey);
}
}
}
} catch (Exception e) {
if (trace) {
println("DEBUG: Invalid address from constant: " + e.getMessage());
}
}
}
}
// Also check for address space references (like *[ram]0x77d4c8)
else if (input.isAddress() && input.getAddress() != null) {
long addressValue = input.getAddress().getOffset();
if (trace) {
println("DEBUG: Found address varnode: 0x" + Long.toHexString(addressValue));
}
if (looksLikeAddress(addressValue)) {
try {
Address targetAddr = input.getAddress();
if (isInMainMemorySpace(targetAddr)) {
String addrKey = targetAddr.toString();
if (!foundAddresses.contains(addrKey)) {
int operandOffset = findAbsoluteAddressOffset(instruction, targetAddr, trace);
if (operandOffset >= 0) {
recordRelocation(instruction.getAddress(), targetAddr, instruction.getMnemonicString(),
"pcode_address", operandOffset);
foundAddresses.add(addrKey);
}
}
}
} catch (Exception e) {
if (trace) {
println("DEBUG: Invalid address from varnode: " + e.getMessage());
}
}
}
}
}
}
} catch (Exception e) {
if (trace) {
println("DEBUG: Error analyzing pcode: " + e.getMessage());
}
}
}
private void analyzeReferences(Instruction instruction, boolean trace, Set<String> foundAddresses) {
// Check references from this instruction (original approach)
Reference[] refs = instruction.getReferencesFrom();
for (Reference ref : refs) {
Address toAddr = ref.getToAddress();
boolean isInMainMemorySpace = isInMainMemorySpace(toAddr);
if (trace) {
println("DEBUG: Reference to " + toAddr + " isInMainMemorySpace: " + isInMainMemorySpace);
}
if (isInMainMemorySpace) {
String addrKey = toAddr.toString();
if (!foundAddresses.contains(addrKey)) {
// Check if the target address appears in the instruction bytes (absolute
// addressing)
int operandOffset = findAbsoluteAddressOffset(instruction, toAddr, trace);
if (operandOffset >= 0) {
recordRelocation(instruction.getAddress(), toAddr, instruction.getMnemonicString(),
"reference_" + ref.getReferenceType().getName(), operandOffset);
foundAddresses.add(addrKey);
} else {
if (trace) {
println("DEBUG: operandOffset was not found: " + operandOffset);
}
}
}
}
}
}
private int findAbsoluteAddressOffset(Instruction instruction, Address targetAddr, boolean trace) {
try {
byte[] instructionBytes = instruction.getBytes();
long targetValue = targetAddr.getOffset();
// Convert target address to little-endian byte array (x86 32-bit)
byte[] targetBytes = new byte[4];
targetBytes[0] = (byte) (targetValue & 0xFF);
targetBytes[1] = (byte) ((targetValue >> 8) & 0xFF);
targetBytes[2] = (byte) ((targetValue >> 16) & 0xFF);
targetBytes[3] = (byte) ((targetValue >> 24) & 0xFF);
// Search for the target address bytes in the instruction and return offset
int offset = findSequenceOffset(instructionBytes, targetBytes, trace);
return offset;
} catch (Exception e) {
if (trace) {
println("findAbsoluteAddressOffset exception: " + e.getMessage());
}
return -1;
}
}
private String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
if (i > 0)
sb.append(" ");
sb.append(String.format("%02x", bytes[i] & 0xFF));
}
return sb.toString();
}
private int findSequenceOffset(byte[] haystack, byte[] needle, boolean trace) {
if (trace) {
println("findSequenceOffset inspected bytes: " + bytesToHex(haystack) + " (length: " + haystack.length + ")");
}
if (needle.length > haystack.length) {
if (trace) {
println("findSequenceOffset needle.length > haystack.length");
}
return -1;
}
for (int i = 0; i <= haystack.length - needle.length; i++) {
boolean found = true;
for (int j = 0; j < needle.length; j++) {
if (haystack[i + j] != needle[j]) {
found = false;
break;
}
}
if (found) {
return i; // Return the offset where the sequence starts
}
}
return -1;
}
private boolean isRelocatableInstruction(String mnemonic) {
// Instructions that commonly use absolute addresses
return true;
// mnemonic.equals("mov") || mnemonic.equals("lea") ||
// mnemonic.equals("call") || mnemonic.equals("jmp") ||
// mnemonic.equals("push") || mnemonic.equals("cmp") ||
// mnemonic.equals("test") || mnemonic.equals("add") ||
// mnemonic.equals("sub") || mnemonic.equals("and") ||
// mnemonic.equals("or") || mnemonic.equals("xor") ||
// mnemonic.startsWith("j"); // All jumps, we'll filter by byte analysis
}
private void analyzeDataReferences(long instructionsProcessed, long totalWork) {
// Only scan actual data sections, not code sections
MemoryBlock[] blocks = currentProgram.getMemory().getBlocks();
long processedBytes = 0;
int pointerSize = currentProgram.getDefaultPointerSize();
for (MemoryBlock block : blocks) {
// Skip executable blocks (code sections)
if (block.isExecute()) {
continue;
}
// Only scan initialized data blocks
if (!block.isInitialized()) {
continue;
}
if (monitor.isCancelled()) {
println("Operation cancelled by user");
return;
}
if (block.getName().equals(".rsrc")) {
continue;
}
println("Scanning data block: " + block.getName() + " (" + block.getStart() + " - " + block.getEnd() + ")");
Address addr = block.getStart();
while (addr != null && addr.compareTo(block.getEnd()) <= 0) {
try {
// Check if this location contains a pointer-sized value
byte[] bytes = new byte[pointerSize];
currentProgram.getMemory().getBytes(addr, bytes);
long value = 0;
for (int i = 0; i < bytes.length; i++) {
value |= ((long) (bytes[i] & 0xFF)) << (i * 8);
}
if (looksLikeAddress(value)) {
try {
Address targetAddr = currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(value);
if (isInMainMemorySpace(targetAddr)) {
recordRelocation(addr, targetAddr, "data", "pointer", 0);
}
} catch (Exception e) {
// Invalid address, ignore
}
}
addr = addr.add(pointerSize);
processedBytes += pointerSize;
} catch (Exception e) {
addr = addr.add(1);
processedBytes++;
}
}
}
}
private boolean isInMainMemorySpace(Address addr) {
if (addr == null)
return false;
// Check if address is in a loaded memory block
return currentProgram.getMemory().contains(addr) &&
!addr.getAddressSpace().isOverlaySpace();
}
private boolean looksLikeAddress(long value) {
// Heuristic: check if value is in reasonable address range
// Adjust these ranges based on your target architecture
return value >= addrMin
&& value <= addrMax; // Typical executable range
}
private void recordRelocation(Address fromAddr, Address toAddr, String instruction, String type, int operandOffset) {
String relocKey = fromAddr.toString() + " -> " + toAddr.toString();
if (foundRelocations.add(relocKey)) {
String instructionBytes = getInstructionBytesString(fromAddr);
Address operandPtr = fromAddr.add(operandOffset);
String line = String.format("REL(0x%s, 0x%s, 0x%s) // %s [%s] | %s",
fromAddr.toString(),
operandPtr.toString(),
toAddr.toString(),
instruction,
type,
instructionBytes);
outputFile.println(line);
outputFile.flush();
}
}
private String getInstructionBytesString(Address addr) {
try {
Instruction instruction = currentProgram.getListing().getInstructionAt(addr);
if (instruction != null) {
byte[] bytes = instruction.getBytes();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
if (i > 0)
sb.append(" ");
sb.append(String.format("%02x", bytes[i] & 0xFF));
}
return sb.toString();
} else {
// This is a data reference, show the pointer bytes
byte[] bytes = new byte[4]; // Show 4 bytes for data
int bytesRead = currentProgram.getMemory().getBytes(addr, bytes);
if (bytesRead > 0) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytesRead; i++) {
if (i > 0)
sb.append(" ");
sb.append(String.format("%02x", bytes[i] & 0xFF));
}
return sb.toString();
}
}
} catch (Exception e) {
// Check if this is in an initialized memory block
if (currentProgram.getMemory().contains(addr)) {
return "unreadable";
}
}
return "??";
}
private boolean isPartOfFunction(Address addr) {
// Check if there's an instruction at this address
Instruction instruction = currentProgram.getListing().getInstructionAt(addr);
if (instruction != null) {
return true;
}
// Check if this address is within any function's body
Function function = currentProgram.getFunctionManager().getFunctionContaining(addr);
if (function != null) {
// Additional check: make sure we're in the function body, not just data
// referenced by it
AddressSetView functionBody = function.getBody();
return functionBody.contains(addr);
}
return false;
}
}

1009
GhidraScripts/PdbGen.java Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,38 @@
// Script to regenerate all dumped stub functions
// @category _Reman3
// @menupath Reman3.Redump Stub Functions
// @importpackage org.sqlite
import java.util.List;
import ghidra.app.script.GhidraScript;
import ghidra.program.model.listing.Function;
import re3lib.GlobalDumper;
import re3lib.RemanConfig;
import re3lib.TypeDumper;
import re3lib.FunctionDatabase;
import re3lib.FunctionDumper;
public class RedumpStubFunctions extends GhidraScript {
@Override
protected void run() throws Exception {
RemanConfig.INSTANCE = new RemanConfig(this);
RemanConfig.INSTANCE.createDirectories();
try (FunctionDatabase functionDatabase = new FunctionDatabase(this)) {
List<FunctionDatabase.FunctionEntry> entries = functionDatabase.loadAllEntries();
FunctionDumper dumper = new FunctionDumper(this, functionDatabase, null);
for (FunctionDatabase.FunctionEntry entry : entries) {
if (entry.type == FunctionDatabase.Type.Stub) {
Function function = getFunctionAt(entry.address);
if (function == null) {
printerr("Function not found at address: " + entry.address);
continue;
}
// println("Dumping stub function: " + function.getName());
dumper.dumpStubFunction(function, true);
}
}
}
}
}

View File

@@ -0,0 +1,25 @@
// Script to sanitize global symbols in Ghidra
// @category _Reman3
// @menupath Reman3.Sanitize Global Symbols
// @importpackage org.sqlite
import ghidra.app.script.GhidraScript;
import re3lib.GlobalDumper;
import re3lib.RemanConfig;
import re3lib.FunctionDatabase;
public class SanitizeGlobalSymbols extends GhidraScript {
@Override
public 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.sanitizeGlobalSymbols();
globalDumper.dumpGlobals();
}
}
}

View File

@@ -0,0 +1,580 @@
// Source code is decompiled from a .class file using FernFlower decompiler.
package re3lib;
import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import java.io.IOException;
import java.io.Writer;
import java.util.*;
public class DataTypeWriter {
public HashSet<String> requiredFunctionTypes;
public HashMap<String, FunctionDefinition> lazyFunctionTypeBlocks;
private static String[] INTEGRAL_TYPES = new String[] { "char", "short", "int", "long", "long long", "__int64",
"float", "double", "long double", "void" };
private static String[] INTEGRAL_MODIFIERS = new String[] { "signed", "unsigned", "const", "static", "volatile",
"mutable" };
private static String EOL = System.getProperty("line.separator");
private Writer writer;
private DataTypeManager dtm;
private DataOrganization dataOrganization;
private AnnotationHandler annotator;
private boolean cppStyleComments;
// Block represents a single data type declaration with its dependencies
private static class Block {
final DataType dataType;
final String code;
final Set<String> dependencies;
Block(DataType dataType, String code, Set<String> dependencies) {
this.dataType = dataType;
this.code = code;
this.dependencies = new HashSet<>(dependencies);
}
}
public DataTypeWriter(DataTypeManager dtm, Writer writer) throws IOException {
this(dtm, writer, new DefaultAnnotationHandler());
}
public DataTypeWriter(DataTypeManager dtm, Writer writer, boolean cppStyleComments) throws IOException {
this(dtm, writer, new DefaultAnnotationHandler(), cppStyleComments);
}
public DataTypeWriter(DataTypeManager dtm, Writer writer, AnnotationHandler annotator) throws IOException {
this(dtm, writer, annotator, false);
}
public DataTypeWriter(DataTypeManager dtm, Writer writer, AnnotationHandler annotator, boolean cppStyleComments)
throws IOException {
this.cppStyleComments = false;
this.dtm = dtm;
if (dtm != null) {
this.dataOrganization = dtm.getDataOrganization();
}
if (this.dataOrganization == null) {
this.dataOrganization = DataOrganizationImpl.getDefaultOrganization();
}
this.writer = writer;
this.annotator = annotator;
this.cppStyleComments = cppStyleComments;
this.requiredFunctionTypes = new HashSet<>();
this.lazyFunctionTypeBlocks = new HashMap<>();
}
private String comment(String text) {
if (text == null) {
return "";
} else {
return this.cppStyleComments ? "// " + text : "/* " + text + " */";
}
}
public void write(DataTypeManager dataTypeManager, TaskMonitor monitor) throws IOException, CancelledException {
this.write(dataTypeManager.getRootCategory(), monitor);
}
public void write(Category category, TaskMonitor monitor) throws IOException, CancelledException {
DataType[] dataTypes = category.getDataTypes();
this.write(dataTypes, monitor);
Category[] subCategories = category.getCategories();
Category[] var5 = subCategories;
int var6 = subCategories.length;
for (int var7 = 0; var7 < var6; ++var7) {
Category subCategory = var5[var7];
if (monitor.isCancelled()) {
return;
}
this.write(subCategory, monitor);
}
}
public void write(DataType[] dataTypes, TaskMonitor monitor) throws IOException, CancelledException {
write(Arrays.asList(dataTypes), monitor);
}
public void write(List<DataType> dataTypes, TaskMonitor monitor) throws IOException, CancelledException {
this.write(dataTypes, monitor, true);
}
public void write(List<DataType> dataTypes, TaskMonitor monitor, boolean throwExceptionOnInvalidType)
throws IOException, CancelledException {
monitor.initialize((long) dataTypes.size());
// Step 1: Create blocks for each data type
Map<String, Block> blocks = new HashMap<>();
int cnt = 0;
for (DataType dataType : dataTypes) {
monitor.checkCancelled();
if (dataType == null) {
continue;
}
try {
Block block = createBlock(dataType);
if (block != null) {
blocks.put(dataType.getDisplayName(), block);
}
} catch (Exception e) {
if (throwExceptionOnInvalidType) {
throw new IOException("Failed to process data type: " + dataType.getDisplayName(), e);
}
Msg.error(this, "Failed to process data type: " + dataType.getDisplayName(), e);
}
++cnt;
monitor.setProgress((long) cnt);
}
// Step 2: Check if we're missing any function type typedefs
for (String funcName : requiredFunctionTypes) {
if (!blocks.containsKey(funcName)) {
FunctionDefinition funcType = lazyFunctionTypeBlocks.get(funcName);
Set<String> dependencies = new HashSet<>();
StringBuilder code = new StringBuilder();
this.writeFunctionDefinitionBlock(funcType, funcName, code, dependencies);
blocks.put(funcName, new Block(funcType, code.toString(), dependencies));
}
}
// Step 3: Topological sort and write
List<Block> sortedBlocks = topologicalSort(blocks);
for (Block block : sortedBlocks) {
writer.write(block.code);
writer.write(EOL);
}
writer.flush();
}
private Block createBlock(DataType dt) throws IOException {
if (dt instanceof FactoryDataType) {
return null; // Skip only factory types
}
dt = dt.clone(this.dtm);
Set<String> dependencies = new HashSet<>();
StringBuilder code = new StringBuilder();
// if (dt.getDisplayName().contains("HIE_tduLinkedObject")) {
// System.out.println("DEBUG " + dt.getDisplayName());
// }
if (dt.equals(DataType.DEFAULT)) {
code.append("typedef unsigned char ").append(DataType.DEFAULT.getName()).append(";");
} else if (dt instanceof Dynamic) {
// Handle dynamic types
Dynamic dynamicType = (Dynamic) dt;
DataType baseDt = dynamicType.getReplacementBaseType();
if (baseDt != null) {
dependencies.add(baseDt.getDisplayName());
}
code.append(comment("Dynamic type: " + dt.getDisplayName()));
} else if (dt instanceof Structure) {
writeStructureBlock((Structure) dt, code, dependencies);
} else if (dt instanceof Union) {
writeUnionBlock((Union) dt, code, dependencies);
} else if (dt instanceof Enum) {
if (dt.getDisplayName().contains(".conflict"))
return null;
writeEnumBlock((Enum) dt, code, dependencies);
} else if (dt instanceof TypeDef) {
writeTypeDefBlock((TypeDef) dt, code, dependencies);
} else if (dt instanceof BuiltInDataType) {
writeBuiltInBlock((BuiltInDataType) dt, code, dependencies);
} else if (dt instanceof FunctionDefinition) {
// Store these for later, a lot of them are going to be unused
lazyFunctionTypeBlocks.put(dt.getDisplayName(), (FunctionDefinition) dt);
return null;
} else {
code.append(comment("Unable to write datatype. Type unrecognized: " + dt.getClass()));
}
return new Block(dt, code.toString(), dependencies);
}
private void writeStructureBlock(Structure struct, StringBuilder code, Set<String> dependencies) {
String structName = struct.getDisplayName();
// Struct definition
code.append("struct ").append(structName).append(" {");
String descrip = struct.getDescription();
if (descrip != null && descrip.length() > 0) {
code.append(" ").append(comment(descrip));
}
code.append(EOL);
// Process components
for (DataTypeComponent component : struct.getComponents()) {
writeComponentBlock(component, struct, code, dependencies);
}
code.append(annotator.getSuffix(struct, null));
code.append("};");
}
private void writeUnionBlock(Union union, StringBuilder code, Set<String> dependencies) {
String unionName = union.getDisplayName();
// Union definition (no forward declaration needed - let dependency ordering
// handle it)
code.append("union ").append(unionName).append(" {");
String descrip = union.getDescription();
if (descrip != null && descrip.length() > 0) {
code.append(" ").append(comment(descrip));
}
code.append(EOL);
// Process components
for (DataTypeComponent component : union.getComponents()) {
writeComponentBlock(component, union, code, dependencies);
}
code.append(annotator.getSuffix(union, null));
code.append("};");
}
private void writeComponentBlock(DataTypeComponent component, Composite composite, StringBuilder code,
Set<String> dependencies) {
code.append(" ");
code.append(annotator.getPrefix(composite, component));
String fieldName = component.getFieldName();
String originalName = fieldName;
boolean needsFixing = fieldName != null && fieldName.contains("?");
if (fieldName == null || fieldName.length() == 0 || needsFixing) {
fieldName = component.getDefaultFieldName();
}
DataType componentDataType = component.getDataType();
DataType depType = getImmediateDependencyType(componentDataType);
if (depType != null) {
dependencies.add(depType.getDisplayName());
if (depType instanceof FunctionDefinition) {
requiredFunctionTypes.add(depType.getDisplayName());
}
}
code.append(getTypeDeclaration(fieldName, componentDataType, component.getLength()));
code.append(";");
code.append(annotator.getSuffix(composite, component));
String comment = component.getComment();
String commentText = comment != null && comment.length() > 0 ? comment : "";
if (needsFixing) {
commentText += (commentText.length() > 0 ? " " : "") + "(fix name \"" + originalName + "\")";
}
if (commentText.length() > 0) {
code.append(" ").append(comment(commentText));
}
code.append(EOL);
}
private void writeEnumBlock(Enum enumm, StringBuilder code, Set<String> dependencies) {
String enumName = enumm.getDisplayName();
if (enumName.startsWith("define_") && enumName.length() > 7 && enumm.getCount() == 1) {
long val = enumm.getValues()[0];
code.append("#define ").append(enumName.substring(7)).append(" ").append(Long.toString(val));
} else {
code.append("enum ").append(enumName).append(" {");
String description = enumm.getDescription();
if (description != null && description.length() != 0) {
code.append(" ").append(comment(description));
}
code.append(EOL);
String[] names = enumm.getNames();
for (int j = 0; j < names.length; ++j) {
code.append(" ");
code.append(annotator.getPrefix(enumm, names[j]));
code.append(names[j]);
code.append("=");
code.append(Long.toString(enumm.getValue(names[j])));
String comment = enumm.getComment(names[j]);
if (!comment.isBlank()) {
code.append(" ").append(comment(comment));
}
code.append(annotator.getSuffix(enumm, names[j]));
if (j < names.length - 1) {
code.append(",");
}
code.append(EOL);
}
code.append("};");
}
}
private boolean writeFunctionDefinitionBlock(FunctionDefinition funcDef, String name, StringBuilder code,
Set<String> dependencies) {
DataType returnType = funcDef.getReturnType();
ParameterDefinition[] params = funcDef.getArguments();
// Add return type dependency if not built-in
if (returnType != null && !isBuiltInType(returnType)) {
DataType depType = getImmediateDependencyType(returnType);
if (depType != null) {
dependencies.add(depType.getDisplayName());
}
}
// Build function typedef
code.append("typedef ");
if (returnType != null) {
code.append(getTypeDeclaration("", returnType, -1)).append(" ");
} else {
code.append("void ");
}
code.append("(*").append(name).append(")(");
if (params != null && params.length > 0) {
for (int i = 0; i < params.length; i++) {
ParameterDefinition param = params[i];
DataType paramType = param.getDataType();
// Add parameter type dependency if not built-in
if (!isBuiltInType(paramType) && !isPointerType(paramType)) {
DataType depType = getImmediateDependencyType(paramType);
if (depType != null) {
dependencies.add(depType.getDisplayName());
}
}
String paramName = param.getName();
if (paramName == null || paramName.isEmpty()) {
paramName = "param" + (i + 1);
}
code.append(getTypeDeclaration(paramName, paramType, -1));
if (i < params.length - 1) {
code.append(", ");
}
}
} else {
code.append("void");
}
code.append(");");
return true;
}
private boolean writeTypeDefBlock(TypeDef typeDef, StringBuilder code, Set<String> dependencies) {
String typedefName = typeDef.getDisplayName();
DataType dataType = typeDef.getDataType();
// Handle function definition typedefs
if (dataType instanceof FunctionDefinition) {
return writeFunctionDefinitionBlock((FunctionDefinition) dataType, typedefName, code, dependencies);
} // Could be pointer to function
else if (dataType instanceof Pointer) {
Pointer ptr = (Pointer) dataType;
if (ptr.getDataType() instanceof FunctionDefinition) {
return writeFunctionDefinitionBlock((FunctionDefinition) ((Pointer) dataType).getDataType(), typedefName, code,
dependencies);
} else {
// Try to write the typedef as a forward declaration
code.append("typedef ");
code.append(getTypeDeclaration(typedefName, dataType, -1));
code.append(";");
return true;
}
} else {
DataType depType = getImmediateDependencyType(dataType);
if (depType != null && !isBuiltInType(depType)) {
dependencies.add(depType.getDisplayName());
}
String typedefString = getTypeDeclaration(typedefName, dataType, -1);
code.append("typedef ").append(typedefString).append(";");
return true;
}
}
private void writeBuiltInBlock(BuiltInDataType dt, StringBuilder code, Set<String> dependencies) {
String declaration = dt.getCTypeDeclaration(this.dataOrganization);
if (declaration != null) {
code.append(declaration);
}
}
private boolean isPointerType(DataType dt) {
return dt instanceof Pointer;
}
private boolean isBuiltInType(DataType dt) {
return dt instanceof BuiltInDataType;
}
private DataType getImmediateDependencyType(DataType dt) {
// Only unwrap arrays and bitfields, but preserve typedefs and other types
while (dt != null) {
if (dt instanceof Array) {
dt = ((Array) dt).getDataType();
} else if (dt instanceof BitFieldDataType) {
dt = ((BitFieldDataType) dt).getBaseDataType();
} else if (dt instanceof Pointer) {
dt = ((Pointer) dt).getDataType();
} else {
break;
}
}
return dt;
}
private String getTypeDeclaration(String name, DataType dataType, int instanceLength) {
if (name == null) {
name = "";
}
StringBuilder sb = new StringBuilder();
if (dataType instanceof BitFieldDataType) {
BitFieldDataType bfDt = (BitFieldDataType) dataType;
name = name + ":" + bfDt.getDeclaredBitSize();
dataType = bfDt.getBaseDataType();
}
// Handle arrays and pointers
while (dataType instanceof Array) {
Array array = (Array) dataType;
name = name + "[" + array.getNumElements() + "]";
dataType = array.getDataType();
}
while (dataType instanceof Pointer) {
Pointer pointer = (Pointer) dataType;
DataType elem = pointer.getDataType();
if (elem == null) {
break;
}
name = "*" + name;
dataType = elem;
if (elem instanceof Array) {
name = "(" + name + ")";
}
}
String prefix = getDataTypePrefix(dataType);
String dataTypeString;
if (dataType instanceof AbstractIntegerDataType) {
dataTypeString = ((AbstractIntegerDataType) dataType).getCDeclaration();
} else {
dataTypeString = dataType.getDisplayName();
}
String componentString = prefix + dataTypeString;
if (name.length() != 0) {
componentString = componentString + " " + name;
}
return componentString;
}
private String getDataTypePrefix(DataType dataType) {
// Don't add struct/union prefix for typedefs - they already have their own name
if (dataType instanceof TypeDef) {
return "";
}
// Only add struct/union prefix for direct struct/union references (not
// typedefs)
if (dataType instanceof Structure) {
return "struct ";
} else if (dataType instanceof Union) {
return "union ";
} else if (dataType instanceof Enum) {
return "enum ";
} else {
return "";
}
}
private boolean isIntegral(String typedefName, String basetypeName) {
for (String type : INTEGRAL_TYPES) {
if (typedefName.equals(type)) {
return true;
}
}
boolean endsWithIntegralType = false;
for (String type : INTEGRAL_TYPES) {
if (typedefName.endsWith(" " + type)) {
endsWithIntegralType = true;
break;
}
}
for (String modifier : INTEGRAL_MODIFIERS) {
if (typedefName.indexOf(modifier + " ") >= 0 || typedefName.indexOf(" " + modifier) >= 0) {
return true;
}
}
if (endsWithIntegralType) {
return true;
} else if (typedefName.endsWith(" " + basetypeName)) {
return false; // Let it through as a regular typedef
} else {
return false;
}
}
private List<Block> topologicalSort(Map<String, Block> blocks) {
List<Block> result = new ArrayList<>();
Set<String> visited = new HashSet<>();
Set<String> visiting = new HashSet<>();
for (Block block : blocks.values()) {
if (!visited.contains(block.dataType.getDisplayName())) {
topologicalSortVisit(block, blocks, visited, visiting, result);
}
}
return result;
}
private void topologicalSortVisit(Block block, Map<String, Block> blocks,
Set<String> visited, Set<String> visiting, List<Block> result) {
String blockName = block.dataType.getDisplayName();
if (visiting.contains(blockName)) {
// Circular dependency detected, but we'll continue (forward declarations should
// handle this)
return;
}
if (visited.contains(blockName)) {
return;
}
visiting.add(blockName);
// Visit dependencies first
for (String dep : block.dependencies) {
Block depBlock = blocks.get(dep);
if (depBlock != null) {
topologicalSortVisit(depBlock, blocks, visited, visiting, result);
}
}
visiting.remove(blockName);
visited.add(blockName);
result.add(block);
}
}

View File

@@ -0,0 +1,820 @@
package re3lib;
import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.sqlite.JDBC;
import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function;
public class FunctionDatabase implements AutoCloseable {
public static enum Type {
Auto(0),
Fix(1),
Stub(2),
Ref(3);
private final int value;
Type(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static Type fromValue(int value) {
for (Type type : Type.values()) {
if (type.value == value) {
return type;
}
}
throw new IllegalArgumentException("Unknown type value: " + value);
}
}
public static enum CallingConvention {
Cdecl(0),
Stdcall(1),
Fastcall(2);
private final int value;
CallingConvention(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static CallingConvention fromValue(int value) {
for (CallingConvention conv : CallingConvention.values()) {
if (conv.value == value) {
return conv;
}
}
throw new IllegalArgumentException("Unknown calling convention value: " + value);
}
public static CallingConvention fromString(String convStr) {
if (convStr == null) {
return Cdecl; // Default
}
String lower = convStr.toLowerCase();
if (lower.contains("fastcall")) {
return Fastcall;
} else if (lower.contains("stdcall")) {
return Stdcall;
} else {
return Cdecl; // Default
}
}
@Override
public String toString() {
switch (this) {
case Fastcall:
return "fastcall";
case Stdcall:
return "stdcall";
case Cdecl:
default:
return "cdecl";
}
}
}
public static class FunctionEntry {
public Address address;
public String name;
public File file;
public Type type;
public CallingConvention callingConvention;
public String parameterNames; // Semicolon-separated parameter names
public String parameterTypes; // Semicolon-separated parameter types
public String returnType; // Function return type
public FunctionEntry(Address address, String name, File file, Type type, CallingConvention callingConvention,
String parameterNames, String parameterTypes, String returnType) {
this.address = address;
this.name = name;
this.file = file;
this.type = type;
this.callingConvention = callingConvention;
this.parameterNames = parameterNames != null ? parameterNames : "";
this.parameterTypes = parameterTypes != null ? parameterTypes : "";
this.returnType = returnType != null ? returnType : "void";
}
// Helper methods to work with semicolon-separated parameter lists
public String[] getParameterNamesArray() {
if (parameterNames == null || parameterNames.trim().isEmpty()) {
return new String[0];
}
return parameterNames.split(";");
}
public String[] getParameterTypesArray() {
if (parameterTypes == null || parameterTypes.trim().isEmpty()) {
return new String[0];
}
return parameterTypes.split(";");
}
public void setParameterNamesArray(String[] names) {
if (names == null || names.length == 0) {
this.parameterNames = "";
} else {
this.parameterNames = String.join(";", names);
}
}
public void setParameterTypesArray(String[] types) {
if (types == null || types.length == 0) {
this.parameterTypes = "";
} else {
this.parameterTypes = String.join(";", types);
}
}
}
public static class GlobalEntry {
public Address address;
public String name;
public File file;
public GlobalEntry(Address address, String name, File file) {
this.address = address;
this.name = name;
this.file = file;
}
}
private File dbFile;
private transient GhidraScript script;
private Connection connection;
// Prepared statements for better performance
private PreparedStatement findByNameFunctions;
private PreparedStatement findByNameImports;
private PreparedStatement findByAddressFunctions;
private PreparedStatement findByAddressImports;
private PreparedStatement insertOrReplaceFunctions;
private PreparedStatement insertOrReplaceImports;
private PreparedStatement deleteByFilepathFunctions;
private PreparedStatement deleteByFilepathImports;
private PreparedStatement loadAllFunctions;
private PreparedStatement loadAllImports;
// Add these prepared statements after the existing ones
private PreparedStatement findByNameGlobals;
private PreparedStatement findByAddressGlobals;
private PreparedStatement insertOrReplaceGlobals;
private PreparedStatement deleteByFilepathGlobals;
private PreparedStatement loadAllGlobals;
public FunctionDatabase(GhidraScript script) {
this.script = script;
dbFile = RemanConfig.INSTANCE.databasePath;
try {
java.sql.DriverManager.registerDriver(new JDBC());
} catch (SQLException e) {
script.printerr("Error registering JDBC driver: " + e.getMessage());
}
}
public void connect() throws Exception {
if (connection != null && !connection.isClosed()) {
return; // Already connected
}
if (!dbFile.exists()) {
script.println("Database file not found: " + dbFile);
// Create parent directories if they don't exist
dbFile.getParentFile().mkdirs();
}
try {
connection = DriverManager.getConnection("jdbc:sqlite:" + dbFile.getAbsolutePath());
createTablesIfNotExist();
prepareCachedStatements();
script.println("Connected to database: " + dbFile);
} catch (SQLException e) {
script.println("Error connecting to database: " + e.getMessage());
// throw new Exception("Failed to connect to database", e);
throw e;
}
}
public void disconnect() throws Exception {
if (connection != null && !connection.isClosed()) {
try {
// Close prepared statements
closePreparedStatements();
connection.close();
script.println("Disconnected from database");
} catch (SQLException e) {
script.println("Error disconnecting from database: " + e.getMessage());
throw new Exception("Failed to disconnect from database", e);
}
}
}
private void ensureConnection() throws Exception {
if (connection == null || connection.isClosed()) {
connect();
}
}
private void prepareCachedStatements() throws SQLException {
// Find by name
findByNameFunctions = connection.prepareStatement(
"SELECT filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type FROM Functions WHERE name = ?");
findByNameImports = connection.prepareStatement(
"SELECT filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type FROM Imports WHERE name = ?");
// Find by address
findByAddressFunctions = connection.prepareStatement(
"SELECT filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type FROM Functions WHERE address = ?");
findByAddressImports = connection.prepareStatement(
"SELECT filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type FROM Imports WHERE address = ?");
// Insert or replace
insertOrReplaceFunctions = connection.prepareStatement(
"INSERT OR REPLACE INTO Functions (filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
insertOrReplaceImports = connection.prepareStatement(
"INSERT OR REPLACE INTO Imports (filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
// Delete by filepath
deleteByFilepathFunctions = connection.prepareStatement(
"DELETE FROM Functions WHERE filepath = ?");
deleteByFilepathImports = connection.prepareStatement(
"DELETE FROM Imports WHERE filepath = ?");
// Load all entries
loadAllFunctions = connection.prepareStatement(
"SELECT filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type FROM Functions");
loadAllImports = connection.prepareStatement(
"SELECT filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type FROM Imports");
// Global statements
findByNameGlobals = connection.prepareStatement(
"SELECT filepath, name, address FROM Globals WHERE name = ?");
findByAddressGlobals = connection.prepareStatement(
"SELECT filepath, name, address FROM Globals WHERE address = ?");
insertOrReplaceGlobals = connection.prepareStatement(
"INSERT OR REPLACE INTO Globals (filepath, name, address) VALUES (?, ?, ?)");
deleteByFilepathGlobals = connection.prepareStatement(
"DELETE FROM Globals WHERE filepath = ?");
loadAllGlobals = connection.prepareStatement(
"SELECT filepath, name, address FROM Globals");
}
private void closePreparedStatements() throws SQLException {
if (findByNameFunctions != null)
findByNameFunctions.close();
if (findByNameImports != null)
findByNameImports.close();
if (findByAddressFunctions != null)
findByAddressFunctions.close();
if (findByAddressImports != null)
findByAddressImports.close();
if (insertOrReplaceFunctions != null)
insertOrReplaceFunctions.close();
if (insertOrReplaceImports != null)
insertOrReplaceImports.close();
if (deleteByFilepathFunctions != null)
deleteByFilepathFunctions.close();
if (deleteByFilepathImports != null)
deleteByFilepathImports.close();
if (loadAllFunctions != null)
loadAllFunctions.close();
if (loadAllImports != null)
loadAllImports.close();
if (findByNameGlobals != null)
findByNameGlobals.close();
if (findByAddressGlobals != null)
findByAddressGlobals.close();
if (insertOrReplaceGlobals != null)
insertOrReplaceGlobals.close();
if (deleteByFilepathGlobals != null)
deleteByFilepathGlobals.close();
if (loadAllGlobals != null)
loadAllGlobals.close();
}
public List<FunctionEntry> loadAllEntries() throws Exception {
ensureConnection();
List<FunctionEntry> entries = new ArrayList<>();
try {
// Load from Functions table
try (ResultSet rs = loadAllFunctions.executeQuery()) {
while (rs.next()) {
FunctionEntry entry = createEntryFromResultSet(rs);
if (entry != null) {
entries.add(entry);
}
}
}
script.println("Loaded " + entries.size() + " function entries from database");
return entries;
} catch (SQLException e) {
script.println("Error loading entries: " + e.getMessage());
throw new Exception("Failed to load entries", e);
}
}
private FunctionEntry createEntryFromResultSet(ResultSet rs) throws SQLException {
String filepath = rs.getString("filepath");
String name = rs.getString("name");
String addressStr = rs.getString("address");
int typeValue = rs.getInt("type");
int callingConventionValue = rs.getInt("calling_convention");
String parameterNames = rs.getString("parameter_names");
String parameterTypes = rs.getString("parameter_types");
String returnType = rs.getString("return_type");
if (addressStr != null && !addressStr.isEmpty()) {
Address address = script.getCurrentProgram().getAddressFactory().getAddress(addressStr);
File file = new File(RemanConfig.INSTANCE.outputDir, filepath);
Type type = Type.fromValue(typeValue);
CallingConvention callingConvention = CallingConvention.fromValue(callingConventionValue);
return new FunctionEntry(address, name, file, type, callingConvention,
parameterNames, parameterTypes, returnType);
}
return null;
}
private void createTablesIfNotExist() throws SQLException {
String createFunctions = """
CREATE TABLE IF NOT EXISTS Functions (
filepath TEXT,
name TEXT,
address TEXT,
type INTEGER DEFAULT 0,
calling_convention INTEGER DEFAULT 0,
parameter_names TEXT DEFAULT '',
parameter_types TEXT DEFAULT '',
return_type TEXT DEFAULT '',
PRIMARY KEY (name, filepath)
)""";
String createImports = """
CREATE TABLE IF NOT EXISTS Imports (
filepath TEXT,
name TEXT,
address TEXT,
type INTEGER DEFAULT 0,
calling_convention INTEGER DEFAULT 0,
parameter_names TEXT DEFAULT '',
parameter_types TEXT DEFAULT '',
return_type TEXT DEFAULT '',
PRIMARY KEY (name, filepath)
)""";
String createGlobals = """
CREATE TABLE IF NOT EXISTS Globals (
filepath TEXT,
name TEXT,
address TEXT,
PRIMARY KEY (name, filepath)
)""";
connection.prepareStatement(createFunctions).executeUpdate();
connection.prepareStatement(createImports).executeUpdate();
connection.prepareStatement(createGlobals).executeUpdate();
}
// Helper method to find entries by name
public List<FunctionEntry> findEntriesByName(String name) throws Exception {
ensureConnection();
List<FunctionEntry> results = new ArrayList<>();
try {
// Search Functions table
findByNameFunctions.setString(1, name);
try (ResultSet rs = findByNameFunctions.executeQuery()) {
while (rs.next()) {
FunctionEntry entry = createEntryFromResultSet(rs);
if (entry != null) {
results.add(entry);
}
}
}
// Search Imports table
findByNameImports.setString(1, name);
try (ResultSet rs = findByNameImports.executeQuery()) {
while (rs.next()) {
FunctionEntry entry = createEntryFromResultSet(rs);
if (entry != null) {
results.add(entry);
}
}
}
return results;
} catch (SQLException e) {
script.println("Error finding entries by name: " + e.getMessage());
throw new Exception("Failed to find entries by name", e);
}
}
// Helper method to find entries by address
public List<FunctionEntry> findEntriesByAddress(Address address) throws Exception {
ensureConnection();
List<FunctionEntry> results = new ArrayList<>();
String addressStr = address.toString();
try {
// Search Functions table
findByAddressFunctions.setString(1, addressStr);
try (ResultSet rs = findByAddressFunctions.executeQuery()) {
while (rs.next()) {
FunctionEntry entry = createEntryFromResultSet(rs);
if (entry != null) {
results.add(entry);
}
}
}
// Search Imports table
findByAddressImports.setString(1, addressStr);
try (ResultSet rs = findByAddressImports.executeQuery()) {
while (rs.next()) {
FunctionEntry entry = createEntryFromResultSet(rs);
if (entry != null) {
results.add(entry);
}
}
}
return results;
} catch (SQLException e) {
script.println("Error finding entries by address: " + e.getMessage());
throw new Exception("Failed to find entries by address", e);
}
}
// Helper method to add/update entry (insert or replace based on filename)
public void addEntryAt(FunctionEntry entry) throws Exception {
ensureConnection();
String relativePath = new File(RemanConfig.INSTANCE.outputDir).toPath()
.relativize(entry.file.toPath()).toString().replace('\\', '/');
try {
insertOrReplaceFunctions.setString(1, relativePath);
insertOrReplaceFunctions.setString(2, entry.name);
insertOrReplaceFunctions.setString(3, entry.address.toString());
insertOrReplaceFunctions.setInt(4, entry.type.getValue());
insertOrReplaceFunctions.setInt(5, entry.callingConvention.getValue());
insertOrReplaceFunctions.setString(6, entry.parameterNames);
insertOrReplaceFunctions.setString(7, entry.parameterTypes);
insertOrReplaceFunctions.setString(8, entry.returnType);
insertOrReplaceFunctions.executeUpdate();
script.println("Added/updated entry: " + entry.name + " at " + entry.address + " in " + relativePath
+ " (calling convention: " + entry.callingConvention + ", return type: " + entry.returnType + ")");
} catch (SQLException e) {
script.println("Error adding entry: " + e.getMessage());
throw new Exception("Failed to add entry", e);
}
}
// Helper method to add import entry
public void addImportEntry(FunctionEntry entry) throws Exception {
ensureConnection();
String relativePath = new File(RemanConfig.INSTANCE.outputDir).toPath()
.relativize(entry.file.toPath()).toString().replace('\\', '/');
try {
insertOrReplaceImports.setString(1, relativePath);
insertOrReplaceImports.setString(2, entry.name);
insertOrReplaceImports.setString(3, entry.address.toString());
insertOrReplaceImports.setInt(4, entry.type.getValue());
insertOrReplaceImports.setInt(5, entry.callingConvention.getValue());
insertOrReplaceImports.setString(6, entry.parameterNames);
insertOrReplaceImports.setString(7, entry.parameterTypes);
insertOrReplaceImports.setString(8, entry.returnType);
insertOrReplaceImports.executeUpdate();
script.println("Added/updated import entry: " + entry.name + " at " + entry.address + " in " + relativePath
+ " (calling convention: " + entry.callingConvention + ", return type: " + entry.returnType + ")");
} catch (SQLException e) {
script.println("Error adding import entry: " + e.getMessage());
throw new Exception("Failed to add import entry", e);
}
}
// Helper method to remove entry by file path
public void removeEntryAt(String filePath) throws Exception {
ensureConnection();
String relativePath = new File(RemanConfig.INSTANCE.outputDir).toPath()
.relativize(new File(filePath).toPath()).toString().replace('\\', '/');
try {
deleteByFilepathFunctions.setString(1, relativePath);
int deletedCount = deleteByFilepathFunctions.executeUpdate();
deleteByFilepathImports.setString(1, relativePath);
deletedCount += deleteByFilepathImports.executeUpdate();
script.println("Removed " + deletedCount + " entries for file: " + relativePath);
} catch (SQLException e) {
script.println("Error removing entries: " + e.getMessage());
throw new Exception("Failed to remove entries", e);
}
}
public void add(FunctionEntry entry) throws Exception {
// Add entry directly to database
addEntryAt(entry);
}
public void applyDefaultFilters(boolean rebuildAllGlobals) throws Exception {
GlobalDumper globalDumper = new GlobalDumper(script, this);
FunctionDumper dumper = new FunctionDumper(script, this, globalDumper);
if (rebuildAllGlobals) {
globalDumper.removeGlobalManifest();
}
boolean madeAnyChanges = false;
// Load all entries from database
List<FunctionEntry> entries = loadAllEntries();
// Create a hash map to store symbol names
Map<Address, String> symbolNames = new HashMap<>();
Map<String, File> exportedFunctionNames = new HashMap<>();
for (FunctionEntry entry : entries) {
Function function = script.getFunctionAt(entry.address);
if (function != null) {
boolean isAuto = entry.type == Type.Auto;
boolean isFix = entry.type == Type.Fix;
// Get the actual symbol name and store it in the hash map
String symbolName = function.getName();
symbolNames.put(entry.address, symbolName);
if (isAuto && !exportedFunctionNames.containsKey(entry.name)) {
exportedFunctionNames.put(entry.name, entry.file);
} else if (isFix) {
exportedFunctionNames.replace(entry.name, entry.file);
}
}
}
// Print the number of symbol names collected
script.println("Collected " + symbolNames.size() + " symbol names");
boolean dryMode = false;
HashSet<Function> functionsToRegenerate = new HashSet<>();
Iterator<FunctionEntry> iterator = entries.iterator();
while (iterator.hasNext()) {
FunctionEntry entry = iterator.next();
Function function = script.getFunctionAt(entry.address);
boolean pendingDelete = false;
boolean pendingRegenerate = false;
if (rebuildAllGlobals) {
pendingRegenerate = true;
}
// Remove CRT and other blacklisted functions
if (function == null || !dumper.isValidFunction(function)) {
// Remove the file
if (entry.file != null && entry.file.exists()) {
script.println("Removed file: " + entry.file.getAbsolutePath());
pendingDelete = true;
}
// Remove entry from the list
script.println("Removed invalid function entry: " + entry.name + " at " + entry.address);
function = null;
}
// Check if symbol name matches the symbol name parsed from the file
if (function != null) {
String actualSymbolName = symbolNames.get(entry.address);
if (actualSymbolName == null) {
throw new Exception(
"Symbol name not found for function at " + entry.address + " in file " + entry.file.getAbsolutePath());
}
if (actualSymbolName != null && !actualSymbolName.equals(entry.name)) {
File fnExportedFile = exportedFunctionNames.get(entry.name);
if (fnExportedFile != null && fnExportedFile != entry.file) {
// Already exists elsewhere, so remove this file
script.println("Removing duplicate function: " + entry.name + " at " + entry.address + " overridden by "
+ fnExportedFile);
pendingDelete = true;
} else {
// Regeneral this function
script.println("Symbol name mismatch for function at " + entry.address + ": " +
"File name: " + entry.name + ", Actual symbol: " + actualSymbolName);
entry.name = actualSymbolName; // Update the entry name to match the actual symbol
pendingRegenerate = true;
}
}
entry.name = actualSymbolName; // Update the entry name to match the actual symbol
madeAnyChanges = true;
}
if (pendingDelete) {
iterator.remove();
if (!dryMode) {
entry.file.delete();
// Remove from database
removeEntryAt(entry.file.getAbsolutePath());
madeAnyChanges = true;
}
} else if (pendingRegenerate && entry.type != Type.Stub) {
if (!dryMode) {
functionsToRegenerate.add(function);
// Update entry in database with corrected name
addEntryAt(entry);
madeAnyChanges = true;
}
}
}
for (Function function : functionsToRegenerate) {
script.println("Regenerating function: " + function.getName() + " at " + function.getEntryPoint());
dumper.dump(function);
}
if (madeAnyChanges) {
// Update CMake timestamp
RemanConfig.INSTANCE.touchCMakeTimestamp();
globalDumper.dumpGlobals();
TypeDumper typeDumper = new TypeDumper(script);
typeDumper.run();
}
}
// Global-specific methods
public List<GlobalEntry> loadAllGlobals() throws Exception {
ensureConnection();
List<GlobalEntry> globals = new ArrayList<>();
try {
try (ResultSet rs = loadAllGlobals.executeQuery()) {
while (rs.next()) {
GlobalEntry entry = createGlobalEntryFromResultSet(rs);
if (entry != null) {
globals.add(entry);
}
}
}
script.println("Loaded " + globals.size() + " global entries from database");
return globals;
} catch (SQLException e) {
script.println("Error loading globals: " + e.getMessage());
throw new Exception("Failed to load globals", e);
}
}
private GlobalEntry createGlobalEntryFromResultSet(ResultSet rs) throws SQLException {
String filepath = rs.getString("filepath");
String name = rs.getString("name");
String addressStr = rs.getString("address");
if (addressStr != null && !addressStr.isEmpty()) {
Address address = script.getCurrentProgram().getAddressFactory().getAddress(addressStr);
File file = new File(RemanConfig.INSTANCE.outputDir, filepath);
return new GlobalEntry(address, name, file);
}
return null;
}
public List<GlobalEntry> findGlobalsByName(String name) throws Exception {
ensureConnection();
List<GlobalEntry> results = new ArrayList<>();
try {
findByNameGlobals.setString(1, name);
try (ResultSet rs = findByNameGlobals.executeQuery()) {
while (rs.next()) {
GlobalEntry entry = createGlobalEntryFromResultSet(rs);
if (entry != null) {
results.add(entry);
}
}
}
return results;
} catch (SQLException e) {
script.println("Error finding globals by name: " + e.getMessage());
throw new Exception("Failed to find globals by name", e);
}
}
public List<GlobalEntry> findGlobalsByAddress(Address address) throws Exception {
ensureConnection();
List<GlobalEntry> results = new ArrayList<>();
String addressStr = address.toString();
try {
findByAddressGlobals.setString(1, addressStr);
try (ResultSet rs = findByAddressGlobals.executeQuery()) {
while (rs.next()) {
GlobalEntry entry = createGlobalEntryFromResultSet(rs);
if (entry != null) {
results.add(entry);
}
}
}
return results;
} catch (SQLException e) {
script.println("Error finding globals by address: " + e.getMessage());
throw new Exception("Failed to find globals by address", e);
}
}
public void addGlobal(Address address, String name) throws Exception {
ensureConnection();
String filepath = RemanConfig.GLOBAL_H_FILE; // Default filepath for globals
String addressStr = address.toString();
try {
insertOrReplaceGlobals.setString(1, filepath);
insertOrReplaceGlobals.setString(2, name);
insertOrReplaceGlobals.setString(3, addressStr);
insertOrReplaceGlobals.executeUpdate();
script.println("Added/updated global: " + name + " at " + address);
} catch (SQLException e) {
script.println("Error adding global: " + e.getMessage());
throw new Exception("Failed to add global", e);
}
}
public void removeGlobalsByFilepath(String filePath) throws Exception {
ensureConnection();
String relativePath;
// Check if filePath is already a relative path or just a filename
File inputFile = new File(filePath);
if (inputFile.isAbsolute()) {
// Convert absolute path to relative
try {
relativePath = new File(RemanConfig.INSTANCE.outputDir).toPath()
.relativize(inputFile.toPath()).toString().replace('\\', '/');
} catch (IllegalArgumentException e) {
// Fallback if paths can't be relativized (different drives, etc.)
script.println("Warning: Could not relativize path: " + filePath + ", using as-is");
relativePath = filePath.replace('\\', '/');
}
} else {
// Already relative or just a filename, use as-is
relativePath = filePath.replace('\\', '/');
}
try {
deleteByFilepathGlobals.setString(1, relativePath);
int deletedCount = deleteByFilepathGlobals.executeUpdate();
script.println("Removed " + deletedCount + " global entries for file: " + relativePath);
} catch (SQLException e) {
script.println("Error removing global entries: " + e.getMessage());
throw new Exception("Failed to remove global entries", e);
}
}
@Override
public void close() throws Exception {
this.disconnect();
}
}

View File

@@ -0,0 +1,513 @@
package re3lib;
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
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;
public class FunctionDumper {
GhidraScript script;
GlobalDumper globalDumper;
FunctionDatabase functionDatabase;
public HashSet<Address> functionAddrBlackList = new HashSet<>();
public boolean createdFile = false;
// Collects functions called by the current function
public HashSet<Function> functionReferences = new HashSet<>();
// Add flag to force Fix type
public boolean forceFixType = false;
static final Pattern fieldAccessRegex = Pattern.compile("^_([0-9]+)_([0-9]+)_$");
public FunctionDumper(GhidraScript script, FunctionDatabase functionDatabase, GlobalDumper globalDumper) {
this.script = script;
this.functionDatabase = functionDatabase;
this.globalDumper = globalDumper;
initFunctionBlacklist();
}
// Helper method to extract parameter names from Ghidra function
private String extractParameterNames(Function function) {
var parameters = function.getParameters();
if (parameters.length == 0) {
return "";
}
StringBuilder names = new StringBuilder();
for (int i = 0; i < parameters.length; i++) {
if (i > 0) names.append(";");
String paramName = parameters[i].getName();
names.append(paramName != null ? paramName : "param" + i);
}
return names.toString();
}
// Helper method to extract parameter types from Ghidra function
private String extractParameterTypes(Function function) {
var parameters = function.getParameters();
if (parameters.length == 0) {
return "";
}
StringBuilder types = new StringBuilder();
for (int i = 0; i < parameters.length; i++) {
if (i > 0) types.append(";");
String paramType = parameters[i].getDataType().toString();
types.append(paramType != null ? paramType : "void*");
}
return types.toString();
}
// Helper method to extract return type from Ghidra function
private String extractReturnType(Function function) {
var returnType = function.getReturnType();
return returnType != null ? returnType.getDisplayName() : "void";
}
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(RemanConfig.INSTANCE.functionBlacklistPath);
// Build blacklist if not loaded
if (functionAddrBlackList == null) {
boolean modified = false;
Iterator<Function> 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, RemanConfig.INSTANCE.functionBlacklistPath);
}
}
}
public void dumpStubFunction(Function externalFunction, boolean force) throws Exception {
String sanitizedExtFunctionName = Utils.sanitizeIdentifier(externalFunction.getName());
List<FunctionDatabase.FunctionEntry> entries1 = functionDatabase
.findEntriesByAddress(externalFunction.getEntryPoint());
boolean needStub = true;
if (!force) {
for (FunctionDatabase.FunctionEntry entry : entries1) {
if (entry.type == FunctionDatabase.Type.Auto || entry.type == FunctionDatabase.Type.Fix) {
needStub = false;
break;
}
}
if (!needStub) {
script.println("Function exists for " + externalFunction.getName() + " - skipping generating stub");
return;
}
}
String fileName = sanitizedExtFunctionName + ".cxx";
File f4 = new File(RemanConfig.INSTANCE.dirDecompStub, fileName);
script.println("Generating function stub for " + externalFunction.getName() + " => " + f4.toString());
// Extract calling convention from Ghidra function
String callingConventionName = externalFunction.getCallingConventionName();
FunctionDatabase.CallingConvention callingConvention = FunctionDatabase.CallingConvention
.fromString(callingConventionName);
script.println("Detected calling convention: " + callingConventionName + " -> " + callingConvention);
// Extract parameter information and return type
String parameterNames = extractParameterNames(externalFunction);
String parameterTypes = extractParameterTypes(externalFunction);
String returnType = extractReturnType(externalFunction);
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 <r3/binders/auto.h>");
writer2.println("#include <r3/binders/stub.h>");
writer2.println("#include <gh_global.h>");
writer2.println();
writer2.println("// " + externalFunction.getEntryPoint());
writer2.println("// " + externalFunction.getName());
// Parse function signature to extract calling convention, return type, and
// parameters
String signature = externalFunction.getSignature().getPrototypeString(false);
signature = signature.replace(externalFunction.getName(), sanitizedExtFunctionName);
script.println("Santized Signature: " + signature);
// Generate function stub using appropriate forwarding function
writer2.println("extern \"C\" " + signature + " {");
// Determine which stub function to use based on calling convention
String stubFunction;
if (callingConvention == FunctionDatabase.CallingConvention.Stdcall) {
stubFunction = "gh_stub_impl_stdcall";
} else if (callingConvention == FunctionDatabase.CallingConvention.Fastcall) {
stubFunction = "gh_stub_impl_fastcall";
} else {
// Default to cdecl for most cases
stubFunction = "gh_stub_impl_cdecl";
}
// Generate parameter list for the call
StringBuilder paramList = new StringBuilder();
var params = externalFunction.getParameters();
for (int i = 0; i < params.length; i++) {
if (i > 0)
paramList.append(", ");
paramList.append(params[i].getName());
}
// Generate the stub call
String addrString = "0x" +
externalFunction.getEntryPoint().toString().replace("0x", "");
if (returnType.equals("void")) {
writer2.println(" " + stubFunction + "<(stub_t)" + addrString + ", void>(" + paramList.toString() + ");");
} else {
writer2.println(" return " + stubFunction + "<(stub_t)" + addrString + ", " + returnType + ">(" +
paramList.toString() + ");");
}
writer2.println("}");
}
if (!f4.exists()) {
createdFile = true;
}
// Add stub function to database with calling convention and parameter information
FunctionDatabase.FunctionEntry newEntry = new FunctionDatabase.FunctionEntry(externalFunction.getEntryPoint(),
externalFunction.getName(), f4, FunctionDatabase.Type.Stub, callingConvention,
parameterNames, parameterTypes, returnType);
functionDatabase.addEntryAt(newEntry);
}
public void dump(Function function)
throws Exception {
String sanitizedFunctionName = Utils.sanitizeIdentifier(function.getName());
String fileName = sanitizedFunctionName + ".cxx";
Address entrypoint = function.getEntryPoint();
List<FunctionDatabase.FunctionEntry> entries = functionDatabase.findEntriesByAddress(entrypoint);
FunctionDatabase.Type targetType = FunctionDatabase.Type.Auto;
// Extract calling convention from Ghidra function
String callingConventionName = function.getCallingConventionName();
FunctionDatabase.CallingConvention callingConvention = FunctionDatabase.CallingConvention
.fromString(callingConventionName);
script.println("Detected calling convention: " + callingConventionName + " -> " + callingConvention);
// Extract parameter information and return type
String parameterNames = extractParameterNames(function);
String parameterTypes = extractParameterTypes(function);
String returnType = extractReturnType(function);
script.println("Parameters: " + parameterNames + " | Types: " + parameterTypes + " | Return: " + returnType);
// Handle forceFixType flag
if (forceFixType) {
targetType = FunctionDatabase.Type.Fix;
// Remove any existing Auto entries for this function
for (FunctionDatabase.FunctionEntry entry : entries) {
if (entry.type == FunctionDatabase.Type.Auto) {
script.println("Removing existing Auto entry: " + entry.file);
if (entry.file.exists()) {
entry.file.delete();
}
functionDatabase.removeEntryAt(entry.file.toString());
}
}
} else {
// Original logic for determining target type
for (FunctionDatabase.FunctionEntry entry : entries) {
script.println("Found existing decompiled entry at " + entry.file + " - " + entry.name);
if (entry.type == FunctionDatabase.Type.Fix) {
targetType = FunctionDatabase.Type.Ref;
}
}
}
// Always remove stub entries regardless of mode
for (FunctionDatabase.FunctionEntry entry : entries) {
if (entry.type == FunctionDatabase.Type.Stub) {
// Remove the stub file, since we now use the decompiled file
File stubFile = entry.file;
if (stubFile.exists()) {
script.println("Removing function stub " + stubFile);
stubFile.delete();
createdFile = true;
functionDatabase.removeEntryAt(entry.file.toString());
}
}
}
File targetFilename = null;
if (targetType == FunctionDatabase.Type.Ref) {
targetFilename = new File(RemanConfig.INSTANCE.dirDecompRef, fileName);
} else if (targetType == FunctionDatabase.Type.Fix) {
targetFilename = new File(RemanConfig.INSTANCE.dirDecompFix, fileName);
} else {
targetFilename = new File(RemanConfig.INSTANCE.dirDecompAuto, fileName);
}
// Handle overwrite prompting for Fix type
if (targetFilename.exists()) {
if (targetType == FunctionDatabase.Type.Fix) {
script.println("Fix file already exists: " + targetFilename);
boolean overwrite = script.askYesNo("Overwrite existing Fix file?",
"The Fix file " + targetFilename.getName() + " already exists. Do you want to overwrite it?");
if (!overwrite) {
script.println("Aborted: User chose not to overwrite existing Fix file.");
return;
}
}
targetFilename.delete();
script.println("Overwriting existing file " + targetFilename);
} else {
createdFile = true;
}
File f0 = targetFilename;
script.println("Processing " + function.getName() + " => " + f0.toString());
// Update database with calling convention and parameter information
FunctionDatabase.FunctionEntry newEntry = new FunctionDatabase.FunctionEntry(entrypoint, function.getName(), f0,
targetType, callingConvention, parameterNames, parameterTypes, returnType);
functionDatabase.addEntryAt(newEntry);
List<Function> externalFunctionCalls = new ArrayList<>();
HashMap<String, String> replacementMap = new HashMap<>();
String newFunctionName = sanitizedFunctionName;
if (callingConvention == FunctionDatabase.CallingConvention.Stdcall ||
callingConvention == FunctionDatabase.CallingConvention.Fastcall) {
newFunctionName = "__" + callingConvention.toString() + " " + newFunctionName;
}
String originalFunctionName = function.getName();
if (newFunctionName != originalFunctionName) {
replacementMap.put(originalFunctionName, newFunctionName);
}
DecompileResults decompRes = RemanConfig.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 <r3/binders/auto.h>");
writer2.println("#include <gh_global.h>");
writer2.println();
writer2.println("extern \"C\" {");
HighFunction highFunction = decompRes.getHighFunction();
HashSet<String> headers = new HashSet<>();
StringWriter codeWriter = new StringWriter();
PrettyPrinter pp = new PrettyPrinter(decompRes.getFunction(), decompRes.getCCodeMarkup(), null);
Iterator<ClangLine> lines = pp.getLines().iterator();
while (lines.hasNext()) {
ClangLine line = lines.next();
for (int i = 0; i < line.getIndent(); i++) {
codeWriter.write(' ');
}
List<ClangToken> 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;
// script.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<offset, size>
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();
}
// Check if it's a function pointer, otherwise add to globals
if (address.isMemoryAddress()) {
// script.println("Address: " + address + " - " + sym.getName());
Function maybeFunction = script.getFunctionAt(address);
if (maybeFunction != null) {
externalFunctionCalls.add(maybeFunction);
} else {
script.println("Add globals " + address + " - " + gsym.getName() + " - " + token.getText());
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)) {
externalFunctionCalls.add(calledFunction);
String fname = calledFunction.getName();
String fsname = Utils.sanitizeIdentifier(fname);
if (fsname != fname) {
replacementMap.put(fname, fsname);
}
}
}
}
}
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 (Function externalFunction : externalFunctionCalls) {
String proto = externalFunction.getSignature().getPrototypeString(false);
String name = externalFunction.getName();
proto = proto.replace(name, Utils.sanitizeIdentifier(name));
// Add calling convention information to the comment
String callingConv = externalFunction.getCallingConventionName();
FunctionDatabase.CallingConvention conv = FunctionDatabase.CallingConvention.fromString(callingConv);
headers.add("" + proto
+ "; // " + externalFunction.getEntryPoint() + " // "
+ name + " // " + conv);
}
for (String header : headers) {
writer2.println(header);
}
writer2.println();
writer2.print("// " + function.getEntryPoint());
String codeString = codeWriter.toString();
for (HashMap.Entry<String, String> entry : replacementMap.entrySet()) {
String oldName = entry.getKey();
String newName = entry.getValue();
codeString = codeString.replace(oldName, newName);
}
writer2.print(codeString);
writer2.println("}");
writer2.println();
}
// Possibly generate stubs for external functions
for (Function externalFunction : externalFunctionCalls) {
dumpStubFunction(externalFunction, false);
}
}
}

View File

@@ -22,10 +22,9 @@ 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.DataTypeManager;
import ghidra.program.model.data.DataTypePath;
import ghidra.program.model.data.FunctionDefinition;
import ghidra.program.model.data.Pointer;
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;
@@ -48,91 +47,22 @@ public class GlobalDumper {
};
GhidraScript script;
File manifestFile;
HashMap<Address, GlobalRec> globalAddrs = new HashMap<>();
FunctionDatabase functionDatabase;
public GlobalDumper(GhidraScript script) {
public GlobalDumper(GhidraScript script, FunctionDatabase functionDatabase) {
this.script = script;
manifestFile = new File(RecompileConfig.INSTANCE.outputDir, "globals.txt");
this.functionDatabase = functionDatabase;
}
public void removeGlobalManifest() {
if (manifestFile.exists()) {
manifestFile.delete();
// Remove globals from database
try {
functionDatabase.removeGlobalsByFilepath(RemanConfig.INSTANCE.GLOBAL_H_FILE);
} catch (Exception e) {
script.println("Error removing global manifest: " + e.getMessage());
}
}
public boolean loadGlobalManifest() throws Exception {
// Globals are stored in the format of
// <address> || <name> || <type>
if (!manifestFile.exists()) {
script.println("Global manifest file not found: " + manifestFile);
return false;
}
// Get the dataTypeManagerService
DataTypeManagerService dataTypeManagerService = (DataTypeManagerService) script.getState().getTool()
.getService(DataTypeManagerService.class);
DataTypeManager dtm = script.getCurrentProgram().getDataTypeManager();
DataTypeParser dtp = new DataTypeParser(dataTypeManagerService, AllowedDataTypes.ALL);
try (BufferedReader reader = new BufferedReader(new FileReader(manifestFile))) {
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split("\\|\\|");
if (parts.length == 4) {
Address address = script.parseAddress(parts[0].trim());
String name = parts[1].trim();
String categoryPath = parts[2].trim();
String dataTypePath = parts[3].trim();
DataTypePath typePath = new DataTypePath(categoryPath, dataTypePath);
DataType type = null;
type = dtm.getDataType(typePath);
if (type == null) {
// script.println("Parsing type: " + dataTypePath);
type = dtp.parse(dataTypePath);
}
if (type == null) {
script.println("WARNING: Failed to find type: " + dataTypePath + " for global: " + name + " at " + address);
continue;
}
globalAddrs.put(address, new GlobalRec(address, name, type));
} else {
script.println("Invalid global manifest line: " + line);
}
}
}
script.println("Loaded " + globalAddrs.size() + " globals from " + manifestFile);
return true;
}
public void addGlobal(Address addr, HighSymbol sym) throws Exception {
if (addr.compareTo(RecompileConfig.INSTANCE.staticMemoryBlockStart) < 0
|| addr.compareTo(RecompileConfig.INSTANCE.staticMemoryBlockEnd) > 0) {
throw new Exception("Global address out of range: " + addr);
}
DataType dt = sym.getDataType();
// if(symb.get
if (sym.getDataType().getName() == "undefined") {
// script.println("UNDEFINED: " + addr + " - " + dt.getDisplayName() + " - " +
// dt.getClass().getName());
Data data = script.getDataAt(addr);
if (data != null) {
dt = data.getDataType();
// script.println("DATA: " + addr + " - " + dt.getDisplayName());
}
}
if (dt == null) {
script.println("WARNING: Missing type for global: " + sym.getName() + " at " + addr);
return;
}
// script.println("Global: " + addr + " - " + sym.getName() + " - " +
// dt.getDisplayName());
globalAddrs.put(addr, new GlobalRec(addr, sym.getName(), dt));
}
String escapeCString(String str) {
str = str.replace("\\", "\\\\");
str = str.replace("\"", "\\\"");
@@ -162,20 +92,52 @@ public class GlobalDumper {
}
public void dumpGlobals() throws Exception {
File globalSymbolsListH = new File(RecompileConfig.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 <r3/binders/global.h>");
hwriter.println();
File globalSymbolsListC = new File(RecompileConfig.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 <r3/binders/global.h>");
hwriter.println();
List<GlobalRec> globals = new ArrayList<>(globalAddrs.values());
// Load globals directly from database
List<FunctionDatabase.GlobalEntry> dbGlobals = functionDatabase.loadAllGlobals();
List<GlobalRec> globals = new ArrayList<>();
// Convert database entries to GlobalRec objects
for (FunctionDatabase.GlobalEntry entry : dbGlobals) {
DataType type = null;
// Try to get from existing data at address
Data data = script.getDataAt(entry.address);
if (data != null) {
type = data.getDataType();
}
if (type == null) {
script.println("WARNING: Could not determine type for global: " + entry.name + " at " + entry.address);
// Get the dataTypeManagerService for parsing types
DataTypeManagerService dataTypeManagerService = (DataTypeManagerService) script.getState().getTool()
.getService(DataTypeManagerService.class);
DataTypeParser dtp = new DataTypeParser(dataTypeManagerService, AllowedDataTypes.ALL);
type = dtp.parse("undefined4");
}
// Retrieve the current symbol name (may have changed since stored)
Symbol sym = script.getSymbolAt(entry.address);
String currentName = entry.name;
if (sym != null) {
currentName = sym.getName();
}
globals.add(new GlobalRec(entry.address, currentName, type));
}
globals.sort((o1, o2) -> o1.address.compareTo(o2.address));
for (GlobalRec global : globals) {
@@ -203,11 +165,18 @@ public class GlobalDumper {
// 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 + ")";
} else if (dt instanceof Pointer) {
DataType baseType = ((Pointer) dt).getDataType();
if (baseType == null) {
script.println("WARNING: Missing base type for pointer: " + name + " at " + addr);
dataType = "pointer&";
} else if (baseType instanceof FunctionDefinition) {
script.println("Value is a function type " + name + " at " + addr);
dataType = ((FunctionDefinition) baseType).getDisplayName();
} else {
dataType = baseType.getDisplayName() + "*&";
}
initBlk += "(" + dataType + ")GH_MEM(0x" + addr + ")";
fullyDefinedType = true;
}
String linkagePrefix = "extern ";
@@ -243,45 +212,58 @@ public class GlobalDumper {
cwriter.close();
}
public void saveGlobalManifest() throws Exception {
File backupFile = new File(manifestFile.getParentFile(), manifestFile.getName() + ".bak");
if (backupFile.exists()) {
if (!backupFile.delete()) {
throw new Exception("Failed to delete backup file: " + backupFile + ", globals will not be saved!");
}
}
if (manifestFile.exists()) {
if (!manifestFile.renameTo(backupFile))
throw new Exception("Failed to rename manifest file: " + manifestFile + ", globals will not be saved!");
public void addGlobal(Address addr, HighSymbol sym) throws Exception {
if (sym.getName().equals("ExceptionList")) {
return;
}
try (PrintWriter writer = new PrintWriter(manifestFile)) {
script.println("Saving global manifest to " + manifestFile);
GlobalRec[] globals = globalAddrs.values().toArray(new GlobalRec[0]);
Arrays.sort(globals, (a, b) -> a.address.compareTo(b.address));
for (GlobalRec global : globals) {
DataTypePath path = global.type.getDataTypePath();
writer.println(global.address.toString() + " || " + global.name + " || " + path.getCategoryPath() + " || "
+ path.getDataTypeName());
if (addr.compareTo(RemanConfig.INSTANCE.staticMemoryBlockStart) < 0
|| addr.compareTo(RemanConfig.INSTANCE.staticMemoryBlockEnd) > 0) {
throw new Exception("Global address out of range: " + addr);
}
DataType dt = sym.getDataType();
// if(symb.get
if (sym.getDataType().getName() == "undefined") {
// script.println("UNDEFINED: " + addr + " - " + dt.getDisplayName() + " - " +
// dt.getClass().getName());
Data data = script.getDataAt(addr);
if (data != null) {
dt = data.getDataType();
// script.println("DATA: " + addr + " - " + dt.getDisplayName());
}
}
if (dt == null) {
script.println("WARNING: Missing type for global: " + sym.getName() + " at " + addr);
return;
}
// script.println("Global: " + addr + " - " + sym.getName() + " - " +
// dt.getDisplayName());
// Add directly to database instead of storing in memory
functionDatabase.addGlobal(addr, sym.getName());
}
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);
public void sanitizeGlobalSymbols() throws Exception {
// Load globals from database, sanitize symbol names, and update both Ghidra
// symbols and database
List<FunctionDatabase.GlobalEntry> dbGlobals = functionDatabase.loadAllGlobals();
for (FunctionDatabase.GlobalEntry entry : dbGlobals) {
String sanitizedName = Utils.sanitizeIdentifier(entry.name);
if (!sanitizedName.equals(entry.name)) {
Symbol symbol = script.getSymbolAt(entry.address);
if (symbol != null) {
script.println("Renaming global symbol: " + global.name + " -> " + sanitizedName);
AddLabelCmd cmd = new AddLabelCmd(global.address, sanitizedName,
script.println("Renaming global symbol: " + entry.name + " -> " + sanitizedName);
AddLabelCmd cmd = new AddLabelCmd(entry.address, sanitizedName,
symbol.getParentNamespace(),
SourceType.USER_DEFINED);
if (!cmd.applyTo(script.getCurrentProgram())) {
script.println("Error renaming symbol: " + cmd.getStatusMsg());
} else {
// Update the database with the new name
functionDatabase.addGlobal(entry.address, sanitizedName);
}
global.name = sanitizedName;
}
}
}

View File

@@ -42,7 +42,7 @@ public class PCallTracer {
Program program;
public PCallTracer() {
this.script = RecompileConfig.INSTANCE.script;
this.script = RemanConfig.INSTANCE.script;
this.program = this.script.getCurrentProgram();
// this.decomp = RecompileConfig.INSTANCE.decompCache;
}

View File

@@ -10,13 +10,17 @@ import ghidra.program.flatapi.FlatProgramAPI;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
public class RecompileConfig {
// A general configuration for the reman project
// including all paths, specific addresses and stuff
public class RemanConfig {
private static final String RECOMPILE_PREFIX = "game_re";
// Version control project root
public final String rootDir;
// The output directory for the recompiled game
public final String outputDir;
// The output directory for the original game
public final String originalDir;
public final String typeBlacklistPath;
public final String categoryPathBlacklistPath;
public final String functionBlacklistPath;
@@ -24,6 +28,9 @@ public class RecompileConfig {
public final Address staticMemoryBlockStart;
public final Address staticMemoryBlockEnd;
// The path to the database file
public final File databasePath;
// The automatically decompiled files
public final File dirDecompAuto;
// The manually decompiled files (will not be overwritten by the auto
@@ -48,10 +55,13 @@ public class RecompileConfig {
public final GhidraScript script;
public static RecompileConfig INSTANCE;
public static RemanConfig INSTANCE;
public RecompileConfig(GhidraScript script) {
staticMemoryBlockStart = script.getCurrentProgram().getAddressFactory().getAddress("00597000");
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("00400000");
staticMemoryBlockEnd = script.getCurrentProgram().getAddressFactory().getAddress("00843fff");
this.script = script;
@@ -59,11 +69,15 @@ public class RecompileConfig {
rootDir = new File(script.getSourceFile().getAbsolutePath()).getParentFile().getParentFile().toString();
outputDir = new File(rootDir, RECOMPILE_PREFIX).toString();
script.println("Output path: " + outputDir);
originalDir = new File(rootDir, "game").toString();
typeBlacklistPath = new File(outputDir, "type_blacklist.txt").toString();
categoryPathBlacklistPath = new File(outputDir, "type_path_blacklist.txt").toString();
functionBlacklistPath = new File(outputDir, "function_blacklist.txt").toString();
databasePath = new File(outputDir, "gh.db");
dirDecompAuto = new File(outputDir, "gh_auto");
dirDecompFix = new File(outputDir, "gh_fix");
dirDecompRef = new File(outputDir, "gh_ref");

View File

@@ -8,15 +8,23 @@ import java.util.Iterator;
import java.util.List;
import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.CategoryPath;
import ghidra.program.model.data.Composite;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Enum;
import ghidra.program.model.data.EnumDataType;
import ghidra.program.model.data.FunctionDefinition;
import ghidra.program.model.data.Pointer;
import ghidra.program.model.data.ProgramBasedDataTypeManager;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.TypeDef;
import ghidra.program.model.data.TypedefDataType;
import ghidra.program.model.data.Union;
import ghidra.program.model.data.UnionDataType;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Program;
import re3lib.FunctionDatabase.GlobalEntry;
public class TypeDumper {
Program currentProgram;
@@ -25,15 +33,38 @@ public class TypeDumper {
public TypeDumper(GhidraScript script) {
this.script = script;
currentProgram = script.getCurrentProgram();
RecompileConfig.INSTANCE = new RecompileConfig(script);
RemanConfig.INSTANCE = new RemanConfig(script);
}
public void run() throws Exception {
ProgramBasedDataTypeManager dtm = currentProgram.getDataTypeManager();
HashSet<String> typeBlacklist = Utils.loadSimpleBlacklist(RecompileConfig.INSTANCE.typeBlacklistPath);
HashSet<String> requiredFunctionTypes = new HashSet<>();
FunctionDatabase fd = new FunctionDatabase(script);
List<GlobalEntry> globals = fd.loadAllGlobals();
for (GlobalEntry globalEntry : globals) {
// Fetch type of global from ghidra
Address addr = globalEntry.address;
if (globalEntry.name.equals("p_fn_vDisplayAll"))
script.println("EE" + globalEntry.name + "EE");
// script.print("Global: " + globalEntry.name);
Data data = script.getDataAt(addr);
if (data != null) {
DataType type = data.getDataType();
if (type instanceof Pointer) {
DataType inner = ((Pointer) type).getDataType();
if (inner instanceof FunctionDefinition) {
requiredFunctionTypes.add(inner.getDisplayName());
script.println("Adding required global function type: " + type.getDisplayName());
}
}
}
}
HashSet<String> typeBlacklist = Utils.loadSimpleBlacklist(RemanConfig.INSTANCE.typeBlacklistPath);
HashSet<String> categoryPathBlacklist = Utils
.loadSimpleBlacklist(RecompileConfig.INSTANCE.categoryPathBlacklistPath);
.loadSimpleBlacklist(RemanConfig.INSTANCE.categoryPathBlacklistPath);
if (typeBlacklist == null) {
script.println("Building struct blacklist from existing data types");
@@ -45,7 +76,7 @@ public class TypeDumper {
typeBlacklist.add(dt.getDisplayName());
}
}
Utils.saveStructBlacklist(typeBlacklist, RecompileConfig.INSTANCE.typeBlacklistPath);
Utils.saveStructBlacklist(typeBlacklist, RemanConfig.INSTANCE.typeBlacklistPath);
}
List<DataType> filteredTypes = new ArrayList<>();
@@ -74,32 +105,42 @@ public class TypeDumper {
Iterator<DataType> it = dtm.getAllDataTypes();
while (it.hasNext()) {
DataType dt = it.next();
if (typeBlacklist.contains(dt.getDisplayName()))
continue;
CategoryPath catPath = dt.getCategoryPath();
if (catPath.getPathElements().length > 0 && categoryPathBlacklist.contains(catPath.getPathElements()[0]))
continue;
// script.println("Type: " + dt.getDisplayName() + " - CatPath: " + dt.getCategoryPath());
if (dt instanceof Structure || dt instanceof TypeDef || dt instanceof EnumDataType
|| dt instanceof Union || dt instanceof Enum || dt instanceof FunctionDefinition) {
// if (dt.getName().equals("ImageBaseOffset32"))
// throw new Exception("Found: " + dt.getDisplayName() + " - " + catPath.getPathElements()[0] + " - " + dt.getClass().getSimpleName());
if (dt.getDisplayName().contains("level_displayFn") || dt.getDisplayName().contains("_M_IX86"))
script.println("DEBUG " + dt.getDisplayName() + " - " + dt.getClass().getSimpleName());
// if (dt.getDisplayName().contains("tdstObjectTypeElement_") ||
// dt.getDisplayName().contains("ObjectTypeElementHandle"))
if (dt instanceof Structure || dt instanceof TypeDef || dt instanceof EnumDataType) {
// script.println("Adding: " + dt.getDisplayName() + " - " +
// dt.getClass().getSimpleName());
filteredTypes.add(dt);
}
// }
}
try (PrintWriter writer = new PrintWriter(new File(RecompileConfig.INSTANCE.outputDir, "gh_types.h"),
// String s = "";
// for (DataType dataType : filteredTypes) {
// s += dataType.getDisplayName() + ", ";
// }
// script.println(s);
try (PrintWriter writer = new PrintWriter(new File(RemanConfig.INSTANCE.outputDir, "gh_types.h"),
"UTF-8")) {
Utils.headerGuardPre(writer, "STRUCTS");
writer.println("// AUTO-GENERATED FILE ");
writer.println("#include <r3/binders/type.h>");
DataTypeWriter dtw = new DataTypeWriter(dtm, writer);
dtw.blacklistedTypes = typeBlacklist;
dtw.requiredFunctionTypes = requiredFunctionTypes;
dtw.write(filteredTypes, script.getMonitor());
Utils.headerGuardPost(writer, "STRUCTS");

View File

@@ -22,7 +22,10 @@ public class Utils {
}
public static String sanitizeIdentifier(String name) {
return name.replaceAll("[^a-zA-Z0-9_]", "_");
String r = name;
r = r.replaceAll("\\?", "UNK");
r = r.replaceAll("[^a-zA-Z0-9_]", "_");
return r;
}
public static HashSet<String> loadSimpleBlacklist(String path) {
@@ -51,7 +54,7 @@ public class Utils {
}
public static HashSet<Address> loadFunctionBlacklist(String path) {
GhidraScript script = RecompileConfig.INSTANCE.script;
GhidraScript script = RemanConfig.INSTANCE.script;
HashSet<Address> fnBlacklist = new HashSet<>();
File blacklistFile = new File(path);
try (Scanner scanner = new Scanner(blacklistFile)) {
@@ -60,7 +63,7 @@ public class Utils {
// Strip comment
String line1 = line.split("//")[0].trim();
// Deserialize address
Address addr = RecompileConfig.INSTANCE.currentProgram.getAddressFactory().getAddress(line1);
Address addr = RemanConfig.INSTANCE.currentProgram.getAddressFactory().getAddress(line1);
fnBlacklist.add(addr);
}
script.println("Loaded blacklist with " + fnBlacklist.size() + " entries");
@@ -71,7 +74,7 @@ public class Utils {
}
public static void saveFunctionBlacklist(HashSet<Address> fnBlacklist, String path) {
GhidraScript script = RecompileConfig.INSTANCE.script;
GhidraScript script = RemanConfig.INSTANCE.script;
File blacklistFile = new File(path);
try (PrintWriter writer = new PrintWriter(blacklistFile)) {
for (Address addr : fnBlacklist) {

73
GhidraScripts/readme.md Normal file
View File

@@ -0,0 +1,73 @@
# Ghidra Scripts
Add this to your ghidra scripts folder to add the reman decompile scripts to ghidra
NOTE: Make sure to also add the include `sqlite-jdbc-3.49.1.0.jar` to the ghidra scripts folders, as this is required for the ghidra scripts to read the decompile database.
## Decompile database
The decompile database is a sqlite database that contains a list of all files that implement decompiled functions and their source address. It is used to regenerate files, check for duplicates, and more.
To generate the database from the current set of files, run the scan_sources script in the /game_re folder.
Make sure you have set up the tooling by running the /tooling/setup script.
## IDE Notes
This should work with the redhat java plugin for vscode, you however need to manually add the referenced libraries to the settings, like so:
```json
{
"java.project.referencedLibraries": [
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\Base\\lib\\Base.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\Decompiler\\lib\\Decompiler.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\BSim\\lib\\BSim.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\BSimFeatureVisualizer\\lib\\BSimFeatureVisualizer.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\Base\\lib\\Base.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\BytePatterns\\lib\\BytePatterns.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\ByteViewer\\lib\\ByteViewer.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\CodeCompare\\lib\\CodeCompare.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\DebugUtils\\lib\\DebugUtils.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\Decompiler\\lib\\Decompiler.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\DecompilerDependent\\lib\\DecompilerDependent.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\FileFormats\\lib\\FileFormats.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\FunctionGraph\\lib\\FunctionGraph.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\FunctionGraphDecompilerExtension\\lib\\FunctionGraphDecompilerExtension.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\FunctionID\\lib\\FunctionID.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\GhidraGo\\lib\\GhidraGo.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\GhidraServer\\lib\\GhidraServer.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\GnuDemangler\\lib\\GnuDemangler.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\GraphFunctionCalls\\lib\\GraphFunctionCalls.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\GraphServices\\lib\\GraphServices.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\MicrosoftCodeAnalyzer\\lib\\MicrosoftCodeAnalyzer.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\MicrosoftDemangler\\lib\\MicrosoftDemangler.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\MicrosoftDmang\\lib\\MicrosoftDmang.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\PDB\\lib\\PDB.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\ProgramDiff\\lib\\ProgramDiff.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\ProgramGraph\\lib\\ProgramGraph.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\Python\\lib\\Python.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\Recognizers\\lib\\Recognizers.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\Sarif\\lib\\Sarif.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\SourceCodeLookup\\lib\\SourceCodeLookup.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\SwiftDemangler\\lib\\SwiftDemangler.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\SystemEmulation\\lib\\SystemEmulation.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\VersionTracking\\lib\\VersionTracking.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\VersionTrackingBSim\\lib\\VersionTrackingBSim.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\WildcardAssembler\\lib\\WildcardAssembler.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\DB\\lib\\DB.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\Docking\\lib\\Docking.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\Emulation\\lib\\Emulation.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\FileSystem\\lib\\FileSystem.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\Generic\\lib\\Generic.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\Graph\\lib\\Graph.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\Gui\\lib\\Gui.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\Help\\lib\\Help.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\Project\\lib\\Project.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\Pty\\lib\\Pty.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\SoftwareModeling\\lib\\SoftwareModeling.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\Utility\\lib\\Utility.jar",
"c:\\Projects\\R3\\java\\ghidra\\sqlite-jdbc-3.49.1.0.jar"
]
}
```

Binary file not shown.

9
game_re/.gitignore vendored
View File

@@ -1,5 +1,10 @@
gh_auto/*
gh_ref/*
old/
*.bak
gh_cmake_timestamp
functions.dat
functions.dat
*.zip
.tmp
.txt
*.db
logs/

View File

@@ -1,84 +1,125 @@
# Build for 32-bit compatibility
add_compile_options(-m32)
add_link_options(-m32)
function(setup_target TARGET DBG_MODE)
set(SOURCES
r3/main.cxx
r3/binders/stub.cxx
gh_global.cxx)
add_subdirectory(third_party/spdlog)
if(DBG_MODE)
add_library(${TARGET} SHARED ${SOURCES})
else()
add_executable(${TARGET} ${SOURCES})
set_target_properties(
${TARGET} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
)
endif()
add_executable(game_re
r3/main.cpp
r3/binders/static_mem.cxx
gh_global.cxx
)
target_compile_features(${TARGET} PUBLIC cxx_std_20)
target_include_directories(${TARGET} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_features(game_re PUBLIC cxx_std_20)
if(WIN32 AND R3_32BIT)
target_link_libraries(${TARGET} PRIVATE
binkw32
dinput8
)
endif()
target_include_directories(game_re PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/third_party/bink
)
if(WIN32)
target_link_directories(game_re PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/bink)
target_include_directories(game_re PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/bink)
target_link_libraries(game_re PRIVATE binkw32)
# Copy to output dir
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/binkw32.dll
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/third_party/bink/binkw32.dll ${CMAKE_CURRENT_BINARY_DIR}
target_compile_definitions(${TARGET} PRIVATE
R3_GAME_DATA_DIR=\"${GAME_DATA_DIR}\"
)
add_custom_target(copy_binkw32 ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/binkw32.dll)
add_dependencies(game_re copy_binkw32)
endif()
target_compile_definitions(game_re PRIVATE
R3_GAME_DATA_DIR=\"${GAME_DATA_DIR}\"
)
if(NOT DBG_MODE)
get_filename_component(R3_DATA_SEGMENT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/gh_datasegment.bin" ABSOLUTE)
target_compile_definitions(${TARGET} PRIVATE
R3_DATA_SEGMENT_FILE=\"${R3_DATA_SEGMENT_FILE}\"
)
endif()
get_filename_component(R3_DATA_SEGMENT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/gh_datasegment.bin" ABSOLUTE)
target_compile_definitions(game_re PRIVATE
R3_DATA_SEGMENT_FILE=\"${R3_DATA_SEGMENT_FILE}\"
)
if(WIN32)
target_link_directories(game_re PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/mssdk/lib)
target_include_directories(game_re SYSTEM AFTER PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/mssdk/include)
target_link_libraries(game_re PRIVATE
d3d8
dinput8
target_compile_definitions(${TARGET} PRIVATE
_CRT_SECURE_NO_WARNINGS=1
_CRT_NONSTDC_NO_WARNINGS=1
SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_TRACE
)
endif()
target_compile_definitions(game_re PRIVATE
_CRT_SECURE_NO_WARNINGS=1
_CRT_NONSTDC_NO_WARNINGS=1)
target_link_libraries(${TARGET} PRIVATE spdlog CLI11 magic_enum)
target_link_libraries(game_re PRIVATE spdlog)
file(GLOB GH_AUTO_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/gh_auto/*.cxx)
file(GLOB GH_FIX_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/gh_fix/*.cxx)
file(GLOB GH_STUB_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/gh_stub/*.cxx)
file(GLOB GH_AUTO_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/gh_auto/*.cxx)
file(GLOB GH_FIX_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/gh_fix/*.cxx)
file(GLOB GH_STUB_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/gh_stub/*.cxx)
target_sources(${TARGET} PRIVATE
${GH_AUTO_SOURCES}
${GH_FIX_SOURCES}
${GH_STUB_SOURCES}
)
target_sources(game_re PRIVATE
${GH_AUTO_SOURCES}
${GH_FIX_SOURCES}
${GH_STUB_SOURCES}
)
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
target_compile_definitions(${TARGET} PRIVATE MSVC=1)
# Ignore -Wformat-security
target_compile_options(game_re PRIVATE -Wno-format-security)
# Disable SAFESEH on Windows
if(WIN32)
target_link_options(${TARGET} PRIVATE /SAFESEH:NO)
endif()
else()
target_compile_definitions(${TARGET} PRIVATE MSVC=0)
# Ignore -Wmicrosoft-cast
target_compile_options(game_re PRIVATE -Wno-microsoft-cast)
# Ignore -Wformat-security
target_compile_options(${TARGET} 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
)
# Ignore -Wmicrosoft-cast
target_compile_options(${TARGET} PRIVATE -Wno-microsoft-cast)
target_precompile_headers(game_re PRIVATE
"$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/r3/binders/auto_pch.cxx>"
)
# Disable safeseh
# target_link_options(${TARGET} PRIVATE -Wl,/SAFESEH:NO)
endif()
# 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
)
target_precompile_headers(${TARGET} PRIVATE
"$<$<COMPILE_LANGUAGE:CXX>:${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)
target_link_libraries(${TARGET} PRIVATE
DbgHelp
hooker
)
find_program(gh_tool
NAMES gh_tool gh_tool.exe
HINTS ${CMAKE_CURRENT_LIST_DIR}/../tooling/bin
REQUIRED
)
execute_process(
COMMAND ${gh_tool} -d${CMAKE_CURRENT_SOURCE_DIR}/gh.db
hooks -o ${CMAKE_CURRENT_BINARY_DIR}/hooks.def
)
target_include_directories(${TARGET} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
else()
target_sources(${TARGET} PRIVATE
r3/binders/static_mem.cxx
)
endif()
endfunction()
setup_target(game_re OFF)
setup_target(game_dbg ON)

View File

@@ -1 +0,0 @@
gh_fix

View File

@@ -202,4 +202,5 @@
00408d30 // strcmp
0054c925 // _chdir
0054bce5 // strlwr
00402960 // sprintf
00402960 // sprintf
0059736c // Direct3DCreate8

View File

@@ -3,13 +3,14 @@
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
// 00401410
HWND getHWND(void)
// 004013f0
HANDLE __cdecl r3_getDrawSemaphore(void)
{
return g_gameHWND;
return g_drawSemaphore;
}
}

BIN
game_re/gh_datasegment.bin (Stored with Git LFS)

Binary file not shown.

View File

@@ -3,9 +3,9 @@
#pragma once
#include <cstddef>
#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;

View File

@@ -1,28 +0,0 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
// 0043e1d0
/* Allocate error manager system numbers */
byte Erm_fn_ucInitErrMsg(void)
{
byte RVar1;
tdstLastErrorInfo *pdVar2;
int iVar2;
RVar1 = g_ucErmNbOfModule;
if (g_ucErmNbOfModule == 0) {
for (size_t i = 0; i < std::size(g_stErmTheLastErrorInfo); i++) {
g_stErmTheLastErrorInfo[i].lastErr = 0;
g_stErmTheLastErrorInfo[i].ulChannelId = 0;
}
}
g_ucErmNbOfModule = g_ucErmNbOfModule + 1;
return RVar1;
}
}

View File

@@ -1,53 +0,0 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
#include <spdlog/spdlog.h>
extern "C" {
void r3_noop(void *p_cTxt1, void *p_cTxt2); // 00401100 // r3_noop
tdstLastErrorInfo *Erm_fn_p_stFindstMyLastErrorInfo(
ulong ulChannelId); // 0043e2b0 // Erm_fn_p_stFindstMyLastErrorInfo
// 0043e410
/* Check CpaError.h */
void Erm_fn_v_UpdateLastError(ushort uwStartOfWarningsId, byte ucModuleId,
ulong ulChannelId, ushort uwErrNum,
long lDebugData, uchar ucOpenInfoWindow,
uchar ucStopForDebug, char *szPersonalMsg)
{
tdstLastErrorInfo *ptVar2;
ptVar2 = Erm_fn_p_stFindstMyLastErrorInfo(ulChannelId);
if (ptVar2 == (tdstLastErrorInfo *)0x0) {
throw std::runtime_error(
fmt::format("{} {}", s_Error_in_the_Erm__005bd374,
s_There_is_no_more_Channel_error_t_005bd388));
}
if (ptVar2->lastErr != 0) {
throw std::runtime_error(
fmt::format("{}", s_Strange__The_last_error_was_neve_005bd348));
}
ptVar2->lastErr = uwErrNum;
ptVar2->ucLastFailedModuleId = ucModuleId;
ptVar2->ulChannelId = ulChannelId;
if (uwErrNum < uwStartOfWarningsId) {
if (szPersonalMsg == (char *)0x0) {
throw std::runtime_error(fmt::format(
"Unkown fatal error ({}, module: {})", uwErrNum, ucModuleId));
} else {
throw std::runtime_error(
fmt::format("Unkown fatal error ({}, module: {}, {})", uwErrNum,
ucModuleId, szPersonalMsg));
}
}
if (szPersonalMsg == (char *)0x0) {
return;
} else {
SPDLOG_WARN("Erm_Warn: {}, module: {}, {}", uwErrNum, ucModuleId,
szPersonalMsg);
}
}
}

View File

@@ -1,26 +0,0 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
// 0043ff60
/* WARNING: Globals starting with '_' overlap smaller symbols at the same address */
void FUN_0043ff60(float param_1,float param_2,float param_3)
{
longlong lVar1;
longlong lVar2;
longlong lVar3;
lVar1 = r3_ftol(param_1 * 255.0);
lVar2 = r3_ftol(param_2 * 255.0);
lVar3 = r3_ftol(param_3 * 255.0);
DAT_007a2c14 = ((int)lVar1 << 8 | (uint)lVar2) << 8 | (uint)lVar3;
return;
}
}

View File

@@ -1,41 +0,0 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
undefined4* FUN_0046ecc0(undefined2 param_1, undefined2 param_2); // 0046ecc0 // FUN_0046ecc0
// 0046f240
/* WARNING: Globals starting with '_' overlap smaller symbols at the same address */
undefined4 FUN_0046f240(short param_1,short param_2,undefined4 *param_3)
{
uint uVar1;
undefined4 *puVar2;
uint uVar3;
int iVar4;
DAT_005e6b04 = 1;
do {
} while (DAT_005e6b00 != 0);
uVar1 = (uint)param_2;
uVar3 = uVar1 & 0x8000000f;
if ((int)uVar3 < 0) {
uVar3 = (uVar3 - 1 | 0xfffffff0) + 1;
}
puVar2 = (undefined4 *)FUN_0046ecc0((int)(uVar1 + ((int)uVar1 >> 0x1f & 0xfU)) >> 4,uVar3);
puVar2[0x19] = 0xffffffff;
puVar2[0x18] = 0;
for (iVar4 = 0x1c; iVar4 != 0; iVar4 = iVar4 + -1) {
*param_3 = *puVar2;
puVar2 = puVar2 + 1;
param_3 = param_3 + 1;
}
DAT_005e6b04 = 0;
return 1;
}
}

View File

@@ -1,30 +0,0 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
undefined FUN_0047c340(dword* param_1, dword* param_2, undefined4 param_3); // 0047c340 // FUN_0047c340
undefined FUN_0046f240(short param_1, short param_2, undefined4 * param_3); // 0046f240 // FUN_0046f240
undefined FUN_0046f060(short param_1, undefined4 * param_2); // 0046f060 // FUN_0046f060
// 0047c150
void FUN_0047c150(short param_1,short param_2,int param_3)
{
int iVar1;
dword local_d0 [24];
dword local_70 [28];
iVar1 = FUN_0046f060(param_1,local_d0);
if ((iVar1 != 0) && (iVar1 = FUN_0046f240(param_1,param_2,local_70), iVar1 != 0)) {
if (param_3 != 0) {
DAT_005f5e24 = param_3;
}
FUN_0047c340(local_d0,local_70,DAT_005f5e24);
}
return;
}
}

View File

@@ -0,0 +1,26 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
undefined FUN_004993a0(undefined4 param_1); // 004993a0 // FUN_004993a0 // cdecl
undefined FUN_00498e90(undefined4 param_1); // 00498e90 // FUN_00498e90 // cdecl
undefined FUN_00499540(undefined4 param_1); // 00499540 // FUN_00499540 // cdecl
// 004995f0
void FUN_004995f0(undefined4 param_1,undefined4 param_2)
{
int iVar1;
iVar1 = FUN_00499540(param_1);
if (iVar1 != 0) {
FUN_00498e90(param_2);
FUN_004993a0(param_2);
}
return;
}
}

View File

@@ -0,0 +1,37 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
// 00506510
int __cdecl IPT_fn_hGetEntryActionHandle(char *param_1)
{
char *pcVar1;
int iVar2;
uint uVar3;
int iVar4;
int iVar5;
/* 0x106510 47 IPT_fn_hGetEntryActionHandle */
iVar5 = 0;
uVar3 = 0;
iVar4 = 0;
do {
if (DAT_00840e9c <= uVar3) {
return iVar5;
}
pcVar1 = *(char **)(iVar4 + 8 + DAT_00840ea0);
if ((pcVar1 != (char *)0x0) && (iVar2 = strcmpi(pcVar1,param_1), iVar2 == 0)) {
iVar5 = iVar4 + DAT_00840ea0;
}
uVar3 = uVar3 + 1;
iVar4 = iVar4 + 0x1c;
} while (iVar5 == 0);
return iVar5;
}
}

View File

@@ -1,16 +0,0 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
#include <bink.h>
extern "C" {
// 00441e40
void binkInit(void) {
BinkSetSoundSystem(&BinkOpenDirectSound, 0);
BinkSetSoundOnOff(0, 0);
BinkSetIOSize(0x80000000);
return;
}
}

90
game_re/gh_fix/entry.cxx Normal file
View File

@@ -0,0 +1,90 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
#include <spdlog/spdlog.h>
extern "C" {
undefined4 crt_createProgramHeap(undefined4 param_1) {
return gh_stub_impl_cdecl<(stub_t)0x00404902, undefined4>(param_1);
}
undefined4 ioinit(void) {
return gh_stub_impl_cdecl<(stub_t)0x004046bf, undefined4>();
}
void crt_initConsole(void) {
return gh_stub_impl_cdecl<(stub_t)0x00404503, void>();
}
LPSTR crt_setupEnv(void) {
return gh_stub_impl_cdecl<(stub_t)0x004043d1, LPSTR>();
}
undefined4 crt_main2(void) {
return gh_stub_impl_cdecl<(stub_t)0x00404184, undefined4>();
}
undefined4 crt_main1(void) {
return gh_stub_impl_cdecl<(stub_t)0x004040cb, undefined4>();
}
void crt_static_init(void) {
return gh_stub_impl_cdecl<(stub_t)0x004027be, void>();
}
char *crt_0(void) { return gh_stub_impl_cdecl<(stub_t)0x00404073, char *>(); }
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;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
DVar1 = GetVersion();
#pragma clang diagnostic pop
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();
crt_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);
}
}

196
game_re/gh_fix/gfx_init.cxx Normal file
View File

@@ -0,0 +1,196 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
undefined FUN_00496ac0(void); // 00496ac0 // FUN_00496ac0 // cdecl
undefined FUN_00470b00(void); // 00470b00 // FUN_00470b00 // cdecl
undefined FUN_00484ea0(undefined4 param_1); // 00484ea0 // FUN_00484ea0 // cdecl
//
// 0046f870
undefined4 gfx_init(HWND hwnd, int param_2, UINT param_3, UINT param_4,
int param_5)
{
undefined4 *puVar1;
HRESULT HVar2;
int iVar3;
D3DFORMAT AdapterFormat;
D3DPRESENT_PARAMETERS *pDVar4;
D3DDISPLAYMODE DStack_54;
D3DDISPLAYMODE displayMode;
D3DPRESENT_PARAMETERS DStack_34;
puVar1 = &DAT_007eaf60;
for (iVar3 = 0x13; iVar3 != 0; iVar3 = iVar3 + -1) {
*puVar1 = 0;
puVar1 = puVar1 + 1;
}
puVar1 = &g_gfx_lastColorOp;
for (iVar3 = 0x58; iVar3 != 0; iVar3 = iVar3 + -1) {
*puVar1 = 0;
puVar1 = puVar1 + 1;
}
puVar1 = &DAT_007eb044;
do {
*puVar1 = 0xbf800000;
puVar1 = puVar1 + 0xb;
} while ((int)puVar1 < 0x7eb1a4);
DAT_005bf684 = param_2;
if (param_2 == 0) {
DWORD_005e6c20 = g_GLI_width0;
DWORD_005e6c24 = g_GLI_height0;
DAT_005e6c28 = g_GLI_bitdepth0;
if (param_3 == 0) {
param_3 = g_GLI_width0;
}
if (param_4 == 0) {
param_4 = g_GLI_height0;
}
if (param_5 == 0) {
param_5 = g_GLI_bitdepth0;
}
} else {
DWORD_005e6c20 = param_3;
DWORD_005e6c24 = param_4;
DAT_005e6c28 = param_5;
}
static FnD3Create8 fn_Direct3DCreate8 = getDirect3DCreate8();
gfx_d3d = fn_Direct3DCreate8(0xdc);
if (gfx_d3d == (IDirect3D8 *)0x0) {
return 1;
}
HVar2 = (*gfx_d3d->lpVtbl->GetAdapterDisplayMode)(gfx_d3d, 0, &displayMode);
if (HVar2 < 0) {
return 1;
}
pDVar4 = &DStack_34;
for (iVar3 = 0xd; iVar3 != 0; iVar3 = iVar3 + -1) {
pDVar4->BackBufferWidth = 0;
pDVar4 = (D3DPRESENT_PARAMETERS *)&pDVar4->BackBufferHeight;
}
DStack_34.Windowed = (BOOL)(DAT_005bf684 == 0);
if (DAT_005bf684 == 0) {
DStack_34.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC;
DStack_34.BackBufferFormat = displayMode.Format;
param_5 = FUN_00484ea0(displayMode.Format);
AdapterFormat = displayMode.Format;
DAT_005e6c28 = param_5;
} else {
DStack_34.SwapEffect = D3DSWAPEFFECT_FLIP;
if (param_5 == 0x10) {
DStack_34.BackBufferFormat = D3DFMT_R5G6B5;
AdapterFormat = D3DFMT_R5G6B5;
} else {
DStack_34.BackBufferFormat = D3DFMT_A8R8G8B8;
AdapterFormat = D3DFMT_X8R8G8B8;
}
}
DStack_34.FullScreen_PresentationInterval = (UINT)(DAT_005bf684 != 0);
DStack_34.BackBufferHeight = param_4;
DStack_34.BackBufferCount = 1;
DStack_34.EnableAutoDepthStencil = 1;
DStack_34.FullScreen_RefreshRateInHz = 0;
DStack_34.BackBufferWidth = param_3;
if (0x10 < param_5) {
HVar2 = (*gfx_d3d->lpVtbl->CheckDeviceFormat)(
gfx_d3d, g_GLI_adapter, D3DDEVTYPE_HAL, AdapterFormat, 2,
D3DRTYPE_SURFACE, D3DFMT_D24S8);
if (HVar2 == 0) {
DStack_34.AutoDepthStencilFormat = D3DFMT_D24S8;
DAT_0063be50 = 1;
goto LAB_0046fa6f;
}
HVar2 = (*gfx_d3d->lpVtbl->CheckDeviceFormat)(
gfx_d3d, g_GLI_adapter, D3DDEVTYPE_HAL, AdapterFormat, 2,
D3DRTYPE_SURFACE, D3DFMT_D32);
DAT_0063be50 = 0;
if (HVar2 == 0) {
DStack_34.AutoDepthStencilFormat = D3DFMT_D32;
goto LAB_0046fa6f;
}
}
DAT_0063be50 = 0;
DStack_34.AutoDepthStencilFormat = D3DFMT_D16;
(*gfx_d3d->lpVtbl->CheckDeviceFormat)(gfx_d3d, g_GLI_adapter, D3DDEVTYPE_HAL,
AdapterFormat, 2, D3DRTYPE_SURFACE,
D3DFMT_D16);
LAB_0046fa6f:
DStack_34.Flags = 1;
if (g_GLI_tnl == '\0') {
HVar2 =
(*gfx_d3d->lpVtbl->CreateDevice)(gfx_d3d, g_GLI_adapter, D3DDEVTYPE_HAL,
hwnd, 0x24, &DStack_34, &gfx_device);
if (HVar2 < 0) {
return 1;
}
} else {
HVar2 =
(*gfx_d3d->lpVtbl->CreateDevice)(gfx_d3d, g_GLI_adapter, D3DDEVTYPE_HAL,
hwnd, 0x44, &DStack_34, &gfx_device);
if ((HVar2 < 0) && (HVar2 = (*gfx_d3d->lpVtbl->CreateDevice)(
gfx_d3d, g_GLI_adapter, D3DDEVTYPE_HAL, hwnd, 0x24,
&DStack_34, &gfx_device),
HVar2 < 0)) {
return 1;
}
}
(*gfx_device->lpVtbl->SetRenderState)(gfx_device, D3DRS_NORMALIZENORMALS, 0);
DAT_007eafa4 = 0;
(*gfx_device->lpVtbl->SetRenderState)(gfx_device, D3DRS_ZENABLE, 1);
DAT_007eafa0 = 1;
(*gfx_device->lpVtbl->SetRenderState)(gfx_device, D3DRS_ZFUNC, 4);
DAT_007eaf7c = 4;
(*gfx_device->lpVtbl->SetRenderState)(gfx_device, D3DRS_DITHERENABLE, 1);
(*gfx_device->lpVtbl->SetRenderState)(gfx_device, D3DRS_SPECULARENABLE, 0);
(*gfx_device->lpVtbl->SetRenderState)(gfx_device, D3DRS_CULLMODE, 1);
(*gfx_device->lpVtbl->SetTextureStageState)(gfx_device, 0, D3DTSS_COLORARG1,
2);
(*gfx_device->lpVtbl->SetTextureStageState)(gfx_device, 0, D3DTSS_COLORARG2,
0);
(*gfx_device->lpVtbl->SetTextureStageState)(gfx_device, 0, D3DTSS_COLOROP, 4);
(*gfx_device->lpVtbl->SetTextureStageState)(gfx_device, 0, D3DTSS_MINFILTER,
2);
(*gfx_device->lpVtbl->SetTextureStageState)(gfx_device, 0, D3DTSS_MAGFILTER,
2);
(*gfx_device->lpVtbl->SetTextureStageState)(gfx_device, 1, D3DTSS_MINFILTER,
2);
(*gfx_device->lpVtbl->SetTextureStageState)(gfx_device, 1, D3DTSS_MAGFILTER,
2);
FUN_00470b00();
(*gfx_device->lpVtbl->SetRenderState)(gfx_device, D3DRS_ALPHATESTENABLE, 0);
(*gfx_device->lpVtbl->SetRenderState)(gfx_device, D3DRS_ALPHAFUNC, 7);
(*gfx_device->lpVtbl->SetRenderState)(gfx_device, D3DRS_ALPHAREF, 0xc0);
(*gfx_device->lpVtbl->SetRenderState)(gfx_device, D3DRS_CLIPPING, 1);
(*gfx_device->lpVtbl->SetRenderState)(gfx_device, D3DRS_LIGHTING, 0);
DAT_007eafcc = 0x3f800000;
DAT_007eafc8 = 0x3f800000;
DAT_007eafc4 = 0x3f800000;
DAT_007eafc0 = 0x3f800000;
DAT_007eafdc = 0x3f800000;
DAT_007eafd8 = 0x3f800000;
DAT_007eafd4 = 0x3f800000;
DAT_007eafd0 = 0x3f800000;
DAT_007eaff8 = 0;
DAT_007eaff4 = 0;
DAT_007eaff0 = 0;
DAT_007eaffc = 0x3f800000;
DAT_007eb000 = 0;
(*gfx_device->lpVtbl->SetMaterial)(gfx_device, (D3DMATERIAL8 *)&DAT_007eafc0);
(*gfx_device->lpVtbl->SetRenderState)(gfx_device, D3DRS_FOGVERTEXMODE, 3);
if ((g_startOfGfxStruct.d3dSurface != (IDirect3DSurface8 *)0x0) ||
(HVar2 = (*gfx_device->lpVtbl->GetBackBuffer)(
gfx_device, 0, D3DBACKBUFFER_TYPE_MONO,
&g_startOfGfxStruct.d3dSurface),
HVar2 == 0)) {
(*gfx_device->lpVtbl->GetDisplayMode)(gfx_device, &DStack_54);
DStack_54.Height = 0;
DStack_54.Width = DStack_54.RefreshRate;
g_perfCounterRate = (float)DStack_54.RefreshRate;
FUN_00496ac0();
}
return 0;
}
}

View File

@@ -0,0 +1,209 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
#include <bink.h>
extern "C" {
undefined FUN_00401270(void); // 00401270 // FUN_00401270 // cdecl
undefined FUN_0047bb20(undefined4 param_1); // 0047bb20 // FUN_0047bb20 // cdecl
HANDLE r3_getDrawSemaphore(void); // 004013f0 // r3_getDrawSemaphore // cdecl
undefined FUN_0047bb10(void); // 0047bb10 // FUN_0047bb10 // cdecl
void r3_validateBinkVideoQuality(
byte videoBpp,
byte wantedVideoQuality); // 00442090 // r3_validateBinkVideoQuality //
// stdcall
BOOL GLD_bGetViewportAttributes(
short param_1, short combinedWindowHandle,
GLD_ViewportAttributes
*out); // 0046f240 // GLD_bGetViewportAttributes // cdecl
int IPT_fn_hGetEntryActionHandle(
const char *param_1); // 00506510 // IPT_fn_hGetEntryActionHandle // cdecl
undefined FUN_0046f680(undefined param_1,
undefined4 param_2); // 0046f680 // FUN_0046f680 // cdecl
undefined FUN_00441f30(void); // 00441f30 // FUN_00441f30 // cdecl
undefined FUN_00470f20(void); // 00470f20 // FUN_00470f20 // cdecl
undefined FUN_0047bfe0(undefined4 param_1); // 0047bfe0 // FUN_0047bfe0 // cdecl
undefined FUN_00485320(undefined4* outPtr, undefined4 param_2,
undefined4 param_3, undefined4 unused); // 00485320 // FUN_00485320 // cdecl
undefined SND_fn_vKillAllObjectSound(
void); // 0040a220 // SND_fn_vKillAllObjectSound // cdecl
undefined *getMoviePath(void); // 0055aa00 // getMoviePath // cdecl
undefined FUN_004420f0(undefined4 param_1); // 004420f0 // FUN_004420f0 // cdecl
undefined r3_binkLoop(void); // 004427a0 // r3_binkLoop // cdecl
undefined FUN_00485400(undefined4 param_1); // 00485400 // FUN_00485400 // cdecl
undefined FUN_004422c0(undefined4 param_1); // 004422c0 // FUN_004422c0 // cdecl
undefined FUN_00444810(void); // 00444810 // FUN_00444810 // cdecl
HBINK r3_binkOpen(char *movieFilename,
ulong flags); // 00442240 // r3_binkOpen // cdecl
void Erm_fn_v_UpdateLastError(
ushort uwStartOfWarningsId, byte ucModuleId, ulong ulChannelId,
ushort uwErrNum, long lDebugData, uchar ucOpenInfoWindow,
uchar ucStopForDebug,
char *szPersonalMsg); // 0043e410 // Erm_fn_v_UpdateLastError // stdcall
undefined FUN_0046f410(uint unused0,
uint unused1); // 0046f410 // FUN_0046f410 // cdecl
void r3_checkMovieDisc(
char *movieName); // 00445a10 // r3_checkMovieDisc // stdcall
undefined FUN_0046ed40(undefined param_1, undefined param_2,
undefined2 param_3); // 0046ed40 // FUN_0046ed40 // cdecl
uint32_t r3_doesMovieHaveSoundtrack(
char *param_1); // 00442130 // r3_doesMovieHaveSoundtrack // cdecl
// 00442330
/* WARNING: Inlined function: FUN_00485390 */
void r3_BNK_playMovie(char *param_1, char param_2, int param_3)
{
uint uVar1;
byte bVar2;
undefined *puVar3;
char *puVar4;
int haveSoundtrack;
longlong lVar5;
longlong lVar6;
float fVar5;
float extraout_ST0;
undefined4 uVar7;
char auStack_1b4[65];
undefined1 auStack_b0[64];
GLD_ViewportAttributes GStack_70;
bVar2 = BYTE_007a2c54;
g_currentBinkMovie.drawSemaphore = (HANDLE)r3_getDrawSemaphore();
DAT_007a2e01 = FUN_0047bb10();
g_StopVideoActionHandle = IPT_fn_hGetEntryActionHandle(s_StopVideo_005bd740);
uVar1 = (uint)bVar2;
DWORD_005bd62c = uVar1;
if (param_2 != '\0') {
SND_fn_vKillAllObjectSound();
}
r3_validateBinkVideoQuality(g_bink_videoBpp, g_bink_realVideoQuality);
haveSoundtrack = FUN_00444810();
BinkSetSoundTrack(haveSoundtrack + 1);
if (param_1 == 0) {
r3_checkMovieDisc(*(char **)(DAT_007a2c4c + 4 + uVar1 * 8));
uVar7 = *(undefined4 *)(DAT_007a2c4c + 4 + uVar1 * 8);
/* maybe, not initialized yet */
puVar3 = getMoviePath();
sprintf((char *)auStack_1b4, s_percent_s_path_2, puVar3, uVar7);
puVar4 = strlwr(auStack_1b4);
haveSoundtrack = r3_doesMovieHaveSoundtrack(puVar4);
if (haveSoundtrack == 0) {
/* BINKIOSIZE | BINKNOSKIP | BINKSNDTRACK */
uVar7 = 0x1084000;
} else {
/* BINKIOSIZE | BINKNOSKIP */
uVar7 = 0x1080000;
}
g_binkHandle = (HBINK)r3_binkOpen(auStack_1b4, uVar7);
if (g_binkHandle != (HBINK)0x0)
goto LAB_00442549;
uVar7 = *(undefined4 *)(DAT_007a2c4c + 4 + uVar1 * 8);
puVar3 = getMoviePath();
sprintf((char *)auStack_1b4, s_percent_s_path_3, 0x5d26a8, puVar3, uVar7);
puVar4 = strlwr((char *)*(uint **)(DAT_007a2c4c + 4 + uVar1 * 8));
haveSoundtrack = r3_doesMovieHaveSoundtrack(puVar4);
if (haveSoundtrack == 0) {
/* BINKNOSKIP | BINKSNDTRACK | BINKPRELOADALL */
uVar7 = 0x86000;
} else {
/* BINKNOSKIP | BINKPRELOADALL */
uVar7 = 0x82000;
}
} else {
/* Similar logic to above */
r3_checkMovieDisc((char *)param_1);
sprintf((char *)auStack_1b4, s_percent_s_path_2, s_Videos_005bd72c,
param_1);
puVar4 = strlwr(auStack_1b4);
haveSoundtrack = r3_doesMovieHaveSoundtrack(puVar4);
if (haveSoundtrack == 0) {
/* BINKIOSIZE | BINKNOSKIP | BINKSNDTRACK */
uVar7 = 0x1084000;
} else {
/* BINKIOSIZE | BINKNOSKIP */
uVar7 = 0x1080000;
}
g_binkHandle = (HBINK)r3_binkOpen(auStack_1b4, uVar7);
if ((g_binkHandle != (HBINK)0x0) ||
(g_currentBinkMovie.movieName[0] == '\0'))
goto LAB_00442549;
/* g_currentBinkMovie.movieName */
sprintf((char *)auStack_1b4, s_percent_s_path_3,
g_currentBinkMovie.movieName, s_Videos_005bd72c, param_1);
puVar4 = strlwr(param_1);
haveSoundtrack = r3_doesMovieHaveSoundtrack(puVar4);
if (haveSoundtrack == 0) {
uVar7 = 0x86000;
} else {
uVar7 = 0x82000;
}
}
g_binkHandle = (HBINK)r3_binkOpen(auStack_1b4, uVar7);
if (g_binkHandle == (HBINK)0x0) {
return;
}
LAB_00442549:
g_binkMovieEnded = 0;
DAT_007a2dbc = 0;
DAT_007a2dc0 = 0;
DAT_007a2da8 = 0;
DAT_007a2dac = 0;
DAT_007a2db0 = 0;
DAT_007a2db8 = 0;
DAT_007a2e14 = 1;
if (g_binkHandle == (HBINK)0x0) {
Erm_fn_v_UpdateLastError(6, g_BNK_moduleId, 0, 7, -1, 0xff, 0xff,
(char *)auStack_1b4);
} else {
DAT_007a2dd4 = g_binkHandle->Width;
FLOAT_007a2dd8 = (float)g_binkHandle->Height;
g_bink_videoBpp = FUN_00485320(&g_binkDestStorage, g_binkHandle->Width,
g_binkHandle->Height, 0);
haveSoundtrack = g_binkDestStorage;
if (g_binkDestStorage != 0) {
r3_validateBinkVideoQuality(g_bink_videoBpp, g_bink_realVideoQuality);
FUN_00485400(haveSoundtrack, 0);
FUN_004420f0(0);
uVar7 = FUN_00401270(0, 0);
FUN_0046f680(uVar7, 0);
FUN_0046ed40(0, 0, 1);
FUN_0046f410(0, 0xff);
FUN_0046ed40(0, 0, 1);
GLD_bGetViewportAttributes(0, 0, &GStack_70);
fVar5 = (float)DAT_007a2dd4 *
((float)GStack_70.dwWidth / (float)(DAT_007a2dd4 * 2));
extraout_ST0 = (float)(fVar5 + fVar5);
lVar5 = r3_ftol(extraout_ST0);
lVar6 = r3_ftol((float)((float)(uint)FLOAT_007a2dd8 * extraout_ST0));
DAT_007a2ddc = (GStack_70.dwHeight - (int)lVar6) >> 1;
DAT_007a2de0 = DAT_007a2ddc + (int)lVar6;
DAT_007a2de4 = (GStack_70.dwWidth - (int)lVar5) >> 1;
DAT_007a2de8 = DAT_007a2de4 + (int)lVar5;
BinkSetSoundOnOff(g_binkHandle, 1);
if (param_3 == -1) {
param_3 = DAT_007a2dd0;
}
BinkSetVolume(g_binkHandle, param_3);
FUN_0047bfe0(4);
FUN_00470f20();
r3_binkLoop();
g_binkDestStorage = 0;
BinkSetSoundOnOff(g_binkHandle, 0);
FUN_004422c0(g_binkHandle);
g_binkHandle = (HBINK)0x0;
FUN_00441f30();
FUN_0047bb20(4);
uVar7 = FUN_00401270(0, 0);
FUN_0046f680(uVar7);
FUN_0046ed40(0, 0, 3);
FUN_0046f410(0, 0xff);
FUN_0046ed40(0, 0, 3);
return;
}
}
return;
}
}

View File

@@ -0,0 +1,118 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
undefined r3_wait_for_dvd(char *param_1, char *param_2,
undefined4 param_3); // 0043e540 // r3_wait_for_dvd
// 004464f0
void r3_checkDisc(void)
{
char cVar1;
DWORD logicalDriveBits;
UINT UVar2;
int iVar3;
char *pcVar4;
char *pcVar5;
CHAR local_41c[256];
CHAR local_31c[264];
char local_214[260];
int local_110;
char local_10c[260];
int local_8;
logicalDriveBits = GetLogicalDrives();
g_driveLetter[0] = s_driveLetterTemplate[0];
g_driveLetter[1] = s_driveLetterTemplate[1];
g_driveLetter[2] = s_driveLetterTemplate[2];
g_driveLetter[3] = s_driveLetterTemplate[3];
local_110 = 0;
g_currentBinkMovie.movieName[0] = '\0';
#if RE_AUTHENTIC == 0
do {
do {
if (local_110 != 0) {
return;
}
for (local_8 = 0; local_8 < 0x20; local_8 = local_8 + 1) {
if ((logicalDriveBits & 1 << ((byte)local_8 & 0x1f)) != 0) {
g_driveLetter[0] = (byte)local_8 + 0x41;
UVar2 = GetDriveTypeA(g_driveLetter);
if (UVar2 == 5) {
GetVolumeInformationA(g_driveLetter, s_volumeNameBuffer, 0x80,
(LPDWORD)0x0, (LPDWORD)0x0, (LPDWORD)0x0,
(LPSTR)0x0, 0);
iVar3 = strcmpi(s_volumeNameBuffer, s_R3_DVD_005bdfd8);
if ((iVar3 == 0) ||
(iVar3 = strcmpi(s_volumeNameBuffer, s_R3_DVD_005be0ec),
iVar3 == 0)) {
sprintf(g_currentBinkMovie.movieName, s_fmt_c_colon_s,
local_8 + 0x41, s_r3_program_files);
local_110 = 1;
break;
}
}
}
}
} while (local_110 != 0);
GetWindowsDirectoryA(local_31c, 0x104);
iVar3 = -1;
pcVar4 = local_31c;
do {
pcVar5 = pcVar4;
if (iVar3 == 0)
break;
iVar3 = iVar3 + -1;
pcVar5 = pcVar4 + 1;
cVar1 = *pcVar4;
pcVar4 = pcVar5;
} while (cVar1 != '\0');
*(undefined4 *)(pcVar5 + -1) = s_UbiSoft_Ubi_ini + Field<0, 4>();
*(undefined4 *)(pcVar5 + 3) = s_UbiSoft_Ubi_ini + Field<4, 4>();
*(undefined4 *)(pcVar5 + 7) = s_UbiSoft_Ubi_ini + Field<8, 4>();
*(undefined4 *)(pcVar5 + 0xb) = s_UbiSoft_Ubi_ini + Field<12, 4>();
pcVar5[0xf] = s_UbiSoft_Ubi_ini[0x10];
GetPrivateProfileStringA(lpAppName_005b68f0, s_Language_005b6840,
s_English_005b684c, local_41c, 0xff, local_31c);
iVar3 = strcmpi(local_41c, s_French_005b6828);
if (iVar3 == 0) {
sprintf(local_10c, s_Veuillez_ins_rer_le_DVD_dans_vot_005be500);
sprintf(local_214, s_Impossible_de_trouver_le_DVD_____005be238,
s_windowTitle);
} else {
iVar3 = strcmpi(local_41c, s_Spanish_005b67a0);
if (iVar3 == 0) {
sprintf(local_10c, s_Introduce_el_DVD_de_Rayman_3_en_l_005be4c0);
sprintf(local_214, s_DVD_s_no_v_lido_005be1ec, s_windowTitle);
} else {
iVar3 = strcmpi(local_41c, s_Italian_005b6730);
if (iVar3 == 0) {
sprintf(local_10c, s_Inserisci_il_DVD_di_Rayman_3_nel_005be484);
sprintf(local_214, s_Impossibile_trovare_il_DVD____s_005be198,
s_windowTitle);
} else {
iVar3 = strcmpi(local_41c, s_German_005b66c4);
if (iVar3 == 0) {
sprintf(local_10c, s_Bitte_legen_Sie_DVD_von_Rayman_3_005be438);
sprintf(local_214, s_Die__s_DVDROM_kann_nicht_gelesen_005be130,
s_windowTitle);
} else {
sprintf(local_10c, s_Please_insert_the_DVD_in_the_DVD_005be400);
sprintf(local_214, s__s_DVD_missing_005be0f4, s_windowTitle);
}
}
}
}
iVar3 = r3_wait_for_dvd(local_10c, local_214, 5);
if (iVar3 == 2) {
/* WARNING: Subroutine does not return */
exit(-1);
}
} while (true);
#endif
}
}

View File

@@ -0,0 +1,28 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <r3/config/static.hpp>
#include <gh_global.h>
extern "C" {
// 00445f20
char *r3_getVignettePath(void)
{
char cVar1;
int iVar2;
char *pcVar3;
char *pcVar4;
char filename[256];
auto &config = getDefaultConfig();
strcpy(filename, config.gameRootDir.c_str());
strcat(filename, "/ubi.ini");
GetPrivateProfileStringA(lpAppName_005b68f0, s_VignettesFile_005be2dc,
(LPCSTR)&lpDefault_005cf96c,
(char *)&lpReturnedString_007d9aa0, 0xff, filename);
return (char *)&lpReturnedString_007d9aa0;
}
}

View File

@@ -0,0 +1,20 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
// 004464b0
char * r3_getVolumeInformation(void)
{
s_volumeNameBuffer[0] = (char)lpDefault_005cf96c;
GetVolumeInformationA
(g_driveLetter,s_volumeNameBuffer,0x80,(LPDWORD)0x0,(LPDWORD)0x0,(LPDWORD)0x0,(LPSTR)0x0
,0);
return s_volumeNameBuffer;
}
}

View File

@@ -0,0 +1,57 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
undefined r3_module1_init(void); // 0043e630 // r3_module1_init // cdecl
byte Erm_fn_ucInitErrMsg(void); // 0043e1d0 // Erm_fn_ucInitErrMsg // cdecl
undefined r3_module_big_init(void); // 00443f10 // r3_module_big_init // cdecl
void Mmg_fn_vFirstInitMmgModule(byte ucMaxNbChannel); // 0043f830 // Mmg_fn_vFirstInitMmgModule // cdecl
// 00401000
void __cdecl r3_initAllModules(void)
{
char cVar1;
size_t sVar2;
size_t sVar3;
uint uVar4;
char *pcVar5;
CHAR exePath [255];
char acStack_101 [257];
if (g_errModDInput == 0xff) {
g_errModDInput = Erm_fn_ucInitErrMsg();
}
if (g_errModMmg == 0xff) {
g_errModMmg = Erm_fn_ucInitErrMsg();
}
/* Init the memory manager */
Mmg_fn_vFirstInitMmgModule(10);
/* Set to exe path */
GetModuleFileNameA((HMODULE)0x0,exePath,0xff);
uVar4 = 0xffffffff;
pcVar5 = exePath;
do {
if (uVar4 == 0) break;
uVar4 = uVar4 - 1;
cVar1 = *pcVar5;
pcVar5 = pcVar5 + 1;
} while (cVar1 != '\0');
sVar2 = ~uVar4;
do {
sVar3 = sVar2;
sVar2 = sVar3 - 1;
if ((int)sVar2 < 0) break;
} while (exePath[sVar2] != '\\');
strncpy(acStack_101 + 1,exePath,sVar2);
acStack_101[sVar3] = '\0';
SetCurrentDirectoryA(acStack_101 + 1);
r3_module1_init();
r3_module_big_init();
return;
}
}

View File

@@ -1,24 +0,0 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
// 0045d2e0
void r3_initUnusedSM(void)
{
WORD_007d9e68 = 1;
/* 0x53 */
sz_S[0] = s_S_005bf008[0];
sz_S[1] = s_S_005bf008[1];
WORD_007d9e6c = 2;
/* 0x4d */
sz_M[0] = s_M_005bf004[0];
sz_M[1] = s_M_005bf004[1];
return;
}
}

View File

@@ -0,0 +1,66 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
undefined FUN_00447130(void); // 00447130 // FUN_00447130 // cdecl
void doGraphics(byte param_1); // 00447460 // doGraphics // cdecl
bool UNKr3_renderViewport(byte viewportIdx); // 00447200 // ?r3_renderViewport // cdecl
int get_one(void); // 0046f2c0 // get_one // cdecl
undefined FUN_00451530(undefined4 param_1); // 00451530 // FUN_00451530 // cdecl
undefined FUN_0048a920(undefined4 param_1); // 0048a920 // FUN_0048a920 // cdecl
void r3_setRendererState(void); // 0046fec0 // r3_setRendererState // cdecl
undefined FUN_0045fc70(undefined4 param_1); // 0045fc70 // FUN_0045fc70 // cdecl
// 00446fc0
/* WARNING: Inlined function: get_one */
void __cdecl r3_levelDisplayFn(byte param)
{
int iVar1;
int *piVar2;
char cVar3;
FUN_00447130();
WaitForSingleObject(g_stEngineStructure.drawSemaphore,0xffffffff);
if (((g_stEngineStructure + Field<1556, 4>() == 0) || (DAT_005d2b18 != 0)) || (param == 0)) {
if (DAT_005e693c != 0) {
ReleaseSemaphore(g_stEngineStructure.drawSemaphore,1,(LPLONG)0x0);
return;
}
FUN_0048a920(~-(uint)(DAT_007d98fc != '\0') &
g_stEngineStructure.stEngineTimer.ulUsefulDeltaTime);
FUN_00451530(param);
DAT_0063be24 = 1;
UNKr3_renderViewport(param);
doGraphics(param);
if (DAT_005d2b18 != 0) {
if (param == 0) {
param = 0;
for (piVar2 = (int *)(g_stEngineStructure + Field<1500, 4>()); piVar2 != (int *)0x0;
piVar2 = (int *)piVar2[1]) {
iVar1 = *(int *)(*(int *)(*piVar2 + 4) + 0x10);
cVar3 = FUN_0045fc70(*(undefined4 *)(iVar1 + 4));
if (cVar3 != '\0') {
param = param + 1;
}
if (param == DAT_005d2b18) {
FUN_0045fc70(*(undefined4 *)(iVar1 + 4));
}
}
}
if (DAT_005d2b18 != 0) {
r3_setRendererState();
}
}
/* WARNING: Could not inline here */
get_one();
ReleaseSemaphore(g_stEngineStructure.drawSemaphore,1,(LPLONG)0x0);
}
return;
}
}

View File

@@ -0,0 +1,60 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
void r3_beginLoadLevel(void); // 00447860 // r3_beginLoadLevel // cdecl
FIL_ConcatFile * FIL_fn_vOpenConcatFile(char * fileName); // 0055d890 // FIL_fn_vOpenConcatFile // cdecl
undefined r3_waitForDvd(const char * param_1, const char * param_2, undefined4 param_3); // 0043e540 // r3_waitForDvd // cdecl
void r3_unlockLoadLevelMutex(void); // 00447890 // r3_unlockLoadLevelMutex // cdecl
// 004fa4a0
void r3_loadVignette(char *param_1)
{
char cVar1;
int iVar2;
char *local_11c;
char *local_118;
char *local_10c;
char *local_108;
char local_104 [256];
r3_beginLoadLevel();
g_fileWrapper1 = FIL_fn_vOpenConcatFile(param_1);
if (g_fileWrapper1 == (FIL_ConcatFile *)0x0) {
local_108 = param_1;
local_10c = local_104;
do {
cVar1 = *local_108;
*local_10c = cVar1;
local_108 = local_108 + 1;
local_10c = local_10c + 1;
} while (cVar1 != '\0');
sprintf(param_1,s_percent_s_path_2,0x5d26a8,local_104);
g_fileWrapper1 = FIL_fn_vOpenConcatFile(param_1);
while (g_fileWrapper1 == (FIL_ConcatFile *)0x0) {
iVar2 = r3_waitForDvd(s_Please_insert_the_CD_005be980,s_Please_insert_the_CD_005be980,0x40035)
;
if (iVar2 == 2) {
/* WARNING: Subroutine does not return */
exit(-1);
}
g_fileWrapper1 = FIL_fn_vOpenConcatFile(param_1);
}
local_118 = local_104;
local_11c = param_1;
do {
cVar1 = *local_118;
*local_11c = cVar1;
local_118 = local_118 + 1;
local_11c = local_11c + 1;
} while (cVar1 != '\0');
}
r3_unlockLoadLevelMutex();
return;
}
}

View File

@@ -5,28 +5,27 @@
#include <r3/config/static.hpp>
extern "C" {
undefined FUN_00470db0(void); // 00470db0 // FUN_00470db0
undefined r3_checkDisc(void); // 004464f0 // r3_checkDisc
undefined FUN_00503710(void); // 00503710 // FUN_00503710
undefined r3_initAllModules(void); // 00401000 // r3_initAllModules
undefined FUN_00472150(void); // 00472150 // FUN_00472150
undefined r3_wait_for_dvd(char *param_1, char *param_2,
undefined4 param_3); // 0043e540 // r3_wait_for_dvd
int setupWindow(HINSTANCE instance, undefined4 param_2,
int windowedParam); // 00402140 // setupWindow
undefined FUN_00470db0(void); // 00470db0 // FUN_00470db0
undefined r3_checkDisc(void); // 004464f0 // r3_checkDisc
undefined FUN_00503710(void); // 00503710 // FUN_00503710
undefined r3_initAllModules(void); // 00401000 // r3_initAllModules
undefined FUN_00472150(void); // 00472150 // FUN_00472150
undefined r3_waitForDvd(char *param_1, char *param_2,
undefined4 param_3); // 0043e540 // r3_waitForDvd
undefined FUN_004725a0(void); // 004725a0 // FUN_004725a0
int r3_get_gli_width1(void); // 0047baf0 // r3_get_gli_width1
undefined gfx_init2(void); // 00470be0 // gfx_init2
void g_setInitVar0(void); // 00401310 // g_setInitVar0
int r3_get_gli_height1(void); // 0047bb00 // r3_get_gli_height1
undefined FUN_004010b0(void); // 004010b0 // FUN_004010b0
undefined FUN_00401320(void); // 00401320 // FUN_00401320
undefined r3_windowLockCursor(void); // 00401320 // r3_windowLockCursor
void r3_noop(void *p_cTxt1, void *p_cTxt2); // 00401100 // r3_noop
undefined r3_initEngine(void); // 00401220 // r3_initEngine
undefined FUN_005038e0(void); // 005038e0 // FUN_005038e0
undefined FUN_004fb300(void); // 004fb300 // FUN_004fb300
undefined spawnThread(void); // 004477d0 // spawnThread
undefined
r3_setupWindow(HINSTANCE hInstance, undefined4 param_2,
undefined4 maximizeWindow); // 00402140 // r3_setupWindow
undefined r3_engineLoop(void); // 00401220 // r3_engineLoop
// 00401630
int r3_main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR *cmdline,
@@ -34,6 +33,7 @@ int r3_main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR *cmdline,
{
undefined4 uVar1;
undefined2 uVar2;
undefined2 uVar3;
LPSTR pCVar3;
char *pcVar4;
@@ -44,68 +44,228 @@ int r3_main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR *cmdline,
HANDLE hTargetProcessHandle;
HANDLE hSourceHandle;
HANDLE hSourceProcessHandle;
LPSTR *ppCVar8;
uint32_t uVar9;
uint *ppCVar8;
HWND hWnd;
int iVar10;
int iVar11;
int iVar12;
int iVar13;
uint uVar14;
void *unaff_ESI;
undefined4 *puVar15;
void *unaff_EDI;
undefined4 *puVar16;
HKEY unaff_ESI;
char *pcVar17;
undefined4 uStack_83c;
HKEY pHStack_838;
HANDLE pvStack_834;
UINT UStack_830;
BYTE aBStack_82c[4];
DWORD DStack_828;
DWORD DStack_824;
tagRECT tStack_820;
char acStack_810[260];
CHAR languageStr[256];
CHAR pathToUbi_ini[260];
char acStack_508[260];
CHAR windowsDir[260];
char acStack_300[256];
char acStack_200[256];
char acStack_100[256];
void *p_cTxt1;
void *p_cTxt2;
undefined4 uStack_85c;
undefined4 uStack_858;
LPSTR lpBuffer;
UINT uiParam;
BYTE uStack_83c[4];
DWORD pHStack_838;
DWORD pvStack_834;
char UStack_830[16];
char tStack_820[260];
CHAR aCStack_71c[256];
char acStack_61c[16];
CHAR pathToUbi_ini[228];
char acStack_528[16];
char acStack_518[244];
char acStack_424[0x104];
char acStack_320[16];
char acStack_310[240];
char acStack_220[256];
char acStack_120[260];
HINSTANCE instance;
uint *puStack_14;
undefined4 uStack_10;
int iStack_8;
BOOL BVar18;
char cVar1;
undefined4 chars;
DWORD dwOptions;
tagRECT *lpRect;
HANDLE *lpTargetHandle;
undefined2 uVar2;
LPRECT lpRect;
LPHANDLE lpTargetHandle;
undefined4 uVar22;
#if RE_AUTHENTIC == 0
lpBuffer = pathToUbi_ini;
uiParam = 0x104;
/* Append windows dir / ubi.ini */
uStack_858 = 0x40164d;
GetWindowsDirectoryA(lpBuffer, 0x104);
iVar13 = -1;
pcVar4 = acStack_61c;
do {
pcVar17 = pcVar4;
if (iVar13 == 0)
break;
iVar13 = iVar13 + -1;
pcVar17 = pcVar4 + 1;
cVar1 = *pcVar4;
pcVar4 = pcVar17;
} while (cVar1 != '\0');
*(undefined4 *)(pcVar17 + -1) = s_UbiSoft_Ubi_ini + Field<0, 4>();
*(undefined4 *)(pcVar17 + 3) = s_UbiSoft_Ubi_ini + Field<4, 4>();
*(undefined4 *)(pcVar17 + 7) = s_UbiSoft_Ubi_ini + Field<8, 4>();
*(undefined4 *)(pcVar17 + 0xb) = s_UbiSoft_Ubi_ini + Field<12, 4>();
pcVar17[0xf] = s_UbiSoft_Ubi_ini[0x10];
pCVar3 = GetCommandLineA();
R3Config &gameConfig = getDefaultConfig();
// Store and change to game directory
chdir(gameConfig.gameRootDir.c_str());
strcpy(r3_main_data_005d28b6.gameDataDir, gameConfig.gameRootDir.c_str());
strcpy(languageStr, gameConfig.language.c_str());
pcVar4 = pCVar3 + 1;
iVar13 = -(int)pcVar4;
do {
cVar1 = *pcVar4;
pcVar4[(int)(tStack_820 + iVar13)] = cVar1;
pcVar4 = pcVar4 + 1;
} while (cVar1 != '\0');
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 { // We have the .exe path
pcVar4 = strrchr(tStack_820, 0x5c);
*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(lpAppName_005b68f0, s_Directory_005b68f8, s_None,
tStack_820, 0xff, acStack_61c);
iVar13 = strcmpi(tStack_820, s_None);
}
if (iVar13 != 0) {
chdir(tStack_820);
}
LAB_00401765:
/* strcpy */
iVar13 = 0;
do {
cVar1 = tStack_820[iVar13];
r3_main_data_005d28b6.gameDataDir[iVar13] = cVar1;
iVar13 = iVar13 + 1;
} while (cVar1 != '\0');
strlwr(r3_main_data_005d28b6.gameDataDir);
iVar13 = -1;
pcVar4 = r3_main_data_005d28b6.gameDataDir;
do {
if (iVar13 == 0)
break;
iVar13 = iVar13 + -1;
cVar1 = *pcVar4;
pcVar4 = pcVar4 + 1;
} while (cVar1 != '\0');
joined_r0x00401792:
if (iVar13 != -2) {
uVar14 = 0xffffffff;
pcVar4 = r3_main_data_005d28b6.gameDataDir;
do {
if (uVar14 == 0)
break;
uVar14 = uVar14 - 1;
cVar1 = *pcVar4;
pcVar4 = pcVar4 + 1;
} while (cVar1 != '\0');
if (r3_main_data_005d28b6.gameDataDir[~uVar14 - 2] != '\\')
goto LAB_004017ce;
uVar14 = 0xffffffff;
pcVar4 = r3_main_data_005d28b6.gameDataDir;
do {
if (uVar14 == 0)
break;
uVar14 = uVar14 - 1;
cVar1 = *pcVar4;
pcVar4 = pcVar4 + 1;
} while (cVar1 != '\0');
r3_main_data_005d28b6.gameDataDir[~uVar14 - 2] = '\0';
iVar13 = -1;
pcVar4 = r3_main_data_005d28b6.gameDataDir;
do {
if (iVar13 == 0)
break;
iVar13 = iVar13 + -1;
cVar1 = *pcVar4;
pcVar4 = pcVar4 + 1;
} while (cVar1 != '\0');
goto joined_r0x00401792;
}
LAB_004017ce:
pFVar5 = fopen(acStack_61c, fopen_mode_r_text);
GetPrivateProfileStringA(lpAppName_005b68f0, s_Adapter_005b68e4,
(LPCSTR)&lpDefault_005cf96c, acStack_310, 0xff,
acStack_61c);
if ((pFVar5 == (FILE *)0x0) || (acStack_310[0] == '\0')) {
/* Concat game data dir with r3 setup exe */
iVar13 = 0;
do {
cVar1 = r3_main_data_005d28b6.gameDataDir[iVar13];
acStack_518[iVar13] = cVar1;
iVar13 = iVar13 + 1;
} while (cVar1 != '\0');
iVar13 = -1;
pcVar4 = acStack_518;
do {
pcVar17 = pcVar4;
if (iVar13 == 0)
break;
iVar13 = iVar13 + -1;
pcVar17 = pcVar4 + 1;
cVar1 = *pcVar4;
pcVar4 = pcVar17;
} while (cVar1 != '\0');
*(undefined4 *)(pcVar17 + -1) =
s__R3_Setup_DX8_exe_005b68d0 + Field<0, 4>();
*(undefined4 *)(pcVar17 + 3) = s__R3_Setup_DX8_exe_005b68d0 + Field<4, 4>();
*(undefined4 *)(pcVar17 + 7) = s__R3_Setup_DX8_exe_005b68d0 + Field<8, 4>();
*(undefined4 *)(pcVar17 + 0xb) =
s__R3_Setup_DX8_exe_005b68d0 + Field<12, 4>();
*(undefined2 *)(pcVar17 + 0xf) =
s__R3_Setup_DX8_exe_005b68d0 + Field<16, 2>();
pFVar5 = fopen(acStack_518, fopen_mode_r_binary);
if (pFVar5 == (FILE *)0x0) {
MessageBoxA((HWND)0x0, s_Unable_to_find_R3_Setup_DX8_exe__005b6880,
s_Rayman_3_Error_005b68bc, 0x10);
return -1;
}
fclose(pFVar5);
spawnl(0, acStack_518, acStack_518, 0);
pFVar5 = fopen(acStack_61c, fopen_mode_r_text);
if (pFVar5 == (FILE *)0x0) {
return -1;
}
}
fclose(pFVar5);
/* Open reg key
HKEY_LOCAL_MACHINE\\SOFTWARE\\UBI SOFT\\RAYMAN 3 */
HKEY key;
LVar6 =
RegOpenKeyExA(HKEY_LOCAL_MACHINE, s_SOFTWARE_UBI_SOFT_RAYMAN_3_005b6864,
0, 0x20019, &key);
if (LVar6 == 0) {
LVar6 = RegQueryValueExA(key, s_CompleteInstall_005b6854, (LPDWORD)0x0,
&pvStack_834, uStack_83c, &pHStack_838);
DAT_007d9cc4 = (uint)(LVar6 == 0);
if (key != (HKEY)0x0) {
RegCloseKey(key);
}
} else {
DAT_007d9cc4 = 0;
}
GetPrivateProfileStringA(lpAppName_005b68f0, s_Language_005b6840,
s_English_005b684c, aCStack_71c, 0xff, acStack_61c);
sprintf(g_mutexName_Rayman3, s_percents, lpAppName_005b68f0);
sprintf(g_windowTitle, s_percents, s_windowTitle);
/* Setup localized quiting/restoring strings */
iVar13 = strcmpi(languageStr, s_French_005b6828);
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>();
puVar15 = (undefined4 *)s_ou_appuyez_sur_Echap_pour_quitte_005b67d0;
puVar16 = (undefined4 *)s_quitting1;
pcVar4 = s_ou_appuyez_sur_Echap_pour_quitte_005b67d0;
pcVar17 = s_quitting1;
for (iVar13 = 0xb; uVar22 = s_QUITTER + Field<4, 4>(), iVar13 != 0;
iVar13 = iVar13 + -1) {
*puVar16 = *puVar15;
puVar15 = puVar15 + 1;
puVar16 = puVar16 + 1;
*(undefined4 *)pcVar17 = *(undefined4 *)pcVar4;
pcVar4 = pcVar4 + 4;
pcVar17 = pcVar17 + 4;
}
s_wndStrQuiting[0] = s_QUITTER[0];
s_wndStrQuiting[1] = s_QUITTER[1];
@@ -121,30 +281,30 @@ int r3_main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR *cmdline,
s_wndStrQuiting[6] = s_QUITTER[6];
s_wndStrQuiting[7] = s_QUITTER[7];
s_QUITTER + Field<4, 4>() = uVar22;
sprintf(lpString_0077d2c0, s__s___Pause_005b67c4, s_windowTitle);
puVar15 = (undefined4 *)s_Restauration;
puVar16 = (undefined4 *)s_wndStrRestoring;
sprintf(g_windowTitle1, s__s___Pause_005b67c4, s_windowTitle);
pcVar4 = s_Restauration;
pcVar17 = s_wndStrRestoring;
for (iVar13 = 7; iVar13 != 0; iVar13 = iVar13 + -1) {
*puVar16 = *puVar15;
puVar15 = puVar15 + 1;
puVar16 = puVar16 + 1;
*(undefined4 *)pcVar17 = *(undefined4 *)pcVar4;
pcVar4 = pcVar4 + 4;
pcVar17 = pcVar17 + 4;
}
} else {
iVar13 = strcmpi(languageStr, s_Spanish_005b67a0);
iVar13 = strcmpi(aCStack_71c, s_Spanish_005b67a0);
if (iVar13 == 0) {
sprintf(s_windowTitleRestoring, s__s___Restablecer_datos____005b6784,
sprintf(g_windowTitleRestoring, s__s___Restablecer_datos____005b6784,
s_windowTitle);
uVar2 = s_SALIR_005b675c + Field<4, 2>();
puVar15 = (undefined4 *)s_Pulsa_ESC_para_salir_Rayman_3__005b6764;
puVar16 = (undefined4 *)s_quitting1;
pcVar4 = s_Pulsa_ESC_para_salir_Rayman_3__005b6764;
pcVar17 = s_quitting1;
for (iVar13 = 7; chars = s_SALIR_005b675c + Field<0, 4>(), iVar13 != 0;
iVar13 = iVar13 + -1) {
*puVar16 = *puVar15;
puVar15 = puVar15 + 1;
puVar16 = puVar16 + 1;
*(undefined4 *)pcVar17 = *(undefined4 *)pcVar4;
pcVar4 = pcVar4 + 4;
pcVar17 = pcVar17 + 4;
}
*(undefined2 *)puVar16 = *(undefined2 *)puVar15;
*(undefined *)((int)puVar16 + 2) = *(undefined *)((int)puVar15 + 2);
*(undefined2 *)pcVar17 = *(undefined2 *)pcVar4;
pcVar17[2] = pcVar4[2];
uVar3 = s_SALIR_005b675c + Field<4, 2>();
uVar22 = s_SALIR_005b675c + Field<0, 4>();
s_SALIR_005b675c[0] = (char)chars;
@@ -161,36 +321,42 @@ int r3_main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR *cmdline,
s_wndStrQuiting[5] = s_SALIR_005b675c[5];
s_SALIR_005b675c + Field<0, 4>() = uVar22;
s_SALIR_005b675c + Field<4, 2>() = uVar3;
sprintf(lpString_0077d2c0, s__s___Rotura_005b6750, s_windowTitle);
puVar15 = (undefined4 *)s_Restablecer_datos____005b6738;
puVar16 = (undefined4 *)s_wndStrRestoring;
sprintf(g_windowTitle1, s__s___Rotura_005b6750, s_windowTitle);
pcVar4 = s_Restablecer_datos____005b6738;
pcVar17 = s_wndStrRestoring;
for (iVar13 = 5; iVar13 != 0; iVar13 = iVar13 + -1) {
*puVar16 = *puVar15;
puVar15 = puVar15 + 1;
puVar16 = puVar16 + 1;
*(undefined4 *)pcVar17 = *(undefined4 *)pcVar4;
pcVar4 = pcVar4 + 4;
pcVar17 = pcVar17 + 4;
}
*(undefined *)puVar16 = *(undefined *)puVar15;
*pcVar17 = *pcVar4;
} else {
iVar13 = strcmpi(languageStr, s_Italian_005b6730);
iVar13 = strcmpi(aCStack_71c, s_Italian_005b6730);
if (iVar13 == 0) {
sprintf(s_windowTitleRestoring, s__s___Ripristino_dati____005b6718,
sprintf(g_windowTitleRestoring, s__s___Ripristino_dati____005b6718,
s_windowTitle);
uVar2 = s_USCIRE_005b66ec + Field<4, 2>();
puVar15 = (undefined4 *)s_Premi_ESC_per_uscire_da_Rayman_3_005b66f4;
puVar16 = (undefined4 *)s_quitting1;
pcVar4 = s_Premi_ESC_per_uscire_da_Rayman_3_005b66f4;
pcVar17 = s_quitting1;
for (iVar13 = 8; cVar1 = s_USCIRE_005b66ec[6], iVar13 != 0;
iVar13 = iVar13 + -1) {
*puVar16 = *puVar15;
puVar15 = puVar15 + 1;
puVar16 = puVar16 + 1;
*(undefined4 *)pcVar17 = *(undefined4 *)pcVar4;
pcVar4 = pcVar4 + 4;
pcVar17 = pcVar17 + 4;
}
s_wndStrQuiting[0] = s_USCIRE_005b66ec[0];
s_wndStrQuiting[1] = s_USCIRE_005b66ec[1];
s_wndStrQuiting[2] = s_USCIRE_005b66ec[2];
s_wndStrQuiting[3] = s_USCIRE_005b66ec[3];
*(undefined2 *)puVar16 = *(undefined2 *)puVar15;
s_wndStrQuiting + Field<4, 3>() = CONCAT12(cVar1, uVar2);
sprintf(lpString_0077d2c0, s__s___Pausa_005b66e0, s_windowTitle);
*(undefined2 *)pcVar17 = *(undefined2 *)pcVar4;
uVar3 = s_USCIRE_005b66ec + Field<4, 2>();
s_wndStrQuiting[6] = cVar1;
s_USCIRE_005b66ec[4] = (char)uVar2;
s_USCIRE_005b66ec[5] = SUB21(uVar2, 1);
s_wndStrQuiting[4] = s_USCIRE_005b66ec[4];
s_wndStrQuiting[5] = s_USCIRE_005b66ec[5];
s_USCIRE_005b66ec + Field<4, 2>() = uVar3;
sprintf(g_windowTitle1, s__s___Pausa_005b66e0, s_windowTitle);
s_wndStrRestoring[0] = s_Ripristino_dati____005b66cc[0];
s_wndStrRestoring[1] = s_Ripristino_dati____005b66cc[1];
s_wndStrRestoring[2] = s_Ripristino_dati____005b66cc[2];
@@ -209,21 +375,21 @@ int r3_main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR *cmdline,
s_Ripristino_dati____005b66cc + Field<16, 2>();
s_wndStrRestoring[0x12] = s_Ripristino_dati____005b66cc[0x12];
} else {
iVar13 = strcmpi(languageStr, s_German_005b66c4);
iVar13 = strcmpi(aCStack_71c, s_German_005b66c4);
if (iVar13 == 0) {
sprintf(s_windowTitleRestoring, s__s___Daten_Reparatur____005b66ac,
sprintf(g_windowTitleRestoring, s__s___Daten_Reparatur____005b66ac,
s_windowTitle);
chars = s_BEENDIGEN_005b6678 + Field<0, 4>();
puVar15 = (undefined4 *)&CHAR_E_005b6684;
puVar16 = (undefined4 *)s_quitting1;
pcVar4 = &CHAR_E_005b6684;
pcVar17 = s_quitting1;
for (iVar13 = 9; uVar2 = s_BEENDIGEN_005b6678 + Field<8, 2>(),
uVar22 = s_BEENDIGEN_005b6678 + Field<4, 4>(), iVar13 != 0;
iVar13 = iVar13 + -1) {
*puVar16 = *puVar15;
puVar15 = puVar15 + 1;
puVar16 = puVar16 + 1;
*(undefined4 *)pcVar17 = *(undefined4 *)pcVar4;
pcVar4 = pcVar4 + 4;
pcVar17 = pcVar17 + 4;
}
*(undefined2 *)puVar16 = *(undefined2 *)puVar15;
*(undefined2 *)pcVar17 = *(undefined2 *)pcVar4;
uVar1 = s_BEENDIGEN_005b6678 + Field<0, 4>();
s_BEENDIGEN_005b6678[0] = (char)chars;
s_BEENDIGEN_005b6678[1] = SUB41(chars, 1);
@@ -234,7 +400,7 @@ int r3_main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR *cmdline,
s_wndStrQuiting[2] = s_BEENDIGEN_005b6678[2];
s_wndStrQuiting[3] = s_BEENDIGEN_005b6678[3];
s_BEENDIGEN_005b6678 + Field<0, 4>() = uVar1;
*(undefined *)((int)puVar16 + 2) = *(undefined *)((int)puVar15 + 2);
pcVar17[2] = pcVar4[2];
uVar3 = s_BEENDIGEN_005b6678 + Field<8, 2>();
chars = s_BEENDIGEN_005b6678 + Field<4, 4>();
s_BEENDIGEN_005b6678[4] = (char)uVar22;
@@ -251,7 +417,7 @@ int r3_main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR *cmdline,
s_wndStrQuiting[9] = s_BEENDIGEN_005b6678[9];
s_BEENDIGEN_005b6678 + Field<4, 4>() = chars;
s_BEENDIGEN_005b6678 + Field<8, 2>() = uVar3;
sprintf(lpString_0077d2c0, s__s___Pause_005b67c4, s_windowTitle);
sprintf(g_windowTitle1, s__s___Pause_005b67c4, s_windowTitle);
s_wndStrRestoring[0] = s_Daten_Reparatur____005b6664[0];
s_wndStrRestoring[1] = s_Daten_Reparatur____005b6664[1];
s_wndStrRestoring[2] = s_Daten_Reparatur____005b6664[2];
@@ -272,19 +438,19 @@ int r3_main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR *cmdline,
s_wndStrRestoring[0x11] = s_Daten_Reparatur____005b6664[0x11];
s_wndStrRestoring[0x12] = s_Daten_Reparatur____005b6664[0x12];
} else {
sprintf(s_windowTitleRestoring, s__s___Restoring_data____005b664c,
sprintf(g_windowTitleRestoring, s__s___Restoring_data____005b664c,
s_windowTitle);
chars = s_QUIT + Field<0, 4>();
puVar15 = (undefined4 *)s_or_press_ESC_to_quit_Rayman_3__005b662c;
puVar16 = (undefined4 *)s_quitting1;
pcVar4 = s_or_press_ESC_to_quit_Rayman_3__005b662c;
pcVar17 = s_quitting1;
for (iVar13 = 7; cVar1 = s_QUIT[4], iVar13 != 0;
iVar13 = iVar13 + -1) {
*puVar16 = *puVar15;
puVar15 = puVar15 + 1;
puVar16 = puVar16 + 1;
*(undefined4 *)pcVar17 = *(undefined4 *)pcVar4;
pcVar4 = pcVar4 + 4;
pcVar17 = pcVar17 + 4;
}
*(undefined2 *)puVar16 = *(undefined2 *)puVar15;
*(undefined *)((int)puVar16 + 2) = *(undefined *)((int)puVar15 + 2);
*(undefined2 *)pcVar17 = *(undefined2 *)pcVar4;
pcVar17[2] = pcVar4[2];
uVar22 = s_QUIT + Field<0, 4>();
s_QUIT[0] = (char)chars;
s_QUIT[1] = SUB41(chars, 1);
@@ -296,7 +462,7 @@ int r3_main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR *cmdline,
s_wndStrQuiting[3] = s_QUIT[3];
s_wndStrQuiting[4] = cVar1;
s_QUIT + Field<0, 4>() = uVar22;
sprintf(lpString_0077d2c0, s__s___Pause_005b67c4, s_windowTitle);
sprintf(g_windowTitle1, s__s___Pause_005b67c4, s_windowTitle);
s_wndStrRestoring[0] = s_Restoring_data_____005b6610[0];
s_wndStrRestoring[1] = s_Restoring_data_____005b6610[1];
s_wndStrRestoring[2] = s_Restoring_data_____005b6610[2];
@@ -318,108 +484,179 @@ int r3_main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR *cmdline,
}
}
}
#else
auto &config = getDefaultConfig();
strcpy(g_windowTitle, "Reman3");
strcpy(g_windowTitle1, "Reman3 - Paused");
strcpy(g_windowTitleRestoring, "Restoring data");
strcpy(r3_main_data_005d28b6.gameDataDir, config.gameRootDir.c_str());
strlwr(r3_main_data_005d28b6.gameDataDir);
strcpy(g_mutexName_Rayman3, "Rayman3");
#endif
/* Create draw semaphore
Initial count = 1
Maximum count = 1 */
g_drawSemaphore =
CreateSemaphoreA((LPSECURITY_ATTRIBUTES)0x0, 1, 1, s_DRAWSEM_005b6608);
if (hPrevInstance != (HINSTANCE)0x0) {
return -1;
}
// FIXME: Not sure where this is set
/*if (iStack_8 != 0) {
return -1;
}*/
#if RE_AUTHENTIC == 0
/* Load DirectPlay probably unused */
// hLibModule = LoadLibraryA(s_dpnhpast_dll_005b65f8);
// if (hLibModule == (HMODULE)0x0) {
// iVar13 = strcmpi(languageStr, s_French_005b6828);
// if (iVar13 == 0) {
// MessageBoxA((HWND)0x0, lpText_005b6598, s_Erreur_Rayman_3_005b65e4,
// 0x10); return -1;
// }
// iVar13 = strcmpi(languageStr, s_Spanish_005b67a0);
// if (iVar13 == 0) {
// MessageBoxA((HWND)0x0, lpText_005b6540, s_Rayman_3_005b6588, 0x10);
// return -1;
// }
// iVar13 = strcmpi(languageStr, s_Italian_005b6730);
// if (iVar13 == 0) {
// MessageBoxA((HWND)0x0, lpText_005b64f0, s_Rayman_3_005b6588, 0x10);
// return -1;
// }
// iVar13 = strcmpi(languageStr, s_German_005b66c4);
// if (iVar13 != 0) {
// MessageBoxA((HWND)0x0, s_Check_your_version_of_DirectX__V_005b6430,
// s_Rayman_3_Error_005b68bc, 0x10);
// return -1;
// }
// MessageBoxA((HWND)0x0, lpText_005b6478, s_Rayman_3_005b6588, 0x10);
// return -1;
// }
// FreeLibrary(hLibModule);
/* For GLIMode
1 = maximize
0 = windowed */
g_runMaximized = (int)(acStack_200[0] != '0');
// r3_checkDisc();
dwOptions = 0;
BVar18 = 0;
lpTargetHandle = &pvStack_834;
DVar7 = 0x1f03ff;
g_hinstance = hInstance;
hTargetProcessHandle = GetCurrentProcess();
hSourceHandle = GetCurrentThread();
hSourceProcessHandle = GetCurrentProcess();
DuplicateHandle(hSourceProcessHandle, hSourceHandle, hTargetProcessHandle,
lpTargetHandle, DVar7, BVar18, dwOptions);
g_mainThreadHandle = pvStack_834;
/* Copy cmdline */
strcpy(g_appCmdLine, GetCommandLineA());
// SetErrorMode(1);
r3_initAllModules();
iVar13 = r3_setupWindow(hInstance, showCmd, g_runMaximized);
if (iVar13 == 0) {
hLibModule = LoadLibraryA(s_dpnhpast_dll_005b65f8);
if (hLibModule == (HMODULE)0x0) {
iVar13 = strcmpi(aCStack_71c, s_French_005b6828);
if (iVar13 == 0) {
MessageBoxA((HWND)0x0, lpText_005b6598, s_Erreur_Rayman_3_005b65e4, 0x10);
return -1;
}
iVar13 = strcmpi(aCStack_71c, s_Spanish_005b67a0);
if (iVar13 == 0) {
MessageBoxA((HWND)0x0, lpText_005b6540, s_Rayman_3_005b6588, 0x10);
return -1;
}
iVar13 = strcmpi(aCStack_71c, s_Italian_005b6730);
if (iVar13 == 0) {
MessageBoxA((HWND)0x0, lpText_005b64f0, s_Rayman_3_005b6588, 0x10);
return -1;
}
iVar13 = strcmpi(aCStack_71c, s_German_005b66c4);
if (iVar13 != 0) {
MessageBoxA((HWND)0x0, s_Check_your_version_of_DirectX__V_005b6430,
s_Rayman_3_Error_005b68bc, 0x10);
return -1;
}
MessageBoxA((HWND)0x0, lpText_005b6478, s_Rayman_3_005b6588, 0x10);
return -1;
}
g_setInitVar0();
FUN_00401320();
spawnThread();
gfx_init2();
lpRect = &tStack_820;
hWnd = GetDesktopWindow();
GetWindowRect(hWnd, lpRect);
BVar18 = 1;
iVar13 = r3_get_gli_height1();
iVar13 = iVar13 + 0x20;
iVar10 = r3_get_gli_width1();
iVar10 = iVar10 + 0xc;
iVar11 = r3_get_gli_height1();
iVar11 = (tStack_820.bottom - iVar11) / 2;
iVar12 = r3_get_gli_width1();
MoveWindow(g_gameHWND, (tStack_820.right - iVar12) / 2, iVar11, iVar10,
iVar13, BVar18);
FUN_004010b0();
SystemParametersInfoA(0x10, 0, &UStack_830, 0);
SystemParametersInfoA(0x11, 0, (PVOID)0x0, 0);
ShowCursor(0);
uStack_83c = 0;
SystemParametersInfoA(0x61, 1, &uStack_83c, 0);
g_engineRunning = 1;
r3_initEngine();
FUN_004725a0();
FUN_005038e0();
FUN_00503710();
FUN_004fb300();
FUN_00472150();
FUN_00470db0();
uStack_83c = 0;
SystemParametersInfoA(0x61, 0, &uStack_83c, 0);
ShowCursor(1);
SystemParametersInfoA(0x11, UStack_830, (PVOID)0x0, 0);
CloseHandle(pvStack_834);
return 0;
FreeLibrary(hLibModule);
#endif
p_cTxt1 = (void *)0x401e2a;
CreateMutexA((LPSECURITY_ATTRIBUTES)0x0, 1, g_mutexName_Rayman3);
DVar7 = GetLastError();
if (DVar7 == 0xb7) {
/* Mutex already exists */
return -1;
}
p_cTxt2 = (void *)0x401e5a;
#if RE_AUTHENTIC == 0
GetWindowsDirectoryA(acStack_424, 0x104);
iVar13 = -1;
/* Append ubi.ini */
pcVar4 = acStack_424;
do {
pcVar17 = pcVar4;
if (iVar13 == 0)
break;
iVar13 = iVar13 + -1;
pcVar17 = pcVar4 + 1;
cVar1 = *pcVar4;
pcVar4 = pcVar17;
} while (cVar1 != '\0');
*(undefined4 *)(pcVar17 + -1) = s_UbiSoft_Ubi_ini + Field<0, 4>();
*(undefined4 *)(pcVar17 + 3) = s_UbiSoft_Ubi_ini + Field<4, 4>();
*(undefined4 *)(pcVar17 + 7) = s_UbiSoft_Ubi_ini + Field<8, 4>();
*(undefined4 *)(pcVar17 + 0xb) = s_UbiSoft_Ubi_ini + Field<12, 4>();
pcVar17[0xf] = s_UbiSoft_Ubi_ini[0x10];
#else
strcpy(acStack_424, config.gameRootDir.c_str());
strcat(acStack_424, "/ubi.ini");
instance = hInstance;
#endif
/* Read graphics settings */
GetPrivateProfileStringA(lpAppName_005b68f0, s_Adapter_005b68e4,
(LPCSTR)&lpDefault_005cf96c, acStack_320, 0xff,
acStack_424);
GetPrivateProfileStringA(lpAppName_005b68f0, s_Identifier_005b6420,
(LPCSTR)&lpDefault_005cf96c, acStack_120, 0xff,
acStack_424);
GetPrivateProfileStringA(lpAppName_005b68f0, s_Gli_Mode_005b6414,
(LPCSTR)&lpDefault_005cf96c, acStack_220, 0xff,
acStack_424);
/* If they're all set */
if (((acStack_320[0] != '\0') && (acStack_120[0] != '\0')) &&
(acStack_220[0] != '\0')) {
/* For GLIMode
1 = maximize
0 = windowed */
g_runMaximized = (int)(acStack_220[0] != '0');
r3_checkDisc();
dwOptions = 0;
BVar18 = 0;
HANDLE duplicatedHandle;
DVar7 = 0x1f03ff;
g_hinstance = instance;
hTargetProcessHandle = GetCurrentProcess();
hSourceHandle = GetCurrentThread();
hSourceProcessHandle = GetCurrentProcess();
DuplicateHandle(hSourceProcessHandle, hSourceHandle, hTargetProcessHandle,
&duplicatedHandle, DVar7, BVar18, dwOptions);
/* Copy cmdline */
LPSTR cmdline = GetCommandLineA();
strncpy(g_appCmdLine, cmdline, std::size(g_appCmdLine));
/* SEM_FAILCRITICALERRORS */
SetErrorMode(1);
pcVar4 = strstr(cmdline, s_dashCC);
if (pcVar4 == (char *)0x0) {
r3_initAllModules();
iVar13 = setupWindow(instance, 0, g_runMaximized);
if (iVar13 == 0) {
return -1;
}
g_setInitVar0();
r3_windowLockCursor();
spawnThread();
r3_noop(p_cTxt1, p_cTxt2);
gfx_init2();
RECT rect;
hWnd = GetDesktopWindow();
GetWindowRect(hWnd, &rect);
BVar18 = 1;
iVar13 = r3_get_gli_height1();
iVar13 = iVar13 + 0x20;
iVar10 = r3_get_gli_width1();
iVar10 = iVar10 + 0xc;
iVar11 = r3_get_gli_height1();
iVar11 = (int)(rect.bottom - iVar11) / 2;
iVar12 = r3_get_gli_width1();
MoveWindow(g_gameHWND, 0, 0, iVar10,
iVar13, BVar18);
FUN_004010b0();
#if RE_AUTHENTIC == 0
DWORD screensaveActive;
SystemParametersInfoA(SPI_GETSCREENSAVEACTIVE, 0, &screensaveActive, 0);
SystemParametersInfoA(SPI_SETSCREENSAVEACTIVE, 0, (PVOID)0x0, 0);
ShowCursor(0);
uStack_85c = 0;
SystemParametersInfoA(0x61, 1, &uStack_85c, 0);
#endif
g_engineRunning = 1;
r3_engineLoop();
/* cleanup starts here */
FUN_004725a0();
FUN_005038e0();
FUN_00503710();
FUN_004fb300();
FUN_00472150();
FUN_00470db0();
#if RE_AUTHENTIC == 0
uStack_85c = 0;
SystemParametersInfoA(0x61, 0, &uStack_85c, 0);
ShowCursor(1);
SystemParametersInfoA(0x11, uiParam, (PVOID)0x0, 0);
#endif
CloseHandle(duplicatedHandle);
}
return 0;
}
sprintf(UStack_830, s_Please_run_the__s_setup__005b63f4, s_windowTitle);
sprintf(acStack_528, s__s_not_initialized__005b63e0, s_windowTitle);
r3_waitForDvd(UStack_830, acStack_528, 0);
/* WARNING: Subroutine does not return */
exit(-1);
}
}

View File

@@ -1,24 +0,0 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
void Erm_fn_v_UpdateLastError(ushort uwStartOfWarningsId, byte ucModuleId, ulong ulChannelId, ushort uwErrNum, long lDebugData, uchar ucOpenInfoWindow, uchar ucStopForDebug, char * szPersonalMsg); // 0043e410 // Erm_fn_v_UpdateLastError
byte Erm_fn_ucInitErrMsg(void); // 0043e1d0 // Erm_fn_ucInitErrMsg
// 00504ef0
void r3_module10_init(void)
{
/* 0x104ef0 95 IPT_fn_vFirstInitInput */
if (g_errMod10 == 0xff) {
g_errMod10 = Erm_fn_ucInitErrMsg();
return;
}
Erm_fn_v_UpdateLastError(3,g_errMod0,0,4,-1,0xff,0xff,(char *)0x0);
return;
}
}

View File

@@ -1,27 +0,0 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
// 00401100
/* Sometimes: Erm_fn_v_PrintErrMsg
Also used as noop function */
void r3_noop(void *p_cTxt1,void *p_cTxt2)
{
/* 0x1100 145 SND_PrintUsedStaticMemory
0x1100 205 SND_fn_vChangeVolumeSound
0x1100 210 SND_fn_vFadeOut
0x1100 215 SND_fn_vInitStereoSound
0x1100 230 SND_fn_vSetDopplerFactorSound
0x1100 231 SND_fn_vSetFadeOutTicks
0x1100 233 SND_fn_vSetMusicFadeOut
0x1100 237 SND_fn_vSetReverseStereoSound
0x1100 239 SND_fn_vSetStereoSound */
return;
}

View File

@@ -5,61 +5,102 @@
#include <r3/config/static.hpp>
extern "C" {
undefined r3_config_setIdentifier(
const char *param_1); // 00470570 // r3_config_setIdentifier
undefined
r3_config_setIdentifier(char *param_1); // 00470570 // r3_config_setIdentifier
void r3_set_GameDataPath(char *param_1); // 0055a8d0 // r3_set_GameDataPath
void r3_config_setTexturesMem(
const char *param_1); // 00470f30 // r3_config_setTexturesMem
char *param_1); // 00470f30 // r3_config_setTexturesMem
void r3_noop(void *p_cTxt1, void *p_cTxt2); // 00401100 // r3_noop
undefined
r3_read_game_config_udp_port(void); // 00446040 // r3_read_game_config_udp_port
undefined
r3_config_setGLIMode(const char *param_1); // 004704e0 // r3_config_setGLIMode
undefined r3_set_GameDataBinPath(
const char *param_1); // 0055a8d0 // r3_set_GameDataBinPath
r3_config_setGLIMode(char *param_1); // 004704e0 // r3_config_setGLIMode
undefined r3_read_game_config_modem_quality(
void); // 00445fc0 // r3_read_game_config_modem_quality
// 004460c0
void r3_read_gli_config(void) {
R3Config &config = getDefaultConfig();
r3_config_setGLIMode(config.gfxGliMode.c_str());
r3_config_setIdentifier(config.gfxIdentifier.c_str());
r3_config_setTexturesMem(config.gfxTexturesMem.c_str());
g_GLI_adapter = config.gfxAdapter;
r3_config_setIdentifier(config.gfxIdentifier.c_str());
g_config_tex_compressed = config.gfxTexturesCompressed;
g_GLI_tnl = config.gfxTnl;
g_GLI_trilinear = config.gfxTrilinear;
r3_config_setTexturesMem(config.gfxTexturesMem.c_str());
g_config_unused0 = 0;
g_config_camera_hor_axis = config.cameraHorizontalAxis;
g_config_camera_ver_axis = config.cameraVerticalAxis;
r3_set_GameDataBinPath(config.gameDataBinPath.c_str());
/* WARNING: Inlined function: r3_config_set_adapter */
/* WARNING: Inlined function: r3_config_setTexturesCompressed */
/* WARNING: Inlined function: r3_config_setTnl */
/* WARNING: Inlined function: r3_config_setTrilinearFiltering */
// GetPrivateProfileStringA
// (sectionName,s_SingleProcessor_005be308,&lpDefault_005be318,stringBuffer,0x104,local_204
// );
// /* Set single processor mode */
// iVar4 = strcmpi(stringBuffer,(char *)&s_Yes);
// if (iVar4 == 0) {
// sectionName[4] = '\x01';
// sectionName[5] = '\0';
// sectionName[6] = '\0';
// sectionName[7] = '\0';
// sectionName[0] = -0x1a;
// sectionName[1] = 'c';
// sectionName[2] = 'D';
// sectionName[3] = '\0';
// sectionName + Field<0, 4>() = GetCurrentProcess();
// SetProcessAffinityMask((HANDLE)sectionName + Field<0, 4>(),sectionName +
// Field<4, 4>());
// }
// sectionName[4] = -0xe;
// sectionName[5] = 'c';
// sectionName[6] = 'D';
// sectionName[7] = '\0';
// r3_read_game_config_modem_quality();
// r3_read_game_config_udp_port();
void r3_read_gli_config(void)
{
UINT tempOutVal;
void *pcVar2;
void *pcVar3;
HANDLE hProcess;
int iVar4;
char *pcVar1;
char *pcVar4;
void *in_stack_fffffce0;
char *ptr0;
char *ptr1;
char local_218[20];
char local_204[168];
char local_15c[32];
char stringBuffer[256];
char cVar1;
DWORD_PTR dwProcessAffinityMask;
const char *iniPath = getIniPath();
GetPrivateProfileStringA(lpAppName_005b68f0, s_GLI_Mode_005be3e0,
g_default_display_mode, stringBuffer, 0xff, iniPath);
r3_config_setGLIMode(stringBuffer);
g_GLI_adapter =
GetPrivateProfileIntA(lpAppName_005b68f0, s_Adapter_005b68e4, 0, iniPath);
/* set adapter */
GetPrivateProfileStringA(lpAppName_005b68f0, s_Identifier_005b6420,
(LPCSTR)&lpDefault_005cf96c, stringBuffer, 0xff,
iniPath);
r3_config_setIdentifier(stringBuffer);
tempOutVal = GetPrivateProfileIntA(lpAppName_005b68f0,
s_TexturesCompressed_005be3cc, 0, iniPath);
g_config_tex_compressed = (undefined1)tempOutVal;
tempOutVal =
GetPrivateProfileIntA(lpAppName_005b68f0, (LPCSTR)&s_Tnl, 0, iniPath);
g_GLI_tnl = (undefined1)tempOutVal;
tempOutVal = GetPrivateProfileIntA(lpAppName_005b68f0, s_TriLinear_005be3bc,
0, iniPath);
g_GLI_trilinear = (undefined1)tempOutVal;
pcVar2 = (void *)GetPrivateProfileIntA(lpAppName_005b68f0,
s_DynamicShadows_005be3ac, 0, iniPath);
pcVar3 = (void *)GetPrivateProfileIntA(lpAppName_005b68f0,
s_StaticShadows_005be39c, 0, iniPath);
//r3_noop(pcVar2, pcVar3);
pcVar2 = (void *)GetPrivateProfileIntA(lpAppName_005b68f0, s_Outline_005be394,
0, iniPath);
//r3_noop(pcVar2, in_stack_fffffce0);
GetPrivateProfileStringA(lpAppName_005b68f0, s_TexturesMem_005be384,
(LPCSTR)&s_Agp, stringBuffer, 0xff, iniPath);
r3_config_setTexturesMem(stringBuffer);
GetPrivateProfileStringA(lpAppName_005b68f0, s_SoundOnHD_005be374, "0",
stringBuffer, 0x104, iniPath);
sscanf(stringBuffer, s_percent_d, &g_soundOnHD);
GetPrivateProfileStringA(lpAppName_005b68f0, s_Complete_005be364, "1",
stringBuffer, 0x104, iniPath);
sscanf(stringBuffer, s_percent_d, &g_complete);
g_config_unused0 = 0;
g_config_camera_hor_axis = GetPrivateProfileIntA(
lpAppName_005b68f0, s_Camera_HorizontalAxis_005be34c, 2, iniPath);
g_config_camera_ver_axis = GetPrivateProfileIntA(
lpAppName_005b68f0, s_Camera_VerticalAxis_005be338, 5, iniPath);
GetPrivateProfileStringA(lpAppName_005b68f0, s_StartDirectory_005be31c,
s_Gamedata_005be32c, stringBuffer, 0x104, iniPath);
r3_set_GameDataPath(stringBuffer);
GetPrivateProfileStringA(lpAppName_005b68f0, s_SingleProcessor_005be308, "No",
stringBuffer, 0x104, iniPath);
/* Set single processor mode */
iVar4 = strcmpi(stringBuffer, (char *)&s_Yes);
if (iVar4 == 0) {
dwProcessAffinityMask = 1;
hProcess = GetCurrentProcess();
SetProcessAffinityMask(hProcess, dwProcessAffinityMask);
}
r3_read_game_config_modem_quality();
r3_read_game_config_udp_port();
return;
}
}

View File

@@ -0,0 +1,118 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
undefined FUN_00470350(void); // 00470350 // FUN_00470350 // cdecl
undefined r3_load_textures_2(void); // 00471760 // r3_load_textures_2 // cdecl
void r3_levelDisplayFn(byte param); // 00446fc0 // r3_levelDisplayFn // cdecl
void r3_noop(void * p_cTxt1, void * p_cTxt2); // 00401100 // r3_noop // cdecl
undefined r3_closeConcatTextureFile(void); // 004711d0 // r3_closeConcatTextureFile // cdecl
undefined FUN_00470db0(void); // 00470db0 // FUN_00470db0 // cdecl
undefined FUN_00503710(void); // 00503710 // FUN_00503710 // cdecl
undefined FUN_00443120(undefined4 param_1); // 00443120 // FUN_00443120 // cdecl
undefined FUN_00442c50(void); // 00442c50 // FUN_00442c50 // cdecl
undefined FUN_00470410(void); // 00470410 // FUN_00470410 // cdecl
undefined FUN_00472150(void); // 00472150 // FUN_00472150 // cdecl
undefined FUN_00445460(void); // 00445460 // FUN_00445460 // cdecl
undefined FUN_00442f70(undefined4 param_1); // 00442f70 // FUN_00442f70 // cdecl
undefined FUN_00445440(void); // 00445440 // FUN_00445440 // cdecl
undefined SND_fn_vResumeSound(void); // 0040a1e0 // SND_fn_vResumeSound // cdecl
undefined IPT_fn_vActivateAllEntryElements(void); // 00505490 // IPT_fn_vActivateAllEntryElements // cdecl
undefined r3_windowLockCursor(void); // 00401320 // r3_windowLockCursor // cdecl
undefined FUN_00402470(HWND param_1); // 00402470 // FUN_00402470 // cdecl
undefined gfx_init2(void); // 00470be0 // gfx_init2 // cdecl
undefined FUN_004725a0(void); // 004725a0 // FUN_004725a0 // cdecl
undefined FUN_0051a900(short hGLDDevice); // 0051a900 // FUN_0051a900 // cdecl
undefined FUN_005038e0(void); // 005038e0 // FUN_005038e0 // cdecl
undefined FUN_004fb300(void); // 004fb300 // FUN_004fb300 // cdecl
undefined FUN_004fa650(void); // 004fa650 // FUN_004fa650 // cdecl
undefined r3_processInput1(void); // 00446f10 // r3_processInput1 // cdecl
undefined FUN_0047bae0(void); // 0047bae0 // FUN_0047bae0 // cdecl
undefined FUN_0051a7a0(short hGLDDevice, undefined4 param_2); // 0051a7a0 // FUN_0051a7a0 // cdecl
// 00401490
/* WARNING: Inlined function: r3_get_engine_mode */
undefined4 r3_restore(undefined4 param_1)
{
HWND hWnd;
int iVar1;
DWORD DVar2;
hWnd = g_gameHWND;
if (g_engineRunning != 0) {
return 0;
}
if (g_gameHWND == (HWND)0x0) {
return 0;
}
SetWindowTextA(g_gameHWND,g_windowTitleRestoring);
UpdateWindow(hWnd);
SetForegroundWindow(hWnd);
if (p_fn_vDisplayAll == (void*)&r3_noop) {
/* Set window callback? */
p_fn_vDisplayAll = &r3_levelDisplayFn;
}
if (PTR_r3_processInput1_005bdb1c == (void*)&r3_noop) {
PTR_r3_processInput1_005bdb1c = r3_processInput1;
IPT_fn_vActivateAllEntryElements();
}
iVar1 = FUN_0047bae0();
if (iVar1 == 0) goto LAB_004015f7;
DVar2 = WaitForSingleObject(g_drawSemaphore,500);
if (DVar2 == 0x102) {
return 0;
}
FUN_004725a0();
if (g_currentBinkMovie + Field<32, 4>() == 0) {
FUN_00470410();
}
FUN_0051a900(g_stEngineStructure.hGLDDevice);
FUN_005038e0();
FUN_00503710();
FUN_004fb300();
FUN_00472150();
FUN_00470db0();
FUN_00445440();
gfx_init2();
FUN_00445460();
FUN_00402470(hWnd);
FUN_0051a7a0(g_stEngineStructure.hGLDDevice,0);
if (g_currentBinkMovie + Field<32, 4>() == 0) {
FUN_00442f70(0);
FUN_00443120(0);
FUN_00442f70(1);
FUN_00443120(1);
FUN_00470350();
if (g_currentBinkMovie + Field<32, 4>() != 0) goto LAB_004015bc;
}
else {
LAB_004015bc:
FUN_00445440();
}
r3_load_textures_2();
if (((g_stEngineStructure.eEngineMode == E_EM_ModeStartingProgram) ||
(g_stEngineStructure.eEngineMode == E_EM_ModeEnterGame)) ||
(g_stEngineStructure.eEngineMode == E_EM_ModeEnterLevel)) {
FUN_004fa650();
}
r3_closeConcatTextureFile();
ReleaseSemaphore(g_drawSemaphore,1,(LPLONG)0x0);
LAB_004015f7:
g_stEngineStructure + Field<91, 1>() = 0;
SetWindowTextA(hWnd,g_windowTitle);
UpdateWindow(hWnd);
SetForegroundWindow(hWnd);
FUN_00442c50();
SND_fn_vResumeSound();
r3_windowLockCursor();
/* Keep suspended
*/
return 0;
}
}

View File

@@ -1,155 +0,0 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
undefined4 get_one(void); // 00485bd0 // get_one
void set_unk(HWND wnd); // 0043e620 // set_unk
int r3_get_gli_width0(void); // 004012c0 // r3_get_gli_width0
int r3_get_gli_height0(void); // 004012d0 // r3_get_gli_height0
undefined4 FUN_0046ed70(char * param_1, short * param_2); // 0046ed70 // FUN_0046ed70
undefined FUN_0046f640(undefined param_1, short param_2, undefined4 * param_3); // 0046f640 // FUN_0046f640
void FUN_0047c150(short param_1, short param_2, int param_3); // 0047c150 // FUN_0047c150
long r3_windowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // 004025e0 // r3_windowProc
int r3_get_gli_width1(void); // 0047baf0 // r3_get_gli_width1
void r3_load_splash_bitmap(HWND unused); // 00402450 // r3_load_splash_bitmap
int r3_get_gli_height1(void); // 0047bb00 // r3_get_gli_height1
undefined4 FUN_0046f0b0(short param_1, undefined4 * param_2, short * param_3); // 0046f0b0 // FUN_0046f0b0
void r3_set_window_wh(undefined4 param_1, undefined4 param_2); // 004012a0 // r3_set_window_wh
// 00402140
undefined4 r3_setupWindow(HINSTANCE hInstance,undefined4 param_2,int maximizeWindow)
{
ATOM AVar1;
int iVar2;
HWND hWnd;
HWND pHVar3;
bool bVar4;
char acStack_e0 [28];
int iStack_c4;
int iStack_c0;
undefined4 uStack_bc;
HWND pHStack_b8;
HWND pHStack_b4;
undefined4 uStack_b0;
undefined4 uStack_ac;
undefined4 auStack_80 [5];
undefined4 uStack_6c;
DWORD dwStyle;
int iVar5;
int iVar6;
undefined local_28 [28];
HBRUSH pHStack_c;
LPCSTR pCStack_8;
char *pcStack_4;
INT_0077d0a4 = 1;
/* WindowClassA (overlaps usage below) */
local_28 + Field<0, 4>() = 0x3003;
local_28 + Field<4, 4>() = r3_windowProc;
local_28 + Field<8, 4>() = 0;
local_28 + Field<12, 4>() = 0;
local_28 + Field<16, 4>() = hInstance;
local_28 + Field<20, 4>() = LoadIconA(hInstance,(LPCSTR)0x65);
local_28 + Field<24, 4>() = LoadCursorA((HINSTANCE)0x0,(LPCSTR)0x7f00);
pHStack_c = (HBRUSH)0x6;
pCStack_8 = (LPCSTR)0x0;
pcStack_4 = g_windowTitle;
AVar1 = RegisterClassA((WNDCLASSA *)local_28);
if (AVar1 != 0) {
bVar4 = maximizeWindow == 0;
if (bVar4) {
iVar5 = GetSystemMetrics(0x20);
iVar5 = iVar5 * 2 + 0x140;
iVar6 = GetSystemMetrics(0x21);
iVar2 = GetSystemMetrics(4);
iVar6 = iVar2 + 0xf0 + iVar6 * 2;
dwStyle = 0x90cf0000;
}
else {
iVar6 = 0xf0;
iVar5 = 0x140;
dwStyle = 0x91000000;
}
uStack_6c = 0x40221d;
hWnd = CreateWindowExA(0,g_windowTitle,g_windowTitle,dwStyle,(uint)bVar4,(uint)bVar4,iVar5,iVar6
,(HWND)0x0,(HMENU)0x0,hInstance,(LPVOID)0x0);
g_gameHWND1 = hWnd;
if (hWnd != (HWND)0x0) {
g_gameHWND = hWnd;
SetWindowTextA(hWnd,s_windowTitle);
if (maximizeWindow == 0) {
/* SW_NORMAL */
iVar5 = 1;
}
else {
/* SW_MAXIMIZE */
iVar5 = 3;
}
ShowWindow(hWnd,iVar5);
SetWindowPos(hWnd,(HWND)0x0,0,0,0,0,0x43);
EnableWindow(hWnd,1);
SetFocus(hWnd);
UpdateWindow(hWnd);
SetForegroundWindow(hWnd);
pHVar3 = GetFocus();
while (pHVar3 != hWnd) {
SetWindowPos(hWnd,(HWND)0x0,0,0,0,0,0x43);
EnableWindow(hWnd,1);
SetFocus(hWnd);
UpdateWindow(hWnd);
SetForegroundWindow(hWnd);
pHVar3 = GetFocus();
}
set_unk(hWnd);
r3_load_splash_bitmap(hWnd);
INT_0077d0a4 = 1;
iVar5 = get_one();
/* always taken */
if (iVar5 != 0) {
iVar5 = get_one();
/* never taken */
if (iVar5 == 0) {
/* WARNING: Subroutine does not return */
exit(-1);
}
iVar5 = r3_get_gli_height1();
iVar6 = r3_get_gli_width1();
r3_set_window_wh(iVar6,iVar5);
GetClientRect(g_gameHWND,(LPRECT)(local_28 + 0x18));
uStack_b0 = 1;
iStack_c4 = r3_get_gli_width0();
iStack_c0 = r3_get_gli_height0();
uStack_bc = 0x10;
pHStack_b8 = g_gameHWND;
pHStack_b4 = g_gameHWND;
uStack_ac = 10;
iVar5 = FUN_0046ed70(acStack_e0,(short *)&WORD_0077d4d4);
if (iVar5 != 0) {
local_28 + Field<0, 4>() = 0;
local_28 + Field<4, 4>() = (WNDPROC)0x0;
iVar5 = FUN_0046f0b0(WORD_0077d4d4,auStack_80,(short *)&WORD_0077d4d6);
if ((iVar5 != 0) &&
(iVar5 = FUN_0046f640((char)WORD_0077d4d4,WORD_0077d4d6,&DWORD_0077d4d8), iVar5 != 0))
{
if (DWORD_0077d4d8 != 0) {
FUN_0047c150(WORD_0077d4d4,WORD_0077d4d6,DWORD_0077d4d8);
}
return 1;
}
}
/* Failed */
return 0;
}
/* WARNING: Subroutine does not return */
exit(-1);
}
}
/* Failed */
return 0;
}
}

View File

@@ -1,29 +0,0 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
// 00442090
void r3_validateBinkVideoQuality(byte videoBpp, byte wantedVideoQuality)
{
byte bVar1;
bVar1 = wantedVideoQuality;
if (4 < wantedVideoQuality) {
bVar1 = 4;
}
g_bink_realVideoQuality = g_bink_wantedVideoQuality;
if ((g_bink_wantedVideoQuality <= bVar1) &&
(g_bink_realVideoQuality = 4, wantedVideoQuality < 5)) {
g_bink_realVideoQuality = wantedVideoQuality;
}
wantedVideoQuality = (uint)g_bink_realVideoQuality;
g_bink_videoBpp = videoBpp;
g_bink_wantedVideoQualityPlus1 = wantedVideoQuality + 1;
DAT_007a2e0c = -(uint)(wantedVideoQuality != 0) & 0x80000000;
return;
}
}

View File

@@ -0,0 +1,41 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
undefined r3_setRendererState1(undefined4 param_1, undefined4 param_2, undefined4 param_3); // 0046fe20 // r3_setRendererState1 // cdecl
undefined FUN_0043e4f0(void); // 0043e4f0 // FUN_0043e4f0 // cdecl
undefined r3_gfxFrameUNK(void); // 0046fed0 // r3_gfxFrame? // cdecl
undefined FUN_00441d70(undefined4 param_1, undefined4 param_2, undefined4 param_3, undefined4 param_4, undefined4 param_5); // 00441d70 // FUN_00441d70 // cdecl
void IPT_fn_vReadInput(void); // 00505fe0 // IPT_fn_vReadInput // cdecl
// 0043e540
int __cdecl r3_waitForDvd(const char *param_1,const char *param_2,uint param_3)
{
ushort uVar1;
int iVar2;
char local_64 [100];
r3_setRendererState1(1,1,0);
iVar2 = FUN_00441d70((undefined4)param_1,0x42c80000,0x43480000,0,0xffffffff);
if (iVar2 == 0) {
iVar2 = MessageBoxA(g_gameHWND1,param_1,param_2,param_3 | 0x10000);
return iVar2;
}
if ((param_3 & 5) != 0) {
FUN_00441d70((undefined4)s_quitting1,0x42c80000,0x438c0000,0,0xffffffff);
FUN_0043e4f0();
sprintf(local_64,s__jc_z_d__s_005bd460,DAT_005bd454,s_wndStrQuiting);
FUN_00441d70((undefined4)local_64,0x43340000,0x43b40000,0,0xffffffff);
r3_gfxFrameUNK();
IPT_fn_vReadInput();
uVar1 = GetAsyncKeyState(0x1b);
return ((uVar1 & 0x8000) != 0) + 1;
}
return 1;
}
}

View File

@@ -0,0 +1,37 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
HWND getHWND(void); // 00401300 // getHWND // cdecl
// 00401320
void __cdecl r3_windowLockCursor(void)
{
HWND pHVar1;
tagRECT *ptVar2;
RECT RStack_30;
tagRECT local_20;
tagRECT tStack_10;
if (g_initVar0 != '\0') {
ptVar2 = &local_20;
pHVar1 = getHWND();
GetWindowRect(pHVar1,ptVar2);
ptVar2 = &tStack_10;
pHVar1 = getHWND();
GetClientRect(pHVar1,ptVar2);
RStack_30.left = local_20.left + 5;
RStack_30.top = local_20.bottom - tStack_10.bottom;
RStack_30.right = tStack_10.right + -5 + RStack_30.left;
RStack_30.bottom = RStack_30.top + -5 + tStack_10.bottom;
// ClipCursor(&RStack_30);
// ShowCursor(0);
}
return;
}
}

View File

@@ -4,11 +4,11 @@
#include <gh_global.h>
extern "C" {
undefined FUN_004013a0(void); // 004013a0 // FUN_004013a0
undefined FUN_00401320(void); // 00401320 // FUN_00401320
undefined r3_windowLockCursor(void); // 00401320 // r3_windowLockCursor // cdecl
undefined r3_windowUnlockCursor(void); // 004013a0 // r3_windowUnlockCursor // cdecl
// 004025e0
long r3_windowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
long __stdcall r3_windowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
long lVar1;
@@ -16,14 +16,14 @@ long r3_windowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
if (uMsg < WM_SETCURSOR + 1) {
if (uMsg == WM_SETCURSOR) {
if (((g_engineShouldRun != 0) && (g_engineRunning != 0)) && (g_runMaximized != 0)) {
FUN_00401320();
r3_windowLockCursor();
return 1;
}
}
else {
if (uMsg == WM_CLOSE) {
FUN_004013a0();
DAT_0077d0b8 = 1;
r3_windowUnlockCursor();
g_windowCloseRequested = 1;
if (g_drawSemaphore != (HANDLE)0x0) {
CloseHandle(g_drawSemaphore);
}

View File

@@ -0,0 +1,23 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
// 004013a0
void r3_windowUnlockCursor(void)
{
HCURSOR hCursor;
/* IDC_ARROW */
hCursor = LoadCursorA((HINSTANCE)0x0,(LPCSTR)0x7f00);
SetCursor(hCursor);
ClipCursor((RECT *)0x0);
ShowCursor(1);
return;
}
}

View File

@@ -0,0 +1,105 @@
// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!!
#include <r3/binders/auto.h>
#include <gh_global.h>
extern "C" {
long CALLBACK r3_windowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // 004025e0 // r3_windowProc
undefined fn_bCreateMainDisplayScreen(void); // 004022f0 // fn_bCreateMainDisplayScreen
void loadSplashBitmap(HWND unused); // 00402450 // loadSplashBitmap
void setGameHWND3(HWND wnd); // 0043e620 // setGameHWND3
// 00402140
int setupWindow(HINSTANCE instance,undefined4 param_2,int windowedParam)
{
ATOM AVar1;
int windowHeight;
int yCaption;
HWND hWnd;
HWND pHVar2;
int r0;
BOOL success;
bool windowed;
GLD_DeviceAttributes *windowParams;
DWORD dwStyle;
WNDCLASSA wndClass;
int showWindow;
int windowWidth;
g_windowInitialized = 1;
/* WindowClassA (overlaps usage below) */
wndClass.style = 0x3003;
wndClass.lpfnWndProc = r3_windowProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = instance;
wndClass.hIcon = LoadIconA(instance,(LPCSTR)0x65);
wndClass.hCursor = LoadCursorA((HINSTANCE)0x0,(LPCSTR)0x7f00);
wndClass.hbrBackground = (HBRUSH)COLOR_WINDOWFRAME;
wndClass.lpszMenuName = (LPCSTR)0x0;
wndClass.lpszClassName = g_windowTitle;
AVar1 = RegisterClassA(&wndClass);
if (AVar1 != 0) {
windowed = windowedParam == 0;
if (windowed) {
/* SM_CXSIZEFRAME */
windowWidth = GetSystemMetrics(32);
/* x*2 + 320 */
windowWidth = windowWidth * 2 + 320;
/* SM_CYSIZEFRAME, retrieves the size of the vertical resizing border */
windowHeight = GetSystemMetrics(33);
/* SM_CYCAPTION, The height of a caption area, in pixels */
yCaption = GetSystemMetrics(4);
/* ebp still 0 at this point */
windowHeight = yCaption + 240 + windowHeight * 2;
dwStyle = 0x90cf0000;
}
else {
windowHeight = 0xf0;
windowWidth = 0x140;
dwStyle = 0x91000000;
}
hWnd = CreateWindowExA(0,g_windowTitle,g_windowTitle,dwStyle,(uint)windowed,(uint)windowed,
windowWidth,windowHeight,(HWND)0x0,(HMENU)0x0,instance,(LPVOID)0x0);
g_gameHWND1 = hWnd;
if (hWnd != (HWND)0x0) {
g_gameHWND = hWnd;
SetWindowTextA(hWnd,s_windowTitle);
if (windowedParam == 0) {
/* SW_NORMAL */
showWindow = 1;
}
else {
/* SW_MAXIMIZE */
showWindow = 3;
}
ShowWindow(hWnd,showWindow);
SetWindowPos(hWnd,(HWND)0x0,0,0,0,0,0x43);
EnableWindow(hWnd,1);
SetFocus(hWnd);
UpdateWindow(hWnd);
SetForegroundWindow(hWnd);
pHVar2 = GetFocus();
while (pHVar2 != hWnd) {
SetWindowPos(hWnd,(HWND)0x0,0,0,0,0,0x43);
EnableWindow(hWnd,1);
SetFocus(hWnd);
UpdateWindow(hWnd);
SetForegroundWindow(hWnd);
pHVar2 = GetFocus();
}
setGameHWND3(hWnd);
loadSplashBitmap(hWnd);
/* unused? */
g_windowInitialized = 1;
r0 = fn_bCreateMainDisplayScreen();
return r0;
}
}
/* Failed */
return 0;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -3,12 +3,11 @@
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
#include <stdexcept>
// 00401320
// FUN_00401320
extern "C" undefined FUN_00401320(void) {
// TODO: Implement this function
throw GHStubException("Function not implemented: FUN_00401320");
// 0043e1d0
// Erm_fn_ucInitErrMsg
extern "C" byte Erm_fn_ucInitErrMsg(void) {
return gh_stub_impl_cdecl<(stub_t)0x0043e1d0, byte>();
}

View File

@@ -0,0 +1,13 @@
// AUTO-GENERATED FILE!!!!
// This function has yet to be decompiled using 'Dump Current Function' in ghidra
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
// 0043e410
// Erm_fn_v_UpdateLastError
extern "C" void Erm_fn_v_UpdateLastError(ushort uwStartOfWarningsId, byte ucModuleId, ulong ulChannelId, ushort uwErrNum, long lDebugData, uchar ucOpenInfoWindow, uchar ucStopForDebug, char * szPersonalMsg) {
gh_stub_impl_stdcall<(stub_t)0x0043e410, void>(uwStartOfWarningsId, ucModuleId, ulChannelId, uwErrNum, lDebugData, ucOpenInfoWindow, ucStopForDebug, szPersonalMsg);
}

View File

@@ -0,0 +1,13 @@
// AUTO-GENERATED FILE!!!!
// This function has yet to be decompiled using 'Dump Current Function' in ghidra
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
// 0055d890
// FIL_fn_vOpenConcatFile
extern "C" FIL_ConcatFile * FIL_fn_vOpenConcatFile(char * fileName) {
return gh_stub_impl_cdecl<(stub_t)0x0055d890, FIL_ConcatFile *>(fileName);
}

View File

@@ -3,12 +3,11 @@
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
#include <stdexcept>
// 004010b0
// FUN_004010b0
extern "C" undefined FUN_004010b0(void) {
// TODO: Implement this function
throw GHStubException("Function not implemented: FUN_004010b0");
return gh_stub_impl_cdecl<(stub_t)0x004010b0, undefined>();
}

View File

@@ -3,12 +3,11 @@
// with possible manualy fixes
#include <r3/binders/auto.h>
#include <r3/binders/stub.h>
#include <gh_global.h>
#include <stdexcept>
// 004464f0
// r3_checkDisc
extern "C" undefined r3_checkDisc(void) {
// TODO: Implement this function
throw GHStubException("Function not implemented: r3_checkDisc");
// 00401270
// FUN_00401270
extern "C" undefined FUN_00401270(void) {
return gh_stub_impl_cdecl<(stub_t)0x00401270, undefined>();
}

Some files were not shown because too many files have changed in this diff Show More