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
-Wl,/BASE:0x20000000
-Wl,/DYNAMICBASE:NO
-Wl,/SECTION:.reserved,RW,0x400000
)
target_link_directories(${TARGET} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/dllhack)
target_link_libraries(${TARGET} PRIVATE
DbgHelp
Rayman3
)
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{};
extern "C" {
cdecl void CDAPFN0506_CDAPFN0506_X_IPT_fn_vResetInputEntry();
}
struct R3Bin {
R3Bin() { loadOriginal(); }
void loadOriginal() {
void* ptr = (void*)&CDAPFN0506_CDAPFN0506_X_IPT_fn_vResetInputEntry;
SPDLOG_DEBUG("Loading original binary");
auto &config = getDefaultConfig();
std::string path = config.gameRootDir + "/Rayman3.exe";
// Reserve 4MB at the original base address
module = (HINSTANCE)VirtualAlloc((LPVOID)GH_BASE_ADDR, 4 * 1024 * 1024, MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!module) {
// 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");
module = LoadLibraryA(path.c_str());
if (!module)
throw std::runtime_error("Failed to load original binary");
fixupImports(module);
g_gh_translationOffset = translationOffset =
uintptr_t(module) - GH_BASE_ADDR;
// 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

View File

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