DLLHack wip
This commit is contained in:
parent
1e91d93470
commit
532c1653c0
|
@ -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()
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
LIBRARY Rayman3
|
||||||
|
EXPORTS
|
||||||
|
CDAPFN0506_CDAPFN0506_X_IPT_fn_vResetInputEntry @1
|
Binary file not shown.
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue