diff --git a/DATA/VERSIONS.txt b/DATA/VERSIONS.txt index 064d733..ffafce8 100644 --- a/DATA/VERSIONS.txt +++ b/DATA/VERSIONS.txt @@ -1,3 +1,14 @@ +19-01-2015 -- version 2.4 +========================= +- The FPS override now scans the binary to try and find the correct addresses + to perform the patching required for variable FPS support (Nwks) + + +15-12-2014 -- version 2.3 +========================= +- Make FPS override work with the Steamworks version (all credit goes to boowoo90 for the quick fix) + + 28-09-2013 -- version 2.2 ========================= - Updated AA, SSAO and screenshot functionality to be compatible with latest Dark Souls version diff --git a/DSfix.v11.suo b/DSfix.v11.suo index bc786d9..aaa1b11 100644 Binary files a/DSfix.v11.suo and b/DSfix.v11.suo differ diff --git a/DSfix.vcxproj b/DSfix.vcxproj index c6303f0..ce32a8a 100644 --- a/DSfix.vcxproj +++ b/DSfix.vcxproj @@ -112,7 +112,7 @@ MachineX86 E:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Lib\x86;%(AdditionalLibraryDirectories) DINPUT8.def - lib\GFWLCompatibility.lib;libovr.lib;winmm.lib;detours.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;psapi.lib;%(AdditionalDependencies) + winmm.lib;detours.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;psapi.lib;%(AdditionalDependencies) Default @@ -130,7 +130,7 @@ 0x0409 - cp $(TargetPath) "F:\Program Files (x86)\Steam\steamapps\common\Dark Souls Prepare to Die Edition\DATA" + cp $(TargetPath) "E:\Steam\steamapps\common\Dark Souls Prepare to Die Edition\DATA" @@ -302,6 +302,7 @@ WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL + @@ -323,6 +324,7 @@ + diff --git a/FPS.cpp b/FPS.cpp index 81972ea..9aeb8c6 100644 --- a/FPS.cpp +++ b/FPS.cpp @@ -9,32 +9,40 @@ #include "main.h" #include "Detouring.h" #include "RenderstateManager.h" +#include "memory.h" +#ifndef WITHOUT_GFWL_LIB void enableGFWLCompatibility(void); - -#define JMP32_SZ 5 -#define CALL32_SZ 5 -#define NOPOP 0x90 -#define JMPOP 0xE9 -#define CALLOP 0xE8 +#endif // Globals -static DWORD originalBase = NULL; -static DWORD imageBase = NULL; +static DWORD OriginalBase = 0x0400000; +static DWORD ImageBase = NULL; // Hook Globals double lastRenderTime; static LARGE_INTEGER timerFreq; static LARGE_INTEGER counterAtStart; -// Hook Addresses -//------------------------------------ +// Hook Parameters +//----------------------------------- +// Dark Souls executable timestamp +DWORD EXE_TIMESTAMP = 0x546FA3C5; // Steam Beta build 2.0 + // Time-step value address -#define ADDR_TS 0x01245E80 // 1.0.0 was 0x012497F0, 1.0.1 was 0x012498E0 +DWORD ADDR_TS = 0x011E4D70; // 1.0.0 was 0x012497F0, 1.0.1 was 0x012498E0 +LPCSTR TS_PATTERN = "0080264400009444000058420000C0428988083D0000A044"; +DWORD TS_OFFSET = 0x00000010; + // Presentation interval address -#define ADDR_PRESINT 0x01025E5E // 1.0.0 was 0x010275AE, 1.0.1 was 0x0102788E +DWORD ADDR_PRESINT = 0x00FFA15E; // 1.0.0 was 0x010275AE, 1.0.1 was 0x0102788E +LPCSTR PRESINT_PATTERN = "FF15xxxxxxxx83C408C78648020000020000005EC20800"; +DWORD PRESINT_OFFSET = 0x0000000F; + // getDrawThreadMsgCommand address in HGCommandDispatcher loop -#define ADDR_GETCMD 0x00BD5A8D // 1.0.0 was 0x00BD601D, 1.0.1 was 0x00BD60ED +DWORD ADDR_GETCMD = 0x00BAC3DD; // 1.0.0 was 0x00BD601D, 1.0.1 was 0x00BD60ED +LPCSTR GETCMD_PATTERN = "6A018BCDE8xxxxxxxx8BF08BCEE8xxxxxxxx83F805"; +DWORD GETCMD_OFFSET = 0x0000000D; //---------------------------------------------------------------------------------------- // Support Functions @@ -43,25 +51,18 @@ static LARGE_INTEGER counterAtStart; // Misc //------------------------------------ DWORD getAbsoluteAddress(DWORD offset) { - if (imageBase) - return imageBase + offset; + if (ImageBase) + return ImageBase + offset; else return NULL; } DWORD convertAddress(DWORD Address) { - return getAbsoluteAddress(Address - originalBase); + return getAbsoluteAddress(Address - OriginalBase); } // Memory //------------------------------------ -void writeToAddress(void* Data, DWORD Address, int Size) { - DWORD oldProtect; - VirtualProtect((LPVOID)Address, Size, PAGE_READWRITE, &oldProtect); - memcpy((void*)Address, Data, Size); - VirtualProtect((LPVOID)Address, Size, oldProtect, &oldProtect); -} - void updateAnimationStepTime(float stepTime, float minFPS, float maxFPS) { float FPS = 1.0f/(stepTime/1000); @@ -84,49 +85,6 @@ double getElapsedTime(void) { return (double)( (c.QuadPart - counterAtStart.QuadPart) * 1000.0 / (double)timerFreq.QuadPart ); } -// Detour -//------------------------------------ -// Make sure to adjust length according to instructions below detoured address! -// Partially overwritten instructions will mess-up disassembly and capacity to debug -void *DetourApply(BYTE *orig, BYTE *hook, int len, BYTE type) -{ - BYTE OP, SZ; - - if (type == JMPOP) { - OP = JMPOP; - SZ = JMP32_SZ; - } - else if (type == CALLOP) { - OP = CALLOP; - SZ = CALL32_SZ; - } - else return 0; - - DWORD dwProt = 0; - BYTE *jmp = (BYTE*)malloc(len+SZ); - VirtualProtect(orig, len, PAGE_READWRITE, &dwProt); - memcpy(jmp, orig, len); - - jmp += len; // increment to the end of the copied bytes - jmp[0] = OP; - *(DWORD*)(jmp+1) = (DWORD)(orig+len - jmp) - SZ; - - memset(orig, NOPOP, len); - - orig[0] = OP; - *(DWORD*)(orig+1) = (DWORD)(hook - orig) - SZ; - VirtualProtect(orig, len, dwProt, 0); - - return (jmp-len); -} - -void DetourRemove(BYTE *src, BYTE *jmp, int len) { - DWORD dwProt = 0; - VirtualProtect(src, len, PAGE_READWRITE, &dwProt); - memcpy(src, jmp, len); - VirtualProtect(src, len, dwProt, 0); -} - //---------------------------------------------------------------------------------------- // Hook functions //---------------------------------------------------------------------------------------- @@ -162,15 +120,72 @@ __declspec(naked) void getDrawThreadMsgCommand(void) { // Game Patches //---------------------------------------------------------------------------------------- void applyFPSPatch() { - enableGFWLCompatibility(); - - // Get imageBase - HANDLE exeHandle = NULL; - originalBase = 0x0400000; - exeHandle = GetModuleHandle(NULL); - if(exeHandle != NULL) - imageBase = (DWORD)exeHandle; + SDLOG(0, "Starting FPS unlock...\n"); +#ifndef WITHOUT_GFWL_LIB + SDLOG(0, "Applying GFWL compatibility\n"); + enableGFWLCompatibility(); +#endif + + // Get image info + MODULEINFO moduleInfo; + PIMAGE_DOS_HEADER dosHeader; + PIMAGE_NT_HEADERS ntHeader; + IMAGE_FILE_HEADER header; + + if(GetModuleInformation(GetCurrentProcess(), GetModuleHandle(NULL), &moduleInfo, sizeof(moduleInfo))) + { + ImageBase = (DWORD)moduleInfo.lpBaseOfDll; + SDLOG(0, "ImageBase at 0x%08X\n", ImageBase); + + dosHeader = (PIMAGE_DOS_HEADER)ImageBase; + ntHeader = (PIMAGE_NT_HEADERS)((DWORD)(dosHeader) + (dosHeader->e_lfanew)); + header = ntHeader->FileHeader; + DWORD TimeStamp = header.TimeDateStamp; + SDLOG(0, "Executable timestamp: 0x%08X, config: 0x%08X\n", TimeStamp, EXE_TIMESTAMP); + + // Perform pattern matching if timestamp differs + if (TimeStamp != EXE_TIMESTAMP) { + SDLOG(0, "Trying pattern matching...\n"); + + DWORD address; + address = GetMemoryAddressFromPattern(NULL, TS_PATTERN, TS_OFFSET); + if(address != NULL) { + SDLOG(0, "ADDR_TS found at 0x%08X\n", address); + ADDR_TS = address; + } + else { + SDLOG(0, "Could not match ADDR_TS pattern, FPS not unlocked\n"); + return; + } + address = GetMemoryAddressFromPattern(NULL, PRESINT_PATTERN, PRESINT_OFFSET); + if(address != NULL) { + SDLOG(0, "ADDR_PRESINT found at 0x%08X\n", address); + ADDR_PRESINT = address; + } + else { + SDLOG(0, "Could not match ADDR_PRESINT pattern, FPS not unlocked\n"); + return; + } + address = GetMemoryAddressFromPattern(NULL, GETCMD_PATTERN, GETCMD_OFFSET); + if(address != NULL) { + SDLOG(0, "ADDR_GETCMD found at 0x%08X\n", address); + ADDR_GETCMD = address; + } + else { + SDLOG(0, "Could not match ADDR_GETCMD pattern, FPS not unlocked\n"); + return; + } + SDLOG(0, "Pattern matching successful\n"); + } + else + SDLOG(0, "Using configured addresses\n"); + } + else + { + SDLOG(0, "GetModuleInformation failed, FPS not unlocked\n"); + return; + } // Init counter for frame-rate calculations lastRenderTime = 0.0f; @@ -191,5 +206,5 @@ void applyFPSPatch() { address = convertAddress(ADDR_GETCMD); DetourApply((BYTE*)address, (BYTE*)getDrawThreadMsgCommand, 5, CALLOP); - SDLOG(0, "FPS rate unlocked\n"); + SDLOG(0, "FPS unlocked\n"); } diff --git a/RenderstateManager.cpp b/RenderstateManager.cpp index f4f90aa..6914a09 100644 --- a/RenderstateManager.cpp +++ b/RenderstateManager.cpp @@ -62,7 +62,7 @@ HRESULT RSManager::redirectPresent(CONST RECT *pSourceRect, CONST RECT *pDestRec } if(timingIntroMode) { skippedPresents++; - if(skippedPresents >= 300u && !Settings::get().getUnlockFPS()) { + if(skippedPresents >= 1200u && !Settings::get().getUnlockFPS()) { SDLOG(1, "Intro mode ended (timeout)!\n"); timingIntroMode = false; } diff --git a/main.h b/main.h index 8124bae..c974f46 100644 --- a/main.h +++ b/main.h @@ -18,10 +18,12 @@ #pragma once -#define VERSION "2.2" +#define VERSION "2.4" #define RELEASE_VER +#define WITHOUT_GFWL_LIB + #ifndef RELEASE_VER #define SDLOG(_level, _str, ...) if(Settings::get().getLogLevel() > _level) { sdlog(_str, __VA_ARGS__); } #else diff --git a/memory.cpp b/memory.cpp new file mode 100644 index 0000000..f728df6 --- /dev/null +++ b/memory.cpp @@ -0,0 +1,264 @@ +////////////////////////////////////////////////////////////////////// +// MemorySearchFunctions.cpp +// ------------------------------------------------------------------- +// Pattern search algorithm and other memory related issues. +// +// +////////////////////////////////////////////////////////////////////// + +#include "memory.h" +#include "main.h" + +#ifdef WITHOUT_GFWL_LIB + +////////////////////////////////////////////////////////////////////// +// GetMemoryAddressFromPattern +// ------------------------------------------------------------------- +// Returns the address of szSearchPattern+offset if found in szDllName +// +// The search criteria are determined by the first character of +// szSearchPattern: +// +// ! An ordinal inside (ex. !NameOfFuntion or !10005) +// # An actual hexadecimal address (ex. #6fba80b4) +// other Fingerprint pattern (see below) +// +// Patterns are interpreted as a string of bytes. The value 00 to ff +// represents an actual value. A byte represented as 'xx' is not +// important to the fingerprint and are masked out. Example of masked +// bytes are absolute addresses/offsets inside the code that are +// likely to change location on blizzard patches. +// +// Once the address of the ordinal, actual address or fingerprint has +// been found, the offset is added to the result and passed back to +// the calling function. +// +// If the address is not found the function returns 0 +// +// +////////////////////////////////////////////////////////////////////// +DWORD GetMemoryAddressFromPattern(LPSTR szDllName, LPCSTR szSearchPattern, DWORD offset) +{ + DWORD lResult = 0; + + // Check for actual address + if (szSearchPattern[0] == '#') + { + LPSTR t=""; + lResult=strtoul(&szSearchPattern[1], &t, 0x10); + return lResult+=(lResult?offset:0); + } + + // Check for ordinal + if (szSearchPattern[0] == '!') + { + HMODULE hModule = GetModuleHandle(szDllName); + + // First let's try to find ordinal by name + if (hModule) + lResult = (DWORD)GetProcAddress(hModule, &szSearchPattern[1]); + + // No luck, lets try by ordinal number instead + if (!lResult) + { + LPSTR x=""; + lResult = (DWORD)GetProcAddress(hModule, (LPCSTR)MAKELONG(strtoul(&szSearchPattern[1], &x, 10),0)); + } + + return lResult+=(lResult?offset:0); + } + + // Parse fingerprint + DWORD len=(strlen(szSearchPattern))/2; + WORD *pPattern=new WORD[len]; + + DWORD SearchSize = NULL, SearchAddress = NULL; + MODULEINFO moduleInfo; + HMODULE hDllModule = GetModuleHandle(szDllName); + if(hDllModule != NULL) + if(GetModuleInformation(GetCurrentProcess(), hDllModule, &moduleInfo, sizeof(moduleInfo))) + { + SearchAddress = (DWORD)moduleInfo.lpBaseOfDll; + SearchSize = moduleInfo.SizeOfImage; + + MakeSearchPattern(szSearchPattern,pPattern); + if (lResult = (DWORD)PatternSearch((BYTE*)SearchAddress, SearchSize, pPattern, len)) + lResult+=offset; + } + else + lResult = NULL; + + delete [] pPattern; + return lResult; +} + +////////////////////////////////////////////////////////////////////// +// Pattern search algorithm written by Druttis. +// +// Patterns string is in the form of +// +// 0xMMVV, 0xMMVV, 0xMMVV +// +// Where MM = Mask & VV = Value +// +// Pattern Equals is doing the following match +// +// (BB[p] & MM[p]) == VV[p] +// +// Where BB = buffer data +// +// That means : +// +// a0, b0, c0, d0, e0 is equal to +// +// 1) 0xffa0, 0xffb0, 0x0000, 0x0000, 0xffe0 +// 2) 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +// 3) 0x8080, 0x3030, 0x0000, 0xffdd, 0xffee +// +// I think you got the idea of it...BOOL _fastcall PatternEquals(LPBYTE buf, LPWORD pat, DWORD plen) +////////////////////////////////////////////////////////////////////// +BOOL PatternEquals(LPBYTE buf, LPWORD pat, DWORD plen) +{ + // + // Just a counter + DWORD i; + // + // Offset + DWORD ofs = 0; + // + // Loop + for (i = 0; plen > 0; i++) { + // + // Compare mask buf and compare result + // Swapped mask/data. Old code was buggy. + if ((buf[ofs] & ((pat[ofs] & 0xff00)>>8)) != (pat[ofs] & 0xff)) + return FALSE; + // + // Move ofs in zigzag direction + plen--; + if ((i & 1) == 0) + ofs += plen; + else + ofs -= plen; + } + // + // Yep, we found + return TRUE; +} + +// +// Search for the pattern, returns the pointer to buf+ofset matching +// the pattern or null. +LPVOID PatternSearch(LPBYTE buf, DWORD blen, LPWORD pat, DWORD plen) +{ + // + // Offset and End of search + DWORD ofs; + DWORD end; + // + // Buffer length and Pattern length may not be 0 + if ((blen == 0) || (plen == 0)) + return NULL; + // + // Calculate End of search + end = blen - plen; + // + // Do the booring loop + for (ofs = 0; ofs != end; ofs++) { + // Return offset to first byte of buf matching width the pattern + if (PatternEquals(&buf[ofs], pat, plen)) + return &buf[ofs]; + } + // + // Me no find, me return 0, NULL, nil + return NULL; +} + + +////////////////////////////////////////////////////////////////////// +// MakeSearchPattern +// ------------------------------------------------------------------- +// Convert a pattern-string into a pattern array for use with pattern +// search. +// +// +////////////////////////////////////////////////////////////////////// +VOID MakeSearchPattern(LPCSTR pString, LPWORD pat) +{ + char *tmp=new char[strlen(pString)+1]; + strcpy(tmp, pString); + + for (int i=(strlen(tmp)/2)-1; strlen(tmp) > 0; i--) + { + char *x=""; + BYTE value=(BYTE)strtoul(&tmp[i*2], &x, 0x10); + if (strlen(x)) + pat[i]=0; + else + pat[i]=MAKEWORD(value, 0xff); + + tmp[i*2]=0; + } + delete [] tmp; +} + +#endif + +////////////////////////////////////////////////////////////////////// +// Misc. Functions +// +////////////////////////////////////////////////////////////////////// +void writeToAddress(void* Data, DWORD Address, int Size) +{ + DWORD oldProtect; + VirtualProtect((LPVOID)Address, Size, PAGE_READWRITE, &oldProtect); + memcpy((void*)Address, Data, Size); + VirtualProtect((LPVOID)Address, Size, oldProtect, &oldProtect); +} + +// Detour +//------------------------------------ +//Make sure to adjust length according to instructions below detoured address! +//Partially overwritten instructions will mess-up disassembly and capacity to debug +void *DetourApply(BYTE *orig, BYTE *hook, int len, BYTE type) +{ + BYTE OP, SZ; + + if (type == JMPOP) + { + OP = JMPOP; + SZ = JMP32_SZ; + } + else if (type == CALLOP) + { + OP = CALLOP; + SZ = CALL32_SZ; + } + else return 0; + + DWORD dwProt = 0; + BYTE *jmp = (BYTE*)malloc(len+SZ); + VirtualProtect(orig, len, PAGE_READWRITE, &dwProt); + memcpy(jmp, orig, len); + + jmp += len; // increment to the end of the copied bytes + jmp[0] = OP; + *(DWORD*)(jmp+1) = (DWORD)(orig+len - jmp) - SZ; + + memset(orig, NOPOP, len); + + orig[0] = OP; + *(DWORD*)(orig+1) = (DWORD)(hook - orig) - SZ; + VirtualProtect(orig, len, dwProt, 0); + + return (jmp-len); +} + + +void DetourRemove(BYTE *src, BYTE *jmp, int len) +{ + DWORD dwProt = 0; + VirtualProtect(src, len, PAGE_READWRITE, &dwProt); + memcpy(src, jmp, len); + VirtualProtect(src, len, dwProt, 0); +} \ No newline at end of file diff --git a/memory.h b/memory.h new file mode 100644 index 0000000..9f4cf3f --- /dev/null +++ b/memory.h @@ -0,0 +1,22 @@ +#ifndef _MEM_H +#define _MEM_H + +#include +#include + +#define JMP32_SZ 5 +#define CALL32_SZ 5 +#define NOPOP 0x90 +#define JMPOP 0xE9 +#define CALLOP 0xE8 + +DWORD GetMemoryAddressFromPattern(LPSTR szDllName, LPCSTR szSearchPattern, DWORD offset); +BOOL PatternEquals(LPBYTE buf, LPWORD pat, DWORD plen); +LPVOID PatternSearch(LPBYTE buf, DWORD blen, LPWORD pat, DWORD plen); +VOID MakeSearchPattern(LPCSTR pString, LPWORD pat); + +void writeToAddress(void* Data, DWORD Address, int Size); +void *DetourApply(BYTE *orig, BYTE *hook, int len, BYTE type); +void DetourRemove(BYTE *src, BYTE *restore, const int len); + +#endif \ No newline at end of file