Deploy site
@@ -4,9 +4,585 @@ <title>Lonami's Site - My Blog</title>
<link href="https://lonami.dev/blog/atom.xml" rel="self" type="application/atom+xml"/> <link href="https://lonami.dev/blog/"/> <generator uri="https://www.getzola.org/">Zola</generator> - <updated>2021-02-22T00:00:00+00:00</updated> + <updated>2021-03-06T00:00:00+00:00</updated> <id>https://lonami.dev/blog/atom.xml</id> <entry xml:lang="en"> + <title>Writing our own Cheat Engine: Code finder</title> + <published>2021-03-06T00:00:00+00:00</published> + <updated>2021-03-06T00:00:00+00:00</updated> + <link href="https://lonami.dev/blog/woce-5/" type="text/html"/> + <id>https://lonami.dev/blog/woce-5/</id> + <content type="html"><p>This is part 5 on the <em>Writing our own Cheat Engine</em> series:</p> +<ul> +<li><a href="/blog/woce-1">Part 1: Introduction</a> (start here if you're new to the series!)</li> +<li><a href="/blog/woce-2">Part 2: Exact Value scanning</a></li> +<li><a href="/blog/woce-3">Part 3: Unknown initial value</a></li> +<li><a href="/blog/woce-4">Part 4: Floating points</a></li> +<li>Part 5: Code finder</li> +</ul> +<p>In part 4 we spent a good deal of time trying to make our scans generic, and now we have something that works<sup class="footnote-reference"><a href="#1">1</a></sup>! Now that the scanning is fairly powerful and all covered, the Cheat Engine tutorial shifts focus into slightly more advanced techniques that you will most certainly need in anything bigger than a toy program.</p> +<p>It's time to write our very own <strong>debugger</strong> in Rust!</p> +<h2 id="code-finder">Code finder</h2> +<details open><summary>Cheat Engine Tutorial: Step 5</summary> +<blockquote> +<p>Sometimes the location something is stored at changes when you restart the game, or even while you're playing… In that case you can use 2 things to still make a table that works. In this step I'll try to describe how to use the Code Finder function.</p> +<p>The value down here will be at a different location each time you start the tutorial, so a normal entry in the address list wouldn't work. First try to find the address. (You've got to this point so I assume you know how to.)</p> +<p>When you've found the address, right-click the address in Cheat Engine and choose &quot;Find out what writes to this address&quot;. A window will pop up with an empty list.</p> +<p>Then click on the Change value button in this tutorial, and go back to Cheat Engine. If everything went right there should be an address with assembler code there now.</p> +<p>Click it and choose the replace option to replace it with code that does nothing. That will also add the code address to the code list in the advanced options window. (Which gets saved if you save your table.)</p> +<p>Click on stop, so the game will start running normal again, and close to close the window. Now, click on Change value, and if everything went right the Next button should become enabled.</p> +<p>Note: When you're freezing the address with a high enough speed it may happen that next becomes visible anyhow</p> +</blockquote> +</details> +<h2 id="baby-steps-to-debugging">Baby steps to debugging</h2> +<p>Although I have used debuggers before, I have never had a need to write one myself so it's time for some research.</p> +<p>Searching on DuckDuckGo, I can find entire series to <a href="http://system.joekain.com/debugger/">Writing a Debugger</a>. We would be done by now if only that series wasn't written for Linux. The Windows documentation contains a section called <a href="https://docs.microsoft.com/en-us/windows/win32/debug/creating-a-basic-debugger">Creating a Basic Debugger</a>, but as far as I can tell, it only teaches you the <a href="https://docs.microsoft.com/en-us/windows/win32/debug/debugging-functions">functions</a> needed to configure the debugging loop. Which mind you, we will need, but in due time.</p> +<p>According to <a href="https://www.gironsec.com/blog/2013/12/writing-your-own-debugger-windows-in-c/">Writing your own windows debugger in C</a>, the steps needed to write a debugger are:</p> +<ul> +<li><a href="https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-suspendthread"><code>SuspendThread(proc)</code></a>. It makes sense that we need to pause all the threads<sup class="footnote-reference"><a href="#2">2</a></sup> before messing around with the code the program is executing, or things are very prone to go wrong.</li> +<li><a href="https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadcontext"><code>GetThreadContext(proc)</code></a>. This function retrieves the appropriate context of the specified thread and is highly processor specific. It basically takes a snapshot of all the registers. Think of registers like extremely fast, but also extremely limited, memory the processor uses.</li> +<li><a href="https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-debugbreakprocess"><code>DebugBreakProcess</code></a>. Essentially <a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/x86-instructions#miscellaneous">writes out the 0xCC opcode</a>, <code>int 3</code> in assembly, also known as software breakpoint. It's written wherever the Register Instruction Pointer (RIP<sup class="footnote-reference"><a href="#3">3</a></sup>) currently points to, so in essence, when the thread resumes, it will immediately <a href="https://stackoverflow.com/q/3915511/">trigger the breakpoint</a>.</li> +<li><a href="https://docs.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-continuedebugevent"><code>ContinueDebugEvent</code></a>. Presumably continues debugging.</li> +</ul> +<p>There are pages documenting <a href="https://docs.microsoft.com/en-us/windows/win32/debug/debugging-events">all of the debug events</a> that our debugger will be able to handle.</p> +<p>Okay, nice! Software breakpoints seem to be done by writing out memory to the region where the program is reading instructions from. We know how to write memory, as that's what all the previous posts have been doing to complete the corresponding tutorial steps. After the breakpoint is executed, all we need to do is <a href="https://stackoverflow.com/q/3747852/">restore the original memory back</a> so that the next time the program executes the code it sees no difference.</p> +<p>But a software breakpoint will halt execution when the code executes the interrupt instruction. This step of the tutorial wants us to find <em>what writes to a memory location</em>. Where should we place the breakpoint to detect such location? Writing out the instruction to the memory we want to break in won't do; it's not an instruction, it's just data.</p> +<p>The name may have given it away. If we're talking about software breakpoints, it makes sense that there would exist such a thing as <a href="https://en.wikipedia.org/wiki/Breakpoint#Hardware"><em>hardware</em> breakpoints</a>. Because they're tied to the hardware, they're highly processor-specific, but luckily for us, the processor on your usual desktop computer probably has them! Even the <a href="https://interrupt.memfault.com/blog/cortex-m-breakpoints">cortex-m</a> does. The wikipedia page also tells us the name of the thing we're looking for, watchpoints:</p> +<blockquote> +<p>Other kinds of conditions can also be used, such as the reading, writing, or modification of a specific location in an area of memory. This is often referred to as a conditional breakpoint, a data breakpoint, or a watchpoint.</p> +</blockquote> +<p>A breakpoint that triggers when a specific memory location is written to is exactly what we need, and <a href="https://stackoverflow.com/a/19109153/">x86 has debug registers D0 to D3 to track memory addresses</a>. As far as I can tell, there is no API in specific to mess with the registers. But we don't need any of that! We can just go ahead and <a href="https://doc.rust-lang.org/stable/unstable-book/library-features/asm.html">write some assembly by hand</a> to access these registers. At the time of writing, inline assembly is unstable, so we need a nightly compiler. Run <code>rustup toolchain install nightly</code> if you haven't yet, and execute the following code with <code>cargo +nightly run</code>:</p> +<pre><code class="language-rust" data-lang="rust">#![feature(asm)] // top of the file + +fn main() { + let x: u64 = 123; + unsafe { + asm!(&quot;mov dr7, {}&quot;, in(reg) x); + } +} + +</code></pre> +<p><code>dr7</code> stands is the <a href="https://en.wikipedia.org/wiki/X86_debug_register">debug control register</a>, and running this we get…</p> +<pre><code>&gt;cargo +nightly run + Compiling memo v0.1.0 + Finished dev [unoptimized + debuginfo] target(s) in 0.74s + Running `target\debug\memo.exe` +error: process didn't exit successfully: `target\debug\memo.exe` (exit code: 0xc0000096, STATUS_PRIVILEGED_INSTRUCTION) +</code></pre> +<p>…an exception! In all fairness, I have no idea what that code would have done. So maybe the <code>STATUS_PRIVILEGED_INSTRUCTION</code> is just trying to protect us. Can we read from the register instead, and see it's default value?</p> +<pre><code class="language-rust" data-lang="rust">let x: u64; +unsafe { + asm!(&quot;mov {}, dr7&quot;, out(reg) x); +} +assert_eq!(x, 5); +</code></pre> +<pre><code>&gt;cargo +nightly run +... +error: process didn't exit successfully: `target\debug\memo.exe` (exit code: 0xc0000096, STATUS_PRIVILEGED_INSTRUCTION) +</code></pre> +<p>Nope. Okay, it seems directly reading from or writing to the debug register is a ring-0 thing. Surely there's a way around this. But first we should figure out how to enumerate and pause all the threads.</p> +<h2 id="pausing-all-the-threads">Pausing all the threads</h2> +<p>It seems there is no straightforward way to enumerate the threads. One has to <a href="https://stackoverflow.com/a/1206915/">create a &quot;toolhelp&quot;</a> and poll the entries. I won't bore you with the details. Let's add <code>tlhelp32</code> to the crate features of <code>winapi</code> and try it out:</p> +<pre><code class="language-rust" data-lang="rust"> +#[derive(Debug)] +pub struct Toolhelp { + handle: winapi::um::winnt::HANDLE, +} + +impl Drop for Toolhelp { + fn drop(&amp;mut self) { + unsafe { winapi::um::handleapi::CloseHandle(self.handle) }; + } +} + +pub fn enum_threads(pid: u32) -&gt; io::Result&lt;Vec&lt;u32&gt;&gt; { + const ENTRY_SIZE: u32 = mem::size_of::&lt;winapi::um::tlhelp32::THREADENTRY32&gt;() as u32; + + // size_of(dwSize + cntUsage + th32ThreadID + th32OwnerProcessID) + const NEEDED_ENTRY_SIZE: u32 = 4 * mem::size_of::&lt;DWORD&gt;() as u32; + + // SAFETY: it is always safe to attempt to call this function. + let handle = unsafe { + winapi::um::tlhelp32::CreateToolhelp32Snapshot(winapi::um::tlhelp32::TH32CS_SNAPTHREAD, 0) + }; + if handle == winapi::um::handleapi::INVALID_HANDLE_VALUE { + return Err(io::Error::last_os_error()); + } + let toolhelp = Toolhelp { handle }; + + let mut result = Vec::new(); + let mut entry = winapi::um::tlhelp32::THREADENTRY32 { + dwSize: ENTRY_SIZE, + cntUsage: 0, + th32ThreadID: 0, + th32OwnerProcessID: 0, + tpBasePri: 0, + tpDeltaPri: 0, + dwFlags: 0, + }; + + // SAFETY: we have a valid handle, and point to memory we own with the right size. + if unsafe { winapi::um::tlhelp32::Thread32First(toolhelp.handle, &amp;mut entry) } != FALSE { + loop { + if entry.dwSize &gt;= NEEDED_ENTRY_SIZE &amp;&amp; entry.th32OwnerProcessID == pid { + result.push(entry.th32ThreadID); + } + + entry.dwSize = ENTRY_SIZE; + // SAFETY: we have a valid handle, and point to memory we own with the right size. + if unsafe { winapi::um::tlhelp32::Thread32Next(toolhelp.handle, &amp;mut entry) } == FALSE { + break; + } + } + } + + Ok(result) +} +</code></pre> +<p>Annoyingly, invalid handles returned by <a href="https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot"><code>CreateToolhelp32Snapshot</code></a>, are <code>INVALID_HANDLE_VALUE</code> (which is -1), not null. But that's not a big deal, we simply can't use <code>NonNull</code> here. The function ignores the process identifier when using <code>TH32CS_SNAPTHREAD</code>, used to include all threads, and we need to compare the process identifier ourselves.</p> +<p>In summary, we create a &quot;toolhelp&quot; (wrapped in a helper <code>struct</code> so that whatever happens, <code>Drop</code> will clean it up), initialize a thread enntry (with everything but the structure size to zero) and call <code>Thread32First</code> the first time, <code>Thread32Next</code> subsequent times. It seems to work all fine!</p> +<pre><code class="language-rust" data-lang="rust">dbg!(process::enum_threads(pid)); +</code></pre> +<pre><code>[src\main.rs:46] process::enum_threads(pid) = Ok( + [ + 10560, + ], +) +</code></pre> +<p>According to this, the Cheat Engine tutorial is only using one thread. Good to know. Much like processes, threads need to be opened before we can use them, with <a href="https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openthread"><code>OpenThread</code></a>:</p> +<pre><code class="language-rust" data-lang="rust">pub struct Thread { + tid: u32, + handle: NonNull&lt;c_void&gt;, +} + +impl Thread { + pub fn open(tid: u32) -&gt; io::Result&lt;Self&gt; { + // SAFETY: the call doesn't have dangerous side-effects + NonNull::new(unsafe { + winapi::um::processthreadsapi::OpenThread( + winapi::um::winnt::THREAD_SUSPEND_RESUME, + FALSE, + tid, + ) + }) + .map(|handle| Self { tid, handle }) + .ok_or_else(io::Error::last_os_error) + } + + pub fn tid(&amp;self) -&gt; u32 { + self.tid + } +} + +impl Drop for Thread { + fn drop(&amp;mut self) { + unsafe { winapi::um::handleapi::CloseHandle(self.handle.as_mut()) }; + } +} +</code></pre> +<p>Just your usual RAII pattern. The thread is opened with permission to suspend and resume it. Let's try to pause the handles with <a href="https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-suspendthread"><code>SuspendThread</code></a> to make sure that this thread is actually the one we're looking for:</p> +<pre><code class="language-rust" data-lang="rust">pub fn suspend(&amp;mut self) -&gt; io::Result&lt;usize&gt; { + // SAFETY: the handle is valid. + let ret = unsafe { + winapi::um::processthreadsapi::SuspendThread(self.handle.as_ptr()) + }; + if ret == -1i32 as u32 { + Err(io::Error::last_os_error()) + } else { + Ok(ret as usize) + } +} + +pub fn resume(&amp;mut self) -&gt; io::Result&lt;usize&gt; { + // SAFETY: the handle is valid. + let ret = unsafe { + winapi::um::processthreadsapi::ResumeThread(self.handle.as_ptr()) + }; + if ret == -1i32 as u32 { + Err(io::Error::last_os_error()) + } else { + Ok(ret as usize) + } +} +</code></pre> +<p>Both suspend and resume return the previous &quot;suspend count&quot;. It's kind of like a barrier or semaphore where the thread only runs if the suspend count is zero. Trying it out:</p> +<pre><code class="language-rust" data-lang="rust">let mut threads = thread::enum_threads(pid) + .unwrap() + .into_iter() + .map(Thread::open) + .collect::&lt;Result&lt;Vec&lt;_&gt;, _&gt;&gt;() + .unwrap(); + +threads + .iter_mut() + .for_each(|thread| { + println!(&quot;Pausing thread {} for 10 seconds…&quot;, thread.tid()); + thread.suspend().unwrap(); + + std::thread::sleep(std::time::Duration::from_secs(10)); + + println!(&quot;Wake up, {}!&quot;, thread.tid()); + thread.resume().unwrap(); + }); +</code></pre> +<p>If you run this code with the process ID of the Cheat Engine tutorial, you will see that the tutorial window freezes for ten seconds! Because the main and only thread is paused, it cannot process any window events, so it becomes unresponsive. It is now &quot;safe&quot; to mess around with the thread context.</p> +<h2 id="setting-hardware-breakpoints">Setting hardware breakpoints</h2> +<p>I'm definitely not the first person to wonder <a href="https://social.msdn.microsoft.com/Forums/en-US/0cb3360d-3747-42a7-bc0e-668c5d9ee1ee/how-to-set-a-hardware-breakpoint">How to set a hardware breakpoint?</a>. This is great, because it means I don't need to ask that question myself. It appears we need to change the debug register <em>via the thread context</em>.</p> +<p>One has to be careful to use the right context structure. Confusingly enough, <a href="https://stackoverflow.com/q/17504174/"><code>WOW64_CONTEXT</code></a> is 32 bits, not 64. <code>CONTEXT</code> alone seems to be the right one:</p> +<pre><code class="language-rust" data-lang="rust">pub fn get_context(&amp;self) -&gt; io::Result&lt;winapi::um::winnt::CONTEXT&gt; { + let context = MaybeUninit::&lt;winapi::um::winnt::CONTEXT&gt;::zeroed(); + // SAFETY: it's a C struct, and all-zero is a valid bit-pattern for the type. + let mut context = unsafe { context.assume_init() }; + context.ContextFlags = winapi::um::winnt::CONTEXT_ALL; + + // SAFETY: the handle is valid and structure points to valid memory. + if unsafe { + winapi::um::processthreadsapi::GetThreadContext(self.handle.as_ptr(), &amp;mut context) + } == FALSE + { + Err(io::Error::last_os_error()) + } else { + Ok(context) + } +} +</code></pre> +<p>Trying it out:</p> +<pre><code class="language-rust" data-lang="rust">thread.suspend().unwrap(); + +let context = thread.get_context().unwrap(); +println!(&quot;Dr0: {:016x}&quot;, context.Dr0); +println!(&quot;Dr7: {:016x}&quot;, context.Dr7); +println!(&quot;Dr6: {:016x}&quot;, context.Dr6); +println!(&quot;Rax: {:016x}&quot;, context.Rax); +println!(&quot;Rbx: {:016x}&quot;, context.Rbx); +println!(&quot;Rcx: {:016x}&quot;, context.Rcx); +println!(&quot;Rip: {:016x}&quot;, context.Rip); +</code></pre> +<pre><code>Dr0: 0000000000000000 +Dr7: 0000000000000000 +Dr6: 0000000000000000 +Rax: 0000000000001446 +Rbx: 0000000000000000 +Rcx: 0000000000000000 +Rip: 00007ffda4259904 +</code></pre> +<p>Looks about right! Hm, I wonder what happens if I use Cheat Engine to add the watchpoint on the memory location we care about?</p> +<pre><code>Dr0: 000000000157e650 +Dr7: 00000000000d0001 +</code></pre> +<p>Look at that! The debug registers changed! DR0 contains the location we want to watch for writes, and the debug control register DR7 changed. Cheat Engine sets the same values on all threads (for some reason I now see more than one thread printed for the tutorial, not sure what's up with that; maybe the single-thread is the weird one out).</p> +<p>Hmm, what happens if I watch for access instead of write?</p> +<pre><code>Dr0: 000000000157e650 +Dr7: 00000000000f0001 +</code></pre> +<p>What if I set both?</p> +<pre><code>Dr0: 000000000157e650 +Dr7: 0000000000fd0005 +</code></pre> +<p>Most intriguing! This was done by telling Cheat Engine to find &quot;what writes&quot; to the address, then &quot;what accesses&quot; the address. I wonder if the order matters?</p> +<pre><code>Dr0: 000000000157e650 +Dr7: 0000000000df0005 +</code></pre> +<p>&quot;What accesses&quot; and then &quot;what writes&quot; does change it. Very well! We're only concerned in a single breakpoint, so we won't worry about this, but it's good to know that we can inspect what Cheat Engine is doing. It's also interesting to see how Cheat Engine is using hardware breakpoints and not software breakpoints.</p> +<p>For simplicity, our code is going to assume that we're the only ones messing around with the debug registers, and that there will only be a single debug register in use. Make sure to add <code>THREAD_SET_CONTEXT</code> to the permissions when opening the thread handle:</p> +<pre><code class="language-rust" data-lang="rust">pub fn set_context(&amp;self, context: &amp;winapi::um::winnt::CONTEXT) -&gt; io::Result&lt;()&gt; { + // SAFETY: the handle is valid and structure points to valid memory. + if unsafe { + winapi::um::processthreadsapi::SetThreadContext(self.handle.as_ptr(), context) + } == FALSE + { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } +} + +pub fn watch_memory_write(&amp;self, addr: usize) -&gt; io::Result&lt;()&gt; { + let mut context = self.get_context()?; + context.Dr0 = addr as u64; + context.Dr7 = 0x00000000000d0001; + self.set_context(&amp;context)?; + todo!() +} +</code></pre> +<p>If we do this (and temporarily get rid of the <code>todo!()</code>), trying to change the value in the Cheat Engine tutorial will greet us with a warm message:</p> +<blockquote> +<p><strong>Tutorial-x86_64</strong></p> +<p>External exception 80000004.</p> +<p>Press OK to ignore and risk data corruption.<br /> +Press Abort to kill the program.</p> +<p><kbd>OK</kbd> <kbd>Abort</kbd></p> +</blockquote> +<p>There is no debugger attached yet that could possibly handle this exception, so the exception just propagates. Let's fix that.</p> +<h2 id="handling-debug-events">Handling debug events</h2> +<p>Now that we've succeeded on setting breakpoints, we can actually follow the steps described in <a href="https://docs.microsoft.com/en-us/windows/win32/debug/creating-a-basic-debugger">Creating a Basic Debugger</a>. It starts by saying that we should use <a href="https://docs.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-debugactiveprocess"><code>DebugActiveProcess</code></a> to attach our processor, the debugger, to the process we want to debug, the debuggee. This function lives under the <code>debugapi</code> header, so add it to <code>winapi</code> features:</p> +<pre><code class="language-rust" data-lang="rust">pub struct DebugToken { + pid: u32, +} + +pub fn debug(pid: u32) -&gt; io::Result&lt;DebugToken&gt; { + if unsafe { winapi::um::debugapi::DebugActiveProcess(pid) } == FALSE { + return Err(io::Error::last_os_error()); + }; + let token = DebugToken { pid }; + if unsafe { winapi::um::winbase::DebugSetProcessKillOnExit(FALSE) } == FALSE { + return Err(io::Error::last_os_error()); + }; + Ok(token) +} + +impl Drop for DebugToken { + fn drop(&amp;mut self) { + unsafe { winapi::um::debugapi::DebugActiveProcessStop(self.pid) }; + } +} +</code></pre> +<p>Once again, we create a wrapper <code>struct</code> with <code>Drop</code> to stop debugging the process once the token is dropped. The call to <code>DebugSetProcessKillOnExit</code> in our <code>debug</code> method ensures that, if our process (the debugger) dies, the process we're debugging (the debuggee) stays alive. We don't want to be restarting the entire Cheat Engine tutorial every time our Rust code crashes!</p> +<p>With the debugger attached, we can wait for debug events. We will put this method inside of <code>impl DebugToken</code>, so that the only way you can call it is if you successfully attached to another process:</p> +<pre><code class="language-rust" data-lang="rust">impl DebugToken { + pub fn wait_event( + &amp;self, + timeout: Option&lt;Duration&gt;, + ) -&gt; io::Result&lt;winapi::um::minwinbase::DEBUG_EVENT&gt; { + let mut result = MaybeUninit::uninit(); + let timeout = timeout + .map(|d| d.as_millis().try_into().ok()) + .flatten() + .unwrap_or(winapi::um::winbase::INFINITE); + + // SAFETY: can only wait for events with a token, so the debugger is active. + if unsafe { winapi::um::debugapi::WaitForDebugEvent(result.as_mut_ptr(), timeout) } == FALSE + { + Err(io::Error::last_os_error()) + } else { + // SAFETY: the call returned non-zero, so the structure is initialized. + Ok(unsafe { result.assume_init() }) + } + } +} +</code></pre> +<p><code>WaitForDebugEvent</code> wants a timeout in milliseconds, so our function lets the user pass the more Rusty <code>Duration</code> type. <code>None</code> will indicate &quot;there is no timeout&quot;, i.e., it's infinite. If the duration is too large to fit in the <code>u32</code> (<code>try_into</code> fails), it will also be infinite.</p> +<p>If we attach the debugger, set the hardware watchpoint, and modify the memory location from the tutorial, an event with <code>dwDebugEventCode = 3</code> will be returned! Now, back to the page with the <a href="https://docs.microsoft.com/en-us/windows/win32/debug/debugging-events">Debugging Events</a>… Gah! It only has the name of the constants, not the values. Well, good thing <a href="https://docs.rs/">docs.rs</a> has a source view! We can just check the values in the <a href="https://docs.rs/winapi/0.3.9/src/winapi/um/minwinbase.rs.html#203-211">source code for <code>winapi</code></a>:</p> +<pre><code class="language-rust" data-lang="rust">pub const EXCEPTION_DEBUG_EVENT: DWORD = 1; +pub const CREATE_THREAD_DEBUG_EVENT: DWORD = 2; +pub const CREATE_PROCESS_DEBUG_EVENT: DWORD = 3; +pub const EXIT_THREAD_DEBUG_EVENT: DWORD = 4; +pub const EXIT_PROCESS_DEBUG_EVENT: DWORD = 5; +pub const LOAD_DLL_DEBUG_EVENT: DWORD = 6; +pub const UNLOAD_DLL_DEBUG_EVENT: DWORD = 7; +pub const OUTPUT_DEBUG_STRING_EVENT: DWORD = 8; +pub const RIP_EVENT: DWORD = 9; +</code></pre> +<p>So, we've got a <code>CREATE_PROCESS_DEBUG_EVENT</code>:</p> +<blockquote> +<p>Generated whenever a new process is created in a process being debugged or whenever the debugger begins debugging an already active process. The system generates this debugging event before the process begins to execute in user mode and before the system generates any other debugging events for the new process.</p> +</blockquote> +<p>It makes sense that this is our first event. By the way, if you were trying this out with a <code>sleep</code> lying around in your code, you may have noticed that the window froze until the debugger terminated. That's because:</p> +<blockquote> +<p>When the system notifies the debugger of a debugging event, it also suspends all threads in the affected process. The threads do not resume execution until the debugger continues the debugging event by using <a href="https://docs.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-continuedebugevent"><code>ContinueDebugEvent</code></a>.</p> +</blockquote> +<p>Let's call <code>ContinueDebugMethod</code> but also wait on more than one event and see what happens:</p> +<pre><code class="language-rust" data-lang="rust">for _ in 0..10 { + let event = debugger.wait_event(None).unwrap(); + println!(&quot;Got {}&quot;, event.dwDebugEventCode); + debugger.cont(event, true).unwrap(); +} +</code></pre> +<pre><code>Got 3 +Got 6 +Got 6 +Got 6 +Got 6 +Got 6 +Got 6 +Got 6 +Got 6 +Got 6 +</code></pre> +<p>That's a lot of <code>LOAD_DLL_DEBUG_EVENT</code>. Pumping it up to one hundred and also showing the index we get the following:</p> +<pre><code>0. Got 3 +1. Got 6 +... +40. Got 6 +41. Got 2 +42. Got 1 +43. Got 4 +</code></pre> +<p>In order, we got:</p> +<ul> +<li>One <code>CREATE_PROCESS_DEBUG_EVENT</code>.</li> +<li>Forty <code>LOAD_DLL_DEBUG_EVENT</code>.</li> +<li>One <code>CREATE_THREAD_DEBUG_EVENT</code>.</li> +<li>One <code>EXCEPTION_DEBUG_EVENT</code>.</li> +<li>One <code>EXIT_THREAD_DEBUG_EVENT</code>.</li> +</ul> +<p>And, if after all this, you change the value in the Cheat Engine tutorial (thus triggering our watch point), we get <code>EXCEPTION_DEBUG_EVENT</code>!</p> +<blockquote> +<p>Generated whenever an exception occurs in the process being debugged. Possible exceptions include attempting to access inaccessible memory, executing breakpoint instructions, attempting to divide by zero, or any other exception noted in Structured Exception Handling.</p> +</blockquote> +<p>If we print out all the fields in the <a href="https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-exception_debug_info"><code>EXCEPTION_DEBUG_INFO</code></a> structure:</p> +<pre><code>Watching writes to 10e3a0 for 10s +First chance: 1 +ExceptionCode: 2147483652 +ExceptionFlags: 0 +ExceptionRecord: 0x0 +ExceptionAddress: 0x10002c5ba +NumberParameters: 0 +ExceptionInformation: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +</code></pre> +<p>The <code>ExceptionCode</code>, which is <code>0x80000004</code>, corresponds with <code>EXCEPTION_SINGLE_STEP</code>:</p> +<blockquote> +<p>A trace trap or other single-instruction mechanism signaled that one instruction has been executed.</p> +</blockquote> +<p>The <code>ExceptionAddress</code> is supposed to be &quot;the address where the exception occurred&quot;. Very well! I have already completed this step of the tutorial, and I know the instruction is <code>mov [rax],edx</code> (or, as Cheat Engine shows, the bytes <code>89 10</code> in hexadecimal). The opcode for the <code>nop</code> instruction is <code>90</code> in hexadecimal, so if we replace two bytes at this address, we should be able to complete the tutorial.</p> +<p>Note that we also need to flush the instruction cache, as noted in the Windows documentation:</p> +<blockquote> +<p>Debuggers frequently read the memory of the process being debugged and write the memory that contains instructions to the instruction cache. After the instructions are written, the debugger calls the <a href="https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-flushinstructioncache"><code>FlushInstructionCache</code></a> function to execute the cached instructions.</p> +</blockquote> +<p>So we add a new method to <code>impl Process</code>:</p> +<pre><code class="language-rust" data-lang="rust">/// Flushes the instruction cache. +/// +/// Should be called when writing to memory regions that contain code. +pub fn flush_instruction_cache(&amp;self) -&gt; io::Result&lt;()&gt; { + // SAFETY: the call doesn't have dangerous side-effects. + if unsafe { + winapi::um::processthreadsapi::FlushInstructionCache( + self.handle.as_ptr(), + ptr::null(), + 0, + ) + } == FALSE + { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } +} +</code></pre> +<p>And write some quick and dirty code to get this done:</p> +<pre><code class="language-rust" data-lang="rust">let addr = ...; +println!(&quot;Watching writes to {:x} for 10s&quot;, addr); +threads.iter_mut().for_each(|thread| { + thread.watch_memory_write(addr).unwrap(); +}); +loop { + let event = debugger.wait_event(None).unwrap(); + if event.dwDebugEventCode == 1 { + let exc = unsafe { event.u.Exception() }; + if exc.ExceptionRecord.ExceptionCode == 2147483652 { + let addr = exc.ExceptionRecord.ExceptionAddress as usize; + match process.write_memory(addr, &amp;[0x90, 0x90]) { + Ok(_) =&gt; eprintln!(&quot;Patched [{:x}] with NOP&quot;, addr), + Err(e) =&gt; eprintln!(&quot;Failed to patch [{:x}] with NOP: {}&quot;, addr, e), + }; + process.flush_instruction_cache().unwrap(); + debugger.cont(event, true).unwrap(); + break; + } + } + debugger.cont(event, true).unwrap(); +} +</code></pre> +<p>Although it seems to work:</p> +<pre><code>Watching writes to 15103f0 for 10s +Patched [10002c5ba] with NOP +</code></pre> +<p>It really doesn't:</p> +<blockquote> +<p><strong>Tutorial-x86_64</strong></p> +<p>Access violation.</p> +<p>Press OK to ignore and risk data corruption.<br /> +Press Abort to kill the program.</p> +<p><kbd>OK</kbd> <kbd>Abort</kbd></p> +</blockquote> +<p>Did we write memory somewhere we shouldn't? The documentation does mention &quot;segment-relative&quot; and &quot;linear virtual addresses&quot;:</p> +<blockquote> +<p><code>GetThreadSelectorEntry</code> returns the descriptor table entry for a specified selector and thread. Debuggers use the descriptor table entry to convert a segment-relative address to a linear virtual address. The <code>ReadProcessMemory</code> and <code>WriteProcessMemory</code> functions require linear virtual addresses.</p> +</blockquote> +<p>But nope! This isn't the problem. The problem is that the <code>ExceptionRecord.ExceptionAddress</code> is <em>after</em> the execution happened, so it's already 2 bytes beyond where it should be. We were accidentally writing out the first half of the next instruction, which, yeah, could not end good.</p> +<p>So does it work if I do this instead?:</p> +<pre><code class="language-rust" data-lang="rust">process.write_memory(addr - 2, &amp;[0x90, 0x90]) +// ^^^ new +</code></pre> +<p>This totally does work. Step 5: complete 🎉</p> +<h2 id="properly-patching-instructions">Properly patching instructions</h2> +<p>You may not be satisfied at all with our solution. Not only are we hardcoding some magic constants to set hardware watchpoints, we're also relying on knowledge specific to the Cheat Engine tutorial (insofar that we're replacing two bytes worth of instruction with NOPs).</p> +<p>Properly supporting more than one hardware breakpoint, along with supporting different types of breakpoints, is definitely doable. The meaning of the bits for the debug registers is well defined, and you can definitely study that to come up with <a href="https://github.com/mmorearty/hardware-breakpoints">something more sophisticated</a> and support multiple different breakpoints. But for now, that's out of the scope of this series. The tutorial only wants us to use an on-write watchpoint, and our solution is fine and portable for that use case.</p> +<p>However, relying on the size of the instructions is pretty bad. The instructions x86 executes are of variable length, so we can't possibly just look back until we find the previous instruction, or even naively determine its length. A lot of unrelated sequences of bytes are very likely instructions themselves. We need a disassembler. No, we're not writing our own.</p> +<p>Searching on <a href="https://crates.io">crates.io</a> for &quot;disassembler&quot; yields a few results, and the first one I've found is <a href="https://crates.io/crates/iced-x86">iced-x86</a>. I like the name, it has a decent amount of GitHub stars, and it was last updated less than a month ago. I don't know about you, but I think we've just hit a jackpot!</p> +<p>It's quite heavy though, so I will add it behind a feature gate, and users that want it may opt into it:</p> +<pre><code class="language-toml" data-lang="toml">[features] +patch-nops = [&quot;iced-x86&quot;] + +[dependencies] +iced-x86 = { version = &quot;1.10.3&quot;, optional = true } +</code></pre> +<p>You can make use of it with <code>cargo run --features=patch-nops</code>. I don't want to turn this blog post into a tutorial for <code>iced-x86</code>, but in essence, we need to make use of its <code>Decoder</code>. Here's the plan:</p> +<ol> +<li>Find the memory region corresponding to the address we want to patch.</li> +<li>Read the entire region.</li> +<li>Decode the read bytes until the instruction pointer reaches our address.</li> +<li>Because we just parsed the previous instruction, we know its length, and can be replaced with NOPs.</li> +</ol> +<pre><code class="language-rust" data-lang="rust">#[cfg(feature = &quot;patch-nops&quot;)] +pub fn nop_last_instruction(&amp;self, addr: usize) -&gt; io::Result&lt;()&gt; { + use iced_x86::{Decoder, DecoderOptions, Formatter, Instruction, NasmFormatter}; + + let region = self + .memory_regions() + .into_iter() + .find(|region| { + let base = region.BaseAddress as usize; + base &lt;= addr &amp;&amp; addr &lt; base + region.RegionSize + }) + .ok_or_else(|| io::Error::new(io::ErrorKind::Other, &quot;no matching region found&quot;))?; + + let bytes = self.read_memory(region.BaseAddress as usize, region.RegionSize)?; + + let mut decoder = Decoder::new(64, &amp;bytes, DecoderOptions::NONE); + decoder.set_ip(region.BaseAddress as _); + + let mut instruction = Instruction::default(); + while decoder.can_decode() { + decoder.decode_out(&amp;mut instruction); + if instruction.next_ip() as usize == addr { + return self + .write_memory(instruction.ip() as usize, &amp;vec![0x90; instruction.len()]) + .map(drop); + } + } + + Err(io::Error::new( + io::ErrorKind::Other, + &quot;no matching instruction found&quot;, + )) +} +</code></pre> +<p>Pretty straightforward! We can set the &quot;instruction pointer&quot; of the decoder so that it matches with the address we're reading from. The <code>next_ip</code> method comes in really handy. Overall, it's a bit inefficient, because we could reuse the regions retrieved previously, but other than that, there is not much room for improvement.</p> +<p>With this, we are no longer hardcoding the instruction size or guessing which instruction is doing what. You may wonder, what if the region does not start with valid executable code? It could be possible that the instructions are in some memory region with garbage except for a very specific location with real code. I don't know how Cheat Engine handles this, but I think it's reasonable to assume that the region starts with valid code. If you can think of any more reliable way to figure out the instruction right before a given address, please let me know!</p> +<h2 id="finale">Finale</h2> +<p>That was quite a deep dive! We have learnt about the existence of the various breakpoint types (software, hardware, and even behaviour, such as watchpoints), how to debug a separate process, and how to correctly update the code other process is running on-the-fly. The <a href="https://github.com/lonami/memo">code for this post</a> is available over at my GitHub. You can run <code>git checkout step5</code> after cloning the repository to get the right version of the code.</p> +<p>Although we've only talked about <em>setting</em> breakpoints, there are of course <a href="https://reverseengineering.stackexchange.com/a/16547">ways of detecting them</a>. There's <a href="https://www.codeproject.com/Articles/30815/An-Anti-Reverse-Engineering-Guide">entire guides about it</a>. Again, we currently hardcode the fact we want to add a single watchpoint using the first debug register. A proper solution here would be to actually calculate the needs that need to be set, as well as keeping track of how many breakpoints have been added so far.</p> +<p>Hardware breakpoints are also limited, since they're simply a bunch of registers, and our machine does not have infinite registers. How are other debuggers like <code>gdb</code> able to create a seemingly unlimited amount of breakpoints? Well, the GDB wiki actually has a page on <a href="https://sourceware.org/gdb/wiki/Internals%20Watchpoints">Internals Watchpoints</a>, and it's really interesting! <code>gdb</code> essentially single-steps through the entire program and tests the expressions after every instruction:</p> +<blockquote> +<p>Software watchpoints are very slow, since GDB needs to single-step the program being debugged and test the value of the watched expression(s) after each instruction.</p> +</blockquote> +<p>However, that's not the only way. One could <a href="https://stackoverflow.com/a/7805842/">change the protection level</a> of the region of interest (for example, remove the write permission), and when the program tries to write there, it will fail! In any case, the GDB wiki is actually a pretty nice resource. It also has a section on <a href="https://sourceware.org/gdb/wiki/Internals/Breakpoint%20Handling">Breakpoint Handling</a>, which contains some additional insight.</p> +<p>With regards to code improvements, <code>DebugToken::wait_event</code> could definitely be both nicer and safer to use, with a custom <code>enum</code>, so the user does not need to rely on magic constants or having to resort to <code>unsafe</code> access to get the right <code>union</code> variant.</p> +<p>In the next post, we'll tackle the sixth step of the tutorial: Pointers. It reuses the debugging techniques presented here to backtrack where the pointer for our desired value is coming from, so here we will need to actually <em>understand</em> what the instructions are doing, not just patching them out!</p> +<h3 id="footnotes">Footnotes</h3> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>I'm not super happy about the design of it all, but we won't actually need anything beyond scanning for integers for the rest of the steps so it doesn't really matter.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p>There seems to be a way to pause the entire process in one go, with the [undocumented <code>NtSuspendProcess</code>] function!</p> +</div> +<div class="footnote-definition" id="3"><sup class="footnote-definition-label">3</sup> +<p>It really is called that. The naming went from &quot;IP&quot; (instruction pointer, 16 bits), to &quot;EIP&quot; (extended instruction pointer, 32 bits) and currently &quot;RIP&quot; (64 bits). The naming convention for upgraded registers is the same (RAX, RBX, RCX, and so on). The <a href="https://wiki.osdev.org/CPU_Registers_x86_64">OS Dev wiki</a> is a great resource for this kind of stuff.</p> +</div> +</content> + </entry> + <entry xml:lang="en"> <title>Writing our own Cheat Engine: Floating points</title> <published>2021-02-22T00:00:00+00:00</published> <updated>2021-02-22T00:00:00+00:00</updated>@@ -18,6 +594,7 @@ <li><a href="/blog/woce-1">Part 1: Introduction</a> (start here if you're new to the series!)</li>
<li><a href="/blog/woce-2">Part 2: Exact Value scanning</a></li> <li><a href="/blog/woce-3">Part 3: Unknown initial value</a></li> <li>Part 4: Floating points</li> +<li><a href="/blog/woce-5">Part 5: Code finder</a></li> </ul> <p>In part 3 we did a fair amount of plumbing in order to support scan modes beyond the trivial &quot;exact value scan&quot;. As a result, we have abstracted away the <code>Scan</code>, <code>CandidateLocations</code> and <code>Value</code> types as a separate <code>enum</code> each. Scanning for changed memory regions in an opened process can now be achieved with three lines of code:</p> <pre><code class="language-rust" data-lang="rust">let regions = process.memory_regions();@@ -385,7 +962,7 @@ <p>You may <a href="https://github.com/lonami/memo">obtain the code for this post</a> over at my GitHub. You can run <code>git checkout step4</code> after cloning the repository to get the right version of the code. The code has gone through a lot of iterations, and I'd still like to polish it a bit more, so it might slightly differ from the code presented in this entry.</p>
<p>If you feel adventurous, Cheat Engine has different options for scanning floating point types: &quot;rounded (default)&quot;, &quot;rounded (extreme)&quot;, and truncated. Optionally, it can scan for &quot;simple values only&quot;. You could go ahead and toy around with these!</p> <p>We didn't touch on types with different lengths, such as strings. You could support UTF-8, UTF-16, or arbitrary byte sequences. This post also didn't cover scanning for multiple things at once, known as &quot;groupscan commands&quot;, although from what I can tell, these are just a nice way to scan for arbitrary byte sequences.</p> <p>We also didn't look into supporting different the same scan with different alignments. All these things may be worth exploring depending on your requirements. You could even get rid of such genericity and go with something way simpler. Supporting <code>i32</code>, <code>f32</code> and <code>f64</code> is enough to complete the Cheat Engine tutorial. But I wanted something more powerful, although my solution currently can't scan for a sequence such as &quot;exact type, unknown, exact matching the unknown&quot;. So yeah.</p> -<p>In the next post, we'll tackle the fifth step of the tutorial: Code finder. Cheat Engine attaches its debugger to the process for this one, and then replaces the instruction that performs the write with a different no-op so that nothing is written anymore. This will be quite the challenge!</p> +<p>In the <a href="/blog/woce-5">next post</a>, we'll tackle the fifth step of the tutorial: Code finder. Cheat Engine attaches its debugger to the process for this one, and then replaces the instruction that performs the write with a different no-op so that nothing is written anymore. This will be quite the challenge!</p> <h3 id="footnotes">Footnotes</h3> <div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> <p><a href="https://doc.rust-lang.org/stable/std/ops/trait.Drop.html#copy-and-drop-are-exclusive"><code>Copy</code> and <code>Drop</code> are exclusive</a>. See also <a href="https://doc.rust-lang.org/stable/error-index.html#E0184">E0184</a>.</p>@@ -431,6 +1008,7 @@ <li><a href="/blog/woce-1">Part 1: Introduction</a> (start here if you're new to the series!)</li>
<li><a href="/blog/woce-2">Part 2: Exact Value scanning</a></li> <li>Part 3: Unknown initial value</li> <li><a href="/blog/woce-4">Part 4: Floating points</a></li> +<li><a href="/blog/woce-5">Part 5: Code finder</a></li> </ul> <p>In part 2 we left off with a bit of a cliff-hanger. Our little program is now able to scan for an exact value, remember the couple hundred addresses pointing to said value, and perform subsequent scans to narrow the list of addresses down until we're left with a handful of them.</p> <p>However, it is not always the case that you have an exact value to work with. The best you can do in these cases is guess what the software might be storing. For example, it could be a floating point for your current movement speed in a game, or an integer for your current health.</p>@@ -785,6 +1363,7 @@ <li><a href="/blog/woce-1">Part 1: Introduction</a> (start here if you're new to the series!)</li>
<li>Part 2: Exact Value scanning</li> <li><a href="/blog/woce-3">Part 3: Unknown initial value</a></li> <li><a href="/blog/woce-4">Part 4: Floating points</a></li> +<li><a href="/blog/woce-5">Part 5: Code finder</a></li> </ul> <p>In the introduction, we spent a good deal of time enumerating all running processes just so we could find out the pid we cared about. With the pid now in our hands, we can do pretty much anything to its corresponding process.</p> <p>It's now time to read the process' memory and write to it. If our process was a single-player game, this would enable us to do things like setting a very high value on the player's current health pool, making us invincible. This technique will often not work for multi-player games, because the server likely knows your true current health (the most you could probably do is make the client render an incorrect value). However, if the server is crappy and it trusts the client, then you're still free to mess around with your current health.</p>@@ -1206,6 +1785,7 @@ <li>Part 1: Introduction</li>
<li><a href="/blog/woce-2">Part 2: Exact Value scanning</a></li> <li><a href="/blog/woce-3">Part 3: Unknown initial value</a></li> <li><a href="/blog/woce-4">Part 4: Floating points</a></li> +<li><a href="/blog/woce-5">Part 5: Code finder</a></li> </ul> <p><a href="https://cheatengine.org/">Cheat Engine</a> is a tool designed to modify single player games and contains other useful tools within itself that enable its users to debug games or other applications. It comes with a memory scanner, (dis)assembler, inspection tools and a handful other things. In this series, we will be writing our own tiny Cheat Engine capable of solving all steps of the tutorial, and diving into how it all works underneath.</p> <p>Needless to say, we're doing this for private and educational purposes only. One has to make sure to not violate the EULA or ToS of the specific application we're attaching to. This series, much like cheatengine.org, does not condone the illegal use of the code shared.</p>
@@ -1,4 +1,4 @@
-<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=description content="Official Lonami's website"><meta name=viewport content="width=device-width, initial-scale=1.0, user-scalable=yes"><title> Lonami's Blog </title><link rel=stylesheet href=/style.css><body><article><nav class=sections><ul class=left><li><a href=/>lonami's site</a><li><a href=/blog class=selected>blog</a><li><a href=/golb>golb</a></ul><div class=right><a href=https://github.com/LonamiWebs><img src=/img/github.svg alt=github></a><a href=/blog/atom.xml><img src=/img/rss.svg alt=rss></a></div></nav><main><h1 class=title>My Blog</h1><p id=welcome onclick=pls_stop()>Welcome to my blog!<p>Here I occasionally post new entries, mostly tech related. Perhaps it's tips for a new game I'm playing, perhaps it has something to do with FFI, or perhaps I'm fighting the borrow checker (just kidding, I'm over that. Mostly).<hr><ul><li><a href=https://lonami.dev/blog/woce-4/>Writing our own Cheat Engine: Floating points</a><span class=dim> [mod sw; 'windows, 'rust, 'hacking] </span><li><a href=https://lonami.dev/blog/woce-3/>Writing our own Cheat Engine: Unknown initial value</a><span class=dim> [mod sw; 'windows, 'rust, 'hacking] </span><li><a href=https://lonami.dev/blog/woce-2/>Writing our own Cheat Engine: Exact Value scanning</a><span class=dim> [mod sw; 'windows, 'rust, 'hacking] </span><li><a href=https://lonami.dev/blog/woce-1/>Writing our own Cheat Engine: Introduction</a><span class=dim> [mod sw; 'windows, 'rust, 'hacking] </span><li><a href=https://lonami.dev/blog/university/>Data Mining, Warehousing and Information Retrieval</a><span class=dim> [mod algos; 'series, 'bigdata, 'databases] </span><li><a href=https://lonami.dev/blog/new-computer/>My new computer</a><span class=dim> [mod hw; 'showoff] </span><li><a href=https://lonami.dev/blog/tips-outpost/>Tips for Outpost</a><span class=dim> [mod games; 'tips] </span><li><a href=https://lonami.dev/blog/ctypes-and-windows/>Python ctypes and Windows</a><span class=dim> [mod sw; 'python, 'ffi, 'windows] </span><li><a href=https://lonami.dev/blog/pixel-dungeon/>Shattered Pixel Dungeon</a><span class=dim> [mod games; 'tips] </span><li><a href=https://lonami.dev/blog/installing-nixos-2/>Installing NixOS, Take 2</a><span class=dim> [mod sw; 'os, 'nixos] </span><li><a href=https://lonami.dev/blog/breaking-ror/>Breaking Risk of Rain</a><span class=dim> [mod games; 'tips] </span><li><a href=https://lonami.dev/blog/world-edit/>WorldEdit Commands</a><span class=dim> [mod games; 'minecraft, 'worldedit, 'tips] </span><li><a href=https://lonami.dev/blog/asyncio/>An Introduction to Asyncio</a><span class=dim> [mod sw; 'python, 'asyncio] </span><li><a href=https://lonami.dev/blog/posts/>Atemporal Blog Posts</a><span class=dim> [mod algos; 'algorithms, 'culture, 'debate, 'foodforthought, 'graphics, 'optimization] </span><li><a href=https://lonami.dev/blog/graphs/>Graphs</a><span class=dim> [mod algos; 'graphs] </span><li><a href=https://lonami.dev/blog/installing-nixos/>Installing NixOS</a><span class=dim> [mod sw; 'os, 'nixos] </span></ul><script> +<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=description content="Official Lonami's website"><meta name=viewport content="width=device-width, initial-scale=1.0, user-scalable=yes"><title> Lonami's Blog </title><link rel=stylesheet href=/style.css><body><article><nav class=sections><ul class=left><li><a href=/>lonami's site</a><li><a href=/blog class=selected>blog</a><li><a href=/golb>golb</a></ul><div class=right><a href=https://github.com/LonamiWebs><img src=/img/github.svg alt=github></a><a href=/blog/atom.xml><img src=/img/rss.svg alt=rss></a></div></nav><main><h1 class=title>My Blog</h1><p id=welcome onclick=pls_stop()>Welcome to my blog!<p>Here I occasionally post new entries, mostly tech related. Perhaps it's tips for a new game I'm playing, perhaps it has something to do with FFI, or perhaps I'm fighting the borrow checker (just kidding, I'm over that. Mostly).<hr><ul><li><a href=https://lonami.dev/blog/woce-5/>Writing our own Cheat Engine: Code finder</a><span class=dim> [mod sw; 'windows, 'rust, 'hacking] </span><li><a href=https://lonami.dev/blog/woce-4/>Writing our own Cheat Engine: Floating points</a><span class=dim> [mod sw; 'windows, 'rust, 'hacking] </span><li><a href=https://lonami.dev/blog/woce-3/>Writing our own Cheat Engine: Unknown initial value</a><span class=dim> [mod sw; 'windows, 'rust, 'hacking] </span><li><a href=https://lonami.dev/blog/woce-2/>Writing our own Cheat Engine: Exact Value scanning</a><span class=dim> [mod sw; 'windows, 'rust, 'hacking] </span><li><a href=https://lonami.dev/blog/woce-1/>Writing our own Cheat Engine: Introduction</a><span class=dim> [mod sw; 'windows, 'rust, 'hacking] </span><li><a href=https://lonami.dev/blog/university/>Data Mining, Warehousing and Information Retrieval</a><span class=dim> [mod algos; 'series, 'bigdata, 'databases] </span><li><a href=https://lonami.dev/blog/new-computer/>My new computer</a><span class=dim> [mod hw; 'showoff] </span><li><a href=https://lonami.dev/blog/tips-outpost/>Tips for Outpost</a><span class=dim> [mod games; 'tips] </span><li><a href=https://lonami.dev/blog/ctypes-and-windows/>Python ctypes and Windows</a><span class=dim> [mod sw; 'python, 'ffi, 'windows] </span><li><a href=https://lonami.dev/blog/pixel-dungeon/>Shattered Pixel Dungeon</a><span class=dim> [mod games; 'tips] </span><li><a href=https://lonami.dev/blog/installing-nixos-2/>Installing NixOS, Take 2</a><span class=dim> [mod sw; 'os, 'nixos] </span><li><a href=https://lonami.dev/blog/breaking-ror/>Breaking Risk of Rain</a><span class=dim> [mod games; 'tips] </span><li><a href=https://lonami.dev/blog/world-edit/>WorldEdit Commands</a><span class=dim> [mod games; 'minecraft, 'worldedit, 'tips] </span><li><a href=https://lonami.dev/blog/asyncio/>An Introduction to Asyncio</a><span class=dim> [mod sw; 'python, 'asyncio] </span><li><a href=https://lonami.dev/blog/posts/>Atemporal Blog Posts</a><span class=dim> [mod algos; 'algorithms, 'culture, 'debate, 'foodforthought, 'graphics, 'optimization] </span><li><a href=https://lonami.dev/blog/graphs/>Graphs</a><span class=dim> [mod algos; 'graphs] </span><li><a href=https://lonami.dev/blog/installing-nixos/>Installing NixOS</a><span class=dim> [mod sw; 'os, 'nixos] </span></ul><script> const WELCOME_EN = 'Welcome to my blog!' const WELCOME_ES = '¡Bienvenido a mi blog!' const APOLOGIES = "ok sorry i'll stop"
@@ -1,4 +1,4 @@
-<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=description content="Official Lonami's website"><meta name=viewport content="width=device-width, initial-scale=1.0, user-scalable=yes"><title> Writing our own Cheat Engine: Introduction | Lonami's Blog </title><link rel=stylesheet href=/style.css><body><article><nav class=sections><ul class=left><li><a href=/>lonami's site</a><li><a href=/blog class=selected>blog</a><li><a href=/golb>golb</a></ul><div class=right><a href=https://github.com/LonamiWebs><img src=/img/github.svg alt=github></a><a href=/blog/atom.xml><img src=/img/rss.svg alt=rss></a></div></nav><main><h1 class=title>Writing our own Cheat Engine: Introduction</h1><div class=time><p>2021-02-07<p>last updated 2021-02-19</div><p>This is part 1 on the <em>Writing our own Cheat Engine</em> series:<ul><li>Part 1: Introduction<li><a href=/blog/woce-2>Part 2: Exact Value scanning</a><li><a href=/blog/woce-3>Part 3: Unknown initial value</a><li><a href=/blog/woce-4>Part 4: Floating points</a></ul><p><a href=https://cheatengine.org/>Cheat Engine</a> is a tool designed to modify single player games and contains other useful tools within itself that enable its users to debug games or other applications. It comes with a memory scanner, (dis)assembler, inspection tools and a handful other things. In this series, we will be writing our own tiny Cheat Engine capable of solving all steps of the tutorial, and diving into how it all works underneath.<p>Needless to say, we're doing this for private and educational purposes only. One has to make sure to not violate the EULA or ToS of the specific application we're attaching to. This series, much like cheatengine.org, does not condone the illegal use of the code shared.<p>Cheat Engine is a tool for Windows, so we will be developing for Windows as well. However, you can also <a href=https://stackoverflow.com/q/12977179/4759433>read memory from Linux-like systems</a>. <a href=https://github.com/scanmem/scanmem>GameConqueror</a> is a popular alternative to Cheat Engine on Linux systems, so if you feel adventurous, you could definitely follow along too! The techniques shown in this series apply regardless of how we read memory from a process. You will learn a fair bit about doing FFI in Rust too.<p>We will be developing the application in Rust, because it enables us to interface with the Windows API easily, is memory safe (as long as we're careful with <code>unsafe</code>!), and is speedy (we will need this for later steps in the Cheat Engine tutorial). You could use any language of your choice though. For example, <a href=https://lonami.dev/blog/ctypes-and-windows/>Python also makes it relatively easy to use the Windows API</a>. You don't need to be a Rust expert to follow along, but this series assumes some familiarity with C-family languages. Slightly advanced concepts like the use of <code>unsafe</code> or the <code>MaybeUninit</code> type will be briefly explained. What a <code>fn</code> is or what <code>let</code> does will not be explained.<p><a href=https://github.com/cheat-engine/cheat-engine/>Cheat Engine's source code</a> is mostly written in Pascal and C. And it's <em>a lot</em> of code, with a very flat project structure, and files ranging in the thousand lines of code each. It's daunting<sup class=footnote-reference><a href=#1>1</a></sup>. It's a mature project, with a lot of knowledge encoded in the code base, and a lot of features like distributed scanning or an entire disassembler. Unfortunately, there's not a lot of comments. For these reasons, I'll do some guesswork when possible as to how it's working underneath, rather than actually digging into what Cheat Engine is actually doing.<p>With that out of the way, let's get started!<h2 id=welcome-to-the-cheat-engine-tutorial>Welcome to the Cheat Engine Tutorial</h2><details open><summary>Cheat Engine Tutorial: Step 1</summary> <blockquote><p>This tutorial will teach you the basics of cheating in video games. It will also show you foundational aspects of using Cheat Engine (or CE for short). Follow the steps below to get started.<ol><li>Open Cheat Engine if it currently isn't running.<li>Click on the "Open Process" icon (it's the top-left icon with the computer on it, below "File".).<li>With the Process List window now open, look for this tutorial's process in the list. It will look something like > "00001F98-Tutorial-x86_64.exe" or "0000047C-Tutorial-i386.exe". (The first 8 numbers/letters will probably be different.)<li>Once you've found the process, click on it to select it, then click the "Open" button. (Don't worry about all the > other buttons right now. You can learn about them later if you're interested.)</ol><p>Congratulations! If you did everything correctly, the process window should be gone with Cheat Engine now attached to the > tutorial (you will see the process name towards the top-center of CE).<p>Click the "Next" button below to continue, or fill in the password and click the "OK" button to proceed to that step.)<p>If you're having problems, simply head over to forum.cheatengine.org, then click on "Tutorials" to view beginner-friendly > guides!</blockquote></details><h2 id=enumerating-processes>Enumerating processes</h2><p>Our first step is attaching to the process we want to work with. But we need a way to find that process in the first place! Having to open the task manager, look for the process we care about, noting down the process ID (PID), and slapping it in the source code is not satisfying at all. Instead, let's enumerate all the processes from within the program, and let the user select one by typing its name.<p>From a quick <a href=https://ddg.gg/winapi%20enumerate%20all%20processes>DuckDuckGo search</a>, we find an official tutorial for <a href=https://docs.microsoft.com/en-us/windows/win32/psapi/enumerating-all-processes>Enumerating All Processes</a>, which leads to the <a href=https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocesses><code>EnumProcesses</code></a> call. Cool! Let's slap in the <a href=https://crates.io/crates/winapi><code>winapi</code></a> crate on <code>Cargo.toml</code>, because I don't want to write all the definitions by myself:<pre><code class=language-toml data-lang=toml>[dependencies] +<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=description content="Official Lonami's website"><meta name=viewport content="width=device-width, initial-scale=1.0, user-scalable=yes"><title> Writing our own Cheat Engine: Introduction | Lonami's Blog </title><link rel=stylesheet href=/style.css><body><article><nav class=sections><ul class=left><li><a href=/>lonami's site</a><li><a href=/blog class=selected>blog</a><li><a href=/golb>golb</a></ul><div class=right><a href=https://github.com/LonamiWebs><img src=/img/github.svg alt=github></a><a href=/blog/atom.xml><img src=/img/rss.svg alt=rss></a></div></nav><main><h1 class=title>Writing our own Cheat Engine: Introduction</h1><div class=time><p>2021-02-07<p>last updated 2021-02-19</div><p>This is part 1 on the <em>Writing our own Cheat Engine</em> series:<ul><li>Part 1: Introduction<li><a href=/blog/woce-2>Part 2: Exact Value scanning</a><li><a href=/blog/woce-3>Part 3: Unknown initial value</a><li><a href=/blog/woce-4>Part 4: Floating points</a><li><a href=/blog/woce-5>Part 5: Code finder</a></ul><p><a href=https://cheatengine.org/>Cheat Engine</a> is a tool designed to modify single player games and contains other useful tools within itself that enable its users to debug games or other applications. It comes with a memory scanner, (dis)assembler, inspection tools and a handful other things. In this series, we will be writing our own tiny Cheat Engine capable of solving all steps of the tutorial, and diving into how it all works underneath.<p>Needless to say, we're doing this for private and educational purposes only. One has to make sure to not violate the EULA or ToS of the specific application we're attaching to. This series, much like cheatengine.org, does not condone the illegal use of the code shared.<p>Cheat Engine is a tool for Windows, so we will be developing for Windows as well. However, you can also <a href=https://stackoverflow.com/q/12977179/4759433>read memory from Linux-like systems</a>. <a href=https://github.com/scanmem/scanmem>GameConqueror</a> is a popular alternative to Cheat Engine on Linux systems, so if you feel adventurous, you could definitely follow along too! The techniques shown in this series apply regardless of how we read memory from a process. You will learn a fair bit about doing FFI in Rust too.<p>We will be developing the application in Rust, because it enables us to interface with the Windows API easily, is memory safe (as long as we're careful with <code>unsafe</code>!), and is speedy (we will need this for later steps in the Cheat Engine tutorial). You could use any language of your choice though. For example, <a href=https://lonami.dev/blog/ctypes-and-windows/>Python also makes it relatively easy to use the Windows API</a>. You don't need to be a Rust expert to follow along, but this series assumes some familiarity with C-family languages. Slightly advanced concepts like the use of <code>unsafe</code> or the <code>MaybeUninit</code> type will be briefly explained. What a <code>fn</code> is or what <code>let</code> does will not be explained.<p><a href=https://github.com/cheat-engine/cheat-engine/>Cheat Engine's source code</a> is mostly written in Pascal and C. And it's <em>a lot</em> of code, with a very flat project structure, and files ranging in the thousand lines of code each. It's daunting<sup class=footnote-reference><a href=#1>1</a></sup>. It's a mature project, with a lot of knowledge encoded in the code base, and a lot of features like distributed scanning or an entire disassembler. Unfortunately, there's not a lot of comments. For these reasons, I'll do some guesswork when possible as to how it's working underneath, rather than actually digging into what Cheat Engine is actually doing.<p>With that out of the way, let's get started!<h2 id=welcome-to-the-cheat-engine-tutorial>Welcome to the Cheat Engine Tutorial</h2><details open><summary>Cheat Engine Tutorial: Step 1</summary> <blockquote><p>This tutorial will teach you the basics of cheating in video games. It will also show you foundational aspects of using Cheat Engine (or CE for short). Follow the steps below to get started.<ol><li>Open Cheat Engine if it currently isn't running.<li>Click on the "Open Process" icon (it's the top-left icon with the computer on it, below "File".).<li>With the Process List window now open, look for this tutorial's process in the list. It will look something like > "00001F98-Tutorial-x86_64.exe" or "0000047C-Tutorial-i386.exe". (The first 8 numbers/letters will probably be different.)<li>Once you've found the process, click on it to select it, then click the "Open" button. (Don't worry about all the > other buttons right now. You can learn about them later if you're interested.)</ol><p>Congratulations! If you did everything correctly, the process window should be gone with Cheat Engine now attached to the > tutorial (you will see the process name towards the top-center of CE).<p>Click the "Next" button below to continue, or fill in the password and click the "OK" button to proceed to that step.)<p>If you're having problems, simply head over to forum.cheatengine.org, then click on "Tutorials" to view beginner-friendly > guides!</blockquote></details><h2 id=enumerating-processes>Enumerating processes</h2><p>Our first step is attaching to the process we want to work with. But we need a way to find that process in the first place! Having to open the task manager, look for the process we care about, noting down the process ID (PID), and slapping it in the source code is not satisfying at all. Instead, let's enumerate all the processes from within the program, and let the user select one by typing its name.<p>From a quick <a href=https://ddg.gg/winapi%20enumerate%20all%20processes>DuckDuckGo search</a>, we find an official tutorial for <a href=https://docs.microsoft.com/en-us/windows/win32/psapi/enumerating-all-processes>Enumerating All Processes</a>, which leads to the <a href=https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocesses><code>EnumProcesses</code></a> call. Cool! Let's slap in the <a href=https://crates.io/crates/winapi><code>winapi</code></a> crate on <code>Cargo.toml</code>, because I don't want to write all the definitions by myself:<pre><code class=language-toml data-lang=toml>[dependencies] winapi = { version = "0.3.9", features = ["psapi"] } </code></pre><p>Because <a href=https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocesses><code>EnumProcesses</code></a> is in <code>Psapi.h</code> (you can see this in the online page of its documentation), we know we'll need the <code>psapi</code> crate feature. Another option is to search for it in the <a href=https://docs.rs/winapi/><code>winapi</code> documentation</a> and noting down the parent module where its stored.<p>The documentation for the method has the following remark:<blockquote><p>It is a good idea to use a large array, because it is hard to predict how many processes there will be at the time you call <strong>EnumProcesses</strong>.</blockquote><p><em>Sidenote: reading the documentation for the methods we'll use from the Windows API is extremely important. There's a lot of gotchas involved, so we need to make sure we're extra careful.</em><p>1024 is a pretty big number, so let's go with that:<pre><code class=language-rust data-lang=rust>use std::io; use std::mem;
@@ -1,4 +1,4 @@
-<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=description content="Official Lonami's website"><meta name=viewport content="width=device-width, initial-scale=1.0, user-scalable=yes"><title> Writing our own Cheat Engine: Exact Value scanning | Lonami's Blog </title><link rel=stylesheet href=/style.css><body><article><nav class=sections><ul class=left><li><a href=/>lonami's site</a><li><a href=/blog class=selected>blog</a><li><a href=/golb>golb</a></ul><div class=right><a href=https://github.com/LonamiWebs><img src=/img/github.svg alt=github></a><a href=/blog/atom.xml><img src=/img/rss.svg alt=rss></a></div></nav><main><h1 class=title>Writing our own Cheat Engine: Exact Value scanning</h1><div class=time><p>2021-02-12<p>last updated 2021-02-19</div><p>This is part 2 on the <em>Writing our own Cheat Engine</em> series:<ul><li><a href=/blog/woce-1>Part 1: Introduction</a> (start here if you're new to the series!)<li>Part 2: Exact Value scanning<li><a href=/blog/woce-3>Part 3: Unknown initial value</a><li><a href=/blog/woce-4>Part 4: Floating points</a></ul><p>In the introduction, we spent a good deal of time enumerating all running processes just so we could find out the pid we cared about. With the pid now in our hands, we can do pretty much anything to its corresponding process.<p>It's now time to read the process' memory and write to it. If our process was a single-player game, this would enable us to do things like setting a very high value on the player's current health pool, making us invincible. This technique will often not work for multi-player games, because the server likely knows your true current health (the most you could probably do is make the client render an incorrect value). However, if the server is crappy and it trusts the client, then you're still free to mess around with your current health.<p>Even if we don't want to write to the process' memory, reading is still very useful. Maybe you could enhance your experience by making a custom overlay that displays useful information, or something that makes noise if it detects the life is too low, or even simulating a keyboard event to automatically recover some mana when you're running low.<p>Be warned about anti-cheat systems. Anything beyond a basic game is likely to have some protection measures in place, making the analysis more difficult (perhaps the values are scrambled in memory), or even pinging the server if it detects something fishy.<p><strong>I am not responsible for any bans!</strong> Use your brain before messing with online games, and don't ruin the fun for everyone else. If you get caught for cheating, I don't want to know about it.<p>Now that all <a href=https://www.urbandictionary.com/define.php?term=script%20kiddie>script kiddies</a> have left the room, let's proceed with the post.<h2 id=exact-value-scanning>Exact Value scanning</h2><details open><summary>Cheat Engine Tutorial: Step 2</summary> <blockquote><p>Now that you have opened the tutorial with Cheat Engine let's get on with the next step.<p>You can see at the bottom of this window is the text Health: xxx. Each time you click 'Hit me' your health gets decreased.<p>To get to the next step you have to find this value and change it to 1000<p>To find the value there are different ways, but I'll tell you about the easiest, 'Exact Value': First make sure value type is set to at least 2-bytes or 4-bytes. 1-byte will also work, but you'll run into an easy to fix problem when you've found the address and want to change it. The 8-byte may perhaps works if the bytes after the address are 0, but I wouldn't take the bet. Single, double, and the other scans just don't work, because they store the value in a different way.<p>When the value type is set correctly, make sure the scantype is set to 'Exact Value'. Then fill in the number your health is in the value box. And click 'First Scan'. After a while (if you have a extremely slow pc) the scan is done and the results are shown in the list on the left<p>If you find more than 1 address and you don't know for sure which address it is, click 'Hit me', fill in the new health value into the value box, and click 'Next Scan'. Repeat this until you're sure you've found it. (that includes that there's only 1 address in the list.....)<p>Now double click the address in the list on the left. This makes the address pop-up in the list at the bottom, showing you the current value. Double click the value, (or select it and press enter), and change the value to 1000.<p>If everything went ok the next button should become enabled, and you're ready for the next step.<p>Note: If you did anything wrong while scanning, click "New Scan" and repeat the scanning again. Also, try playing around with the value and click 'hit me'</blockquote></details><h2 id=our-first-scan>Our First Scan</h2><p>The Cheat Engine tutorial talks about "value types" and "scan types" like "exact value".<p>The <strong>value types</strong> will help us narrow down <em>what</em> we're looking for. For example, the integer type <code>i32</code> is represented in memory as 32 bits, or 4 bytes. However, <code>f32</code> is <em>also</em> represented by 4 bytes, and so is <code>u32</code>. Or perhaps the 4 bytes represent RGBA values of a color! So any 4 bytes in memory can be interpreted in many ways, and it's up to us to decide which way we interpret the bytes in.<p>When programming, numbers which are 32-bit wide are common, as they're a good (and fast) size to work with. Scanning for this type is often a good bet. For positive numbers, <code>i32</code> is represented the same as <code>u32</code> in memory, so even if the value turns out to not be signed, the scan is likely to work. Focusing on <code>i32</code> will save us from scanning for <code>f32</code> or even other types, like interpreting 8 bytes for <code>i64</code>, <code>f64</code>, or less bytes like <code>i16</code>.<p>The <strong>scan types</strong> will help us narrow down <em>how</em> we're looking for a value. Scanning for an exact value means what you think it does: interpret all 4 bytes in the process' memory as our value type, and check if they exactly match our value. This will often yield a lot of candidates, but it will be enough to get us started. Variations of the exact scan include checking for all values below a threshold, above, in between, or even just… unknown.<p>What's the point of scanning for unknown values if <em>everything</em> in memory is unknown? Sometimes you don't have a concrete value. Maybe your health pool is a bar and it nevers tell you how much health you actually have, just a visual indicator of your percentage left, even if the health is not stored as a percentage. As we will find later on, scanning for unknown values is more useful than it might appear at first.<p>We can access the memory of our own program by guessing random pointers and trying to read from them. But Windows isolates the memory of each program, so no pointer we could ever guess will let us read from the memory of another process. Luckily for us, searching for "read process memory winapi" leads us to the <a href=https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-readprocessmemory><code>ReadProcessMemory</code></a> function. Spot on.<pre><code class=language-rust data-lang=rust>pub fn read_memory(&self, addr: usize, n: usize) -> io::Result<Vec<u8>> { +<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=description content="Official Lonami's website"><meta name=viewport content="width=device-width, initial-scale=1.0, user-scalable=yes"><title> Writing our own Cheat Engine: Exact Value scanning | Lonami's Blog </title><link rel=stylesheet href=/style.css><body><article><nav class=sections><ul class=left><li><a href=/>lonami's site</a><li><a href=/blog class=selected>blog</a><li><a href=/golb>golb</a></ul><div class=right><a href=https://github.com/LonamiWebs><img src=/img/github.svg alt=github></a><a href=/blog/atom.xml><img src=/img/rss.svg alt=rss></a></div></nav><main><h1 class=title>Writing our own Cheat Engine: Exact Value scanning</h1><div class=time><p>2021-02-12<p>last updated 2021-02-19</div><p>This is part 2 on the <em>Writing our own Cheat Engine</em> series:<ul><li><a href=/blog/woce-1>Part 1: Introduction</a> (start here if you're new to the series!)<li>Part 2: Exact Value scanning<li><a href=/blog/woce-3>Part 3: Unknown initial value</a><li><a href=/blog/woce-4>Part 4: Floating points</a><li><a href=/blog/woce-5>Part 5: Code finder</a></ul><p>In the introduction, we spent a good deal of time enumerating all running processes just so we could find out the pid we cared about. With the pid now in our hands, we can do pretty much anything to its corresponding process.<p>It's now time to read the process' memory and write to it. If our process was a single-player game, this would enable us to do things like setting a very high value on the player's current health pool, making us invincible. This technique will often not work for multi-player games, because the server likely knows your true current health (the most you could probably do is make the client render an incorrect value). However, if the server is crappy and it trusts the client, then you're still free to mess around with your current health.<p>Even if we don't want to write to the process' memory, reading is still very useful. Maybe you could enhance your experience by making a custom overlay that displays useful information, or something that makes noise if it detects the life is too low, or even simulating a keyboard event to automatically recover some mana when you're running low.<p>Be warned about anti-cheat systems. Anything beyond a basic game is likely to have some protection measures in place, making the analysis more difficult (perhaps the values are scrambled in memory), or even pinging the server if it detects something fishy.<p><strong>I am not responsible for any bans!</strong> Use your brain before messing with online games, and don't ruin the fun for everyone else. If you get caught for cheating, I don't want to know about it.<p>Now that all <a href=https://www.urbandictionary.com/define.php?term=script%20kiddie>script kiddies</a> have left the room, let's proceed with the post.<h2 id=exact-value-scanning>Exact Value scanning</h2><details open><summary>Cheat Engine Tutorial: Step 2</summary> <blockquote><p>Now that you have opened the tutorial with Cheat Engine let's get on with the next step.<p>You can see at the bottom of this window is the text Health: xxx. Each time you click 'Hit me' your health gets decreased.<p>To get to the next step you have to find this value and change it to 1000<p>To find the value there are different ways, but I'll tell you about the easiest, 'Exact Value': First make sure value type is set to at least 2-bytes or 4-bytes. 1-byte will also work, but you'll run into an easy to fix problem when you've found the address and want to change it. The 8-byte may perhaps works if the bytes after the address are 0, but I wouldn't take the bet. Single, double, and the other scans just don't work, because they store the value in a different way.<p>When the value type is set correctly, make sure the scantype is set to 'Exact Value'. Then fill in the number your health is in the value box. And click 'First Scan'. After a while (if you have a extremely slow pc) the scan is done and the results are shown in the list on the left<p>If you find more than 1 address and you don't know for sure which address it is, click 'Hit me', fill in the new health value into the value box, and click 'Next Scan'. Repeat this until you're sure you've found it. (that includes that there's only 1 address in the list.....)<p>Now double click the address in the list on the left. This makes the address pop-up in the list at the bottom, showing you the current value. Double click the value, (or select it and press enter), and change the value to 1000.<p>If everything went ok the next button should become enabled, and you're ready for the next step.<p>Note: If you did anything wrong while scanning, click "New Scan" and repeat the scanning again. Also, try playing around with the value and click 'hit me'</blockquote></details><h2 id=our-first-scan>Our First Scan</h2><p>The Cheat Engine tutorial talks about "value types" and "scan types" like "exact value".<p>The <strong>value types</strong> will help us narrow down <em>what</em> we're looking for. For example, the integer type <code>i32</code> is represented in memory as 32 bits, or 4 bytes. However, <code>f32</code> is <em>also</em> represented by 4 bytes, and so is <code>u32</code>. Or perhaps the 4 bytes represent RGBA values of a color! So any 4 bytes in memory can be interpreted in many ways, and it's up to us to decide which way we interpret the bytes in.<p>When programming, numbers which are 32-bit wide are common, as they're a good (and fast) size to work with. Scanning for this type is often a good bet. For positive numbers, <code>i32</code> is represented the same as <code>u32</code> in memory, so even if the value turns out to not be signed, the scan is likely to work. Focusing on <code>i32</code> will save us from scanning for <code>f32</code> or even other types, like interpreting 8 bytes for <code>i64</code>, <code>f64</code>, or less bytes like <code>i16</code>.<p>The <strong>scan types</strong> will help us narrow down <em>how</em> we're looking for a value. Scanning for an exact value means what you think it does: interpret all 4 bytes in the process' memory as our value type, and check if they exactly match our value. This will often yield a lot of candidates, but it will be enough to get us started. Variations of the exact scan include checking for all values below a threshold, above, in between, or even just… unknown.<p>What's the point of scanning for unknown values if <em>everything</em> in memory is unknown? Sometimes you don't have a concrete value. Maybe your health pool is a bar and it nevers tell you how much health you actually have, just a visual indicator of your percentage left, even if the health is not stored as a percentage. As we will find later on, scanning for unknown values is more useful than it might appear at first.<p>We can access the memory of our own program by guessing random pointers and trying to read from them. But Windows isolates the memory of each program, so no pointer we could ever guess will let us read from the memory of another process. Luckily for us, searching for "read process memory winapi" leads us to the <a href=https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-readprocessmemory><code>ReadProcessMemory</code></a> function. Spot on.<pre><code class=language-rust data-lang=rust>pub fn read_memory(&self, addr: usize, n: usize) -> io::Result<Vec<u8>> { todo!() } </code></pre><p>Much like trying to dereference a pointer pointing to released memory or even null, reading from an arbitrary address can fail for the same reasons (and more). We will want to signal this with <code>io::Result</code>. It's funny to note that, even though we're doing something that seems wildly unsafe (reading arbitrary memory, even if the other process is mutating it at the same time), the function is perfectly safe. If we cannot read something, it will return <code>Err</code>, but if it succeeds, it has taken a snapshot of the memory of the process, and the returned value will be correctly initialized.<p>The function will be defined inside our <code>impl Process</code>, since it conveniently holds an open handle to the process in question. It takes <code>&self</code>, because we do not need to mutate anything in the <code>Process</code> instance. After adding the <code>memoryapi</code> feature to <code>Cargo.toml</code>, we can perform the call:<pre><code class=language-rust data-lang=rust>let mut buffer = Vec::<u8>::with_capacity(n);
@@ -1,4 +1,4 @@
-<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=description content="Official Lonami's website"><meta name=viewport content="width=device-width, initial-scale=1.0, user-scalable=yes"><title> Writing our own Cheat Engine: Unknown initial value | Lonami's Blog </title><link rel=stylesheet href=/style.css><body><article><nav class=sections><ul class=left><li><a href=/>lonami's site</a><li><a href=/blog class=selected>blog</a><li><a href=/golb>golb</a></ul><div class=right><a href=https://github.com/LonamiWebs><img src=/img/github.svg alt=github></a><a href=/blog/atom.xml><img src=/img/rss.svg alt=rss></a></div></nav><main><h1 class=title>Writing our own Cheat Engine: Unknown initial value</h1><div class=time><p>2021-02-19</div><p>This is part 3 on the <em>Writing our own Cheat Engine</em> series:<ul><li><a href=/blog/woce-1>Part 1: Introduction</a> (start here if you're new to the series!)<li><a href=/blog/woce-2>Part 2: Exact Value scanning</a><li>Part 3: Unknown initial value<li><a href=/blog/woce-4>Part 4: Floating points</a></ul><p>In part 2 we left off with a bit of a cliff-hanger. Our little program is now able to scan for an exact value, remember the couple hundred addresses pointing to said value, and perform subsequent scans to narrow the list of addresses down until we're left with a handful of them.<p>However, it is not always the case that you have an exact value to work with. The best you can do in these cases is guess what the software might be storing. For example, it could be a floating point for your current movement speed in a game, or an integer for your current health.<p>The problem with this is that there are far too many possible locations storing our desired value. If you count misaligned locations, this means there is a different location to address every single byte in memory. A program with one megabyte of memory already has a <em>million</em> of addresses. Clearly, we need to do better than performing one million memory reads<sup class=footnote-reference><a href=#1>1</a></sup>.<p>This post will shift focus a bit from using <code>winapi</code> to possible techniques to perform the various scans.<h2 id=unknown-initial-value>Unknown initial value</h2><details open><summary>Cheat Engine Tutorial: Step 3</summary> <blockquote><p>Ok, seeing that you've figured out how to find a value using exact value let's move on to the next step.<p>First things first though. Since you are doing a new scan, you have to click on New Scan first, to start a new scan. (You may think this is straighforward, but you'd be surprised how many people get stuck on that step) I won't be explaining this step again, so keep this in mind Now that you've started a new scan, let's continue<p>In the previous test we knew the initial value so we could do a exact value, but now we have a status bar where we don't know the starting value. We only know that the value is between 0 and 500. And each time you click 'hit me' you lose some health. The amount you lose each time is shown above the status bar.<p>Again there are several different ways to find the value. (like doing a decreased value by... scan), but I'll only explain the easiest. "Unknown initial value", and decreased value. Because you don't know the value it is right now, a exact value wont do any good, so choose as scantype 'Unknown initial value', again, the value type is 4-bytes. (most windows apps use 4-bytes)click first scan and wait till it's done.<p>When it is done click 'hit me'. You'll lose some of your health. (the amount you lost shows for a few seconds and then disappears, but you don't need that) Now go to Cheat Engine, and choose 'Decreased Value' and click 'Next Scan' When that scan is done, click hit me again, and repeat the above till you only find a few.<p>We know the value is between 0 and 500, so pick the one that is most likely the address we need, and add it to the list. Now change the health to 5000, to proceed to the next step.</blockquote></details><h2 id=dense-memory-locations>Dense memory locations</h2><p>The key thing to notice here is that, when we read memory from another process, we do so over <em>entire regions</em>. A memory region is represented by a starting offset, a size, and a bunch of other things like protection level.<p>When running the first scan for an unknown value, all we need to remember is the starting offset and size for every single region. All the candidate locations that could point to our value fall within this range, so it is enough for us to store the range definition, and not every location within it.<p>To gain a better understanding of what this means, let's come up with a more specific scenario. With our current approach of doing things, we store an address (<code>usize</code>) for every location pointing to our desired value. In the case of unknown values, all locations are equally valid, since we don't know what value they should point to yet, and any value they point to is good. With this representation, we would end up with a very large vector:<pre><code class=language-rust data-lang=rust>let locations = vec![0x2000, 0x2001, ..., 0x20ff, 0x2100]; +<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=description content="Official Lonami's website"><meta name=viewport content="width=device-width, initial-scale=1.0, user-scalable=yes"><title> Writing our own Cheat Engine: Unknown initial value | Lonami's Blog </title><link rel=stylesheet href=/style.css><body><article><nav class=sections><ul class=left><li><a href=/>lonami's site</a><li><a href=/blog class=selected>blog</a><li><a href=/golb>golb</a></ul><div class=right><a href=https://github.com/LonamiWebs><img src=/img/github.svg alt=github></a><a href=/blog/atom.xml><img src=/img/rss.svg alt=rss></a></div></nav><main><h1 class=title>Writing our own Cheat Engine: Unknown initial value</h1><div class=time><p>2021-02-19</div><p>This is part 3 on the <em>Writing our own Cheat Engine</em> series:<ul><li><a href=/blog/woce-1>Part 1: Introduction</a> (start here if you're new to the series!)<li><a href=/blog/woce-2>Part 2: Exact Value scanning</a><li>Part 3: Unknown initial value<li><a href=/blog/woce-4>Part 4: Floating points</a><li><a href=/blog/woce-5>Part 5: Code finder</a></ul><p>In part 2 we left off with a bit of a cliff-hanger. Our little program is now able to scan for an exact value, remember the couple hundred addresses pointing to said value, and perform subsequent scans to narrow the list of addresses down until we're left with a handful of them.<p>However, it is not always the case that you have an exact value to work with. The best you can do in these cases is guess what the software might be storing. For example, it could be a floating point for your current movement speed in a game, or an integer for your current health.<p>The problem with this is that there are far too many possible locations storing our desired value. If you count misaligned locations, this means there is a different location to address every single byte in memory. A program with one megabyte of memory already has a <em>million</em> of addresses. Clearly, we need to do better than performing one million memory reads<sup class=footnote-reference><a href=#1>1</a></sup>.<p>This post will shift focus a bit from using <code>winapi</code> to possible techniques to perform the various scans.<h2 id=unknown-initial-value>Unknown initial value</h2><details open><summary>Cheat Engine Tutorial: Step 3</summary> <blockquote><p>Ok, seeing that you've figured out how to find a value using exact value let's move on to the next step.<p>First things first though. Since you are doing a new scan, you have to click on New Scan first, to start a new scan. (You may think this is straighforward, but you'd be surprised how many people get stuck on that step) I won't be explaining this step again, so keep this in mind Now that you've started a new scan, let's continue<p>In the previous test we knew the initial value so we could do a exact value, but now we have a status bar where we don't know the starting value. We only know that the value is between 0 and 500. And each time you click 'hit me' you lose some health. The amount you lose each time is shown above the status bar.<p>Again there are several different ways to find the value. (like doing a decreased value by... scan), but I'll only explain the easiest. "Unknown initial value", and decreased value. Because you don't know the value it is right now, a exact value wont do any good, so choose as scantype 'Unknown initial value', again, the value type is 4-bytes. (most windows apps use 4-bytes)click first scan and wait till it's done.<p>When it is done click 'hit me'. You'll lose some of your health. (the amount you lost shows for a few seconds and then disappears, but you don't need that) Now go to Cheat Engine, and choose 'Decreased Value' and click 'Next Scan' When that scan is done, click hit me again, and repeat the above till you only find a few.<p>We know the value is between 0 and 500, so pick the one that is most likely the address we need, and add it to the list. Now change the health to 5000, to proceed to the next step.</blockquote></details><h2 id=dense-memory-locations>Dense memory locations</h2><p>The key thing to notice here is that, when we read memory from another process, we do so over <em>entire regions</em>. A memory region is represented by a starting offset, a size, and a bunch of other things like protection level.<p>When running the first scan for an unknown value, all we need to remember is the starting offset and size for every single region. All the candidate locations that could point to our value fall within this range, so it is enough for us to store the range definition, and not every location within it.<p>To gain a better understanding of what this means, let's come up with a more specific scenario. With our current approach of doing things, we store an address (<code>usize</code>) for every location pointing to our desired value. In the case of unknown values, all locations are equally valid, since we don't know what value they should point to yet, and any value they point to is good. With this representation, we would end up with a very large vector:<pre><code class=language-rust data-lang=rust>let locations = vec![0x2000, 0x2001, ..., 0x20ff, 0x2100]; </code></pre><p>This representation is dense. Every single number in the range <code>0x2000..=0x2100</code> is present. So why bother storing the values individually when the range is enough?:<pre><code class=language-rust data-lang=rust>let locations = EntireRegion { range: 0x2000..=0x2100 }; </code></pre><p>Much better! With two <code>usize</code>, one for the starting location and another for the end, we can indicate that we care about all the locations falling in that range.<p>In fact, some accessible memory regions immediately follow eachother, so we could even compact this further and merge regions which are together. But due to their potential differences with regards to protection levels, we will not attempt to merge regions.<p>We don't want to get rid of the old way of storing locations, because once we start narrowing them down, we will want to go back to storing just a few candidates. To keep things tidy, let's introduce a new <code>enum</code> representing either possibility:<pre><code class=language-rust data-lang=rust>use std::ops::Range;
@@ -1,4 +1,4 @@
-<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=description content="Official Lonami's website"><meta name=viewport content="width=device-width, initial-scale=1.0, user-scalable=yes"><title> Writing our own Cheat Engine: Floating points | Lonami's Blog </title><link rel=stylesheet href=/style.css><body><article><nav class=sections><ul class=left><li><a href=/>lonami's site</a><li><a href=/blog class=selected>blog</a><li><a href=/golb>golb</a></ul><div class=right><a href=https://github.com/LonamiWebs><img src=/img/github.svg alt=github></a><a href=/blog/atom.xml><img src=/img/rss.svg alt=rss></a></div></nav><main><h1 class=title>Writing our own Cheat Engine: Floating points</h1><div class=time><p>2021-02-22</div><p>This is part 4 on the <em>Writing our own Cheat Engine</em> series:<ul><li><a href=/blog/woce-1>Part 1: Introduction</a> (start here if you're new to the series!)<li><a href=/blog/woce-2>Part 2: Exact Value scanning</a><li><a href=/blog/woce-3>Part 3: Unknown initial value</a><li>Part 4: Floating points</ul><p>In part 3 we did a fair amount of plumbing in order to support scan modes beyond the trivial "exact value scan". As a result, we have abstracted away the <code>Scan</code>, <code>CandidateLocations</code> and <code>Value</code> types as a separate <code>enum</code> each. Scanning for changed memory regions in an opened process can now be achieved with three lines of code:<pre><code class=language-rust data-lang=rust>let regions = process.memory_regions(); +<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=description content="Official Lonami's website"><meta name=viewport content="width=device-width, initial-scale=1.0, user-scalable=yes"><title> Writing our own Cheat Engine: Floating points | Lonami's Blog </title><link rel=stylesheet href=/style.css><body><article><nav class=sections><ul class=left><li><a href=/>lonami's site</a><li><a href=/blog class=selected>blog</a><li><a href=/golb>golb</a></ul><div class=right><a href=https://github.com/LonamiWebs><img src=/img/github.svg alt=github></a><a href=/blog/atom.xml><img src=/img/rss.svg alt=rss></a></div></nav><main><h1 class=title>Writing our own Cheat Engine: Floating points</h1><div class=time><p>2021-02-22</div><p>This is part 4 on the <em>Writing our own Cheat Engine</em> series:<ul><li><a href=/blog/woce-1>Part 1: Introduction</a> (start here if you're new to the series!)<li><a href=/blog/woce-2>Part 2: Exact Value scanning</a><li><a href=/blog/woce-3>Part 3: Unknown initial value</a><li>Part 4: Floating points<li><a href=/blog/woce-5>Part 5: Code finder</a></ul><p>In part 3 we did a fair amount of plumbing in order to support scan modes beyond the trivial "exact value scan". As a result, we have abstracted away the <code>Scan</code>, <code>CandidateLocations</code> and <code>Value</code> types as a separate <code>enum</code> each. Scanning for changed memory regions in an opened process can now be achieved with three lines of code:<pre><code class=language-rust data-lang=rust>let regions = process.memory_regions(); let first_scan = process.scan_regions(&regions, Scan::InRange(0, 500)); let second_scan = process.rescan_regions(&first_scan, Scan::DecreasedBy(7)); </code></pre><p>How's that for programmability? No need to fire up Cheat Engine's GUI anymore!<p>The <code>first_scan</code> in the example above remembers all the found <code>Value</code> within the range specified by <code>Scan</code>. Up until now, we have only worked with <code>i32</code>, so that's the type the scans expect and what they work with.<p>Now it's time to introduce support for different types, like <code>f32</code>, <code>i64</code>, or even more atypical ones, like arbitrary sequences of bytes (think of strings) or even numbers in big-endian.<p>Tighten your belt, because this post is quite the ride. Let's get right into it!<h2 id=floating-points>Floating points</h2><details open><summary>Cheat Engine Tutorial: Step 4</summary> <blockquote><p>In the previous tutorial we used bytes to scan, but some games store information in so called 'floating point' notations. (probably to prevent simple memory scanners from finding it the easy way). A floating point is a value with some digits behind the point. (like 5.12 or 11321.1)<p>Below you see your health and ammo. Both are stored as Floating point notations, but health is stored as a float and ammo is stored as a double. Click on hit me to lose some health, and on shoot to decrease your ammo with 0.5<p>You have to set BOTH values to 5000 or higher to proceed.<p>Exact value scan will work fine here, but you may want to experiment with other types too.<p>Hint: It is recommended to disable "Fast Scan" for type double</blockquote></details><h2 id=generic-values>Generic values</h2><p>The <code>Value</code> enumeration holds scanned values, and is currently hardcoded to store <code>i32</code>. The <code>Scan</code> type also holds a value, the value we want to scan for. Changing it to support other types is trivial:<pre><code class=language-rust data-lang=rust>pub enum Scan<T> {@@ -195,4 +195,4 @@ }
)* }; } -</code></pre><p>Our <code>Scan</code> needs to store the <code>Scannable</code> type, and not just the memory, once again. For variants that don't need any value, they can store the <code>ScanMode</code> and size instead.<p>Does this solution work? Yes! It's possible to return a <code>Box<dyn Scannable></code> from a function, and underneath, it may be using any type which is <code>Scannable</code>. Is this the best solution? Well, that's hard to say. This is <em>one</em> of the possible solutions.<p>We have been going around in circles for quite some time now, so I'll leave it there. It's a solution, which may not be pretty, but it works. With these changes, the code is capable of completing all of the steps in the Cheat Engine tutorial up until point!<h2 id=finale>Finale</h2><p>If there's one lesson to learn from this post, it's that there is often no single correct solution to a problem. We could have approached the scan types in many, many ways (and we tried quite a few!), but in the end, choosing one option or the other comes down to your (sometimes self-imposed) requirements.<p>You may <a href=https://github.com/lonami/memo>obtain the code for this post</a> over at my GitHub. You can run <code>git checkout step4</code> after cloning the repository to get the right version of the code. The code has gone through a lot of iterations, and I'd still like to polish it a bit more, so it might slightly differ from the code presented in this entry.<p>If you feel adventurous, Cheat Engine has different options for scanning floating point types: "rounded (default)", "rounded (extreme)", and truncated. Optionally, it can scan for "simple values only". You could go ahead and toy around with these!<p>We didn't touch on types with different lengths, such as strings. You could support UTF-8, UTF-16, or arbitrary byte sequences. This post also didn't cover scanning for multiple things at once, known as "groupscan commands", although from what I can tell, these are just a nice way to scan for arbitrary byte sequences.<p>We also didn't look into supporting different the same scan with different alignments. All these things may be worth exploring depending on your requirements. You could even get rid of such genericity and go with something way simpler. Supporting <code>i32</code>, <code>f32</code> and <code>f64</code> is enough to complete the Cheat Engine tutorial. But I wanted something more powerful, although my solution currently can't scan for a sequence such as "exact type, unknown, exact matching the unknown". So yeah.<p>In the next post, we'll tackle the fifth step of the tutorial: Code finder. Cheat Engine attaches its debugger to the process for this one, and then replaces the instruction that performs the write with a different no-op so that nothing is written anymore. This will be quite the challenge!<h3 id=footnotes>Footnotes</h3><div class=footnote-definition id=1><sup class=footnote-definition-label>1</sup><p><a href=https://doc.rust-lang.org/stable/std/ops/trait.Drop.html#copy-and-drop-are-exclusive><code>Copy</code> and <code>Drop</code> are exclusive</a>. See also <a href=https://doc.rust-lang.org/stable/error-index.html#E0184>E0184</a>.</div><div class=footnote-definition id=2><sup class=footnote-definition-label>2</sup><p>If you added more scan types that require additional bounds, make sure to add them too. For example, the "decreased by" scan requires the type to <code>impl Sub</code>.</div><div class=footnote-definition id=3><sup class=footnote-definition-label>3</sup><p>This is a good time to remind you to read the documentation. It is of special importance when dealing with <code>unsafe</code> methods; I recommend reading it a couple times.</div><div class=footnote-definition id=4><sup class=footnote-definition-label>4</sup><p>Even with this option, it would not be a bad idea to make the trait <code>unsafe</code>.</div><div class=footnote-definition id=5><sup class=footnote-definition-label>5</sup><p>Not for long. As we will find out later, this approach has its limitations.</div><div class=footnote-definition id=6><sup class=footnote-definition-label>6</sup><p>We can still perform the pointer dereference when we know it's aligned. This would likely be an optimization, although it would definitely complicate the code more.</div><div class=footnote-definition id=7><sup class=footnote-definition-label>7</sup><p>It <em>would</em> work if you scanned for unknown values and then checked for decreased values repeatedly. But we can't just leave exact scan broken!</div><div class=footnote-definition id=8><sup class=footnote-definition-label>8</sup><p>Unfortunately, this makes some optimizations harder or even impossible to perform. Providing specialized functions for types where the size is known at compile time could be worth doing. Programming is all tradeoffs.</div><div class=footnote-definition id=9><sup class=footnote-definition-label>9</sup><p><a href=https://blog.rust-lang.org/2021/02/26/const-generics-mvp-beta.html>Rust 1.51</a>, which was not out at the time of writing, would make it a lot easier to allow scanning for fixed-length sequences of bytes, thanks to const generics.</div><div class=footnote-definition id=10><sup class=footnote-definition-label>10</sup><p>Workarounds do exist, such as <a href=https://crates.io/crates/dyn-clone>dtolnay's <code>dyn-clone</code></a>. But I would rather not go that route.</div></main><footer><div><p>Share your thoughts, or simply come hang with me <a href=https://t.me/LonamiWebs><img src=/img/telegram.svg alt=Telegram></a> <a href=mailto:totufals@hotmail.com><img src=/img/mail.svg alt=Mail></a></div></footer></article><p class=abyss>Glaze into the abyss… Oh hi there!+</code></pre><p>Our <code>Scan</code> needs to store the <code>Scannable</code> type, and not just the memory, once again. For variants that don't need any value, they can store the <code>ScanMode</code> and size instead.<p>Does this solution work? Yes! It's possible to return a <code>Box<dyn Scannable></code> from a function, and underneath, it may be using any type which is <code>Scannable</code>. Is this the best solution? Well, that's hard to say. This is <em>one</em> of the possible solutions.<p>We have been going around in circles for quite some time now, so I'll leave it there. It's a solution, which may not be pretty, but it works. With these changes, the code is capable of completing all of the steps in the Cheat Engine tutorial up until point!<h2 id=finale>Finale</h2><p>If there's one lesson to learn from this post, it's that there is often no single correct solution to a problem. We could have approached the scan types in many, many ways (and we tried quite a few!), but in the end, choosing one option or the other comes down to your (sometimes self-imposed) requirements.<p>You may <a href=https://github.com/lonami/memo>obtain the code for this post</a> over at my GitHub. You can run <code>git checkout step4</code> after cloning the repository to get the right version of the code. The code has gone through a lot of iterations, and I'd still like to polish it a bit more, so it might slightly differ from the code presented in this entry.<p>If you feel adventurous, Cheat Engine has different options for scanning floating point types: "rounded (default)", "rounded (extreme)", and truncated. Optionally, it can scan for "simple values only". You could go ahead and toy around with these!<p>We didn't touch on types with different lengths, such as strings. You could support UTF-8, UTF-16, or arbitrary byte sequences. This post also didn't cover scanning for multiple things at once, known as "groupscan commands", although from what I can tell, these are just a nice way to scan for arbitrary byte sequences.<p>We also didn't look into supporting different the same scan with different alignments. All these things may be worth exploring depending on your requirements. You could even get rid of such genericity and go with something way simpler. Supporting <code>i32</code>, <code>f32</code> and <code>f64</code> is enough to complete the Cheat Engine tutorial. But I wanted something more powerful, although my solution currently can't scan for a sequence such as "exact type, unknown, exact matching the unknown". So yeah.<p>In the <a href=/blog/woce-5>next post</a>, we'll tackle the fifth step of the tutorial: Code finder. Cheat Engine attaches its debugger to the process for this one, and then replaces the instruction that performs the write with a different no-op so that nothing is written anymore. This will be quite the challenge!<h3 id=footnotes>Footnotes</h3><div class=footnote-definition id=1><sup class=footnote-definition-label>1</sup><p><a href=https://doc.rust-lang.org/stable/std/ops/trait.Drop.html#copy-and-drop-are-exclusive><code>Copy</code> and <code>Drop</code> are exclusive</a>. See also <a href=https://doc.rust-lang.org/stable/error-index.html#E0184>E0184</a>.</div><div class=footnote-definition id=2><sup class=footnote-definition-label>2</sup><p>If you added more scan types that require additional bounds, make sure to add them too. For example, the "decreased by" scan requires the type to <code>impl Sub</code>.</div><div class=footnote-definition id=3><sup class=footnote-definition-label>3</sup><p>This is a good time to remind you to read the documentation. It is of special importance when dealing with <code>unsafe</code> methods; I recommend reading it a couple times.</div><div class=footnote-definition id=4><sup class=footnote-definition-label>4</sup><p>Even with this option, it would not be a bad idea to make the trait <code>unsafe</code>.</div><div class=footnote-definition id=5><sup class=footnote-definition-label>5</sup><p>Not for long. As we will find out later, this approach has its limitations.</div><div class=footnote-definition id=6><sup class=footnote-definition-label>6</sup><p>We can still perform the pointer dereference when we know it's aligned. This would likely be an optimization, although it would definitely complicate the code more.</div><div class=footnote-definition id=7><sup class=footnote-definition-label>7</sup><p>It <em>would</em> work if you scanned for unknown values and then checked for decreased values repeatedly. But we can't just leave exact scan broken!</div><div class=footnote-definition id=8><sup class=footnote-definition-label>8</sup><p>Unfortunately, this makes some optimizations harder or even impossible to perform. Providing specialized functions for types where the size is known at compile time could be worth doing. Programming is all tradeoffs.</div><div class=footnote-definition id=9><sup class=footnote-definition-label>9</sup><p><a href=https://blog.rust-lang.org/2021/02/26/const-generics-mvp-beta.html>Rust 1.51</a>, which was not out at the time of writing, would make it a lot easier to allow scanning for fixed-length sequences of bytes, thanks to const generics.</div><div class=footnote-definition id=10><sup class=footnote-definition-label>10</sup><p>Workarounds do exist, such as <a href=https://crates.io/crates/dyn-clone>dtolnay's <code>dyn-clone</code></a>. But I would rather not go that route.</div></main><footer><div><p>Share your thoughts, or simply come hang with me <a href=https://t.me/LonamiWebs><img src=/img/telegram.svg alt=Telegram></a> <a href=mailto:totufals@hotmail.com><img src=/img/mail.svg alt=Mail></a></div></footer></article><p class=abyss>Glaze into the abyss… Oh hi there!
@@ -0,0 +1,376 @@
+<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=description content="Official Lonami's website"><meta name=viewport content="width=device-width, initial-scale=1.0, user-scalable=yes"><title> Writing our own Cheat Engine: Code finder | Lonami's Blog </title><link rel=stylesheet href=/style.css><body><article><nav class=sections><ul class=left><li><a href=/>lonami's site</a><li><a href=/blog class=selected>blog</a><li><a href=/golb>golb</a></ul><div class=right><a href=https://github.com/LonamiWebs><img src=/img/github.svg alt=github></a><a href=/blog/atom.xml><img src=/img/rss.svg alt=rss></a></div></nav><main><h1 class=title>Writing our own Cheat Engine: Code finder</h1><div class=time><p>2021-03-06</div><p>This is part 5 on the <em>Writing our own Cheat Engine</em> series:<ul><li><a href=/blog/woce-1>Part 1: Introduction</a> (start here if you're new to the series!)<li><a href=/blog/woce-2>Part 2: Exact Value scanning</a><li><a href=/blog/woce-3>Part 3: Unknown initial value</a><li><a href=/blog/woce-4>Part 4: Floating points</a><li>Part 5: Code finder</ul><p>In part 4 we spent a good deal of time trying to make our scans generic, and now we have something that works<sup class=footnote-reference><a href=#1>1</a></sup>! Now that the scanning is fairly powerful and all covered, the Cheat Engine tutorial shifts focus into slightly more advanced techniques that you will most certainly need in anything bigger than a toy program.<p>It's time to write our very own <strong>debugger</strong> in Rust!<h2 id=code-finder>Code finder</h2><details open><summary>Cheat Engine Tutorial: Step 5</summary> <blockquote><p>Sometimes the location something is stored at changes when you restart the game, or even while you're playing… In that case you can use 2 things to still make a table that works. In this step I'll try to describe how to use the Code Finder function.<p>The value down here will be at a different location each time you start the tutorial, so a normal entry in the address list wouldn't work. First try to find the address. (You've got to this point so I assume you know how to.)<p>When you've found the address, right-click the address in Cheat Engine and choose "Find out what writes to this address". A window will pop up with an empty list.<p>Then click on the Change value button in this tutorial, and go back to Cheat Engine. If everything went right there should be an address with assembler code there now.<p>Click it and choose the replace option to replace it with code that does nothing. That will also add the code address to the code list in the advanced options window. (Which gets saved if you save your table.)<p>Click on stop, so the game will start running normal again, and close to close the window. Now, click on Change value, and if everything went right the Next button should become enabled.<p>Note: When you're freezing the address with a high enough speed it may happen that next becomes visible anyhow</blockquote></details><h2 id=baby-steps-to-debugging>Baby steps to debugging</h2><p>Although I have used debuggers before, I have never had a need to write one myself so it's time for some research.<p>Searching on DuckDuckGo, I can find entire series to <a href=http://system.joekain.com/debugger/>Writing a Debugger</a>. We would be done by now if only that series wasn't written for Linux. The Windows documentation contains a section called <a href=https://docs.microsoft.com/en-us/windows/win32/debug/creating-a-basic-debugger>Creating a Basic Debugger</a>, but as far as I can tell, it only teaches you the <a href=https://docs.microsoft.com/en-us/windows/win32/debug/debugging-functions>functions</a> needed to configure the debugging loop. Which mind you, we will need, but in due time.<p>According to <a href=https://www.gironsec.com/blog/2013/12/writing-your-own-debugger-windows-in-c/>Writing your own windows debugger in C</a>, the steps needed to write a debugger are:<ul><li><a href=https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-suspendthread><code>SuspendThread(proc)</code></a>. It makes sense that we need to pause all the threads<sup class=footnote-reference><a href=#2>2</a></sup> before messing around with the code the program is executing, or things are very prone to go wrong.<li><a href=https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadcontext><code>GetThreadContext(proc)</code></a>. This function retrieves the appropriate context of the specified thread and is highly processor specific. It basically takes a snapshot of all the registers. Think of registers like extremely fast, but also extremely limited, memory the processor uses.<li><a href=https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-debugbreakprocess><code>DebugBreakProcess</code></a>. Essentially <a href=https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/x86-instructions#miscellaneous>writes out the 0xCC opcode</a>, <code>int 3</code> in assembly, also known as software breakpoint. It's written wherever the Register Instruction Pointer (RIP<sup class=footnote-reference><a href=#3>3</a></sup>) currently points to, so in essence, when the thread resumes, it will immediately <a href=https://stackoverflow.com/q/3915511/>trigger the breakpoint</a>.<li><a href=https://docs.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-continuedebugevent><code>ContinueDebugEvent</code></a>. Presumably continues debugging.</ul><p>There are pages documenting <a href=https://docs.microsoft.com/en-us/windows/win32/debug/debugging-events>all of the debug events</a> that our debugger will be able to handle.<p>Okay, nice! Software breakpoints seem to be done by writing out memory to the region where the program is reading instructions from. We know how to write memory, as that's what all the previous posts have been doing to complete the corresponding tutorial steps. After the breakpoint is executed, all we need to do is <a href=https://stackoverflow.com/q/3747852/>restore the original memory back</a> so that the next time the program executes the code it sees no difference.<p>But a software breakpoint will halt execution when the code executes the interrupt instruction. This step of the tutorial wants us to find <em>what writes to a memory location</em>. Where should we place the breakpoint to detect such location? Writing out the instruction to the memory we want to break in won't do; it's not an instruction, it's just data.<p>The name may have given it away. If we're talking about software breakpoints, it makes sense that there would exist such a thing as <a href=https://en.wikipedia.org/wiki/Breakpoint#Hardware><em>hardware</em> breakpoints</a>. Because they're tied to the hardware, they're highly processor-specific, but luckily for us, the processor on your usual desktop computer probably has them! Even the <a href=https://interrupt.memfault.com/blog/cortex-m-breakpoints>cortex-m</a> does. The wikipedia page also tells us the name of the thing we're looking for, watchpoints:<blockquote><p>Other kinds of conditions can also be used, such as the reading, writing, or modification of a specific location in an area of memory. This is often referred to as a conditional breakpoint, a data breakpoint, or a watchpoint.</blockquote><p>A breakpoint that triggers when a specific memory location is written to is exactly what we need, and <a href=https://stackoverflow.com/a/19109153/>x86 has debug registers D0 to D3 to track memory addresses</a>. As far as I can tell, there is no API in specific to mess with the registers. But we don't need any of that! We can just go ahead and <a href=https://doc.rust-lang.org/stable/unstable-book/library-features/asm.html>write some assembly by hand</a> to access these registers. At the time of writing, inline assembly is unstable, so we need a nightly compiler. Run <code>rustup toolchain install nightly</code> if you haven't yet, and execute the following code with <code>cargo +nightly run</code>:<pre><code class=language-rust data-lang=rust>#![feature(asm)] // top of the file + +fn main() { + let x: u64 = 123; + unsafe { + asm!("mov dr7, {}", in(reg) x); + } +} + +</code></pre><p><code>dr7</code> stands is the <a href=https://en.wikipedia.org/wiki/X86_debug_register>debug control register</a>, and running this we get…<pre><code>>cargo +nightly run + Compiling memo v0.1.0 + Finished dev [unoptimized + debuginfo] target(s) in 0.74s + Running `target\debug\memo.exe` +error: process didn't exit successfully: `target\debug\memo.exe` (exit code: 0xc0000096, STATUS_PRIVILEGED_INSTRUCTION) +</code></pre><p>…an exception! In all fairness, I have no idea what that code would have done. So maybe the <code>STATUS_PRIVILEGED_INSTRUCTION</code> is just trying to protect us. Can we read from the register instead, and see it's default value?<pre><code class=language-rust data-lang=rust>let x: u64; +unsafe { + asm!("mov {}, dr7", out(reg) x); +} +assert_eq!(x, 5); +</code></pre><pre><code>>cargo +nightly run +... +error: process didn't exit successfully: `target\debug\memo.exe` (exit code: 0xc0000096, STATUS_PRIVILEGED_INSTRUCTION) +</code></pre><p>Nope. Okay, it seems directly reading from or writing to the debug register is a ring-0 thing. Surely there's a way around this. But first we should figure out how to enumerate and pause all the threads.<h2 id=pausing-all-the-threads>Pausing all the threads</h2><p>It seems there is no straightforward way to enumerate the threads. One has to <a href=https://stackoverflow.com/a/1206915/>create a "toolhelp"</a> and poll the entries. I won't bore you with the details. Let's add <code>tlhelp32</code> to the crate features of <code>winapi</code> and try it out:<pre><code class=language-rust data-lang=rust> +#[derive(Debug)] +pub struct Toolhelp { + handle: winapi::um::winnt::HANDLE, +} + +impl Drop for Toolhelp { + fn drop(&mut self) { + unsafe { winapi::um::handleapi::CloseHandle(self.handle) }; + } +} + +pub fn enum_threads(pid: u32) -> io::Result<Vec<u32>> { + const ENTRY_SIZE: u32 = mem::size_of::<winapi::um::tlhelp32::THREADENTRY32>() as u32; + + // size_of(dwSize + cntUsage + th32ThreadID + th32OwnerProcessID) + const NEEDED_ENTRY_SIZE: u32 = 4 * mem::size_of::<DWORD>() as u32; + + // SAFETY: it is always safe to attempt to call this function. + let handle = unsafe { + winapi::um::tlhelp32::CreateToolhelp32Snapshot(winapi::um::tlhelp32::TH32CS_SNAPTHREAD, 0) + }; + if handle == winapi::um::handleapi::INVALID_HANDLE_VALUE { + return Err(io::Error::last_os_error()); + } + let toolhelp = Toolhelp { handle }; + + let mut result = Vec::new(); + let mut entry = winapi::um::tlhelp32::THREADENTRY32 { + dwSize: ENTRY_SIZE, + cntUsage: 0, + th32ThreadID: 0, + th32OwnerProcessID: 0, + tpBasePri: 0, + tpDeltaPri: 0, + dwFlags: 0, + }; + + // SAFETY: we have a valid handle, and point to memory we own with the right size. + if unsafe { winapi::um::tlhelp32::Thread32First(toolhelp.handle, &mut entry) } != FALSE { + loop { + if entry.dwSize >= NEEDED_ENTRY_SIZE && entry.th32OwnerProcessID == pid { + result.push(entry.th32ThreadID); + } + + entry.dwSize = ENTRY_SIZE; + // SAFETY: we have a valid handle, and point to memory we own with the right size. + if unsafe { winapi::um::tlhelp32::Thread32Next(toolhelp.handle, &mut entry) } == FALSE { + break; + } + } + } + + Ok(result) +} +</code></pre><p>Annoyingly, invalid handles returned by <a href=https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot><code>CreateToolhelp32Snapshot</code></a>, are <code>INVALID_HANDLE_VALUE</code> (which is -1), not null. But that's not a big deal, we simply can't use <code>NonNull</code> here. The function ignores the process identifier when using <code>TH32CS_SNAPTHREAD</code>, used to include all threads, and we need to compare the process identifier ourselves.<p>In summary, we create a "toolhelp" (wrapped in a helper <code>struct</code> so that whatever happens, <code>Drop</code> will clean it up), initialize a thread enntry (with everything but the structure size to zero) and call <code>Thread32First</code> the first time, <code>Thread32Next</code> subsequent times. It seems to work all fine!<pre><code class=language-rust data-lang=rust>dbg!(process::enum_threads(pid)); +</code></pre><pre><code>[src\main.rs:46] process::enum_threads(pid) = Ok( + [ + 10560, + ], +) +</code></pre><p>According to this, the Cheat Engine tutorial is only using one thread. Good to know. Much like processes, threads need to be opened before we can use them, with <a href=https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openthread><code>OpenThread</code></a>:<pre><code class=language-rust data-lang=rust>pub struct Thread { + tid: u32, + handle: NonNull<c_void>, +} + +impl Thread { + pub fn open(tid: u32) -> io::Result<Self> { + // SAFETY: the call doesn't have dangerous side-effects + NonNull::new(unsafe { + winapi::um::processthreadsapi::OpenThread( + winapi::um::winnt::THREAD_SUSPEND_RESUME, + FALSE, + tid, + ) + }) + .map(|handle| Self { tid, handle }) + .ok_or_else(io::Error::last_os_error) + } + + pub fn tid(&self) -> u32 { + self.tid + } +} + +impl Drop for Thread { + fn drop(&mut self) { + unsafe { winapi::um::handleapi::CloseHandle(self.handle.as_mut()) }; + } +} +</code></pre><p>Just your usual RAII pattern. The thread is opened with permission to suspend and resume it. Let's try to pause the handles with <a href=https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-suspendthread><code>SuspendThread</code></a> to make sure that this thread is actually the one we're looking for:<pre><code class=language-rust data-lang=rust>pub fn suspend(&mut self) -> io::Result<usize> { + // SAFETY: the handle is valid. + let ret = unsafe { + winapi::um::processthreadsapi::SuspendThread(self.handle.as_ptr()) + }; + if ret == -1i32 as u32 { + Err(io::Error::last_os_error()) + } else { + Ok(ret as usize) + } +} + +pub fn resume(&mut self) -> io::Result<usize> { + // SAFETY: the handle is valid. + let ret = unsafe { + winapi::um::processthreadsapi::ResumeThread(self.handle.as_ptr()) + }; + if ret == -1i32 as u32 { + Err(io::Error::last_os_error()) + } else { + Ok(ret as usize) + } +} +</code></pre><p>Both suspend and resume return the previous "suspend count". It's kind of like a barrier or semaphore where the thread only runs if the suspend count is zero. Trying it out:<pre><code class=language-rust data-lang=rust>let mut threads = thread::enum_threads(pid) + .unwrap() + .into_iter() + .map(Thread::open) + .collect::<Result<Vec<_>, _>>() + .unwrap(); + +threads + .iter_mut() + .for_each(|thread| { + println!("Pausing thread {} for 10 seconds…", thread.tid()); + thread.suspend().unwrap(); + + std::thread::sleep(std::time::Duration::from_secs(10)); + + println!("Wake up, {}!", thread.tid()); + thread.resume().unwrap(); + }); +</code></pre><p>If you run this code with the process ID of the Cheat Engine tutorial, you will see that the tutorial window freezes for ten seconds! Because the main and only thread is paused, it cannot process any window events, so it becomes unresponsive. It is now "safe" to mess around with the thread context.<h2 id=setting-hardware-breakpoints>Setting hardware breakpoints</h2><p>I'm definitely not the first person to wonder <a href=https://social.msdn.microsoft.com/Forums/en-US/0cb3360d-3747-42a7-bc0e-668c5d9ee1ee/how-to-set-a-hardware-breakpoint>How to set a hardware breakpoint?</a>. This is great, because it means I don't need to ask that question myself. It appears we need to change the debug register <em>via the thread context</em>.<p>One has to be careful to use the right context structure. Confusingly enough, <a href=https://stackoverflow.com/q/17504174/><code>WOW64_CONTEXT</code></a> is 32 bits, not 64. <code>CONTEXT</code> alone seems to be the right one:<pre><code class=language-rust data-lang=rust>pub fn get_context(&self) -> io::Result<winapi::um::winnt::CONTEXT> { + let context = MaybeUninit::<winapi::um::winnt::CONTEXT>::zeroed(); + // SAFETY: it's a C struct, and all-zero is a valid bit-pattern for the type. + let mut context = unsafe { context.assume_init() }; + context.ContextFlags = winapi::um::winnt::CONTEXT_ALL; + + // SAFETY: the handle is valid and structure points to valid memory. + if unsafe { + winapi::um::processthreadsapi::GetThreadContext(self.handle.as_ptr(), &mut context) + } == FALSE + { + Err(io::Error::last_os_error()) + } else { + Ok(context) + } +} +</code></pre><p>Trying it out:<pre><code class=language-rust data-lang=rust>thread.suspend().unwrap(); + +let context = thread.get_context().unwrap(); +println!("Dr0: {:016x}", context.Dr0); +println!("Dr7: {:016x}", context.Dr7); +println!("Dr6: {:016x}", context.Dr6); +println!("Rax: {:016x}", context.Rax); +println!("Rbx: {:016x}", context.Rbx); +println!("Rcx: {:016x}", context.Rcx); +println!("Rip: {:016x}", context.Rip); +</code></pre><pre><code>Dr0: 0000000000000000 +Dr7: 0000000000000000 +Dr6: 0000000000000000 +Rax: 0000000000001446 +Rbx: 0000000000000000 +Rcx: 0000000000000000 +Rip: 00007ffda4259904 +</code></pre><p>Looks about right! Hm, I wonder what happens if I use Cheat Engine to add the watchpoint on the memory location we care about?<pre><code>Dr0: 000000000157e650 +Dr7: 00000000000d0001 +</code></pre><p>Look at that! The debug registers changed! DR0 contains the location we want to watch for writes, and the debug control register DR7 changed. Cheat Engine sets the same values on all threads (for some reason I now see more than one thread printed for the tutorial, not sure what's up with that; maybe the single-thread is the weird one out).<p>Hmm, what happens if I watch for access instead of write?<pre><code>Dr0: 000000000157e650 +Dr7: 00000000000f0001 +</code></pre><p>What if I set both?<pre><code>Dr0: 000000000157e650 +Dr7: 0000000000fd0005 +</code></pre><p>Most intriguing! This was done by telling Cheat Engine to find "what writes" to the address, then "what accesses" the address. I wonder if the order matters?<pre><code>Dr0: 000000000157e650 +Dr7: 0000000000df0005 +</code></pre><p>"What accesses" and then "what writes" does change it. Very well! We're only concerned in a single breakpoint, so we won't worry about this, but it's good to know that we can inspect what Cheat Engine is doing. It's also interesting to see how Cheat Engine is using hardware breakpoints and not software breakpoints.<p>For simplicity, our code is going to assume that we're the only ones messing around with the debug registers, and that there will only be a single debug register in use. Make sure to add <code>THREAD_SET_CONTEXT</code> to the permissions when opening the thread handle:<pre><code class=language-rust data-lang=rust>pub fn set_context(&self, context: &winapi::um::winnt::CONTEXT) -> io::Result<()> { + // SAFETY: the handle is valid and structure points to valid memory. + if unsafe { + winapi::um::processthreadsapi::SetThreadContext(self.handle.as_ptr(), context) + } == FALSE + { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } +} + +pub fn watch_memory_write(&self, addr: usize) -> io::Result<()> { + let mut context = self.get_context()?; + context.Dr0 = addr as u64; + context.Dr7 = 0x00000000000d0001; + self.set_context(&context)?; + todo!() +} +</code></pre><p>If we do this (and temporarily get rid of the <code>todo!()</code>), trying to change the value in the Cheat Engine tutorial will greet us with a warm message:<blockquote><p><strong>Tutorial-x86_64</strong><p>External exception 80000004.<p>Press OK to ignore and risk data corruption.<br> Press Abort to kill the program.<p><kbd>OK</kbd> <kbd>Abort</kbd></blockquote><p>There is no debugger attached yet that could possibly handle this exception, so the exception just propagates. Let's fix that.<h2 id=handling-debug-events>Handling debug events</h2><p>Now that we've succeeded on setting breakpoints, we can actually follow the steps described in <a href=https://docs.microsoft.com/en-us/windows/win32/debug/creating-a-basic-debugger>Creating a Basic Debugger</a>. It starts by saying that we should use <a href=https://docs.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-debugactiveprocess><code>DebugActiveProcess</code></a> to attach our processor, the debugger, to the process we want to debug, the debuggee. This function lives under the <code>debugapi</code> header, so add it to <code>winapi</code> features:<pre><code class=language-rust data-lang=rust>pub struct DebugToken { + pid: u32, +} + +pub fn debug(pid: u32) -> io::Result<DebugToken> { + if unsafe { winapi::um::debugapi::DebugActiveProcess(pid) } == FALSE { + return Err(io::Error::last_os_error()); + }; + let token = DebugToken { pid }; + if unsafe { winapi::um::winbase::DebugSetProcessKillOnExit(FALSE) } == FALSE { + return Err(io::Error::last_os_error()); + }; + Ok(token) +} + +impl Drop for DebugToken { + fn drop(&mut self) { + unsafe { winapi::um::debugapi::DebugActiveProcessStop(self.pid) }; + } +} +</code></pre><p>Once again, we create a wrapper <code>struct</code> with <code>Drop</code> to stop debugging the process once the token is dropped. The call to <code>DebugSetProcessKillOnExit</code> in our <code>debug</code> method ensures that, if our process (the debugger) dies, the process we're debugging (the debuggee) stays alive. We don't want to be restarting the entire Cheat Engine tutorial every time our Rust code crashes!<p>With the debugger attached, we can wait for debug events. We will put this method inside of <code>impl DebugToken</code>, so that the only way you can call it is if you successfully attached to another process:<pre><code class=language-rust data-lang=rust>impl DebugToken { + pub fn wait_event( + &self, + timeout: Option<Duration>, + ) -> io::Result<winapi::um::minwinbase::DEBUG_EVENT> { + let mut result = MaybeUninit::uninit(); + let timeout = timeout + .map(|d| d.as_millis().try_into().ok()) + .flatten() + .unwrap_or(winapi::um::winbase::INFINITE); + + // SAFETY: can only wait for events with a token, so the debugger is active. + if unsafe { winapi::um::debugapi::WaitForDebugEvent(result.as_mut_ptr(), timeout) } == FALSE + { + Err(io::Error::last_os_error()) + } else { + // SAFETY: the call returned non-zero, so the structure is initialized. + Ok(unsafe { result.assume_init() }) + } + } +} +</code></pre><p><code>WaitForDebugEvent</code> wants a timeout in milliseconds, so our function lets the user pass the more Rusty <code>Duration</code> type. <code>None</code> will indicate "there is no timeout", i.e., it's infinite. If the duration is too large to fit in the <code>u32</code> (<code>try_into</code> fails), it will also be infinite.<p>If we attach the debugger, set the hardware watchpoint, and modify the memory location from the tutorial, an event with <code>dwDebugEventCode = 3</code> will be returned! Now, back to the page with the <a href=https://docs.microsoft.com/en-us/windows/win32/debug/debugging-events>Debugging Events</a>… Gah! It only has the name of the constants, not the values. Well, good thing <a href=https://docs.rs/>docs.rs</a> has a source view! We can just check the values in the <a href=https://docs.rs/winapi/0.3.9/src/winapi/um/minwinbase.rs.html#203-211>source code for <code>winapi</code></a>:<pre><code class=language-rust data-lang=rust>pub const EXCEPTION_DEBUG_EVENT: DWORD = 1; +pub const CREATE_THREAD_DEBUG_EVENT: DWORD = 2; +pub const CREATE_PROCESS_DEBUG_EVENT: DWORD = 3; +pub const EXIT_THREAD_DEBUG_EVENT: DWORD = 4; +pub const EXIT_PROCESS_DEBUG_EVENT: DWORD = 5; +pub const LOAD_DLL_DEBUG_EVENT: DWORD = 6; +pub const UNLOAD_DLL_DEBUG_EVENT: DWORD = 7; +pub const OUTPUT_DEBUG_STRING_EVENT: DWORD = 8; +pub const RIP_EVENT: DWORD = 9; +</code></pre><p>So, we've got a <code>CREATE_PROCESS_DEBUG_EVENT</code>:<blockquote><p>Generated whenever a new process is created in a process being debugged or whenever the debugger begins debugging an already active process. The system generates this debugging event before the process begins to execute in user mode and before the system generates any other debugging events for the new process.</blockquote><p>It makes sense that this is our first event. By the way, if you were trying this out with a <code>sleep</code> lying around in your code, you may have noticed that the window froze until the debugger terminated. That's because:<blockquote><p>When the system notifies the debugger of a debugging event, it also suspends all threads in the affected process. The threads do not resume execution until the debugger continues the debugging event by using <a href=https://docs.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-continuedebugevent><code>ContinueDebugEvent</code></a>.</blockquote><p>Let's call <code>ContinueDebugMethod</code> but also wait on more than one event and see what happens:<pre><code class=language-rust data-lang=rust>for _ in 0..10 { + let event = debugger.wait_event(None).unwrap(); + println!("Got {}", event.dwDebugEventCode); + debugger.cont(event, true).unwrap(); +} +</code></pre><pre><code>Got 3 +Got 6 +Got 6 +Got 6 +Got 6 +Got 6 +Got 6 +Got 6 +Got 6 +Got 6 +</code></pre><p>That's a lot of <code>LOAD_DLL_DEBUG_EVENT</code>. Pumping it up to one hundred and also showing the index we get the following:<pre><code>0. Got 3 +1. Got 6 +... +40. Got 6 +41. Got 2 +42. Got 1 +43. Got 4 +</code></pre><p>In order, we got:<ul><li>One <code>CREATE_PROCESS_DEBUG_EVENT</code>.<li>Forty <code>LOAD_DLL_DEBUG_EVENT</code>.<li>One <code>CREATE_THREAD_DEBUG_EVENT</code>.<li>One <code>EXCEPTION_DEBUG_EVENT</code>.<li>One <code>EXIT_THREAD_DEBUG_EVENT</code>.</ul><p>And, if after all this, you change the value in the Cheat Engine tutorial (thus triggering our watch point), we get <code>EXCEPTION_DEBUG_EVENT</code>!<blockquote><p>Generated whenever an exception occurs in the process being debugged. Possible exceptions include attempting to access inaccessible memory, executing breakpoint instructions, attempting to divide by zero, or any other exception noted in Structured Exception Handling.</blockquote><p>If we print out all the fields in the <a href=https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-exception_debug_info><code>EXCEPTION_DEBUG_INFO</code></a> structure:<pre><code>Watching writes to 10e3a0 for 10s +First chance: 1 +ExceptionCode: 2147483652 +ExceptionFlags: 0 +ExceptionRecord: 0x0 +ExceptionAddress: 0x10002c5ba +NumberParameters: 0 +ExceptionInformation: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +</code></pre><p>The <code>ExceptionCode</code>, which is <code>0x80000004</code>, corresponds with <code>EXCEPTION_SINGLE_STEP</code>:<blockquote><p>A trace trap or other single-instruction mechanism signaled that one instruction has been executed.</blockquote><p>The <code>ExceptionAddress</code> is supposed to be "the address where the exception occurred". Very well! I have already completed this step of the tutorial, and I know the instruction is <code>mov [rax],edx</code> (or, as Cheat Engine shows, the bytes <code>89 10</code> in hexadecimal). The opcode for the <code>nop</code> instruction is <code>90</code> in hexadecimal, so if we replace two bytes at this address, we should be able to complete the tutorial.<p>Note that we also need to flush the instruction cache, as noted in the Windows documentation:<blockquote><p>Debuggers frequently read the memory of the process being debugged and write the memory that contains instructions to the instruction cache. After the instructions are written, the debugger calls the <a href=https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-flushinstructioncache><code>FlushInstructionCache</code></a> function to execute the cached instructions.</blockquote><p>So we add a new method to <code>impl Process</code>:<pre><code class=language-rust data-lang=rust>/// Flushes the instruction cache. +/// +/// Should be called when writing to memory regions that contain code. +pub fn flush_instruction_cache(&self) -> io::Result<()> { + // SAFETY: the call doesn't have dangerous side-effects. + if unsafe { + winapi::um::processthreadsapi::FlushInstructionCache( + self.handle.as_ptr(), + ptr::null(), + 0, + ) + } == FALSE + { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } +} +</code></pre><p>And write some quick and dirty code to get this done:<pre><code class=language-rust data-lang=rust>let addr = ...; +println!("Watching writes to {:x} for 10s", addr); +threads.iter_mut().for_each(|thread| { + thread.watch_memory_write(addr).unwrap(); +}); +loop { + let event = debugger.wait_event(None).unwrap(); + if event.dwDebugEventCode == 1 { + let exc = unsafe { event.u.Exception() }; + if exc.ExceptionRecord.ExceptionCode == 2147483652 { + let addr = exc.ExceptionRecord.ExceptionAddress as usize; + match process.write_memory(addr, &[0x90, 0x90]) { + Ok(_) => eprintln!("Patched [{:x}] with NOP", addr), + Err(e) => eprintln!("Failed to patch [{:x}] with NOP: {}", addr, e), + }; + process.flush_instruction_cache().unwrap(); + debugger.cont(event, true).unwrap(); + break; + } + } + debugger.cont(event, true).unwrap(); +} +</code></pre><p>Although it seems to work:<pre><code>Watching writes to 15103f0 for 10s +Patched [10002c5ba] with NOP +</code></pre><p>It really doesn't:<blockquote><p><strong>Tutorial-x86_64</strong><p>Access violation.<p>Press OK to ignore and risk data corruption.<br> Press Abort to kill the program.<p><kbd>OK</kbd> <kbd>Abort</kbd></blockquote><p>Did we write memory somewhere we shouldn't? The documentation does mention "segment-relative" and "linear virtual addresses":<blockquote><p><code>GetThreadSelectorEntry</code> returns the descriptor table entry for a specified selector and thread. Debuggers use the descriptor table entry to convert a segment-relative address to a linear virtual address. The <code>ReadProcessMemory</code> and <code>WriteProcessMemory</code> functions require linear virtual addresses.</blockquote><p>But nope! This isn't the problem. The problem is that the <code>ExceptionRecord.ExceptionAddress</code> is <em>after</em> the execution happened, so it's already 2 bytes beyond where it should be. We were accidentally writing out the first half of the next instruction, which, yeah, could not end good.<p>So does it work if I do this instead?:<pre><code class=language-rust data-lang=rust>process.write_memory(addr - 2, &[0x90, 0x90]) +// ^^^ new +</code></pre><p>This totally does work. Step 5: complete 🎉<h2 id=properly-patching-instructions>Properly patching instructions</h2><p>You may not be satisfied at all with our solution. Not only are we hardcoding some magic constants to set hardware watchpoints, we're also relying on knowledge specific to the Cheat Engine tutorial (insofar that we're replacing two bytes worth of instruction with NOPs).<p>Properly supporting more than one hardware breakpoint, along with supporting different types of breakpoints, is definitely doable. The meaning of the bits for the debug registers is well defined, and you can definitely study that to come up with <a href=https://github.com/mmorearty/hardware-breakpoints>something more sophisticated</a> and support multiple different breakpoints. But for now, that's out of the scope of this series. The tutorial only wants us to use an on-write watchpoint, and our solution is fine and portable for that use case.<p>However, relying on the size of the instructions is pretty bad. The instructions x86 executes are of variable length, so we can't possibly just look back until we find the previous instruction, or even naively determine its length. A lot of unrelated sequences of bytes are very likely instructions themselves. We need a disassembler. No, we're not writing our own.<p>Searching on <a href=https://crates.io>crates.io</a> for "disassembler" yields a few results, and the first one I've found is <a href=https://crates.io/crates/iced-x86>iced-x86</a>. I like the name, it has a decent amount of GitHub stars, and it was last updated less than a month ago. I don't know about you, but I think we've just hit a jackpot!<p>It's quite heavy though, so I will add it behind a feature gate, and users that want it may opt into it:<pre><code class=language-toml data-lang=toml>[features] +patch-nops = ["iced-x86"] + +[dependencies] +iced-x86 = { version = "1.10.3", optional = true } +</code></pre><p>You can make use of it with <code>cargo run --features=patch-nops</code>. I don't want to turn this blog post into a tutorial for <code>iced-x86</code>, but in essence, we need to make use of its <code>Decoder</code>. Here's the plan:<ol><li>Find the memory region corresponding to the address we want to patch.<li>Read the entire region.<li>Decode the read bytes until the instruction pointer reaches our address.<li>Because we just parsed the previous instruction, we know its length, and can be replaced with NOPs.</ol><pre><code class=language-rust data-lang=rust>#[cfg(feature = "patch-nops")] +pub fn nop_last_instruction(&self, addr: usize) -> io::Result<()> { + use iced_x86::{Decoder, DecoderOptions, Formatter, Instruction, NasmFormatter}; + + let region = self + .memory_regions() + .into_iter() + .find(|region| { + let base = region.BaseAddress as usize; + base <= addr && addr < base + region.RegionSize + }) + .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "no matching region found"))?; + + let bytes = self.read_memory(region.BaseAddress as usize, region.RegionSize)?; + + let mut decoder = Decoder::new(64, &bytes, DecoderOptions::NONE); + decoder.set_ip(region.BaseAddress as _); + + let mut instruction = Instruction::default(); + while decoder.can_decode() { + decoder.decode_out(&mut instruction); + if instruction.next_ip() as usize == addr { + return self + .write_memory(instruction.ip() as usize, &vec![0x90; instruction.len()]) + .map(drop); + } + } + + Err(io::Error::new( + io::ErrorKind::Other, + "no matching instruction found", + )) +} +</code></pre><p>Pretty straightforward! We can set the "instruction pointer" of the decoder so that it matches with the address we're reading from. The <code>next_ip</code> method comes in really handy. Overall, it's a bit inefficient, because we could reuse the regions retrieved previously, but other than that, there is not much room for improvement.<p>With this, we are no longer hardcoding the instruction size or guessing which instruction is doing what. You may wonder, what if the region does not start with valid executable code? It could be possible that the instructions are in some memory region with garbage except for a very specific location with real code. I don't know how Cheat Engine handles this, but I think it's reasonable to assume that the region starts with valid code. If you can think of any more reliable way to figure out the instruction right before a given address, please let me know!<h2 id=finale>Finale</h2><p>That was quite a deep dive! We have learnt about the existence of the various breakpoint types (software, hardware, and even behaviour, such as watchpoints), how to debug a separate process, and how to correctly update the code other process is running on-the-fly. The <a href=https://github.com/lonami/memo>code for this post</a> is available over at my GitHub. You can run <code>git checkout step5</code> after cloning the repository to get the right version of the code.<p>Although we've only talked about <em>setting</em> breakpoints, there are of course <a href=https://reverseengineering.stackexchange.com/a/16547>ways of detecting them</a>. There's <a href=https://www.codeproject.com/Articles/30815/An-Anti-Reverse-Engineering-Guide>entire guides about it</a>. Again, we currently hardcode the fact we want to add a single watchpoint using the first debug register. A proper solution here would be to actually calculate the needs that need to be set, as well as keeping track of how many breakpoints have been added so far.<p>Hardware breakpoints are also limited, since they're simply a bunch of registers, and our machine does not have infinite registers. How are other debuggers like <code>gdb</code> able to create a seemingly unlimited amount of breakpoints? Well, the GDB wiki actually has a page on <a href=https://sourceware.org/gdb/wiki/Internals%20Watchpoints>Internals Watchpoints</a>, and it's really interesting! <code>gdb</code> essentially single-steps through the entire program and tests the expressions after every instruction:<blockquote><p>Software watchpoints are very slow, since GDB needs to single-step the program being debugged and test the value of the watched expression(s) after each instruction.</blockquote><p>However, that's not the only way. One could <a href=https://stackoverflow.com/a/7805842/>change the protection level</a> of the region of interest (for example, remove the write permission), and when the program tries to write there, it will fail! In any case, the GDB wiki is actually a pretty nice resource. It also has a section on <a href=https://sourceware.org/gdb/wiki/Internals/Breakpoint%20Handling>Breakpoint Handling</a>, which contains some additional insight.<p>With regards to code improvements, <code>DebugToken::wait_event</code> could definitely be both nicer and safer to use, with a custom <code>enum</code>, so the user does not need to rely on magic constants or having to resort to <code>unsafe</code> access to get the right <code>union</code> variant.<p>In the next post, we'll tackle the sixth step of the tutorial: Pointers. It reuses the debugging techniques presented here to backtrack where the pointer for our desired value is coming from, so here we will need to actually <em>understand</em> what the instructions are doing, not just patching them out!<h3 id=footnotes>Footnotes</h3><div class=footnote-definition id=1><sup class=footnote-definition-label>1</sup><p>I'm not super happy about the design of it all, but we won't actually need anything beyond scanning for integers for the rest of the steps so it doesn't really matter.</div><div class=footnote-definition id=2><sup class=footnote-definition-label>2</sup><p>There seems to be a way to pause the entire process in one go, with the [undocumented <code>NtSuspendProcess</code>] function!</div><div class=footnote-definition id=3><sup class=footnote-definition-label>3</sup><p>It really is called that. The naming went from "IP" (instruction pointer, 16 bits), to "EIP" (extended instruction pointer, 32 bits) and currently "RIP" (64 bits). The naming convention for upgraded registers is the same (RAX, RBX, RCX, and so on). The <a href=https://wiki.osdev.org/CPU_Registers_x86_64>OS Dev wiki</a> is a great resource for this kind of stuff.</div></main><footer><div><p>Share your thoughts, or simply come hang with me <a href=https://t.me/LonamiWebs><img src=/img/telegram.svg alt=Telegram></a> <a href=mailto:totufals@hotmail.com><img src=/img/mail.svg alt=Mail></a></div></footer></article><p class=abyss>Glaze into the abyss… Oh hi there!
@@ -209,6 +209,10 @@ <loc>https://lonami.dev/blog/woce-4/</loc>
<lastmod>2021-02-22</lastmod> </url> <url> + <loc>https://lonami.dev/blog/woce-5/</loc> + <lastmod>2021-03-06</lastmod> + </url> + <url> <loc>https://lonami.dev/blog/world-edit/</loc> <lastmod>2018-07-11</lastmod> </url>