From 4ad724eaae7be3780b5fb891b391bbf4ef26f410 Mon Sep 17 00:00:00 2001
From: jbzdarkid <jbzdarkid@gmail.com>
Date: Sun, 9 Dec 2018 11:48:17 -0800
Subject: Improve internals of sigscanning, fix a small overwrite bug

---
 Source/ChallengeRandomizer.cpp | 265 +++++++++++++++--------------------------
 Source/Memory.cpp              |  37 +++++-
 Source/Memory.h                |   8 +-
 Source/Randomizer.cpp          |   5 +
 Source/Randomizer.h            |   4 -
 5 files changed, 142 insertions(+), 177 deletions(-)

diff --git a/Source/ChallengeRandomizer.cpp b/Source/ChallengeRandomizer.cpp
index 44886b7..fcd4e4a 100644
--- a/Source/ChallengeRandomizer.cpp
+++ b/Source/ChallengeRandomizer.cpp
@@ -1,21 +1,6 @@
 #include "ChallengeRandomizer.h"
 #include <iostream>
 
-int find(const std::vector<byte> &data, const std::vector<byte>& search, size_t startIndex = 0) {
-	for (size_t i=startIndex; i<data.size() - search.size(); i++) {
-		bool match = true;
-		for (size_t j=0; j<search.size(); j++) {
-			if (data[i+j] == search[j]) {
-				continue;
-			}
-			match = false;
-			break;
-		}
-		if (match) return static_cast<int>(i);
-	}
-	return -1;
-}
-
 // Reads the (relative!) address of the RNG, then shifts it to point at RNG2
 void ChallengeRandomizer::AdjustRng(int offset) {
 	int currentRng = _memory->ReadData<int>({offset}, 0x1)[0];
@@ -33,164 +18,104 @@ ChallengeRandomizer::ChallengeRandomizer(const std::shared_ptr<Memory>& memory,
 	if (!alreadyInjected) _memory->WriteData<int>({GLOBALS + 0x30}, {RNG_ADDR + 4});
 	_memory->WriteData<int>({GLOBALS + 0x30, 0}, {seed});
 
-	int do_success_side_effects = -1;
-	int reveal_exit_hall = -1;
-	int begin_endgame_1 = -1;
-
-	_memory->SigScan([&](int offset, const std::vector<byte>& data) {
-		// This injection ensures that the seed is set every time the challenge is started.
-		// We always do this sigscan since it affects the seed.
-		if (do_success_side_effects == -1) {
-			int index = find(data, {0xFF, 0xC8, 0x99, 0x2B, 0xC2, 0xD1, 0xF8, 0x8B, 0xD0});
-			if (index != -1) {
-				do_success_side_effects = offset + index + 0x3E;
-				if (GLOBALS == 0x62A080) do_success_side_effects += 4; // There's an extra 4 opcodes in the new version
-				_memory->WriteData<byte>({do_success_side_effects}, {
-					0x8B, 0x0D, 0x00, 0x00, 0x00, 0x00,			// mov ecx, [0x00000000] ;This is going to be the address of the custom RNG
-					0x67, 0xC7, 0x01, 0x00, 0x00, 0x00, 0x00,	// mov dword ptr ds:[ecx], 0x00000000 ;This is going to be the seed value
-					0x48, 0x83, 0xF8, 0x02,						// cmp rax, 0x2 ;This is the short solve on the record player (which turns it off)
-					0x90, 0x90, 0x90							// nop nop nop
-				});
-				int target = (GLOBALS + 0x30) - (do_success_side_effects + 0x6); // +6 is for the length of the line
-				_memory->WriteData<int>({do_success_side_effects + 0x2}, {target});
-				_memory->WriteData<int>({do_success_side_effects + 0x9}, {seed});
-			}
-		}
-
-		// BLEH.
-		if (reveal_exit_hall == -1) {
-			int index = find(data, {0x45, 0x8B, 0xF7, 0x48, 0x8B, 0x4D});
-			if (index != -1) {
-				reveal_exit_hall = offset + index;
-				_memory->WriteData<byte>({reveal_exit_hall + 0x15}, {0xEB});
-			}
-		}
-		if (begin_endgame_1 == -1) {
-			int index = find(data, {0x83, 0x7C, 0x01, 0xD0, 0x04});
-			if (index != -1) {
-				begin_endgame_1 = offset + index;
-				if (GLOBALS == 0x5B28C0) { // Version differences :/
-					begin_endgame_1 += 0x75;
-				} else if (GLOBALS == 0x62A080) {
-					begin_endgame_1 += 0x86;
-				}
-				_memory->WriteData<byte>({begin_endgame_1}, {0xEB});
-			}
-		}
+	// do_success_side_effects
+	_memory->AddSigScan({0xFF, 0xC8, 0x99, 0x2B, 0xC2, 0xD1, 0xF8, 0x8B, 0xD0}, [&](int index) {
+		if (GLOBALS == 0x5B28C0) { // Version differences
+			index += 0x3E;
+		} else if (GLOBALS == 0x62A080) {
+			index += 0x42;
+		}
+		_memory->WriteData<byte>({index}, {
+			0x8B, 0x0D, 0x00, 0x00, 0x00, 0x00,			// mov ecx, [0x00000000] ;This is going to be the address of the custom RNG
+			0x67, 0xC7, 0x01, 0x00, 0x00, 0x00, 0x00,	// mov dword ptr ds:[ecx], 0x00000000 ;This is going to be the seed value
+			0x48, 0x83, 0xF8, 0x02,						// cmp rax, 0x2 ;This is the short solve on the record player (which turns it off)
+			0x90, 0x90, 0x90							// nop nop nop
+		});
+		int target = (GLOBALS + 0x30) - (index + 0x6); // +6 is for the length of the line
+		_memory->WriteData<int>({index + 0x2}, {target});
+		_memory->WriteData<int>({index + 0x9}, {seed});
 	});
 
-	if (!alreadyInjected) HandleSigScans();
-}
+	// reveal_exit_hall
+	_memory->AddSigScan({0x45, 0x8B, 0xF7, 0x48, 0x8B, 0x4D}, [&](int index){
+		_memory->WriteData<byte>({index + 0x15}, {0xEB});
+	});
 
-void ChallengeRandomizer::HandleSigScans() {
-	static int shuffle_integers = -1;
-	static int shuffle_int = -1;
-	static int cut_random_edges = -1;
-	static int get_empty_decoration_slot = -1;
-	static int get_empty_dot_spot = -1;
-	static int add_exactly_this_many_bisection_dots = -1;
-	static int make_a_shaper = -1;
-	static int init_pattern_data_lotus = -1;
-	static int reroll_lotus_eater_stuff = -1;
-	static int do_lotus_minutes = -1;
-	static int do_lotus_tenths = -1;
-	static int do_lotus_eighths = -1;
+	// begin_endgame_1
+	_memory->AddSigScan({0x83, 0x7C, 0x01, 0xD0, 0x04}, [&](int index){
+		if (GLOBALS == 0x5B28C0) { // Version differences
+			index += 0x75;
+		} else if (GLOBALS == 0x62A080) {
+			index += 0x86;
+		}
+		_memory->WriteData<byte>({index}, {0xEB});
+	});
 
-	_memory->SigScan([&](int offset, const std::vector<byte>& data) {
-		if (shuffle_integers == -1) {
-			int index = find(data, {0x48, 0x89, 0x5C, 0x24, 0x10, 0x56, 0x48, 0x83, 0xEC, 0x20, 0x48, 0x63, 0xDA, 0x48, 0x8B, 0xF1, 0x83, 0xFB, 0x01});
-			if (index != -1) {
-				shuffle_integers = offset + index;
-				AdjustRng(shuffle_integers + 0x23);
-			}
-		}
+	if (!alreadyInjected) {
+		// shuffle_integers
+		_memory->AddSigScan({0x48, 0x89, 0x5C, 0x24, 0x10, 0x56, 0x48, 0x83, 0xEC, 0x20, 0x48, 0x63, 0xDA, 0x48, 0x8B, 0xF1, 0x83, 0xFB, 0x01}, [&](int index) {
+			AdjustRng(index + 0x23);
+		});
 		// shuffle<int>
-		if (shuffle_int == -1) {
-			int index = find(data, {0x33, 0xF6, 0x48, 0x8B, 0xD9, 0x39, 0x31, 0x7E, 0x51});
-			if (index != -1) {
-				shuffle_int = offset + index - 0x16;
-				AdjustRng(shuffle_int + 0x12);
-			}
-		}
-		if (cut_random_edges == -1) {
-			int index = find(data, {0x89, 0x44, 0x24, 0x3C, 0x33, 0xC0, 0x85, 0xC0, 0x75, 0xFA});
-			if (index != -1) {
-				cut_random_edges = offset + index - 0x22;
-				AdjustRng(cut_random_edges + 0x5D);
-			}
-		}
-		if (get_empty_decoration_slot == -1) {
-			int index = find(data, {0x42, 0x83, 0x3C, 0x80, 0x00, 0x75, 0xDF});
-			if (index != -1) {
-				get_empty_decoration_slot = offset + index - 0x2D;
-				AdjustRng(get_empty_decoration_slot + 0x16);
-			}
-		}
-		if (get_empty_dot_spot == -1) {
-			int index = find(data, {0xF7, 0xF3, 0x85, 0xD2, 0x74, 0xEC});
-			if (index != -1) {
-				get_empty_dot_spot = offset + index - 0x2E;
-				AdjustRng(get_empty_dot_spot + 0x23);
-			}
-		}
-		if (add_exactly_this_many_bisection_dots == -1) {
-			int index = find(data, {0x48, 0x8B, 0xB4, 0x24, 0xB8, 0x00, 0x00, 0x00, 0x48, 0x8B, 0xBC, 0x24, 0xB0, 0x00, 0x00, 0x00});
-			if (index != -1) {
-				add_exactly_this_many_bisection_dots = offset + index - 0x20;
-				AdjustRng(add_exactly_this_many_bisection_dots + 0x1C);
-			}
-		}
-		if (make_a_shaper == -1) {
-			int index = find(data, {0xF7, 0xE3, 0xD1, 0xEA, 0x8D, 0x0C, 0x52});
-			if (index != -1) {
-				make_a_shaper = offset + index - 0x19;
-				AdjustRng(make_a_shaper + 0x9);
-				AdjustRng(make_a_shaper + 0x35);
-				AdjustRng(make_a_shaper + 0x62);
-			}
-		}
-		if (/*Entity_Machine_Panel::*/init_pattern_data_lotus == -1) {
-			int index = find(data, {0x40, 0x55, 0x56, 0x48, 0x8D, 0x6C, 0x24, 0xB1});
-			if (index != -1) {
-				init_pattern_data_lotus = offset + index;
-				AdjustRng(init_pattern_data_lotus + 0x433);
-				AdjustRng(init_pattern_data_lotus + 0x45B);
-				AdjustRng(init_pattern_data_lotus + 0x5A7);
-				AdjustRng(init_pattern_data_lotus + 0x5D6);
-				AdjustRng(init_pattern_data_lotus + 0x6F6);
-				AdjustRng(init_pattern_data_lotus + 0xD17);
-				AdjustRng(init_pattern_data_lotus + 0xFDA);
-			}
-		}
-		if (/*Entity_Record_Player::*/reroll_lotus_eater_stuff == -1) {
-			int index = find(data, {0xB8, 0xAB, 0xAA, 0xAA, 0xAA, 0x41, 0xC1, 0xE8});
-			if (index != -1) {
-				reroll_lotus_eater_stuff = offset + index - 0x37;
-				AdjustRng(reroll_lotus_eater_stuff + 0x24);
-				AdjustRng(reroll_lotus_eater_stuff + 0x6B);
-			}
-		}
+		_memory->AddSigScan({0x33, 0xF6, 0x48, 0x8B, 0xD9, 0x39, 0x31, 0x7E, 0x51}, [&](int index) {
+			AdjustRng(index - 0x4);
+		});
+		// cut_random_edges
+		_memory->AddSigScan({0x89, 0x44, 0x24, 0x3C, 0x33, 0xC0, 0x85, 0xC0, 0x75, 0xFA}, [&](int index) {
+			AdjustRng(index + 0x3B);
+		});
+		// get_empty_decoration_slot
+		_memory->AddSigScan({0x42, 0x83, 0x3C, 0x80, 0x00, 0x75, 0xDF}, [&](int index) {
+			AdjustRng(index - 0x17);
+		});
+		// get_empty_dot_spot
+		_memory->AddSigScan({0xF7, 0xF3, 0x85, 0xD2, 0x74, 0xEC}, [&](int index) {
+			AdjustRng(index - 0xB);
+		});
+		// add_exactly_this_many_bisection_dots
+		_memory->AddSigScan({0x48, 0x8B, 0xB4, 0x24, 0xB8, 0x00, 0x00, 0x00, 0x48, 0x8B, 0xBC, 0x24, 0xB0, 0x00, 0x00, 0x00}, [&](int index) {
+			AdjustRng(index - 0x4);
+		});
+		// make_a_shaper
+		_memory->AddSigScan({0xF7, 0xE3, 0xD1, 0xEA, 0x8D, 0x0C, 0x52}, [&](int index) {
+			AdjustRng(index - 0x10);
+			AdjustRng(index + 0x1C);
+			AdjustRng(index + 0x49);
+		});
+		// Entity_Machine_Panel::init_pattern_data_lotus
+		_memory->AddSigScan({0x40, 0x55, 0x56, 0x48, 0x8D, 0x6C, 0x24, 0xB1}, [&](int index) {
+			AdjustRng(index + 0x433);
+			AdjustRng(index + 0x45B);
+			AdjustRng(index + 0x5A7);
+			AdjustRng(index + 0x5D6);
+			AdjustRng(index + 0x6F6);
+			AdjustRng(index + 0xD17);
+			AdjustRng(index + 0xFDA);
+		});
+		// Entity_Record_Player::reroll_lotus_eater_stuff
+		_memory->AddSigScan({0xB8, 0xAB, 0xAA, 0xAA, 0xAA, 0x41, 0xC1, 0xE8}, [&](int index) {
+			AdjustRng(index - 0x52);
+			AdjustRng(index - 0xB);
+		});
+
 		// These disable the random locations on timer panels, which would otherwise increment the RNG.
-		if (do_lotus_minutes == -1) {
-			int index = find(data, {0x0F, 0xBE, 0x6C, 0x08, 0xFF, 0x45});
-			if (index != -1) {
-				do_lotus_minutes = offset + index - 0x2B;
-				_memory->WriteData<byte>({do_lotus_minutes + 0x43B}, {0x31, 0xC0, 0x90, 0x90, 0x90}); // xor eax, eax ;RNG returns 0
-			}
-		}
-		if (do_lotus_tenths == -1) {
-			int index = find(data, {0x00, 0x04, 0x00, 0x00, 0x41, 0x8D, 0x50, 0x09});
-			if (index != -1) {
-				do_lotus_tenths = offset + index - 0x61;
-				_memory->WriteData<byte>({do_lotus_tenths + 0x103}, {0x31, 0xC0, 0x90, 0x90, 0x90}); // xor eax, eax ;RNG returns 0
-			}
-		}
-		if (do_lotus_eighths == -1) {
-			int index = find(data, {0x75, 0xF5, 0x0F, 0xBE, 0x44, 0x08, 0xFF});
-			if (index != -1) {
-				do_lotus_eighths = offset + index - 0x39;
-				_memory->WriteData<byte>({do_lotus_eighths + 0x1E7}, {0x31, 0xC0, 0x90, 0x90, 0x90}); // xor eax, eax ;RNG returns 0
-			}
-		}
-	});
-}
\ No newline at end of file
+		// I'm writing 31 C0 (xor eax, eax), then 3 NOPs, which pretends the RNG returns 0.
+		// do_lotus_minutes
+		_memory->AddSigScan({0x0F, 0xBE, 0x6C, 0x08, 0xFF, 0x45}, [&](int index) {
+			_memory->WriteData<byte>({index + 0x410}, {0x31, 0xC0, 0x90, 0x90, 0x90});
+		});
+		// do_lotus_tenths
+		_memory->AddSigScan({0x00, 0x04, 0x00, 0x00, 0x41, 0x8D, 0x50, 0x09}, [&](int index) {
+			_memory->WriteData<byte>({index + 0xA2}, {0x31, 0xC0, 0x90, 0x90, 0x90});
+		});
+		// do_lotus_eighths
+		_memory->AddSigScan({0x75, 0xF5, 0x0F, 0xBE, 0x44, 0x08, 0xFF}, [&](int index) {
+			_memory->WriteData<byte>({index + 0x1AE}, {0x31, 0xC0, 0x90, 0x90, 0x90});
+		});
+	}
+
+	int failed = _memory->ExecuteSigScans();
+	if (failed != 0) {
+		std::cout << "Failed " << failed << " sigscans";
+	}
+}
diff --git a/Source/Memory.cpp b/Source/Memory.cpp
index 43cb9b3..2d0d4a9 100644
--- a/Source/Memory.cpp
+++ b/Source/Memory.cpp
@@ -63,12 +63,45 @@ int Memory::GetCurrentFrame()
 	return ReadData<int>({SCRIPT_FRAMES}, 1)[0];
 }
 
-void Memory::SigScan(std::function<void(int offset, const std::vector<byte>& data)> scanFunc)
+void Memory::AddSigScan(const std::vector<byte>& scanBytes, const std::function<void(int index)>& scanFunc)
+{
+	_sigScans[scanBytes] = {scanFunc, false};
+}
+
+int find(const std::vector<byte> &data, const std::vector<byte>& search, size_t startIndex = 0) {
+	for (size_t i=startIndex; i<data.size() - search.size(); i++) {
+		bool match = true;
+		for (size_t j=0; j<search.size(); j++) {
+			if (data[i+j] == search[j]) {
+				continue;
+			}
+			match = false;
+			break;
+		}
+		if (match) return static_cast<int>(i);
+	}
+	return -1;
+}
+
+int Memory::ExecuteSigScans()
 {
 	for (int i=0; i<0x200000; i+=0x1000) {
 		std::vector<byte> data = ReadData<byte>({i}, 0x1100);
-		scanFunc(i, data);
+		
+		for (auto& [scanBytes, sigScan] : _sigScans) {
+			if (sigScan.found) continue;
+			int index = find(data, scanBytes);
+			if (index == -1) continue;
+			sigScan.scanFunc(i + index);
+			sigScan.found = true;
+		}
+	}
+
+	int notFound = 0;
+	for (auto it : _sigScans) {
+		if (it.second.found == false) notFound++;
 	}
+	return notFound;
 }
 
 void Memory::ThrowError() {
diff --git a/Source/Memory.h b/Source/Memory.h
index e6110d8..fa9eb60 100644
--- a/Source/Memory.h
+++ b/Source/Memory.h
@@ -42,7 +42,8 @@ public:
 		WriteData<T>({GLOBALS, 0x18, panel*8, offset}, data);
 	}
 
-	void SigScan(std::function<void(int offset, const std::vector<byte>& data)> scanFunc);
+	void AddSigScan(const std::vector<byte>& scanBytes, const std::function<void(int index)>& scanFunc);
+	int ExecuteSigScans();
 
 	void ClearOffsets() {_computedAddresses = std::map<uintptr_t, uintptr_t>();}
 
@@ -78,6 +79,11 @@ private:
 	std::map<uintptr_t, uintptr_t> _computedAddresses;
 	uintptr_t _baseAddress = 0;
 	HANDLE _handle = nullptr;
+	struct SigScan {
+		std::function<void(int)> scanFunc;
+		bool found;
+	};
+	std::map<std::vector<byte>, SigScan> _sigScans;
 
 	friend class Temp;
 	friend class ChallengeRandomizer;
diff --git a/Source/Randomizer.cpp b/Source/Randomizer.cpp
index ae41bb7..3078b22 100644
--- a/Source/Randomizer.cpp
+++ b/Source/Randomizer.cpp
@@ -7,6 +7,11 @@
 
  * Speed up *everything* ? Or maybe we'll just stop using this setting entirely.
 
+ * Disable "power off on fail" for challenge
+ * Add setting for "Don't reset the challenge seed on new challenge"
+ * Don't rerandomize anything outside of challenge on re-click
+ * Change re-randomization prevention?
+
 
  * BUGS:
  * Shipwreck vault is solved reversed? -> Not reversed, just "half", you can normally solve orange. Seems to need pattern name.
diff --git a/Source/Randomizer.h b/Source/Randomizer.h
index 53e4149..c0b2d87 100644
--- a/Source/Randomizer.h
+++ b/Source/Randomizer.h
@@ -45,10 +45,6 @@ private:
 	void ReassignTargets(const std::vector<int>& panels, const std::vector<int>& order, std::vector<int> targets = {});
 	void ReassignNames(const std::vector<int>& panels, const std::vector<int>& order);
 
-	short ReadMetadata();
-	void WriteMetadata(short metadata);
-	int GetCurrentFrame();
-
 	std::shared_ptr<Memory> _memory = std::make_shared<Memory>("witness64_d3d11.exe");
 
 	friend class SwapTests_Shipwreck_Test;
-- 
cgit 1.4.1