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