Deploy site
@@ -4,9 +4,440 @@ <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-03-06T00:00:00+00:00</updated> + <updated>2021-03-13T00:00:00+00:00</updated> <id>https://lonami.dev/blog/atom.xml</id> <entry xml:lang="en"> + <title>Writing our own Cheat Engine: Pointers</title> + <published>2021-03-13T00:00:00+00:00</published> + <updated>2021-03-13T00:00:00+00:00</updated> + <link href="https://lonami.dev/blog/woce-6/" type="text/html"/> + <id>https://lonami.dev/blog/woce-6/</id> + <content type="html"><p>This is part 6 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><a href="/blog/woce-5">Part 5: Code finder</a></li> +<li>Part 6: Pointers</li> +</ul> +<p>In part 5 we wrote our very own debugger. We learnt that Cheat Engine is using hardware breakpoints to watch memory change, and how to do the same ourselves. We also learnt that hardware points are not the only way to achieve the effect of watchpoints, although they certainly are the fastest and cleanest approach.</p> +<p>In this post, we will be reusing some of that knowledge to find out a closely related value, the <em>pointer</em> that points to the real value<sup class="footnote-reference"><a href="#1">1</a></sup>. As a quick reminder, a pointer is nothing but an <code>usize</code><sup class="footnote-reference"><a href="#2">2</a></sup> representing the address of another portion of memory, in this case, the actual value we will be scanning for. A pointer is a value that, well, points elsewhere. In Rust we normally use reference instead, which are safer (typed and their lifetime is tracked) than pointers, but in the end we can achieve the same with both.</p> +<p>Why care about pointers? It turns out that things, such as your current health in-game, are very unlikely to end up in the same memory position when you restart the game (or even change to another level, or even during gameplay). So, if you perform a scan and find that the address where your health is stored is <code>0x73AABABE</code>, you might be tempted to save it and reuse it next time you launch the game. Now you don't need to scan for it again! Alas, as soon as you restart the game, the health is now stored at <code>0x5AADBEEF</code>.</p> +<p>Not all hope is lost! The game must <em>somehow</em> have a way to reliably find this value, and the way it's done is with pointers. There will always be some base address that holds a pointer, and the game code knows where to find this pointer. If we are also able to find the pointer at said base address, and follow it ourselves (&quot;dereferencing&quot; it), we can perform the same steps the game is doing, and reliably find the health no matter how much we restart the game<sup class="footnote-reference"><a href="#3">3</a></sup>.</p> +<h2 id="code-finder">Code finder</h2> +<details open><summary>Cheat Engine Tutorial: Step 6</summary> +<blockquote> +<p>In the previous step I explained how to use the Code finder to handle changing locations. But that method alone makes it difficult to find the address to set the values you want. That's why there are pointers:</p> +<p>At the bottom you'll find 2 buttons. One will change the value, and the other changes the value AND the location of the value. For this step you don't really need to know assembler, but it helps a lot if you do.</p> +<p>First find the address of the value. When you've found it use the function to find out what accesses this address.</p> +<p>Change the value again, and a item will show in the list. Double click that item. (or select and click on more info) and a new window will open with detailed information on what happened when the instruction ran.</p> +<p>If the assembler instruction doesn't have anything between a '[' and ']' then use another item in the list. If it does it will say what it think will be the value of the pointer you need.</p> +<p>Go back to the main cheat engine window (you can keep this extra info window open if you want, but if you close it, remember what is between the [ and ]) and do a 4 byte scan in hexadecimal for the value the extra info told you. When done scanning it may return 1 or a few hundred addresses. Most of the time the address you need will be the smallest one. Now click on manually add and select the pointer checkbox.</p> +<p>The window will change and allow you to type in the address of a pointer and a offset. Fill in as address the address you just found. If the assembler instruction has a calculation (e.g: [esi+12]) at the end then type the value in that's at the end. else leave it 0. If it was a more complicated instruction look at the calculation.</p> +<p>Example of a more complicated instruction:</p> +<p>[EAX*2+EDX+00000310] eax=4C and edx=00801234.</p> +<p>In this case EDX would be the value the pointer has, and EAX*2+00000310 the offset, so the offset you'd fill in would be 2*4C+00000310=3A8. (this is all in hex, use calc.exe from windows in scientific mode to calculate).</p> +<p>Back to the tutorial, click OK and the address will be added, If all went right the address will show P-&gt;xxxxxxx, with xxxxxxx being the address of the value you found. If thats not right, you've done something wrong. Now, change the value using the pointer you added in 5000 and freeze it. Then click Change pointer, and if all went right the next button will become visible.</p> +<p><em>extra</em>: And you could also use the pointer scanner to find the pointer to this address.</p> +</blockquote> +</details> +<h2 id="on-access-watchpoints">On-access watchpoints</h2> +<p>Last time we managed to learn how hardware breakpoints were being set by observing Cheat Engine's behaviour. I think it's now time to handle this properly instead. We'll check out the <a href="https://wiki.osdev.org/CPU_Registers_x86#Debug_Registers">CPU Registers x86 page on OSDev</a> to learn about it:</p> +<ul> +<li>DR0, DR1, DR2 and DR3 can hold a memory address each. This address will be used by the breakpoint.</li> +<li>DR4 is actually an <a href="https://en.wikipedia.org/wiki/X86_debug_register">obsolete synonym</a> for DR6.</li> +<li>DR5 is another obsolete synonym, this time for DR7.</li> +<li>DR6 is debug status. The four lowest bits indicate which breakpoint was hit, and the four highest bits contain additional information. We should make sure to clear this ourselves when a breakpoint is hit.</li> +<li>DR7 is debug control, which we need to study more carefully.</li> +</ul> +<p>Each debug register DR0 through DR3 has two corresponding bits in DR7, starting from the lowest-order bit, to indicate whether the corresponding register is a <strong>L</strong>ocal or <strong>G</strong>lobal breakpoint. So it looks like this:</p> +<pre><code> Meaning: [ .. .. | G3 | L3 | G2 | L2 | G1 | L1 | G0 | L0 ] +Bit-index: 31-08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 +</code></pre> +<p>Cheat Engine was using local breakpoints, because the zeroth bit was set. Probably because we don't want these breakpoints to infect other programs! Because we were using only one breakpoint, only the lowermost bit was being set. The local 1st, 2nd and 3rd bits were unset.</p> +<p>Now, each debug register DR0 through DR4 has four additional bits in DR7, two for the <strong>C</strong>ondition and another two for the <strong>S</strong>ize:</p> +<pre><code> Meaning: [ S3 | C3 | S2 | C2 | S1 | C1 | S0 | C0 | .. .. ] +Bit-index: 31 30 | 29 28 | 27 26 | 25 24 | 23 22 | 21 20 | 19 18 | 17 16 | 15-00 +</code></pre> +<p>The two bits of the condition mean the following:</p> +<ul> +<li><code>00</code> execution breakpoint.</li> +<li><code>01</code> write watchpoint.</li> +<li><code>11</code> read/write watchpoint.</li> +<li><code>10</code> unsupported I/O read/write.</li> +</ul> +<p>When we were using Cheat Engine to add write watchpoints, the bits 17 and 16 were indeed set to <code>01</code>, and the bits 19 and 18 were set to <code>11</code>. Hm, but <em>11<sub>2</sub> = 3<sub>10</sub></em> , and yet, we were watching writes to 4 bytes. So what's up with this? Is there a different mapping for the size which isn't documented at the time of writing? Seems we need to learn from Cheat Engine's behaviour one more time.</p> +<p>For reference, this is what DR7 looked like when we added a single write watchpoint:</p> +<pre><code>hex: 000d_0001 +bin: 00000000_00001101_00000000_00000001 +</code></pre> +<p>And this is the code I will be using to check the breakpoints of different sizes:</p> +<pre><code>thread::enum_threads(pid) + .unwrap() + .into_iter() + .for_each(|tid| { + let thread = thread::Thread::open(tid).unwrap(); + let ctx = thread.get_context().unwrap(); + eprintln!(&quot;hex: {:08x}&quot;, ctx.Dr7); + eprintln!(&quot;bin: {:032b}&quot;, ctx.Dr7); + }); +</code></pre> +<p>Let's compare this to watchpoints for sizes 1, 2, 4 and 8 bytes:</p> +<pre><code>1 byte +hex: 0001_0401 +bin: 00000000_00000001_00000100_00000001 + +2 bytes +hex: 0005_0401 +bin: 00000000_00000101_00000100_00000001 + +4 bytes +hex: 000d_0401 +bin: 00000000_00001101_00000100_00000001 + +8 bytes +hex: 0009_0401 +bin: 00000000_00001001_00000100_00000001 + ^ wut? +</code></pre> +<p>I have no idea what's up with that stray tenth bit. Its use does not seem documented, and things worked fine without it, so we'll ignore it. The lowest bit is set to indicate we're using DR0, bits 17 and 16 represent the write watchpoint, and the size seems to be as follows:</p> +<ul> +<li><code>00</code> for a single byte.</li> +<li><code>01</code> for two bytes (a &quot;word&quot;).</li> +<li><code>11</code> for four bytes (a &quot;double word&quot;).</li> +<li><code>10</code> for eight bytes (a &quot;quadruple word&quot;).</li> +</ul> +<p>Doesn't make much sense if you ask me, but we'll roll with it. Just to confirm, this is what the &quot;on-access&quot; breakpoint looks like according to Cheat Engine:</p> +<pre><code>hex: 000f_0401 +bin: 00000000_00001111_00000100_00000001 +</code></pre> +<p>So it all checks out! The bit pattern is <code>11</code> for read/write (technically, a write is also an access). Let's implement this!</p> +<h2 id="proper-breakpoint-handling">Proper breakpoint handling</h2> +<p>The first thing we need to do is represent the possible breakpoint conditions:</p> +<pre><code class="language-rust" data-lang="rust">#[repr(u8)] +pub enum Condition { + Execute = 0b00, + Write = 0b01, + Access = 0b11, +} +</code></pre> +<p>And also the legal breakpoint sizes:</p> +<pre><code class="language-rust" data-lang="rust">#[repr(u8)] +pub enum Size { + Byte = 0b00, + Word = 0b01, + DoubleWord = 0b11, + QuadWord = 0b10, +} +</code></pre> +<p>We are using <code>#[repr(u8)]</code> so that we can convert a given variant into the corresponding bit pattern. With the right types defined in order to set a breakpoint, we can start implementing the method that will set them (inside <code>impl Thread</code>):</p> +<pre><code class="language-rust" data-lang="rust">pub fn add_breakpoint(&amp;self, addr: usize, cond: Condition, size: Size) -&gt; io::Result&lt;Breakpoint&gt; { + let mut context = self.get_context()?; + todo!() +} +</code></pre> +<p>First, let's try finding an &quot;open spot&quot; where we could set our breakpoint. We will &quot;slide&quot; a the <code>0b11</code> bitmask over the lowest eight bits, and if and only if both the local and global bits are unset, then we're free to set a breakpoint at this index<sup class="footnote-reference"><a href="#4">4</a></sup>:</p> +<pre><code class="language-rust" data-lang="rust">let index = (0..4) + .find_map(|i| ((context.Dr7 &amp; (0b11 &lt;&lt; (i * 2))) == 0).then(|| i)) + .ok_or_else(|| io::Error::new(io::ErrorKind::Other, &quot;no debug register available&quot;))?; +</code></pre> +<p>Once an <code>index</code> is found, we can set the address we want to watch in the corresponding register and update the debug control bits:</p> +<pre><code class="language-rust" data-lang="rust">let addr = addr as u64; +match index { + 0 =&gt; context.Dr0 = addr, + 1 =&gt; context.Dr1 = addr, + 2 =&gt; context.Dr2 = addr, + 3 =&gt; context.Dr3 = addr, + _ =&gt; unreachable!(), +} + +let clear_mask = !((0b1111 &lt;&lt; (16 + index * 4)) | (0b11 &lt;&lt; (index * 2))); +context.Dr7 &amp;= clear_mask; + +context.Dr7 |= 1 &lt;&lt; (index * 2); + +let sc = (((size as u8) &lt;&lt; 2) | (cond as u8)) as u64; +context.Dr7 |= sc &lt;&lt; (16 + index * 4); + +self.set_context(&amp;context)?; +Ok(Breakpoint { + thread: self, + clear_mask, +}) +</code></pre> +<p>Note that we're first creating a &quot;clear mask&quot;. We switch on all the bits that we may use for this breakpoint, and then negate. Effectively, <code>Dr7 &amp; clear_mask</code> will make sure we don't leave any bit high on accident. We apply the mask before OR-ing the rest of bits to also clear any potential garbage on the size and condition bits. Next, we set the bit to enable the new local breakpoint, and also store the size and condition bits at the right location.</p> +<p>With the context updated, we can set it back and return the <code>Breakpoint</code>. It stores the <code>thread</code> and the <code>clear_mask</code> so that it can clean up on <code>Drop</code>. We are technically relying on <code>Drop</code> to run behaviour here, but the cleanup is done on a best-effort basis. If the user intentionally forgets the <code>Breakpoint</code>, maybe they want the <code>Breakpoint</code> to forever be set.</p> +<p>This logic is begging for a testcase though; I'll split it into a new <code>Breakpoint::update_dbg_control</code> method and test that out:</p> +<pre><code class="language-rust" data-lang="rust"> +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn brk_add_one() { + // DR7 starts with garbage which should be respected. + let (clear_mask, dr, dr7) = + Breakpoint::update_dbg_control(0x1700, Condition::Write, Size::DoubleWord).unwrap(); + + assert_eq!(clear_mask, 0xffff_ffff_fff0_fffc); + assert_eq!(dr, DebugRegister::Dr0); + assert_eq!(dr7, 0x0000_0000_000d_1701); + } + + #[test] + fn brk_add_two() { + let (clear_mask, dr, dr7) = Breakpoint::update_dbg_control( + 0x0000_0000_000d_0001, + Condition::Write, + Size::DoubleWord, + ) + .unwrap(); + + assert_eq!(clear_mask, 0xffff_ffff_ff0f_fff3); + assert_eq!(dr, DebugRegister::Dr1); + assert_eq!(dr7, 0x0000_0000_00dd_0005); + } + + #[test] + fn brk_try_add_when_max() { + assert!(Breakpoint::update_dbg_control( + 0x0000_0000_dddd_0055, + Condition::Write, + Size::DoubleWord + ) + .is_none()); + } +} +</code></pre> +<pre><code>running 3 tests +test thread::tests::brk_add_one ... ok +test thread::tests::brk_add_two ... ok +test thread::tests::brk_try_add_when_max ... ok +</code></pre> +<p>Very good! With proper breakpoint handling usable, we can continue.</p> +<h2 id="inferring-the-pointer-value">Inferring the pointer value</h2> +<p>After scanning memory for the location we're looking for (say, our current health), we then add an access watchpoint, and wait for an exception to occur. As a reminder, here's the page with the <a href="https://docs.microsoft.com/en-us/windows/win32/debug/debugging-events">Debugging Events</a>:</p> +<pre><code class="language-rust" data-lang="rust">let addr = ...; +let mut threads = ...; + +let _watchpoints = threads + .iter_mut() + .map(|thread| { + thread + .add_breakpoint(addr, thread::Condition::Access, thread::Size::DoubleWord) + .unwrap() + }) + .collect::&lt;Vec&lt;_&gt;&gt;(); + +loop { + let event = debugger.wait_event(None).unwrap(); + if event.dwDebugEventCode == winapi::um::minwinbase::EXCEPTION_DEBUG_EVENT { + let exc = unsafe { event.u.Exception() }; + if exc.ExceptionRecord.ExceptionCode == winapi::um::minwinbase::EXCEPTION_SINGLE_STEP { + todo!(); + } + } + debugger.cont(event, true).unwrap(); +} +</code></pre> +<p>Now, inside the <code>todo!()</code> we will want to do a few things, namely printing out the instructions &quot;around this location&quot; and dumping the entire thread context on screen. To print the instructions, we need to import <code>iced_x86</code> again, iterate over all memory regions to find the region where the exception happened, read the corresponding bytes, decode the instructions, and when we find the one with a corresponding instruction pointer, print &quot;around it&quot;:</p> +<pre><code class="language-rust" data-lang="rust">use iced_x86::{Decoder, DecoderOptions, Formatter, Instruction, NasmFormatter}; + +let addr = exc.ExceptionRecord.ExceptionAddress as usize; +let region = process + .memory_regions() + .into_iter() + .find(|region| { + let base = region.BaseAddress as usize; + base &lt;= addr &amp;&amp; addr &lt; base + region.RegionSize + }) + .unwrap(); + +let bytes = process + .read_memory(region.BaseAddress as usize, region.RegionSize) + .unwrap(); + +let mut decoder = Decoder::new(64, &amp;bytes, DecoderOptions::NONE); +decoder.set_ip(region.BaseAddress as _); + +let mut formatter = NasmFormatter::new(); +let mut output = String::new(); + +let instructions = decoder.into_iter().collect::&lt;Vec&lt;_&gt;&gt;(); +for (i, ins) in instructions.iter().enumerate() { + if ins.next_ip() as usize == addr { + let low = i.saturating_sub(5); + let high = (i + 5).min(instructions.len()); + for j in low..high { + let ins = &amp;instructions[j]; + print!(&quot;{} {:016X} &quot;, if j == i { &quot;&gt;&gt;&gt;&quot; } else { &quot; &quot; }, ins.ip()); + let k = (ins.ip() - region.BaseAddress as usize as u64) as usize; + let instr_bytes = &amp;bytes[k..k + ins.len()]; + for b in instr_bytes.iter() { + print!(&quot;{:02X}&quot;, b); + } + if instr_bytes.len() &lt; 10 { + for _ in 0..10usize.saturating_sub(instr_bytes.len()) { + print!(&quot; &quot;); + } + } + + output.clear(); + formatter.format(ins, &amp;mut output); + println!(&quot; {}&quot;, output); + } + break; + } +} +debugger.cont(event, true).unwrap(); +break; +</code></pre> +<p>The result is pretty fancy:</p> +<pre><code> 000000010002CAAC 48894DF0 mov [rbp-10h],rcx + 000000010002CAB0 488955F8 mov [rbp-8],rdx + 000000010002CAB4 48C745D800000000 mov qword [rbp-28h],0 + 000000010002CABC 90 nop + 000000010002CABD 488B050CA02D00 mov rax,[rel 100306AD0h] +&gt;&gt;&gt; 000000010002CAC4 8B00 mov eax,[rax] + 000000010002CAC6 8945EC mov [rbp-14h],eax + 000000010002CAC9 B9E8030000 mov ecx,3E8h + 000000010002CACE E88D2FFEFF call 000000010000FA60h + 000000010002CAD3 8945E8 mov [rbp-18h],eax +</code></pre> +<p>Cool! So <code>rax</code> is holding an address, meaning it's a pointer, and the value it reads (dereferences) is stored back into <code>eax</code> (because it does not need <code>rax</code> anymore). Alas, the current thread context has the register state <em>after</em> the instruction was executed, and <code>rax</code> no longer contains the address at this point. However, notice how the previous instruction writes a fixed value to <code>rax</code>, and then that value is used to access memory, like so:</p> +<pre><code class="language-rust" data-lang="rust">let eax = memory[memory[0x100306AD0]]; +</code></pre> +<p>The value at <code>memory[0x100306AD0]</code> <em>is</em> the pointer! No offsets are used, because nothing is added to the pointer after it's read. This means that, if we simply scan for the address we were looking for, we should find out where the pointer is stored:</p> +<pre><code class="language-rust" data-lang="rust">let addr = ...; +let scan = process.scan_regions(&amp;regions, Scan::Exact(addr as u64)); + +scan.into_iter().for_each(|region| { + region.locations.iter().for_each(|ptr_addr| { + println!(&quot;[{:x}] = {:x}&quot;, ptr_addr, addr); + }); +}); +</code></pre> +<p>And just like that:</p> +<pre><code>[100306ad0] = 15de9f0 +</code></pre> +<p>Notice how the pointer address found matches with the offset used by the instructions:</p> +<pre><code> 000000010002CABD 488B050CA02D00 mov rax,[rel 100306AD0h] + this is the same as the value we just found ^^^^^^^^^^ +</code></pre> +<p>Very interesting indeed. We were actually very lucky to have only found a single memory location containing the pointer value, <code>0x15de9f0</code>. Cheat Engine somehow knows that this value is always stored at <code>0x100306ad0</code> (or rather, at <code>Tutorial-x86_64.exe+306AD0</code>), because the address shows green. How does it do this?</p> +<h2 id="base-addresses">Base addresses</h2> +<p>Remember back in <a href="/blog/woce-2">part 2</a> when we introduced the memory regions? They're making a comeback! A memory region contains both the current memory protection option <em>and</em> the protection level when the region was created. If we try printing out the protection levels for both the memory region containing the value, and the memory region containing the pointer, this is what we get (the addresses differ from the ones previously because I restarted the tutorial):</p> +<pre><code>Region holding the value: + BaseAddress: 0xb0000 + AllocationBase: 0xb0000 + AllocationProtect: 0x4 + RegionSize: 1007616 + State: 4096 + Protect: 4 + Type: 0x20000 + +Region holding the pointer: + BaseAddress: 0x100304000 + AllocationBase: 0x100000000 + AllocationProtect: 0x80 + RegionSize: 28672 + State: 4096 + Protect: 4 + Type: 0x1000000 +</code></pre> +<p>Interesting! According to the <a href="https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-memory_basic_information"><code>MEMORY_BASIC_INFORMATION</code> page</a>, the type for the first region is <code>MEM_PRIVATE</code>, and the type for the second region is <code>MEM_IMAGE</code> which:</p> +<blockquote> +<p>Indicates that the memory pages within the region are mapped into the view of an image section.</p> +</blockquote> +<p>The protection also changes from <code>PAGE_EXECUTE_WRITECOPY</code> to simply <code>PAGE_READWRITE</code>, but I don't think it's relevant. Neither the type seems to be much more relevant. In <a href="/blog/woce-2">part 2</a> we also mentioned the concept of &quot;base address&quot;, but decided against using it, because starting to look for regions at address zero seemed to work fine. However, it would make sense that fixed &quot;addresses&quot; start at some known &quot;base&quot;. Let's try getting the <a href="https://stackoverflow.com/a/26573045/4759433">base address for all loaded modules</a>. Currently, we only get the address for the base module, in order to retrieve its name, but now we need them all:</p> +<pre><code class="language-rust" data-lang="rust">pub fn enum_modules(&amp;self) -&gt; io::Result&lt;Vec&lt;winapi::shared::minwindef::HMODULE&gt;&gt; { + let mut size = 0; + if unsafe { + winapi::um::psapi::EnumProcessModules( + self.handle.as_ptr(), + ptr::null_mut(), + 0, + &amp;mut size, + ) + } == FALSE + { + return Err(io::Error::last_os_error()); + } + + let mut modules = Vec::with_capacity(size as usize / mem::size_of::&lt;HMODULE&gt;()); + if unsafe { + winapi::um::psapi::EnumProcessModules( + self.handle.as_ptr(), + modules.as_mut_ptr(), + (modules.capacity() * mem::size_of::&lt;HMODULE&gt;()) as u32, + &amp;mut size, + ) + } == FALSE + { + return Err(io::Error::last_os_error()); + } + + unsafe { + modules.set_len(size as usize / mem::size_of::&lt;HMODULE&gt;()); + } + + Ok(modules) +} +</code></pre> +<p>The first call is used to retrieve the correct <code>size</code>, then we allocate just enough, and make the second call. The returned type are pretty much memory addresses, so let's see if we can find regions that contain them:</p> +<pre><code class="language-rust" data-lang="rust">let mut bases = 0; +let modules = process.enum_modules().unwrap(); +let regions = process.memory_regions(); +regions.iter().for_each(|region| { + if modules.iter().any(|module| { + let base = region.AllocationBase as usize; + let addr = *module as usize; + base &lt;= addr &amp;&amp; addr &lt; base + region.RegionSize + }) { + bases += 1; + } +}); + +println!( + &quot;{}/{} regions have a module address within them&quot;, + bases, + regions.len() +); +</code></pre> +<pre><code>41/353 regions have a module address within them +</code></pre> +<p>Exciting stuff! It appears <code>base == addr</code> also does the trick<sup class="footnote-reference"><a href="#5">5</a></sup>, so now we could build a <code>bases: HashSet&lt;usize&gt;</code> and simply check if <code>bases.contains(&amp;region.AllocationBase as usize)</code> to determine whether <code>region</code> is a base address or not<sup class="footnote-reference"><a href="#6">6</a></sup>. So there we have it! The address holding the pointer value does fall within one of these &quot;base regions&quot;. You can also get the name from one of these module addresses, and print it in the same way as Cheat Engine does it (such as <code>Tutorial-x86_64.exe+306AD0</code>).</p> +<h2 id="finale">Finale</h2> +<p>So, there's no &quot;automated&quot; solution to all of this? That's the end? Well, yes, once you have a pointer you can dereference it once and then write to the given address to complete the tutorial step! I can understand how this would feel a bit underwhelming, but in all fairness, we were required to pretty-print assembly to guess what pointer address we could potentially need to look for. There is an <a href="https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-2a-manual.html">stupidly large amount of instructions</a>, and I'm sure a lot of them can access memory, so automating that would be rough. We were lucky that the instructions right before the one that hit the breakpoint were changing the memory address, but you could imagine this value coming from somewhere completely different. It could also be using a myriad of different techniques to apply the offset. I would argue manual intervention is a must here<sup class="footnote-reference"><a href="#7">7</a></sup>.</p> +<p>We have learnt how to pretty-print instructions, and had a very gentle introduction to figuring out what we may need to look for. The code to retrieve the loaded modules, and their corresponding regions, will come in handy later on. Having access to this information lets us know when to stop looking for additional pointers. As soon as a pointer is found within a memory region corresponding to a base module, we're done! Also, I know the title doesn't really much the contents of this entry (sorry about that), but I'm just following the convention of calling it whatever the Cheat Engine tutorial calls them.</p> +<p>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 step6</code> after cloning the repository to get the right version of the code, although you will have to <code>checkout</code> to individual commits if you want to review, for example, how the instructions were printed out. Only the code necessary to complete the step is included at the <code>step6</code> tag.</p> +<p>In the next post, we'll tackle the sixth step of the tutorial: Code Injection. This will be pretty similar to part 5, but instead of writing out a simple NOP instruction, we will have to get a bit more creative.</p> +<h3 id="footnotes">Footnotes</h3> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>This will only be a gentle introduction to pointers. Part 8 of this series will have to rely on more advanced techniques.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p>Kind of. The size of a pointer isn't necessarily the size as <code>usize</code>, although <code>usize</code> is guaranteed to be able of representing every possible address. For our purposes, we can assume a pointer is as big as <code>usize</code>.</p> +</div> +<div class="footnote-definition" id="3"><sup class="footnote-definition-label">3</sup> +<p>Game updates are likely to pull more code and shuffle stuff around. This is unfortunately a difficult problem to solve. But storing a pointer which is usable across restarts for as long as the game doesn't update is still a pretty darn big improvement over having to constantly scan for the locations we care about. Although if you're smart enough to look for certain unique patterns, even if the code is changed, finding those patterns will give you the new updated address, so it's not <em>impossible</em>.</p> +</div> +<div class="footnote-definition" id="4"><sup class="footnote-definition-label">4</sup> +<p><code>bool::then</code> is a pretty recent addition at the time of writing (1.50.0), so make sure you <code>rustup update</code> if it's erroring out!</p> +</div> +<div class="footnote-definition" id="5"><sup class="footnote-definition-label">5</sup> +<p>I wasn't sure if there would be some metadata before the module base address but within the region, so I went with the range check. What <em>is</em> important however is using <code>AllocationBase</code>, not <code>BaseAddress</code>. They're different, and this did bite me.</p> +</div> +<div class="footnote-definition" id="6"><sup class="footnote-definition-label">6</sup> +<p>As usual, I have no idea if this is how Cheat Engine is doing it, but it seems reasonable.</p> +</div> +<div class="footnote-definition" id="6"><sup class="footnote-definition-label">6</sup> +<p>But nothing's stopping you from implementing some heuristics to get the job done for you. If you run some algorithm in your head to find what the pointer value could be, you can program it in Rust as well, although I don't think it's worth the effort.</p> +</div> +</content> + </entry> + <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>@@ -19,6 +450,7 @@ <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> +<li><a href="/blog/woce-6">Part 6: Pointers</a></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>@@ -570,7 +1002,7 @@ <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> +<p>In the <a href="/blog/woce-6">next post</a>, 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>@@ -599,6 +1031,7 @@ <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> +<li><a href="/blog/woce-6">Part 6: Pointers</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();@@ -1013,6 +1446,7 @@ <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> +<li><a href="/blog/woce-6">Part 6: Pointers</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>@@ -1368,6 +1802,7 @@ <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> +<li><a href="/blog/woce-6">Part 6: Pointers</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>@@ -1790,6 +2225,7 @@ <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> +<li><a href="/blog/woce-6">Part 6: Pointers</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-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> +<!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-6/>Writing our own Cheat Engine: Pointers</a><span class=dim> [mod sw; 'windows, 'rust, 'hacking] </span><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><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] +<!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><li><a href=/blog/woce-6>Part 6: Pointers</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><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>> { +<!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><li><a href=/blog/woce-6>Part 6: Pointers</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><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]; +<!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><li><a href=/blog/woce-6>Part 6: Pointers</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-28</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(); +<!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-28</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><li><a href=/blog/woce-6>Part 6: Pointers</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> {
@@ -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: 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 +<!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<li><a href=/blog/woce-6>Part 6: Pointers</a></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;@@ -373,4 +373,4 @@ 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.<p>As far as I can tell (after having asked a bit around), the encoding is usually self synchronizing (similar to UTF-8), so eventually we should end up with correct instructions. But someone can still intentionally write real code between garbage data which we would then disassemble incorrectly. This is a problem on all variable-length ISAs. Half a solution is to <a href=https://stackoverflow.com/q/3983735/>start at the entry point</a>, decode all instructions, and follow the jumps. The other half would be correctly identifying jumps created just to trip a disassembler up, and jumps pointing to dynamically-calculated addresses!<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 <a href=https://stackoverflow.com/a/4062698/>undocumented <code>NtSuspendProcess</code></a> 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><div class=footnote-definition id=4><sup class=footnote-definition-label>4</sup><p>Well, we don't need an entire disassembler. Knowing the length of each instruction is enough, but that on its own is also a lot of work.</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>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.<p>As far as I can tell (after having asked a bit around), the encoding is usually self synchronizing (similar to UTF-8), so eventually we should end up with correct instructions. But someone can still intentionally write real code between garbage data which we would then disassemble incorrectly. This is a problem on all variable-length ISAs. Half a solution is to <a href=https://stackoverflow.com/q/3983735/>start at the entry point</a>, decode all instructions, and follow the jumps. The other half would be correctly identifying jumps created just to trip a disassembler up, and jumps pointing to dynamically-calculated addresses!<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 <a href=/blog/woce-6>next post</a>, 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 <a href=https://stackoverflow.com/a/4062698/>undocumented <code>NtSuspendProcess</code></a> 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><div class=footnote-definition id=4><sup class=footnote-definition-label>4</sup><p>Well, we don't need an entire disassembler. Knowing the length of each instruction is enough, but that on its own is also a lot of work.</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,283 @@
+<!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: Pointers | 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: Pointers</h1><div class=time><p>2021-03-13</div><p>This is part 6 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><a href=/blog/woce-5>Part 5: Code finder</a><li>Part 6: Pointers</ul><p>In part 5 we wrote our very own debugger. We learnt that Cheat Engine is using hardware breakpoints to watch memory change, and how to do the same ourselves. We also learnt that hardware points are not the only way to achieve the effect of watchpoints, although they certainly are the fastest and cleanest approach.<p>In this post, we will be reusing some of that knowledge to find out a closely related value, the <em>pointer</em> that points to the real value<sup class=footnote-reference><a href=#1>1</a></sup>. As a quick reminder, a pointer is nothing but an <code>usize</code><sup class=footnote-reference><a href=#2>2</a></sup> representing the address of another portion of memory, in this case, the actual value we will be scanning for. A pointer is a value that, well, points elsewhere. In Rust we normally use reference instead, which are safer (typed and their lifetime is tracked) than pointers, but in the end we can achieve the same with both.<p>Why care about pointers? It turns out that things, such as your current health in-game, are very unlikely to end up in the same memory position when you restart the game (or even change to another level, or even during gameplay). So, if you perform a scan and find that the address where your health is stored is <code>0x73AABABE</code>, you might be tempted to save it and reuse it next time you launch the game. Now you don't need to scan for it again! Alas, as soon as you restart the game, the health is now stored at <code>0x5AADBEEF</code>.<p>Not all hope is lost! The game must <em>somehow</em> have a way to reliably find this value, and the way it's done is with pointers. There will always be some base address that holds a pointer, and the game code knows where to find this pointer. If we are also able to find the pointer at said base address, and follow it ourselves ("dereferencing" it), we can perform the same steps the game is doing, and reliably find the health no matter how much we restart the game<sup class=footnote-reference><a href=#3>3</a></sup>.<h2 id=code-finder>Code finder</h2><details open><summary>Cheat Engine Tutorial: Step 6</summary> <blockquote><p>In the previous step I explained how to use the Code finder to handle changing locations. But that method alone makes it difficult to find the address to set the values you want. That's why there are pointers:<p>At the bottom you'll find 2 buttons. One will change the value, and the other changes the value AND the location of the value. For this step you don't really need to know assembler, but it helps a lot if you do.<p>First find the address of the value. When you've found it use the function to find out what accesses this address.<p>Change the value again, and a item will show in the list. Double click that item. (or select and click on more info) and a new window will open with detailed information on what happened when the instruction ran.<p>If the assembler instruction doesn't have anything between a '[' and ']' then use another item in the list. If it does it will say what it think will be the value of the pointer you need.<p>Go back to the main cheat engine window (you can keep this extra info window open if you want, but if you close it, remember what is between the [ and ]) and do a 4 byte scan in hexadecimal for the value the extra info told you. When done scanning it may return 1 or a few hundred addresses. Most of the time the address you need will be the smallest one. Now click on manually add and select the pointer checkbox.<p>The window will change and allow you to type in the address of a pointer and a offset. Fill in as address the address you just found. If the assembler instruction has a calculation (e.g: [esi+12]) at the end then type the value in that's at the end. else leave it 0. If it was a more complicated instruction look at the calculation.<p>Example of a more complicated instruction:<p>[EAX*2+EDX+00000310] eax=4C and edx=00801234.<p>In this case EDX would be the value the pointer has, and EAX*2+00000310 the offset, so the offset you'd fill in would be 2*4C+00000310=3A8. (this is all in hex, use calc.exe from windows in scientific mode to calculate).<p>Back to the tutorial, click OK and the address will be added, If all went right the address will show P->xxxxxxx, with xxxxxxx being the address of the value you found. If thats not right, you've done something wrong. Now, change the value using the pointer you added in 5000 and freeze it. Then click Change pointer, and if all went right the next button will become visible.<p><em>extra</em>: And you could also use the pointer scanner to find the pointer to this address.</blockquote></details><h2 id=on-access-watchpoints>On-access watchpoints</h2><p>Last time we managed to learn how hardware breakpoints were being set by observing Cheat Engine's behaviour. I think it's now time to handle this properly instead. We'll check out the <a href=https://wiki.osdev.org/CPU_Registers_x86#Debug_Registers>CPU Registers x86 page on OSDev</a> to learn about it:<ul><li>DR0, DR1, DR2 and DR3 can hold a memory address each. This address will be used by the breakpoint.<li>DR4 is actually an <a href=https://en.wikipedia.org/wiki/X86_debug_register>obsolete synonym</a> for DR6.<li>DR5 is another obsolete synonym, this time for DR7.<li>DR6 is debug status. The four lowest bits indicate which breakpoint was hit, and the four highest bits contain additional information. We should make sure to clear this ourselves when a breakpoint is hit.<li>DR7 is debug control, which we need to study more carefully.</ul><p>Each debug register DR0 through DR3 has two corresponding bits in DR7, starting from the lowest-order bit, to indicate whether the corresponding register is a <strong>L</strong>ocal or <strong>G</strong>lobal breakpoint. So it looks like this:<pre><code> Meaning: [ .. .. | G3 | L3 | G2 | L2 | G1 | L1 | G0 | L0 ] +Bit-index: 31-08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 +</code></pre><p>Cheat Engine was using local breakpoints, because the zeroth bit was set. Probably because we don't want these breakpoints to infect other programs! Because we were using only one breakpoint, only the lowermost bit was being set. The local 1st, 2nd and 3rd bits were unset.<p>Now, each debug register DR0 through DR4 has four additional bits in DR7, two for the <strong>C</strong>ondition and another two for the <strong>S</strong>ize:<pre><code> Meaning: [ S3 | C3 | S2 | C2 | S1 | C1 | S0 | C0 | .. .. ] +Bit-index: 31 30 | 29 28 | 27 26 | 25 24 | 23 22 | 21 20 | 19 18 | 17 16 | 15-00 +</code></pre><p>The two bits of the condition mean the following:<ul><li><code>00</code> execution breakpoint.<li><code>01</code> write watchpoint.<li><code>11</code> read/write watchpoint.<li><code>10</code> unsupported I/O read/write.</ul><p>When we were using Cheat Engine to add write watchpoints, the bits 17 and 16 were indeed set to <code>01</code>, and the bits 19 and 18 were set to <code>11</code>. Hm, but <em>11<sub>2</sub> = 3<sub>10</sub></em> , and yet, we were watching writes to 4 bytes. So what's up with this? Is there a different mapping for the size which isn't documented at the time of writing? Seems we need to learn from Cheat Engine's behaviour one more time.<p>For reference, this is what DR7 looked like when we added a single write watchpoint:<pre><code>hex: 000d_0001 +bin: 00000000_00001101_00000000_00000001 +</code></pre><p>And this is the code I will be using to check the breakpoints of different sizes:<pre><code>thread::enum_threads(pid) + .unwrap() + .into_iter() + .for_each(|tid| { + let thread = thread::Thread::open(tid).unwrap(); + let ctx = thread.get_context().unwrap(); + eprintln!("hex: {:08x}", ctx.Dr7); + eprintln!("bin: {:032b}", ctx.Dr7); + }); +</code></pre><p>Let's compare this to watchpoints for sizes 1, 2, 4 and 8 bytes:<pre><code>1 byte +hex: 0001_0401 +bin: 00000000_00000001_00000100_00000001 + +2 bytes +hex: 0005_0401 +bin: 00000000_00000101_00000100_00000001 + +4 bytes +hex: 000d_0401 +bin: 00000000_00001101_00000100_00000001 + +8 bytes +hex: 0009_0401 +bin: 00000000_00001001_00000100_00000001 + ^ wut? +</code></pre><p>I have no idea what's up with that stray tenth bit. Its use does not seem documented, and things worked fine without it, so we'll ignore it. The lowest bit is set to indicate we're using DR0, bits 17 and 16 represent the write watchpoint, and the size seems to be as follows:<ul><li><code>00</code> for a single byte.<li><code>01</code> for two bytes (a "word").<li><code>11</code> for four bytes (a "double word").<li><code>10</code> for eight bytes (a "quadruple word").</ul><p>Doesn't make much sense if you ask me, but we'll roll with it. Just to confirm, this is what the "on-access" breakpoint looks like according to Cheat Engine:<pre><code>hex: 000f_0401 +bin: 00000000_00001111_00000100_00000001 +</code></pre><p>So it all checks out! The bit pattern is <code>11</code> for read/write (technically, a write is also an access). Let's implement this!<h2 id=proper-breakpoint-handling>Proper breakpoint handling</h2><p>The first thing we need to do is represent the possible breakpoint conditions:<pre><code class=language-rust data-lang=rust>#[repr(u8)] +pub enum Condition { + Execute = 0b00, + Write = 0b01, + Access = 0b11, +} +</code></pre><p>And also the legal breakpoint sizes:<pre><code class=language-rust data-lang=rust>#[repr(u8)] +pub enum Size { + Byte = 0b00, + Word = 0b01, + DoubleWord = 0b11, + QuadWord = 0b10, +} +</code></pre><p>We are using <code>#[repr(u8)]</code> so that we can convert a given variant into the corresponding bit pattern. With the right types defined in order to set a breakpoint, we can start implementing the method that will set them (inside <code>impl Thread</code>):<pre><code class=language-rust data-lang=rust>pub fn add_breakpoint(&self, addr: usize, cond: Condition, size: Size) -> io::Result<Breakpoint> { + let mut context = self.get_context()?; + todo!() +} +</code></pre><p>First, let's try finding an "open spot" where we could set our breakpoint. We will "slide" a the <code>0b11</code> bitmask over the lowest eight bits, and if and only if both the local and global bits are unset, then we're free to set a breakpoint at this index<sup class=footnote-reference><a href=#4>4</a></sup>:<pre><code class=language-rust data-lang=rust>let index = (0..4) + .find_map(|i| ((context.Dr7 & (0b11 << (i * 2))) == 0).then(|| i)) + .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "no debug register available"))?; +</code></pre><p>Once an <code>index</code> is found, we can set the address we want to watch in the corresponding register and update the debug control bits:<pre><code class=language-rust data-lang=rust>let addr = addr as u64; +match index { + 0 => context.Dr0 = addr, + 1 => context.Dr1 = addr, + 2 => context.Dr2 = addr, + 3 => context.Dr3 = addr, + _ => unreachable!(), +} + +let clear_mask = !((0b1111 << (16 + index * 4)) | (0b11 << (index * 2))); +context.Dr7 &= clear_mask; + +context.Dr7 |= 1 << (index * 2); + +let sc = (((size as u8) << 2) | (cond as u8)) as u64; +context.Dr7 |= sc << (16 + index * 4); + +self.set_context(&context)?; +Ok(Breakpoint { + thread: self, + clear_mask, +}) +</code></pre><p>Note that we're first creating a "clear mask". We switch on all the bits that we may use for this breakpoint, and then negate. Effectively, <code>Dr7 & clear_mask</code> will make sure we don't leave any bit high on accident. We apply the mask before OR-ing the rest of bits to also clear any potential garbage on the size and condition bits. Next, we set the bit to enable the new local breakpoint, and also store the size and condition bits at the right location.<p>With the context updated, we can set it back and return the <code>Breakpoint</code>. It stores the <code>thread</code> and the <code>clear_mask</code> so that it can clean up on <code>Drop</code>. We are technically relying on <code>Drop</code> to run behaviour here, but the cleanup is done on a best-effort basis. If the user intentionally forgets the <code>Breakpoint</code>, maybe they want the <code>Breakpoint</code> to forever be set.<p>This logic is begging for a testcase though; I'll split it into a new <code>Breakpoint::update_dbg_control</code> method and test that out:<pre><code class=language-rust data-lang=rust> +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn brk_add_one() { + // DR7 starts with garbage which should be respected. + let (clear_mask, dr, dr7) = + Breakpoint::update_dbg_control(0x1700, Condition::Write, Size::DoubleWord).unwrap(); + + assert_eq!(clear_mask, 0xffff_ffff_fff0_fffc); + assert_eq!(dr, DebugRegister::Dr0); + assert_eq!(dr7, 0x0000_0000_000d_1701); + } + + #[test] + fn brk_add_two() { + let (clear_mask, dr, dr7) = Breakpoint::update_dbg_control( + 0x0000_0000_000d_0001, + Condition::Write, + Size::DoubleWord, + ) + .unwrap(); + + assert_eq!(clear_mask, 0xffff_ffff_ff0f_fff3); + assert_eq!(dr, DebugRegister::Dr1); + assert_eq!(dr7, 0x0000_0000_00dd_0005); + } + + #[test] + fn brk_try_add_when_max() { + assert!(Breakpoint::update_dbg_control( + 0x0000_0000_dddd_0055, + Condition::Write, + Size::DoubleWord + ) + .is_none()); + } +} +</code></pre><pre><code>running 3 tests +test thread::tests::brk_add_one ... ok +test thread::tests::brk_add_two ... ok +test thread::tests::brk_try_add_when_max ... ok +</code></pre><p>Very good! With proper breakpoint handling usable, we can continue.<h2 id=inferring-the-pointer-value>Inferring the pointer value</h2><p>After scanning memory for the location we're looking for (say, our current health), we then add an access watchpoint, and wait for an exception to occur. As a reminder, here's the page with the <a href=https://docs.microsoft.com/en-us/windows/win32/debug/debugging-events>Debugging Events</a>:<pre><code class=language-rust data-lang=rust>let addr = ...; +let mut threads = ...; + +let _watchpoints = threads + .iter_mut() + .map(|thread| { + thread + .add_breakpoint(addr, thread::Condition::Access, thread::Size::DoubleWord) + .unwrap() + }) + .collect::<Vec<_>>(); + +loop { + let event = debugger.wait_event(None).unwrap(); + if event.dwDebugEventCode == winapi::um::minwinbase::EXCEPTION_DEBUG_EVENT { + let exc = unsafe { event.u.Exception() }; + if exc.ExceptionRecord.ExceptionCode == winapi::um::minwinbase::EXCEPTION_SINGLE_STEP { + todo!(); + } + } + debugger.cont(event, true).unwrap(); +} +</code></pre><p>Now, inside the <code>todo!()</code> we will want to do a few things, namely printing out the instructions "around this location" and dumping the entire thread context on screen. To print the instructions, we need to import <code>iced_x86</code> again, iterate over all memory regions to find the region where the exception happened, read the corresponding bytes, decode the instructions, and when we find the one with a corresponding instruction pointer, print "around it":<pre><code class=language-rust data-lang=rust>use iced_x86::{Decoder, DecoderOptions, Formatter, Instruction, NasmFormatter}; + +let addr = exc.ExceptionRecord.ExceptionAddress as usize; +let region = process + .memory_regions() + .into_iter() + .find(|region| { + let base = region.BaseAddress as usize; + base <= addr && addr < base + region.RegionSize + }) + .unwrap(); + +let bytes = process + .read_memory(region.BaseAddress as usize, region.RegionSize) + .unwrap(); + +let mut decoder = Decoder::new(64, &bytes, DecoderOptions::NONE); +decoder.set_ip(region.BaseAddress as _); + +let mut formatter = NasmFormatter::new(); +let mut output = String::new(); + +let instructions = decoder.into_iter().collect::<Vec<_>>(); +for (i, ins) in instructions.iter().enumerate() { + if ins.next_ip() as usize == addr { + let low = i.saturating_sub(5); + let high = (i + 5).min(instructions.len()); + for j in low..high { + let ins = &instructions[j]; + print!("{} {:016X} ", if j == i { ">>>" } else { " " }, ins.ip()); + let k = (ins.ip() - region.BaseAddress as usize as u64) as usize; + let instr_bytes = &bytes[k..k + ins.len()]; + for b in instr_bytes.iter() { + print!("{:02X}", b); + } + if instr_bytes.len() < 10 { + for _ in 0..10usize.saturating_sub(instr_bytes.len()) { + print!(" "); + } + } + + output.clear(); + formatter.format(ins, &mut output); + println!(" {}", output); + } + break; + } +} +debugger.cont(event, true).unwrap(); +break; +</code></pre><p>The result is pretty fancy:<pre><code> 000000010002CAAC 48894DF0 mov [rbp-10h],rcx + 000000010002CAB0 488955F8 mov [rbp-8],rdx + 000000010002CAB4 48C745D800000000 mov qword [rbp-28h],0 + 000000010002CABC 90 nop + 000000010002CABD 488B050CA02D00 mov rax,[rel 100306AD0h] +>>> 000000010002CAC4 8B00 mov eax,[rax] + 000000010002CAC6 8945EC mov [rbp-14h],eax + 000000010002CAC9 B9E8030000 mov ecx,3E8h + 000000010002CACE E88D2FFEFF call 000000010000FA60h + 000000010002CAD3 8945E8 mov [rbp-18h],eax +</code></pre><p>Cool! So <code>rax</code> is holding an address, meaning it's a pointer, and the value it reads (dereferences) is stored back into <code>eax</code> (because it does not need <code>rax</code> anymore). Alas, the current thread context has the register state <em>after</em> the instruction was executed, and <code>rax</code> no longer contains the address at this point. However, notice how the previous instruction writes a fixed value to <code>rax</code>, and then that value is used to access memory, like so:<pre><code class=language-rust data-lang=rust>let eax = memory[memory[0x100306AD0]]; +</code></pre><p>The value at <code>memory[0x100306AD0]</code> <em>is</em> the pointer! No offsets are used, because nothing is added to the pointer after it's read. This means that, if we simply scan for the address we were looking for, we should find out where the pointer is stored:<pre><code class=language-rust data-lang=rust>let addr = ...; +let scan = process.scan_regions(&regions, Scan::Exact(addr as u64)); + +scan.into_iter().for_each(|region| { + region.locations.iter().for_each(|ptr_addr| { + println!("[{:x}] = {:x}", ptr_addr, addr); + }); +}); +</code></pre><p>And just like that:<pre><code>[100306ad0] = 15de9f0 +</code></pre><p>Notice how the pointer address found matches with the offset used by the instructions:<pre><code> 000000010002CABD 488B050CA02D00 mov rax,[rel 100306AD0h] + this is the same as the value we just found ^^^^^^^^^^ +</code></pre><p>Very interesting indeed. We were actually very lucky to have only found a single memory location containing the pointer value, <code>0x15de9f0</code>. Cheat Engine somehow knows that this value is always stored at <code>0x100306ad0</code> (or rather, at <code>Tutorial-x86_64.exe+306AD0</code>), because the address shows green. How does it do this?<h2 id=base-addresses>Base addresses</h2><p>Remember back in <a href=/blog/woce-2>part 2</a> when we introduced the memory regions? They're making a comeback! A memory region contains both the current memory protection option <em>and</em> the protection level when the region was created. If we try printing out the protection levels for both the memory region containing the value, and the memory region containing the pointer, this is what we get (the addresses differ from the ones previously because I restarted the tutorial):<pre><code>Region holding the value: + BaseAddress: 0xb0000 + AllocationBase: 0xb0000 + AllocationProtect: 0x4 + RegionSize: 1007616 + State: 4096 + Protect: 4 + Type: 0x20000 + +Region holding the pointer: + BaseAddress: 0x100304000 + AllocationBase: 0x100000000 + AllocationProtect: 0x80 + RegionSize: 28672 + State: 4096 + Protect: 4 + Type: 0x1000000 +</code></pre><p>Interesting! According to the <a href=https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-memory_basic_information><code>MEMORY_BASIC_INFORMATION</code> page</a>, the type for the first region is <code>MEM_PRIVATE</code>, and the type for the second region is <code>MEM_IMAGE</code> which:<blockquote><p>Indicates that the memory pages within the region are mapped into the view of an image section.</blockquote><p>The protection also changes from <code>PAGE_EXECUTE_WRITECOPY</code> to simply <code>PAGE_READWRITE</code>, but I don't think it's relevant. Neither the type seems to be much more relevant. In <a href=/blog/woce-2>part 2</a> we also mentioned the concept of "base address", but decided against using it, because starting to look for regions at address zero seemed to work fine. However, it would make sense that fixed "addresses" start at some known "base". Let's try getting the <a href=https://stackoverflow.com/a/26573045/4759433>base address for all loaded modules</a>. Currently, we only get the address for the base module, in order to retrieve its name, but now we need them all:<pre><code class=language-rust data-lang=rust>pub fn enum_modules(&self) -> io::Result<Vec<winapi::shared::minwindef::HMODULE>> { + let mut size = 0; + if unsafe { + winapi::um::psapi::EnumProcessModules( + self.handle.as_ptr(), + ptr::null_mut(), + 0, + &mut size, + ) + } == FALSE + { + return Err(io::Error::last_os_error()); + } + + let mut modules = Vec::with_capacity(size as usize / mem::size_of::<HMODULE>()); + if unsafe { + winapi::um::psapi::EnumProcessModules( + self.handle.as_ptr(), + modules.as_mut_ptr(), + (modules.capacity() * mem::size_of::<HMODULE>()) as u32, + &mut size, + ) + } == FALSE + { + return Err(io::Error::last_os_error()); + } + + unsafe { + modules.set_len(size as usize / mem::size_of::<HMODULE>()); + } + + Ok(modules) +} +</code></pre><p>The first call is used to retrieve the correct <code>size</code>, then we allocate just enough, and make the second call. The returned type are pretty much memory addresses, so let's see if we can find regions that contain them:<pre><code class=language-rust data-lang=rust>let mut bases = 0; +let modules = process.enum_modules().unwrap(); +let regions = process.memory_regions(); +regions.iter().for_each(|region| { + if modules.iter().any(|module| { + let base = region.AllocationBase as usize; + let addr = *module as usize; + base <= addr && addr < base + region.RegionSize + }) { + bases += 1; + } +}); + +println!( + "{}/{} regions have a module address within them", + bases, + regions.len() +); +</code></pre><pre><code>41/353 regions have a module address within them +</code></pre><p>Exciting stuff! It appears <code>base == addr</code> also does the trick<sup class=footnote-reference><a href=#5>5</a></sup>, so now we could build a <code>bases: HashSet<usize></code> and simply check if <code>bases.contains(&region.AllocationBase as usize)</code> to determine whether <code>region</code> is a base address or not<sup class=footnote-reference><a href=#6>6</a></sup>. So there we have it! The address holding the pointer value does fall within one of these "base regions". You can also get the name from one of these module addresses, and print it in the same way as Cheat Engine does it (such as <code>Tutorial-x86_64.exe+306AD0</code>).<h2 id=finale>Finale</h2><p>So, there's no "automated" solution to all of this? That's the end? Well, yes, once you have a pointer you can dereference it once and then write to the given address to complete the tutorial step! I can understand how this would feel a bit underwhelming, but in all fairness, we were required to pretty-print assembly to guess what pointer address we could potentially need to look for. There is an <a href=https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-2a-manual.html>stupidly large amount of instructions</a>, and I'm sure a lot of them can access memory, so automating that would be rough. We were lucky that the instructions right before the one that hit the breakpoint were changing the memory address, but you could imagine this value coming from somewhere completely different. It could also be using a myriad of different techniques to apply the offset. I would argue manual intervention is a must here<sup class=footnote-reference><a href=#7>7</a></sup>.<p>We have learnt how to pretty-print instructions, and had a very gentle introduction to figuring out what we may need to look for. The code to retrieve the loaded modules, and their corresponding regions, will come in handy later on. Having access to this information lets us know when to stop looking for additional pointers. As soon as a pointer is found within a memory region corresponding to a base module, we're done! Also, I know the title doesn't really much the contents of this entry (sorry about that), but I'm just following the convention of calling it whatever the Cheat Engine tutorial calls them.<p>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 step6</code> after cloning the repository to get the right version of the code, although you will have to <code>checkout</code> to individual commits if you want to review, for example, how the instructions were printed out. Only the code necessary to complete the step is included at the <code>step6</code> tag.<p>In the next post, we'll tackle the sixth step of the tutorial: Code Injection. This will be pretty similar to part 5, but instead of writing out a simple NOP instruction, we will have to get a bit more creative.<h3 id=footnotes>Footnotes</h3><div class=footnote-definition id=1><sup class=footnote-definition-label>1</sup><p>This will only be a gentle introduction to pointers. Part 8 of this series will have to rely on more advanced techniques.</div><div class=footnote-definition id=2><sup class=footnote-definition-label>2</sup><p>Kind of. The size of a pointer isn't necessarily the size as <code>usize</code>, although <code>usize</code> is guaranteed to be able of representing every possible address. For our purposes, we can assume a pointer is as big as <code>usize</code>.</div><div class=footnote-definition id=3><sup class=footnote-definition-label>3</sup><p>Game updates are likely to pull more code and shuffle stuff around. This is unfortunately a difficult problem to solve. But storing a pointer which is usable across restarts for as long as the game doesn't update is still a pretty darn big improvement over having to constantly scan for the locations we care about. Although if you're smart enough to look for certain unique patterns, even if the code is changed, finding those patterns will give you the new updated address, so it's not <em>impossible</em>.</div><div class=footnote-definition id=4><sup class=footnote-definition-label>4</sup><p><code>bool::then</code> is a pretty recent addition at the time of writing (1.50.0), so make sure you <code>rustup update</code> if it's erroring out!</div><div class=footnote-definition id=5><sup class=footnote-definition-label>5</sup><p>I wasn't sure if there would be some metadata before the module base address but within the region, so I went with the range check. What <em>is</em> important however is using <code>AllocationBase</code>, not <code>BaseAddress</code>. They're different, and this did bite me.</div><div class=footnote-definition id=6><sup class=footnote-definition-label>6</sup><p>As usual, I have no idea if this is how Cheat Engine is doing it, but it seems reasonable.</div><div class=footnote-definition id=6><sup class=footnote-definition-label>6</sup><p>But nothing's stopping you from implementing some heuristics to get the job done for you. If you run some algorithm in your head to find what the pointer value could be, you can program it in Rust as well, although I don't think it's worth the effort.</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!
@@ -213,6 +213,10 @@ <loc>https://lonami.dev/blog/woce-5/</loc>
<lastmod>2021-03-06</lastmod> </url> <url> + <loc>https://lonami.dev/blog/woce-6/</loc> + <lastmod>2021-03-13</lastmod> + </url> + <url> <loc>https://lonami.dev/blog/world-edit/</loc> <lastmod>2018-07-11</lastmod> </url>