DLLHack wip

This commit is contained in:
Guus Waals 2025-05-30 15:03:10 +08:00
parent 1e91d93470
commit 532c1653c0
5 changed files with 50 additions and 28 deletions

View File

@ -82,10 +82,11 @@ function(setup_target TARGET DBG_MODE)
target_link_options(${TARGET} PRIVATE target_link_options(${TARGET} PRIVATE
-Wl,/BASE:0x20000000 -Wl,/BASE:0x20000000
-Wl,/DYNAMICBASE:NO -Wl,/DYNAMICBASE:NO
-Wl,/SECTION:.reserved,RW,0x400000
) )
target_link_directories(${TARGET} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/dllhack)
target_link_libraries(${TARGET} PRIVATE target_link_libraries(${TARGET} PRIVATE
DbgHelp DbgHelp
Rayman3
) )
else() else()

View File

@ -0,0 +1,3 @@
LIBRARY Rayman3
EXPORTS
CDAPFN0506_CDAPFN0506_X_IPT_fn_vResetInputEntry @1

BIN
game_re/dllhack/Rayman3.lib Normal file

Binary file not shown.

View File

@ -7,31 +7,44 @@
static uintptr_t g_gh_translationOffset{}; static uintptr_t g_gh_translationOffset{};
extern "C" {
cdecl void CDAPFN0506_CDAPFN0506_X_IPT_fn_vResetInputEntry();
}
struct R3Bin { struct R3Bin {
R3Bin() { loadOriginal(); } R3Bin() { loadOriginal(); }
void loadOriginal() { void loadOriginal() {
void* ptr = (void*)&CDAPFN0506_CDAPFN0506_X_IPT_fn_vResetInputEntry;
SPDLOG_DEBUG("Loading original binary"); SPDLOG_DEBUG("Loading original binary");
auto &config = getDefaultConfig(); auto &config = getDefaultConfig();
std::string path = config.gameRootDir + "/Rayman3.exe"; std::string path = config.gameRootDir + "/Rayman3.exe";
// Reserve 4MB at the original base address module = LoadLibraryA(path.c_str());
module = (HINSTANCE)VirtualAlloc((LPVOID)GH_BASE_ADDR, 4 * 1024 * 1024, MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (!module)
if (!module) { throw std::runtime_error("Failed to load original binary");
// Get the error code
DWORD error = GetLastError();
throw std::runtime_error("Failed to allocate memory at original base address: " + std::to_string(error));
}
// module = LoadLibraryA(path.c_str());
// if (!module)
// throw std::runtime_error("Failed to load original binary");
fixupImports(module); fixupImports(module);
g_gh_translationOffset = translationOffset = g_gh_translationOffset = translationOffset =
uintptr_t(module) - GH_BASE_ADDR; uintptr_t(module) - GH_BASE_ADDR;
// Now we have to relocate the module to the new base address
}
inline void relocate(HMODULE module, void* from, void* to, void* check) {
auto relocated_addr = uintptr_t(from) + translationOffset;
auto relocated_to = uintptr_t(to) + translationOffset;
void *checkRead{};
size_t numRead{};
ReadProcessMemory(GetCurrentProcess(), relocated_addr, &checkRead, sizeof(checkRead), &numRead);
WriteProcessMemory(GetCurrentProcess(), relocated_addr, relocated_to, sizeof(relocated_to), NULL);
}
void relocateModule(HMODULE module) {
#define REL(from, to, original) relocate(module, (void*)(from), (void*)(to), (void*)(original))
#include "relocations.def"
} }
// Translate address relative from the original image base address // Translate address relative from the original image base address

View File

@ -27,7 +27,7 @@ public class FindRelocations extends GhidraScript {
addrMax = RemanConfig.INSTANCE.staticMemoryBlockEnd.getOffset(); addrMax = RemanConfig.INSTANCE.staticMemoryBlockEnd.getOffset();
// Create output file for relocations // Create output file for relocations
File relocFile = new File(RemanConfig.INSTANCE.outputDir, "relocations.txt"); File relocFile = new File(RemanConfig.INSTANCE.outputDir, "relocations.def");
outputFile = new PrintWriter(new FileWriter(relocFile)); outputFile = new PrintWriter(new FileWriter(relocFile));
try { try {
@ -96,15 +96,17 @@ public class FindRelocations extends GhidraScript {
Address toAddr = ref.getToAddress(); Address toAddr = ref.getToAddress();
if (isInMainMemorySpace(toAddr)) { if (isInMainMemorySpace(toAddr)) {
// Check if the target address appears in the instruction bytes (absolute addressing) // Check if the target address appears in the instruction bytes (absolute addressing)
if (containsAbsoluteAddress(instruction, toAddr)) { int operandOffset = findAbsoluteAddressOffset(instruction, toAddr);
recordRelocation(instruction.getAddress(), toAddr, mnemonic, "absolute_" + ref.getReferenceType().getName()); if (operandOffset >= 0) {
recordRelocation(instruction.getAddress(), toAddr, mnemonic,
"absolute_" + ref.getReferenceType().getName(), operandOffset);
} }
} }
} }
} }
} }
private boolean containsAbsoluteAddress(Instruction instruction, Address targetAddr) { private int findAbsoluteAddressOffset(Instruction instruction, Address targetAddr) {
try { try {
byte[] instructionBytes = instruction.getBytes(); byte[] instructionBytes = instruction.getBytes();
long targetValue = targetAddr.getOffset(); long targetValue = targetAddr.getOffset();
@ -116,17 +118,17 @@ public class FindRelocations extends GhidraScript {
targetBytes[2] = (byte) ((targetValue >> 16) & 0xFF); targetBytes[2] = (byte) ((targetValue >> 16) & 0xFF);
targetBytes[3] = (byte) ((targetValue >> 24) & 0xFF); targetBytes[3] = (byte) ((targetValue >> 24) & 0xFF);
// Search for the target address bytes in the instruction // Search for the target address bytes in the instruction and return offset
return containsSequence(instructionBytes, targetBytes); return findSequenceOffset(instructionBytes, targetBytes);
} catch (Exception e) { } catch (Exception e) {
return false; return -1;
} }
} }
private boolean containsSequence(byte[] haystack, byte[] needle) { private int findSequenceOffset(byte[] haystack, byte[] needle) {
if (needle.length > haystack.length) { if (needle.length > haystack.length) {
return false; return -1;
} }
for (int i = 0; i <= haystack.length - needle.length; i++) { for (int i = 0; i <= haystack.length - needle.length; i++) {
@ -138,10 +140,10 @@ public class FindRelocations extends GhidraScript {
} }
} }
if (found) { if (found) {
return true; return i; // Return the offset where the sequence starts
} }
} }
return false; return -1;
} }
private boolean isRelocatableInstruction(String mnemonic) { private boolean isRelocatableInstruction(String mnemonic) {
@ -177,7 +179,7 @@ public class FindRelocations extends GhidraScript {
return; return;
} }
if (block.getName() == ".rsrc") { if (block.getName().equals(".rsrc")) {
continue; continue;
} }
@ -199,7 +201,7 @@ public class FindRelocations extends GhidraScript {
try { try {
Address targetAddr = currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(value); Address targetAddr = currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(value);
if (isInMainMemorySpace(targetAddr)) { if (isInMainMemorySpace(targetAddr)) {
recordRelocation(addr, targetAddr, "data", "pointer"); recordRelocation(addr, targetAddr, "data", "pointer", 0);
} }
} catch (Exception e) { } catch (Exception e) {
// Invalid address, ignore // Invalid address, ignore
@ -233,11 +235,14 @@ public class FindRelocations extends GhidraScript {
&& value <= addrMax; // Typical executable range && value <= addrMax; // Typical executable range
} }
private void recordRelocation(Address fromAddr, Address toAddr, String instruction, String type) { private void recordRelocation(Address fromAddr, Address toAddr, String instruction, String type, int operandOffset) {
if (foundRelocations.add(toAddr)) { if (foundRelocations.add(toAddr)) {
String instructionBytes = getInstructionBytesString(fromAddr); String instructionBytes = getInstructionBytesString(fromAddr);
String line = String.format("0x%s -> 0x%s (%s) [%s] | %s", Address operandPtr = fromAddr.add(operandOffset);
String line = String.format("REL(0x%s, 0x%s, 0x%s) // %s [%s] | %s",
fromAddr.toString(), fromAddr.toString(),
operandPtr.toString(),
toAddr.toString(), toAddr.toString(),
instruction, instruction,
type, type,