Skip to content

Commit b3c9940

Browse files
authored
1.2.0
1 parent dc5cade commit b3c9940

3 files changed

Lines changed: 274 additions & 0 deletions

File tree

CMakeLists.txt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
cmake_minimum_required(VERSION 3.24)
2+
project(ER-RandomizedStats LANGUAGES CXX)
3+
4+
5+
add_library(ER-RandomizedStats SHARED
6+
src/dllmain.cpp
7+
)
8+
9+
set_target_properties(ER-RandomizedStats PROPERTIES
10+
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>"
11+
)
12+
13+
target_compile_features(ER-RandomizedStats
14+
PUBLIC
15+
cxx_std_17
16+
)
17+
18+
target_include_directories(ER-RandomizedStats
19+
PUBLIC
20+
${CMAKE_CURRENT_SOURCE_DIR}/src
21+
)
22+
23+
target_compile_definitions(ER-RandomizedStats
24+
PUBLIC
25+
ERRANDOMIZEDSTATS_EXPORTS
26+
_WINDOWS
27+
_USRDLL
28+
_MBCS
29+
$<$<CONFIG:Debug>:_DEBUG>
30+
$<$<CONFIG:Release>:NDEBUG>
31+
$<$<STREQUAL:${CMAKE_CXX_COMPILER_ARCHITECTURE_ID},X86>:WIN32>
32+
)
33+
34+
target_link_libraries(ER-RandomizedStats
35+
PUBLIC
36+
Psapi.lib
37+
)
38+
39+
target_compile_options(ER-RandomizedStats
40+
PUBLIC
41+
/W3
42+
)
43+

src/dllmain.cpp

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#include <windows.h>
2+
#include <thread>
3+
#include <psapi.h>
4+
#include "ext/random.h"
5+
6+
const char* GAMEDATAMAN_AOB = "\x48\x8B\x05\x00\x00\x00\x00\x48\x85\xC0\x74\x05\x48\x8B\x40\x58\xC3\xC3";
7+
const char* GAMEDATAMAN_MASK = "xxx????xxxxxxxxxxx";
8+
9+
struct Offsets {
10+
static const uintptr_t StatBasePtr = 0x8;
11+
static const uintptr_t Vigor = 0x3C;
12+
static const uintptr_t Level = 0x68;
13+
static const uintptr_t DeathCount = 0x94;
14+
};
15+
16+
int GetRandomInt(random_state* state, int min, int max) {
17+
return min + (random_next(state) % (max - min + 1));
18+
}
19+
20+
uintptr_t FindPattern(const char* pattern, const char* mask) {
21+
MODULEINFO modInfo = { 0 };
22+
GetModuleInformation(GetCurrentProcess(), GetModuleHandle(NULL), &modInfo, sizeof(MODULEINFO));
23+
uintptr_t start = (uintptr_t)modInfo.lpBaseOfDll;
24+
uintptr_t size = (uintptr_t)modInfo.SizeOfImage;
25+
size_t patternLen = strlen(mask);
26+
for (uintptr_t i = 0; i < size - patternLen; i++) {
27+
bool found = true;
28+
for (size_t j = 0; j < patternLen; j++) {
29+
if (mask[j] != '?' && pattern[j] != *(char*)(start + i + j)) {
30+
found = false; break;
31+
}
32+
}
33+
if (found) return start + i;
34+
}
35+
return 0;
36+
}
37+
38+
uintptr_t GetRIPRelative(uintptr_t address) {
39+
if (!address) return 0;
40+
int32_t offset = *(int32_t*)(address + 3);
41+
return address + offset + 7;
42+
}
43+
44+
void RandomizeStatsAndLevel(uintptr_t gameDataManAddr, random_state* rng) {
45+
uintptr_t gameDataMan = *(uintptr_t*)gameDataManAddr;
46+
if (!gameDataMan) return;
47+
uintptr_t statBase = *(uintptr_t*)(gameDataMan + Offsets::StatBasePtr);
48+
if (!statBase) return;
49+
50+
for (int i = 0; i < 8; i++) {
51+
*(int*)(statBase + Offsets::Vigor + (i * 4)) = GetRandomInt(rng, 1, 99);
52+
}
53+
54+
*(int*)(statBase + Offsets::Level) = GetRandomInt(rng, 1, 713);
55+
}
56+
57+
void ModThread() {
58+
uintptr_t gameDataManInst = FindPattern(GAMEDATAMAN_AOB, GAMEDATAMAN_MASK);
59+
if (!gameDataManInst) return;
60+
61+
uintptr_t gameDataManAddr = GetRIPRelative(gameDataManInst);
62+
int lastDeathCount = -1;
63+
64+
random_state rng;
65+
random_autoseed(&rng);
66+
67+
while (true) {
68+
uintptr_t gameDataMan = *(uintptr_t*)gameDataManAddr;
69+
if (gameDataMan) {
70+
int currentDeaths = *(int*)(gameDataMan + Offsets::DeathCount);
71+
72+
if (lastDeathCount == -1) {
73+
lastDeathCount = currentDeaths;
74+
}
75+
76+
if (currentDeaths > lastDeathCount) {
77+
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
78+
79+
RandomizeStatsAndLevel(gameDataManAddr, &rng);
80+
81+
lastDeathCount = currentDeaths;
82+
}
83+
}
84+
std::this_thread::sleep_for(std::chrono::milliseconds(500));
85+
}
86+
}
87+
88+
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
89+
if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
90+
CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)ModThread, nullptr, 0, nullptr);
91+
}
92+
return TRUE;
93+
}

src/ext/random.h

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/*
2+
World Class Chaotic Pseudo-Random Number Generator
3+
Algorithm by David Blackman.
4+
5+
computers can't produce true unpredictability without hardware entropy or external inputs.
6+
*/
7+
8+
#ifndef RANDOM_H
9+
#define RANDOM_H
10+
11+
#include <stdint.h>
12+
13+
#ifdef __cplusplus
14+
#include <random>
15+
#else
16+
#include <time.h>
17+
#if defined(_WIN32)
18+
#include <windows.h>
19+
#include <process.h>
20+
#else
21+
#include <unistd.h>
22+
#include <fcntl.h>
23+
#include <sys/types.h>
24+
#include <sys/stat.h>
25+
#endif
26+
#endif
27+
28+
#ifdef __cplusplus
29+
extern "C" {
30+
#endif
31+
32+
typedef struct {
33+
uint64_t a;
34+
uint64_t b;
35+
uint64_t c;
36+
uint64_t d;
37+
} random_state;
38+
39+
static inline uint64_t _random_rotl(uint64_t x, int k) {
40+
return (x << k) | (x >> (64 - k));
41+
}
42+
43+
static inline void random_advance(random_state* s) {
44+
s->b += s->c;
45+
s->a = _random_rotl(s->a, 32);
46+
s->c ^= s->b;
47+
48+
s->d += 0x55aa96a5;
49+
50+
s->a += s->b;
51+
s->c = _random_rotl(s->c, 23);
52+
s->b ^= s->a;
53+
54+
s->a += s->c;
55+
s->b = _random_rotl(s->b, 19);
56+
s->c += s->a;
57+
58+
s->b += s->d;
59+
}
60+
61+
static inline void random_seed(random_state* s, uint64_t seed) {
62+
s->a = seed;
63+
s->b = 0;
64+
s->c = 2000001;
65+
s->d = 0;
66+
for (int i = 0; i < 14; ++i) random_advance(s);
67+
}
68+
69+
static inline void random_seed2(random_state* s, uint64_t seed1, uint64_t seed2) {
70+
s->a = seed1;
71+
s->b = seed2;
72+
s->c = 2000001;
73+
s->d = 0;
74+
for (int i = 0; i < 14; ++i) random_advance(s);
75+
}
76+
77+
static inline void random_autoseed(random_state* s) {
78+
uint64_t seed1 = 0, seed2 = 0;
79+
80+
#ifdef __cplusplus
81+
try {
82+
std::random_device rd;
83+
seed1 = ((uint64_t)rd() << 32) | rd();
84+
seed2 = ((uint64_t)rd() << 32) | rd();
85+
}
86+
catch (...) {
87+
seed1 = (uint64_t)time(NULL);
88+
seed2 = (uint64_t)clock();
89+
}
90+
91+
#elif defined(_WIN32)
92+
FILETIME ft;
93+
GetSystemTimeAsFileTime(&ft);
94+
LARGE_INTEGER pc;
95+
QueryPerformanceCounter(&pc);
96+
97+
seed1 = ((uint64_t)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
98+
seed1 ^= (uint64_t)GetCurrentProcessId() << 32;
99+
seed1 ^= (uint64_t)GetCurrentThreadId();
100+
101+
seed2 = (uint64_t)pc.QuadPart;
102+
seed2 ^= (uint64_t)clock();
103+
104+
#else
105+
int fd = open("/dev/urandom", O_RDONLY);
106+
if (fd >= 0) {
107+
uint64_t buf[2];
108+
if (read(fd, buf, sizeof(buf)) == sizeof(buf)) {
109+
seed1 = buf[0];
110+
seed2 = buf[1];
111+
}
112+
close(fd);
113+
}
114+
115+
if (seed1 == 0 && seed2 == 0) {
116+
seed1 = (uint64_t)time(NULL);
117+
seed2 = (uint64_t)clock();
118+
seed2 ^= (uint64_t)(uintptr_t)s;
119+
}
120+
#endif
121+
122+
random_seed2(s, seed1, seed2);
123+
}
124+
125+
static inline uint64_t random_next(random_state* s) {
126+
random_advance(s);
127+
return s->a;
128+
}
129+
130+
static inline double random_double(random_state* s) {
131+
return (random_next(s) >> 11) * 0x1.0p-53;
132+
}
133+
134+
#ifdef __cplusplus
135+
}
136+
#endif
137+
138+
#endif

0 commit comments

Comments
 (0)