about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorjbzdarkid <jbzdarkid@gmail.com>2019-11-05 10:01:52 -0800
committerjbzdarkid <jbzdarkid@gmail.com>2019-11-05 10:01:52 -0800
commit66b2bc177853d33f4559eb240fbbca354b173fa2 (patch)
tree08739589749ab0def5afbed2520e520736656e3c
parente3758a15a6430e7ab7ce9821c0d9e19bbf7a1e87 (diff)
downloadwitness-tutorializer-66b2bc177853d33f4559eb240fbbca354b173fa2.tar.gz
witness-tutorializer-66b2bc177853d33f4559eb240fbbca354b173fa2.tar.bz2
witness-tutorializer-66b2bc177853d33f4559eb240fbbca354b173fa2.zip
All set... time to wire up actual randomizer
-rw-r--r--App/Main.cpp99
-rw-r--r--Source/Memory.cpp106
-rw-r--r--Source/Memory.h15
-rw-r--r--Source/Source.vcxproj2
4 files changed, 152 insertions, 70 deletions
diff --git a/App/Main.cpp b/App/Main.cpp index 5adf22d..89765fb 100644 --- a/App/Main.cpp +++ b/App/Main.cpp
@@ -8,41 +8,41 @@
8#include <thread> 8#include <thread>
9 9
10#include "Memory.h" 10#include "Memory.h"
11#include <Random.h>
11class Randomizer { 12class Randomizer {
12public: 13public:
13 Randomizer(const std::shared_ptr<Memory>&) {} 14 Randomizer(const std::shared_ptr<Memory>&) {}
14 void Randomize() { 15 void Randomize(int seed) {
15 std::this_thread::sleep_for(std::chrono::milliseconds(1000)); 16 std::this_thread::sleep_for(std::chrono::milliseconds(1000));
16 } 17 }
18
19 void RandomizeChallenge(int seed) {
20 Randomize(seed);
21 }
17}; 22};
18 23
19#define EXE_NAME L"witness64_d3d11.exe" 24// Heartbeat is defined to 0x401 by Memory.h
20#define HEARTBEAT 0x401
21#define RANDOMIZE_READY 0x402 25#define RANDOMIZE_READY 0x402
22#define RANDOMIZING 0403 26#define RANDOMIZING 0403
23#define RANDOMIZE_DONE 0x404 27#define RANDOMIZE_DONE 0x404
28#define RANDOMIZE_CHALLENGE_DONE 0x405
29#define CHALLENGE_ONLY 0x406
24 30
25// Globals 31// Globals
26HWND g_hwnd; 32HWND g_hwnd;
27HWND g_seed; 33HWND g_seed;
28HWND g_randomizerStatus; 34HWND g_randomizerStatus;
29HINSTANCE g_hInstance; 35HINSTANCE g_hInstance;
30auto g_witnessProc = std::make_shared<Memory>(); 36auto g_witnessProc = std::make_shared<Memory>(L"witness64_d3d11.exe");
31std::shared_ptr<Randomizer> g_randomizer; 37std::shared_ptr<Randomizer> g_randomizer;
32 38
33// Notifications I need:
34// Game shutdown
35// Load game?
36
37LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { 39LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
38 if (message == WM_DESTROY) { 40 if (message == WM_DESTROY) {
39 PostQuitMessage(0); 41 PostQuitMessage(0);
40 } else if (message == WM_COMMAND || message == WM_TIMER) { 42 } else if (message == WM_COMMAND || message == WM_TIMER) {
41 switch (LOWORD(wParam)) { 43 switch (LOWORD(wParam)) {
42 case HEARTBEAT: 44 case HEARTBEAT:
43 SetTimer(g_hwnd, HEARTBEAT, 1000, NULL); 45 switch ((ProcStatus)lParam) {
44 // Potential improvement: Change this call to be part of the HEARTBEAT message.
45 switch (g_witnessProc->Heartbeat(EXE_NAME)) {
46 case ProcStatus::NotRunning: 46 case ProcStatus::NotRunning:
47 // Shut down randomizer, wait for startup 47 // Shut down randomizer, wait for startup
48 if (g_randomizer) g_randomizer = nullptr; 48 if (g_randomizer) g_randomizer = nullptr;
@@ -60,21 +60,58 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
60 } 60 }
61 break; 61 break;
62 case RANDOMIZE_READY: 62 case RANDOMIZE_READY:
63 SetWindowText(g_randomizerStatus, L"Randomize");
64 EnableWindow(g_randomizerStatus, TRUE); 63 EnableWindow(g_randomizerStatus, TRUE);
64 if (IsDlgButtonChecked(hwnd, CHALLENGE_ONLY)) {
65 SetWindowText(g_randomizerStatus, L"Randomize Challenge");
66 } else {
67 SetWindowText(g_randomizerStatus, L"Randomize");
68 }
65 break; 69 break;
66 case RANDOMIZING: 70 case RANDOMIZING:
67 if (!g_randomizer) break; 71 if (!g_randomizer) {
72 assert(false);
73 break;
74 }
68 EnableWindow(g_randomizerStatus, FALSE); 75 EnableWindow(g_randomizerStatus, FALSE);
69 SetWindowText(g_randomizerStatus, L"Randomizing..."); 76
70 std::thread([]{ 77 {
71 g_randomizer->Randomize(); 78 int seed = 0;
72 PostMessage(g_hwnd, WM_COMMAND, RANDOMIZE_DONE, NULL); 79 std::wstring text(128, L'\0');
73 }).detach(); 80 int size = GetWindowText(g_seed, text.data(), static_cast<int>(text.size()));
81 if (size > 0) { // Set seed
82 seed = _wtoi(text.c_str());
83 } else { // Random seed
84 seed = Random::RandInt(0, 999999);
85 SetWindowText(g_seed, std::to_wstring(seed).c_str());
86 RedrawWindow(g_seed, NULL, NULL, RDW_UPDATENOW);
87 }
88 std::thread([hwnd, seed]{
89 if (IsDlgButtonChecked(hwnd, CHALLENGE_ONLY)) {
90 SetWindowText(g_randomizerStatus, L"Randomizing Challenge...");
91 g_randomizer->RandomizeChallenge(seed);
92 PostMessage(g_hwnd, WM_COMMAND, RANDOMIZE_CHALLENGE_DONE, NULL);
93 } else {
94 SetWindowText(g_randomizerStatus, L"Randomizing...");
95 g_randomizer->Randomize(seed);
96 PostMessage(g_hwnd, WM_COMMAND, RANDOMIZE_DONE, NULL);
97 }
98 }).detach();
99 }
74 break; 100 break;
75 case RANDOMIZE_DONE: 101 case RANDOMIZE_DONE:
102 EnableWindow(g_randomizerStatus, FALSE);
76 SetWindowText(g_randomizerStatus, L"Randomized!"); 103 SetWindowText(g_randomizerStatus, L"Randomized!");
77 break; 104 break;
105 case RANDOMIZE_CHALLENGE_DONE:
106 EnableWindow(g_randomizerStatus, FALSE);
107 SetWindowText(g_randomizerStatus, L"Randomized Challenge!");
108 break;
109 case CHALLENGE_ONLY:
110 CheckDlgButton(hwnd, CHALLENGE_ONLY, !IsDlgButtonChecked(hwnd, CHALLENGE_ONLY));
111 if (IsWindowEnabled(g_randomizerStatus)) {
112 PostMessage(g_hwnd, WM_COMMAND, RANDOMIZE_READY, NULL);
113 }
114 break;
78 } 115 }
79 } 116 }
80 return DefWindowProc(hwnd, message, wParam, lParam); 117 return DefWindowProc(hwnd, message, wParam, lParam);
@@ -86,20 +123,26 @@ HWND CreateLabel(int x, int y, int width, LPCWSTR text) {
86 x, y, width, 16, g_hwnd, NULL, g_hInstance, NULL); 123 x, y, width, 16, g_hwnd, NULL, g_hInstance, NULL);
87} 124}
88 125
89HWND CreateButton(int x, int y, int width, LPCWSTR text, int message) { 126HWND CreateText(int x, int y, int width, LPCWSTR defaultText = L"") {
127 return CreateWindow(MSFTEDIT_CLASS, defaultText,
128 WS_TABSTOP | WS_VISIBLE | WS_CHILD | WS_BORDER,
129 x, y, width, 26, g_hwnd, NULL, g_hInstance, NULL);
130}
131
90#pragma warning(push) 132#pragma warning(push)
91#pragma warning(disable: 4312) 133#pragma warning(disable: 4312)
134HWND CreateButton(int x, int y, int width, LPCWSTR text, int message) {
92 return CreateWindow(L"BUTTON", text, 135 return CreateWindow(L"BUTTON", text,
93 WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 136 WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
94 x, y, width, 26, g_hwnd, (HMENU)message, g_hInstance, NULL); 137 x, y, width, 26, g_hwnd, (HMENU)message, g_hInstance, NULL);
95#pragma warning(pop)
96} 138}
97 139
98HWND CreateText(int x, int y, int width, LPCWSTR defaultText = L"") { 140HWND CreateCheckbox(int x, int y, int message) {
99 return CreateWindow(MSFTEDIT_CLASS, L"", 141 return CreateWindow(L"BUTTON", L"",
100 WS_TABSTOP | WS_VISIBLE | WS_CHILD | WS_BORDER, 142 WS_VISIBLE | WS_CHILD | BS_CHECKBOX,
101 x, y, width, 26, g_hwnd, NULL, g_hInstance, NULL); 143 x, y, 12, 12, g_hwnd, (HMENU)message, g_hInstance, NULL);
102} 144}
145#pragma warning(pop)
103 146
104int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { 147int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) {
105 LoadLibrary(L"Msftedit.dll"); 148 LoadLibrary(L"Msftedit.dll");
@@ -126,9 +169,13 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
126 169
127 CreateLabel(390, 15, 90, L"Version: " VERSION_STR); 170 CreateLabel(390, 15, 90, L"Version: " VERSION_STR);
128 g_seed = CreateText(10, 10, 100); 171 g_seed = CreateText(10, 10, 100);
129 g_randomizerStatus = CreateButton(120, 10, 110, L"Randomize", RANDOMIZING); 172 g_randomizerStatus = CreateButton(120, 10, 180, L"Randomize", RANDOMIZING);
130 EnableWindow(g_randomizerStatus, FALSE); 173 EnableWindow(g_randomizerStatus, FALSE);
131 PostMessage(g_hwnd, WM_COMMAND, HEARTBEAT, NULL); 174 CreateCheckbox(10, 300, CHALLENGE_ONLY);
175 CreateLabel(30, 300, 200, L"Randomize the challenge only");
176 EnableWindow(g_randomizerStatus, FALSE);
177
178 g_witnessProc->StartHeartbeat(g_hwnd);
132 179
133 ShowWindow(g_hwnd, nCmdShow); 180 ShowWindow(g_hwnd, nCmdShow);
134 UpdateWindow(g_hwnd); 181 UpdateWindow(g_hwnd);
diff --git a/Source/Memory.cpp b/Source/Memory.cpp index b0e2e9d..7b4b9c7 100644 --- a/Source/Memory.cpp +++ b/Source/Memory.cpp
@@ -2,25 +2,87 @@
2#include <psapi.h> 2#include <psapi.h>
3#include <tlhelp32.h> 3#include <tlhelp32.h>
4#include <iostream> 4#include <iostream>
5#include <string>
5#include <cassert> 6#include <cassert>
6 7
7#undef PROCESSENTRY32 8#undef PROCESSENTRY32
8#undef Process32Next 9#undef Process32Next
9 10
11Memory::Memory(const std::wstring& processName) : _processName(processName) {
12}
13
14Memory::~Memory() {
15 if (_threadActive) {
16 _threadActive = false;
17 _thread.join();
18 }
19 if (_handle != nullptr) {
20 CloseHandle(_handle);
21 }
22}
23
24void Memory::StartHeartbeat(HWND window, std::chrono::milliseconds beat) {
25 if (_threadActive) return;
26 _threadActive = true;
27 _thread = std::thread([sharedThis = shared_from_this(), window, beat]{
28 while (sharedThis->_threadActive) {
29 sharedThis->Heartbeat(window);
30 std::this_thread::sleep_for(beat);
31 }
32 });
33 _thread.detach();
34}
35
36void Memory::Heartbeat(HWND window) {
37 if (!_handle && !Initialize()) {
38 // Couldn't initialize, definitely not running
39 PostMessage(window, WM_COMMAND, HEARTBEAT, (LPARAM)ProcStatus::NotRunning);
40 return;
41 }
42
43 DWORD exitCode = 0;
44 assert(_handle);
45 GetExitCodeProcess(_handle, &exitCode);
46 if (exitCode != STILL_ACTIVE) {
47 // Process has exited, clean up.
48 _computedAddresses.clear();
49 _handle = NULL;
50 PostMessage(window, WM_COMMAND, HEARTBEAT, (LPARAM)ProcStatus::NotRunning);
51 return;
52 }
53
54#if GLOBALS == 0x5B28C0
55 int currentFrame = ReadData<int>({0x5BE3B0}, 1)[0];
56#elif GLOBALS == 0x62D0A0
57 int currentFrame = ReadData<int>({0x63954C}, 1)[0];
58#endif
59 int frameDelta = currentFrame - _previousFrame;
60 _previousFrame = currentFrame;
61 if (frameDelta < 0 && currentFrame < 250) {
62 PostMessage(window, WM_COMMAND, HEARTBEAT, (LPARAM)ProcStatus::NewGame);
63 return;
64 }
65
66 // TODO: Some way to return ProcStatus::Randomized vs ProcStatus::NotRandomized vs ProcStatus::DeRandomized;
67
68 PostMessage(window, WM_COMMAND, HEARTBEAT, (LPARAM)ProcStatus::Running);
69}
70
71
10[[nodiscard]] 72[[nodiscard]]
11bool Memory::Initialize(const std::wstring& processName) { 73bool Memory::Initialize() {
12 // First, get the handle of the process 74 // First, get the handle of the process
13 PROCESSENTRY32W entry; 75 PROCESSENTRY32W entry;
14 entry.dwSize = sizeof(entry); 76 entry.dwSize = sizeof(entry);
15 HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 77 HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
16 while (Process32NextW(snapshot, &entry)) { 78 while (Process32NextW(snapshot, &entry)) {
17 if (processName == entry.szExeFile) { 79 if (_processName == entry.szExeFile) {
18 _handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID); 80 _handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
19 break; 81 break;
20 } 82 }
21 } 83 }
22 if (!_handle) { 84 if (!_handle) {
23 std::cerr << "Couldn't find " << processName.c_str() << ", is it open?" << std::endl; 85 std::cerr << "Couldn't find " << _processName.c_str() << ", is it open?" << std::endl;
24 return false; 86 return false;
25 } 87 }
26 88
@@ -33,7 +95,7 @@ bool Memory::Initialize(const std::wstring& processName) {
33 for (DWORD i = 0; i < numModules / sizeof(HMODULE); i++) { 95 for (DWORD i = 0; i < numModules / sizeof(HMODULE); i++) {
34 int length = GetModuleBaseNameW(_handle, moduleList[i], &name[0], static_cast<DWORD>(name.size())); 96 int length = GetModuleBaseNameW(_handle, moduleList[i], &name[0], static_cast<DWORD>(name.size()));
35 name.resize(length); 97 name.resize(length);
36 if (processName == name) { 98 if (_processName == name) {
37 _baseAddress = (uintptr_t)moduleList[i]; 99 _baseAddress = (uintptr_t)moduleList[i];
38 break; 100 break;
39 } 101 }
@@ -45,42 +107,6 @@ bool Memory::Initialize(const std::wstring& processName) {
45 return true; 107 return true;
46} 108}
47 109
48ProcStatus Memory::Heartbeat(const std::wstring& processName) {
49 if (!_handle && !Initialize(processName)) {
50 // Couldn't initialize, definitely not running
51 return ProcStatus::NotRunning;
52 }
53
54 DWORD exitCode = 0;
55 GetExitCodeProcess(_handle, &exitCode);
56 if (exitCode != STILL_ACTIVE) {
57 // Process has exited, clean up.
58 _computedAddresses.clear();
59 _handle = NULL;
60 return ProcStatus::NotRunning;
61 }
62
63 int currentFrame = 0x7FFFFFFF;
64 if (GLOBALS == 0x5B28C0) {
65 currentFrame = ReadData<int>({0x5BE3B0}, 1)[0];
66 } else if (GLOBALS == 0x62D0A0) {
67 currentFrame = ReadData<int>({0x63954C}, 1)[0];
68 } else {
69 assert(false);
70 }
71 if (currentFrame < 80) return ProcStatus::NewGame;
72
73 // TODO: Some way to return ProcStatus::Randomized vs ProcStatus::NotRandomized vs ProcStatus::DeRandomized;
74
75 return ProcStatus::Running;
76}
77
78Memory::~Memory() {
79 if (_handle != nullptr) {
80 CloseHandle(_handle);
81 }
82}
83
84void Memory::AddSigScan(const std::vector<byte>& scanBytes, const std::function<void(int index)>& scanFunc) 110void Memory::AddSigScan(const std::vector<byte>& scanBytes, const std::function<void(int index)>& scanFunc)
85{ 111{
86 _sigScans[scanBytes] = {scanFunc, false}; 112 _sigScans[scanBytes] = {scanFunc, false};
diff --git a/Source/Memory.h b/Source/Memory.h index d7552c5..c19d92b 100644 --- a/Source/Memory.h +++ b/Source/Memory.h
@@ -1,12 +1,14 @@
1#pragma once 1#pragma once
2#include <functional> 2#include <functional>
3#include <map> 3#include <map>
4#include <thread>
4#include <vector> 5#include <vector>
5#include <windows.h> 6#include <windows.h>
6 7
7// #define GLOBALS 0x5B28C0 8// #define GLOBALS 0x5B28C0
8#define GLOBALS 0x62D0A0 9#define GLOBALS 0x62D0A0
9 10
11#define HEARTBEAT 0x401
10enum class ProcStatus { 12enum class ProcStatus {
11 NotRunning, 13 NotRunning,
12 Running, 14 Running,
@@ -17,11 +19,11 @@ enum class ProcStatus {
17// http://stackoverflow.com/q/32798185 19// http://stackoverflow.com/q/32798185
18// http://stackoverflow.com/q/36018838 20// http://stackoverflow.com/q/36018838
19// http://stackoverflow.com/q/1387064 21// http://stackoverflow.com/q/1387064
20class Memory { 22class Memory final : public std::enable_shared_from_this<Memory> {
21public: 23public:
22 Memory() = default; 24 Memory(const std::wstring& processName);
23 ProcStatus Heartbeat(const std::wstring& processName);
24 ~Memory(); 25 ~Memory();
26 void StartHeartbeat(HWND window, std::chrono::milliseconds beat = std::chrono::milliseconds(1000));
25 27
26 Memory(const Memory& memory) = delete; 28 Memory(const Memory& memory) = delete;
27 Memory& operator=(const Memory& other) = delete; 29 Memory& operator=(const Memory& other) = delete;
@@ -74,10 +76,15 @@ private:
74 ThrowError(); 76 ThrowError();
75 } 77 }
76 78
77 bool Initialize(const std::wstring& processName); 79 void Heartbeat(HWND window);
80 bool Initialize();
78 void ThrowError(); 81 void ThrowError();
79 void* ComputeOffset(std::vector<int> offsets); 82 void* ComputeOffset(std::vector<int> offsets);
80 83
84 int _previousFrame = 0;
85 bool _threadActive = false;
86 std::thread _thread;
87 std::wstring _processName;
81 std::map<uintptr_t, uintptr_t> _computedAddresses; 88 std::map<uintptr_t, uintptr_t> _computedAddresses;
82 uintptr_t _baseAddress = 0; 89 uintptr_t _baseAddress = 0;
83 HANDLE _handle = nullptr; 90 HANDLE _handle = nullptr;
diff --git a/Source/Source.vcxproj b/Source/Source.vcxproj index 3e66f83..e7f716c 100644 --- a/Source/Source.vcxproj +++ b/Source/Source.vcxproj
@@ -158,9 +158,11 @@
158 </ItemDefinitionGroup> 158 </ItemDefinitionGroup>
159 <ItemGroup> 159 <ItemGroup>
160 <ClInclude Include="Memory.h" /> 160 <ClInclude Include="Memory.h" />
161 <ClInclude Include="Random.h" />
161 </ItemGroup> 162 </ItemGroup>
162 <ItemGroup> 163 <ItemGroup>
163 <ClCompile Include="Memory.cpp" /> 164 <ClCompile Include="Memory.cpp" />
165 <ClCompile Include="Random.cpp" />
164 </ItemGroup> 166 </ItemGroup>
165 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> 167 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
166 <ImportGroup Label="ExtensionTargets"> 168 <ImportGroup Label="ExtensionTargets">