diff options
-rw-r--r-- | App/Main.cpp | 87 | ||||
-rw-r--r-- | Source/Memory.cpp | 25 | ||||
-rw-r--r-- | Source/Memory.h | 8 |
3 files changed, 80 insertions, 40 deletions
diff --git a/App/Main.cpp b/App/Main.cpp index 2484577..b018892 100644 --- a/App/Main.cpp +++ b/App/Main.cpp | |||
@@ -4,70 +4,103 @@ | |||
4 | 4 | ||
5 | #include <cassert> | 5 | #include <cassert> |
6 | #include <iostream> | 6 | #include <iostream> |
7 | #include <string> | ||
8 | #include <thread> | ||
7 | 9 | ||
8 | #include "Memory.h" | 10 | #include "Memory.h" |
11 | class Randomizer { | ||
12 | public: | ||
13 | Randomizer(const std::shared_ptr<Memory>&) {} | ||
14 | void Randomize() { | ||
15 | std::this_thread::sleep_for(std::chrono::milliseconds(1000)); | ||
16 | } | ||
17 | }; | ||
9 | 18 | ||
10 | #define EXE_NAME L"witness64_d3d11.exe" | 19 | #define EXE_NAME L"witness64_d3d11.exe" |
11 | |||
12 | #define PROC_ATTACH 0x401 | 20 | #define PROC_ATTACH 0x401 |
13 | #define IDC_TOGGLESPEED 0x402 | 21 | #define RANDOMIZE_READY 0x402 |
14 | #define IDC_SPEEDRUNNER 0x403 | 22 | #define RANDOMIZING 0403 |
15 | #define IDC_HARDMODE 0x404 | 23 | #define RANDOMIZE_DONE 0x404 |
16 | #define IDC_READ 0x405 | 24 | #define CHECK_NEWGAME 0x405 |
17 | #define IDC_RANDOM 0x406 | ||
18 | #define IDC_WRITE 0x407 | ||
19 | #define IDC_DUMP 0x408 | ||
20 | #define IDT_RANDOMIZED 0x409 | ||
21 | #define IDC_TOGGLELASERS 0x410 | ||
22 | #define IDC_TOGGLESNIPES 0x411 | ||
23 | 25 | ||
24 | // Globals | 26 | // Globals |
25 | HWND g_hwnd; | 27 | HWND g_hwnd; |
28 | HWND g_seed; | ||
29 | HWND g_randomizerStatus; | ||
26 | HINSTANCE g_hInstance; | 30 | HINSTANCE g_hInstance; |
27 | auto g_witnessProc = std::make_shared<Memory>(); | 31 | auto g_witnessProc = std::make_shared<Memory>(); |
32 | std::shared_ptr<Randomizer> g_randomizer; | ||
33 | |||
34 | // Notifications I need: | ||
35 | // Game shutdown | ||
36 | // Load game? | ||
28 | 37 | ||
29 | LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { | 38 | LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { |
30 | if (message == WM_DESTROY) { | 39 | if (message == WM_DESTROY) { |
31 | PostQuitMessage(0); | 40 | PostQuitMessage(0); |
32 | } else if (message == WM_COMMAND) { | 41 | } else if (message == WM_COMMAND || message == WM_TIMER) { |
33 | switch (LOWORD(wParam)) { | 42 | switch (LOWORD(wParam)) { |
34 | case PROC_ATTACH: | 43 | case PROC_ATTACH: |
35 | if (!g_witnessProc->Initialize(EXE_NAME)) { | 44 | if (!g_witnessProc->Initialize(EXE_NAME)) { |
36 | OutputDebugString(L"Failed to initialize, trying again in 5 seconds"); | 45 | SetTimer(g_hwnd, PROC_ATTACH, 1000, NULL); // Retry in 1s |
37 | SetTimer(g_hwnd, PROC_ATTACH, 5000, NULL); // Re-attach in 10s | 46 | } else { |
47 | g_randomizer = std::make_shared<Randomizer>(g_witnessProc); | ||
48 | PostMessage(g_hwnd, WM_COMMAND, RANDOMIZE_READY, NULL); | ||
49 | SetTimer(g_hwnd, CHECK_NEWGAME, 1000, NULL); // Start checking for new game | ||
50 | } | ||
51 | break; | ||
52 | case CHECK_NEWGAME: | ||
53 | if (g_witnessProc) { | ||
54 | // It shouldn't be possible to pause earlier than this, so subsequent checks will fail. | ||
55 | if (g_witnessProc->GetCurrentFrame() < 80) { // New game | ||
56 | SetWindowText(g_seed, L""); | ||
57 | PostMessage(g_hwnd, WM_COMMAND, RANDOMIZE_READY, NULL); | ||
58 | } | ||
59 | SetTimer(g_hwnd, CHECK_NEWGAME, 1000, NULL); // Continue checking for new game | ||
38 | } | 60 | } |
39 | break; | 61 | break; |
40 | case IDC_TOGGLELASERS: | 62 | case RANDOMIZE_READY: |
41 | OutputDebugString(L"Hello, world!"); | 63 | SetWindowText(g_randomizerStatus, L"Randomize"); |
64 | EnableWindow(g_randomizerStatus, TRUE); | ||
65 | break; | ||
66 | case RANDOMIZING: | ||
67 | if (!g_randomizer) break; | ||
68 | SetWindowText(g_randomizerStatus, L"Randomizing..."); | ||
69 | std::thread([]{ | ||
70 | g_randomizer->Randomize(); | ||
71 | PostMessage(g_hwnd, WM_COMMAND, RANDOMIZE_DONE, NULL); | ||
72 | }).detach(); | ||
73 | break; | ||
74 | case RANDOMIZE_DONE: | ||
75 | SetWindowText(g_randomizerStatus, L"Randomized!"); | ||
42 | break; | 76 | break; |
43 | default: | 77 | default: |
44 | assert(false); | ||
45 | break; | 78 | break; |
46 | } | 79 | } |
47 | } | 80 | } |
48 | return DefWindowProc(hwnd, message, wParam, lParam); | 81 | return DefWindowProc(hwnd, message, wParam, lParam); |
49 | } | 82 | } |
50 | 83 | ||
51 | void CreateLabel(int x, int y, int width, LPCWSTR text) { | 84 | HWND CreateLabel(int x, int y, int width, LPCWSTR text) { |
52 | CreateWindow(L"STATIC", text, | 85 | return CreateWindow(L"STATIC", text, |
53 | WS_TABSTOP | WS_VISIBLE | WS_CHILD | SS_LEFT, | 86 | WS_TABSTOP | WS_VISIBLE | WS_CHILD | SS_LEFT, |
54 | x, y, width, 16, g_hwnd, NULL, g_hInstance, NULL); | 87 | x, y, width, 16, g_hwnd, NULL, g_hInstance, NULL); |
55 | } | 88 | } |
56 | 89 | ||
57 | void CreateButton(int x, int y, int width, LPCWSTR text, int message) { | 90 | HWND CreateButton(int x, int y, int width, LPCWSTR text, int message) { |
58 | #pragma warning(push) | 91 | #pragma warning(push) |
59 | #pragma warning(disable: 4312) | 92 | #pragma warning(disable: 4312) |
60 | CreateWindow(L"BUTTON", text, | 93 | return CreateWindow(L"BUTTON", text, |
61 | WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, | 94 | WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, |
62 | x, y, width, 26, g_hwnd, (HMENU)message, g_hInstance, NULL); | 95 | x, y, width, 26, g_hwnd, (HMENU)message, g_hInstance, NULL); |
63 | #pragma warning(pop) | 96 | #pragma warning(pop) |
64 | } | 97 | } |
65 | 98 | ||
66 | /* | 99 | HWND CreateText(int x, int y, int width, LPCWSTR defaultText = L"") { |
67 | hwndSeed = CreateWindow(MSFTEDIT_CLASS, L"", | 100 | return CreateWindow(MSFTEDIT_CLASS, L"", |
68 | WS_TABSTOP | WS_VISIBLE | WS_CHILD | WS_BORDER, | 101 | WS_TABSTOP | WS_VISIBLE | WS_CHILD | WS_BORDER, |
69 | 100, 10, 50, 26, hwnd, NULL, hInstance, NULL); | 102 | x, y, width, 26, g_hwnd, NULL, g_hInstance, NULL); |
70 | */ | 103 | } |
71 | 104 | ||
72 | int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { | 105 | int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { |
73 | LoadLibrary(L"Msftedit.dll"); | 106 | LoadLibrary(L"Msftedit.dll"); |
@@ -93,7 +126,9 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance | |||
93 | rect.right - 550, 200, 500, 500, nullptr, nullptr, hInstance, nullptr); | 126 | rect.right - 550, 200, 500, 500, nullptr, nullptr, hInstance, nullptr); |
94 | 127 | ||
95 | CreateLabel(390, 15, 90, L"Version: " VERSION_STR); | 128 | CreateLabel(390, 15, 90, L"Version: " VERSION_STR); |
96 | CreateButton(10, 72, 100, L"Button text", IDC_TOGGLELASERS); | 129 | g_seed = CreateText(10, 10, 100); |
130 | g_randomizerStatus = CreateButton(120, 10, 100, L"Randomize", RANDOMIZING); | ||
131 | EnableWindow(g_randomizerStatus, FALSE); | ||
97 | PostMessage(g_hwnd, WM_COMMAND, PROC_ATTACH, NULL); | 132 | PostMessage(g_hwnd, WM_COMMAND, PROC_ATTACH, NULL); |
98 | 133 | ||
99 | ShowWindow(g_hwnd, nCmdShow); | 134 | ShowWindow(g_hwnd, nCmdShow); |
diff --git a/Source/Memory.cpp b/Source/Memory.cpp index 1f1ae0a..d7f0212 100644 --- a/Source/Memory.cpp +++ b/Source/Memory.cpp | |||
@@ -2,6 +2,7 @@ | |||
2 | #include <psapi.h> | 2 | #include <psapi.h> |
3 | #include <tlhelp32.h> | 3 | #include <tlhelp32.h> |
4 | #include <iostream> | 4 | #include <iostream> |
5 | #include <cassert> | ||
5 | 6 | ||
6 | #undef PROCESSENTRY32 | 7 | #undef PROCESSENTRY32 |
7 | #undef Process32Next | 8 | #undef Process32Next |
@@ -53,15 +54,15 @@ Memory::~Memory() { | |||
53 | } | 54 | } |
54 | } | 55 | } |
55 | 56 | ||
56 | int Memory::GetCurrentFrame() | 57 | int Memory::GetCurrentFrame() { |
57 | { | ||
58 | int SCRIPT_FRAMES; | 58 | int SCRIPT_FRAMES; |
59 | if (GLOBALS == 0x5B28C0) { | 59 | if (GLOBALS == 0x5B28C0) { |
60 | SCRIPT_FRAMES = 0x5BE3B0; | 60 | SCRIPT_FRAMES = 0x5BE3B0; |
61 | } else if (GLOBALS == 0x62D0A0) { | 61 | } else if (GLOBALS == 0x62D0A0) { |
62 | SCRIPT_FRAMES = 0x63651C; | 62 | SCRIPT_FRAMES = 0x63954C; |
63 | } else { | 63 | } else { |
64 | throw std::exception("Unknown value for Globals!"); | 64 | assert(false); |
65 | return 0x7FFFFFFF; | ||
65 | } | 66 | } |
66 | return ReadData<int>({SCRIPT_FRAMES}, 1)[0]; | 67 | return ReadData<int>({SCRIPT_FRAMES}, 1)[0]; |
67 | } | 68 | } |
@@ -108,14 +109,15 @@ int Memory::ExecuteSigScans() | |||
108 | } | 109 | } |
109 | 110 | ||
110 | void Memory::ThrowError() { | 111 | void Memory::ThrowError() { |
111 | std::string message(256, '\0'); | 112 | std::wstring message(256, '\0'); |
112 | int length = FormatMessageA(4096, nullptr, GetLastError(), 1024, &message[0], static_cast<DWORD>(message.size()), nullptr); | 113 | int length = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), 1024, &message[0], static_cast<DWORD>(message.size()), nullptr); |
113 | message.resize(length); | 114 | message.resize(length); |
114 | throw std::exception(message.c_str()); | 115 | #ifndef NDEBUG |
116 | MessageBox(NULL, message.c_str(), L"Please tell darkid about this", MB_OK); | ||
117 | #endif | ||
115 | } | 118 | } |
116 | 119 | ||
117 | void* Memory::ComputeOffset(std::vector<int> offsets) | 120 | void* Memory::ComputeOffset(std::vector<int> offsets) { |
118 | { | ||
119 | // Leave off the last offset, since it will be either read/write, and may not be of type unitptr_t. | 121 | // Leave off the last offset, since it will be either read/write, and may not be of type unitptr_t. |
120 | int final_offset = offsets.back(); | 122 | int final_offset = offsets.back(); |
121 | offsets.pop_back(); | 123 | offsets.pop_back(); |
@@ -128,7 +130,10 @@ void* Memory::ComputeOffset(std::vector<int> offsets) | |||
128 | if (search == std::end(_computedAddresses)) { | 130 | if (search == std::end(_computedAddresses)) { |
129 | // If the address is not yet computed, then compute it. | 131 | // If the address is not yet computed, then compute it. |
130 | uintptr_t computedAddress = 0; | 132 | uintptr_t computedAddress = 0; |
131 | if (!ReadProcessMemory(_handle, reinterpret_cast<LPVOID>(cumulativeAddress), &computedAddress, sizeof(uintptr_t), NULL)) { | 133 | if (bool result = !ReadProcessMemory(_handle, reinterpret_cast<LPVOID>(cumulativeAddress), &computedAddress, sizeof(uintptr_t), NULL)) { |
134 | if (GetLastError() == ERROR_PARTIAL_COPY) { | ||
135 | int k = 1; | ||
136 | } | ||
132 | ThrowError(); | 137 | ThrowError(); |
133 | } | 138 | } |
134 | _computedAddresses[cumulativeAddress] = computedAddress; | 139 | _computedAddresses[cumulativeAddress] = computedAddress; |
diff --git a/Source/Memory.h b/Source/Memory.h index 9c00dab..f70de6a 100644 --- a/Source/Memory.h +++ b/Source/Memory.h | |||
@@ -11,8 +11,7 @@ | |||
11 | // http://stackoverflow.com/q/32798185 | 11 | // http://stackoverflow.com/q/32798185 |
12 | // http://stackoverflow.com/q/36018838 | 12 | // http://stackoverflow.com/q/36018838 |
13 | // http://stackoverflow.com/q/1387064 | 13 | // http://stackoverflow.com/q/1387064 |
14 | class Memory | 14 | class Memory { |
15 | { | ||
16 | public: | 15 | public: |
17 | Memory(); | 16 | Memory(); |
18 | bool Initialize(const std::wstring& processName); | 17 | bool Initialize(const std::wstring& processName); |
@@ -46,11 +45,12 @@ public: | |||
46 | void AddSigScan(const std::vector<byte>& scanBytes, const std::function<void(int index)>& scanFunc); | 45 | void AddSigScan(const std::vector<byte>& scanBytes, const std::function<void(int index)>& scanFunc); |
47 | int ExecuteSigScans(); | 46 | int ExecuteSigScans(); |
48 | 47 | ||
49 | void ClearOffsets() {_computedAddresses = std::map<uintptr_t, uintptr_t>();} | ||
50 | |||
51 | private: | 48 | private: |
52 | template<class T> | 49 | template<class T> |
53 | std::vector<T> ReadData(const std::vector<int>& offsets, size_t numItems) { | 50 | std::vector<T> ReadData(const std::vector<int>& offsets, size_t numItems) { |
51 | if (GetExitCodeProcess(_process) != STILL_ACTIVE) { | ||
52 | // Signal error, somehow | ||
53 | } | ||
54 | std::vector<T> data; | 54 | std::vector<T> data; |
55 | data.resize(numItems); | 55 | data.resize(numItems); |
56 | for (int i=0; i<5; i++) { | 56 | for (int i=0; i<5; i++) { |