Blog Post

Reverse Engineering & Binary Augmentation - Snipping Tool

Screencasts of the reverse engineering process to make binary patches to modify discontinued Microsoft Snipping Tool.

Reverse Engineering & Binary Augmentation - Snipping Tool - Screencasts of the reverse engineering process to make binary patches to modify discontinued Microsoft Snipping Tool.

Intro

This post will be mostly a vlog, or a screencast. I've been thinking for a long time to record myself doing a few binary patching sessions. These include many aspects of the reverse engineering process, from the initial idea, to research, to rolling down your sleeves and doing the actual grunt work of finding the location in the binary machine code where to apply the patch, to actually coming up with the binary patch itself, and much more. All of this is a tedious work, which I attempted to demonstrate in the series of screencasts in this post.

I start from the simplest of projects and slowly ramp up the pace to the most advanced one that took close to four hours to demonstrate, and much, much longer to prepare for. These videos are not for everyone, so I warn you ahead of time that if you don't like watching someone digging through binary Assembly code, don't even try to watch these.

I recorded all of the reverse engineering sessions below using a one-take approach, without making any significant cuts to demonstrate the process in its "full glory". I have also made quite a few mistakes there, and misspoke more times than I can even remember. So keep this in mind. It's not easy to write code, or review binary Assembly and talk at the same time.

If you came here just to grab a copy of the patched Snipping Tool, then you can download it here.

Make sure to run it with the command line parameter "1" to enable automatic start of a snip like so:

path-to\SnippingTool.exe 1

Or, you can use my "SnippingTool - auto snip" shortcut file, included in the download to do it for you.

Keep in mind that if you downloaded the patched Snipping Tool from the internet, say, from the link that I gave above, your antivirus software may complain about it or may even block it. This is understandable because you are trying to run a patched version of the Microsoft tool that you downloaded from the internet. So what can go wrong there? 🙄

Thus if you don't want to run a patched executable that you downloaded from some website (which I don't blame you for), follow the steps in the screencasts below to patch it yourself. That way you will be sure that there's no bad code in your own patched version.

Finally, I tried to place time codes for each video below to ensure better navigation in case you want to skip some parts of the video.

So without further adieu, let's begin from the basics.

What Is Binary Augmentation?

Before we begin digging into the nitty-gritty of the reverse engineering process itself, let's try to understand the basic terminology.

I am referring to the binary augmentation, or modification in the title of this video. But what is it?

To understand what this is, let's picture a situation when you have a (compiled) binary executable (or a piece of software, in the layman's terms) and for whatever reason you need to change it. This could be any of the following scenarios:

  • You purchased an expensive software that was discontinued by the manufacturer, and that software no longer runs on the latest version of the operating system that comes with your computer. But you need to continue using that software.
  • Or, alternatively the manufacturer went out of business and you are stuck with their software that no longer runs on the latest version of Windows that your hardware comes with.
  • The software in question may be still supported but it may have bugs, defects or security vulnerabilities that the manufacturer doesn't want or can't fix.
  • It may be cheaper for you to modify the existing software that you already purchased versus paying exorbitant amounts of money for an upgrade.
  • The software in question may be crashing and you don't know the reason why, but the original manufacturer either refuses to fix it, or cannot do it.
  • If the source code to the binary in question is no longer available. Say, if it was lost, or damaged, or can no longer be compiled.
  • Finally, there are also some gray-zone applications for this technique, such as removal of the software DRM, or writing malware. I will not be coving or doing those upon request. But keep in mind that such applications of the binary patching are also quite prevalent.

So, in a nutshell, a binary augmentation is a process of modifying some piece of software without having its source code. If you had the source code, you could simply rebuild such software. But let's face it, source code for most commercial products is not something that just lays around.

Batty Game Patch

Having familiarized with what all this is about, let's start from the simplest of the binary patches.

Some time ago I wrote a blog post about an 8-bit game, called Batty, that I coded a while back and lost its source code. The game was pretty much left unfinished, and I used it in that blog post as my own bad example of "what not to do". But later I decided to use it as an example to apply a binary patch as well.

The patch in question was just a change of a game loop delay that didn't make it play in a smooth fashion anymore. I demonstrated the process below:

Video Timecodes

The following time-coded segments will open in a YouTube player:

  • 4:11 - What I am patching: WaitForSingleObject function delay.
  • 6:05 - Downloading tools: HxD hex editor.
  • 7:33 - Downloading a debugger/disassembler: IDA Free.
  • 8:49 - Opening my binary file in IDA.
  • 9:45 - Placing a breakpoint at the point of interest - WaitForSingleObject function in Kernel32.dll module.
  • 12:28 - Breakpoint triggered on the WaitForSingleObject function. I'm trying to step out to our code (repeatedly pressing F8 in IDA.)
  • 14:16 - Finding the spot to patch in a disassembled code.
  • 15:20 - How to display machine code in IDA.
  • 16:38 - Finding machine code for instructions that we want to patch with - using an online disassembler.
  • 18:54 - Finding where to patch using the hex editor.
  • 20:04 - Applying the binary patch in the hex editor.
  • 20:54 - Reference to "The Martian" movie where Mark Watney was applying a patch to his rover.
  • 21:21 - Testing our binary patch in IDA.
  • 23:21 - Oops, my patch didn't work 🤦‍♂️ - checking why ...
  • 23:48 - Fixing the issue with another binary patch.
  • 25:30 - Checking the second patch with IDA.
  • 26:46 - It worked!
  • 26:53 - Checking the final patch.

The patch above was somewhat easy to do as I was the author of the source code and I knew right away where to apply it. In most situations though this will not be the case. Next I will demonstrate a situation that more closely resembles a real-life reverse engineering example. It will come in three parts.

Snipping Tool - Part 1

I was struggling for a while to find a binary that I wasn't the author of that I could reverse engineer without getting myself into a legal trouble. Eventually I found it in the Microsoft's discontinued Snipping Tool.

The version of that tool that was originally shipped with Windows 7 and later with Windows 10 was discontinued in favor of a "more modern looking" version in Windows 11. The old tool was clearly displaying it in its UI:

Snipping Tool
Microsoft Snipping Tool with the message that it was discontinued.

Because the original manufacturer had abandoned that executable, I decided to use it to apply my binary patches to improve it since I was still using it myself and some of its features did not suit my needs.

I decided to break up my work into three parts that will slowly increase in difficulty:

  1. Looking for a way to allow multiple instances of the Microsoft Snipping Tool to run at the same time.
  2. Trying to remove the bottom banner from the Microsoft Snipping Tool's user interface.
  3. Trying to enable immediate taking of a snip in the Microsoft Snipping Tool if the command line parameter "1" was specified.

The video screencast below will cover the first part:

Video Timecodes

The following time-coded segments will open in a YouTube player:

  • 2:22 - How I picked the Snipping Tool.
  • 4:29 - What I will augment in the Snipping Tool.
  • 10:41 - Using Detect-It-Easy tool to see how the Snipping Tool was compiled.
  • 12:44 - How to copy the Snipping Tool using its MUI file.
  • 14:37 - Opening the Snipping Tool in IDA Free.
  • 25:08 - How to determine the type of a return value from a function: BOOL vs HRESULT.
  • 26:58 - I discovered the /CLIP command line parameter for the Snipping Tool.
  • 28:08 - Brief dive into the x64 calling convention on Windows.
  • 40:15 - I found the use of the CreateMutex API - a possible place for a fix.
  • 44:09 - I found another interesting function: bool BringSnipperToFrontIfAlreadyRunning(int).
  • 48:27 - Checking what is inside the BringSnipperToFrontIfAlreadyRunning function.
  • 55:44 - Setting return value from the BringSnipperToFrontIfAlreadyRunning function to 0 in IDA as a test.
  • 58:57 - Thinking how to shunt the BringSnipperToFrontIfAlreadyRunning function with a binary patch.
  • 1:03:41 - Applying my binary patch in HxD.
  • 1:05:49 - Testing the patch in IDA.

The patch above was quite straightforward but it still took me over an hour to explain it. Let's see if we can get it even further.

Snipping Tool - Part 2

The next installment of my reverse engineering and binary patching series revolved around modification of the user interface of the Snipping Tool to remove the bottom banner that said that the "Snipping Tool is moving...". In my view it was not moving anywhere. 😎

Originally, I thought that it will be an easy task. But I was wrong. I will demonstrate it in the following video screencast:

Video Timecodes

The following time-coded segments will open in a YouTube player:

  • 1:58 - Overview of what we will be doing in part 2.
  • 4:31 - Example of how to edit a Win32 dialog resource with the Resource Hacker.
  • 7:21 - Why Resource Hacker didn't work for the Snipping Tool patch.
  • 10:38 - Opening the Snipping Tool in IDA to analyze how it creates its main window.
  • 11:58 - How are Win32 windows created: CreateWindowExW.
  • 14:54 - First debugging run, looking for the CreateWindowExW function call.
  • 17:02 - Internals of the CreateWindowExW function: CreateWindowInternal and why we need to put a breakpoint in the deepest level function.
  • 22:07 - Setting the breakpoint on CreateWindowExW. What are window classes in Win32?.
  • 26:39 - Example how to set up a breakpoint on a recursive function call (kinda fumbling with it, sorry).
  • 57:48 - Exploring the function MoveWindow to set window size.
  • 59:35 - Exploring the function SetWindowPos to set window size.
  • 1:03:45 - How to set a conditional breakpoint on the SetWindowPos function in IDA.
  • 1:06:07 - Tracing where SetWindowPos is called for our main window.
  • 1:06:34 - IDA bugs.
  • 1:10:50 - Call Stack window in IDA.
  • 1:11:15 - Analyzing CToolbar::DoLayout function in the Snipping Tool.
  • 1:18:40 - More details about the SetWindowPos function.
  • 1:20:22 - Testing window height modification in memory.
  • 1:21:45 - Tracing where the height location is filled in.
  • 1:24:41 - Stepping through the CToolbar::DoLayout function.
  • 1:26:13 - Figuring out the window message for the 0x421 code.
  • 1:38:07 - Continuing to step through the CToolbar::DoLayout function.
  • 1:43:56 - Found the CToolbar::CalcScreenSketchBannerHeight function - analyzing it.
  • 1:49:13 - Deciphering the return and the input parameters for the CToolbar::CalcScreenSketchBannerHeight function.
  • 1:54:21 - Testing a possible patch location. And, it works!.
  • 1:55:03 - Deciding how to do the patch (following an erroneous logic - watch the correction video below.)
  • 2:12:18 - Applying the binary patch to the Snipping Tool.
  • 2:14:54 - Testing our binary patch in IDA.

While coding the patch above I made a serious error, which I will try to correct in the next unplanned part.

Snipping Tool - Part 2 (Correction)

At the end of the part 2 of my video screencast I removed one if statement from the original code without realizing the consequences. I later learned about it by having observed the Snipping Tool's crashes.

In the following screencast I will show my error and will also correct it:

Video Timecodes

The following time-coded segments will open in a YouTube player:

  • 0:44 - Explanation how I found a bug in my patch from the part 2 using Windows Error Reporting with my WERSetup tool.
  • 2:54 - Analyzing crash dump with WinDbg.
  • 3:19 - I found FAST_FAIL_GUARD_ICALL_CHECK_FAILURE exception.
  • 3:42 - Quick info about the Control Flow Guard (CFG) on Windows.
  • 6:09 - Reverting the binary patch (that I made in part 2).
  • 8:15 - Investigation of what causes the crash in my patch.
  • 14:35 - Correcting the bad patch.
  • 21:00 - Coming up with the correct binary patch instructions.
  • 24:50 - Applying corrected binary patch (with some initial struggles).
  • 28:31 - Checking resulting patch/fix with the IDA disassembler.
  • 31:46 - Final testing of the patched Snipping Tool for crashes. It passes!

After correcting the part 2 of my reverse engineering work, we are ready to switch to the most advanced part in this series.

Snipping Tool - Part 3

In the final installment of my reverse engineering and binary patching series I will demonstrate how to add a much larger patch to the Snipping Tool to make it simulate a button click on its own toolbar. This is needed to enable automatic initiation of a snip when the tool starts.

Video Timecodes

The following time-coded segments will open in a YouTube player:

  • 1:34 - Starting to reverse engineer the Snipping Tool - using Detect-It-Easy tool to tell what type of executable it is.
  • 2:41 - Discussing how can we start a snip automatically when the Snipping Tool starts.
  • 4:30 - Analyzing how Snipping Tool's UI is built - using the WinID tool.
  • 7:40 - Looking up documentation for the TOOLBARCLASSNAME.
  • 8:08 - Discussion of how to create a Win32 sample app to test a toolbar button click simulation.
  • 8:47 - Creating a sample Win32 app in Visual Studio 2022: TestToolbar01.
  • 10:03 - Adding a test toolbar to our TestToolbar01 app.
  • 24:20 - How to simulate a toolbar button click?
  • 27:25 - Coding a simulated toolbar button click, explanation of how to convert our compiled code to "shell code".
  • 36:28 - Checking if our needed Win32 APIs are imported into the Snipping Tool via static linking.
  • 39:51 - Writing the logic of our simulated toolbar button click.
  • 46:30 - Dynamically retrieving Win32 APIs that are not statically linked in the Snipping Tool.
  • 58:02 - Getting a compiled Assembly language code for our code snippet to simulate a button click.
  • 1:04:47 - Explanation of what needs to be adjusted in the compiled Assembly code to be able to use it in the Snipping Tool.
  • 1:05:27 - Finding where in the Snipping Tool to put our binary patch.
  • 1:06:17 - Looking up the ending of the WndProc for the main window of the Snipping Tool.
  • 1:19:01 - Explanation of the x86-64 ABI: volatile and nonvolatile registers.
  • 1:20:10 - Thinking how to insert our binary patch into the Snipping Tool.
  • 1:22:13 - Deciding where to put all the machine code for our patch, explanation of the PE file sections.
  • 1:25:24 - Adding an empty executable section to the PE file of the Snipping Tool.
  • 1:26:40 - Explanation of the section flags in characteristics in the PE file.
  • 1:31:00 - Why we need to modify our Assembly code that was compiled in the Visual Studio in the TestToolbar01 app?
  • 1:31:40 - Adjusting our Assembly code line-by-line.
  • 1:38:15 - Placing strings in the code area, relative to where we will need them.
  • 1:49:06 - How to adjust addresses of the CALL instructions for imported Win32 APIs. What is IAT, or Import Address Table.
  • 1:53:05 - Getting to adjusting addresses of local variables.
  • 2:02:30 - Cleaning up our resulting Assembly code.
  • 2:06:16 - Retrieving where HWND and uMsg are stored in the WndProc in the Snipping Tool (making a mistake with the MOV instructions order).
  • 2:10:44 - Finding out the offset where to place our global static variable: gnRanOnce.
  • 2:11:57 - Using x64dbg to locate a read/write section in the PE file for our static variable.
  • 2:20:48 - Figuring out relative offsets to the IAT for our needed Win32 APIs.
  • 2:28:33 - x64dbg fail - what leads to my later error - I selected one line but x64dbg copied another one. (It must have been the 7FF651B23C89 address).
  • 2:32:53 - Example of how to set conditional breakpoints in x64dbg to catch an API call from a specific module.
  • 2:38:35 - Writing small C++ code to calculate offsets for our needed Win32 APIs in the IAT for the Snipping Tool.
  • 2:45:38 - Applying API offsets to our generated Assembly code (making a mistake of using a plus-offset instead of a minus-one.)
  • 2:48:37 - Calculating the size of space on the stack needed for our local variables.
  • 2:55:30 - Preserving 16-byte stack alignment for the x64 calling convention in our Assembly code.
  • 2:59:54 - Adjusting stack offsets for our local variables.
  • 3:00:56 - Compiling our Assembly code patch to an Intel x64 machine code.
  • 3:03:59 - Inserting compiled machine code for the patch into the .text2 PE section in the Snipping Tool.
  • 3:06:03 - Calculating an offset for the JMP instruction from the end of the WndProc to our patch.
  • 3:12:22 - Patching the Snipping Tool's WndProc with our JMP instruction to our binary patch.
  • 3:14:32 - Stepping through our binary patch with a debugger to check it for correctness.
  • 3:18:22 - Our patch did not work. 😢 Checking out why ... The reason: I confused the order of initial Assembly instructions in my patch at 2:06:16.
  • 3:19:52 - Trying to correct my mistake ... and doing it wrong ... again. 🤦‍♂️
  • 3:21:53 - Adjusting our binary patch in the Snipping Tool.
  • 3:23:53 - Checking the patch again in IDA by stepping through it ... and seeing that it's not working.
  • 3:26:58 - Finally correcting the first bug ... and adjusting the patch one more time.
  • 3:28:54 - Take 3: testing the binary patch in IDA.
  • 3:31:32 - Discovering that Win32 API offsets to the IAT are set incorrectly: another silly mistake. I used a plus instead of a minus at 2:45:38.
  • 3:33:02 - Correcting the Win32 API offsets & re-applying the patch.
  • 3:35:13 - Checking it by stepping through our patch with IDA ... one more time.
  • 3:36:17 - Discovering that one Win32 API offset is set incorrectly ... causing one more crash. 🙄
  • 3:37:52 - The first copy-and-paste error from 2:28:33 comes back to bite me. I used the wrong address for the calculation of an offset.
  • 3:40:29 - Stepping through our patch with IDA to check it. It doesn't crash. Yay 👍
  • 3:44:20 - Stepping through the patch with the right command line to verify that it's finally working!
  • 3:47:50 - One final test of the patched Snipping Tool to see that it's working.
I posted the source code for the TestToolbar01 app on my GitHub.
Check this blog post if you want to know how I set up my virtual machine for the reverse engineering work that I demonstrated in the screencasts above.

This will conclude my multi-hour screencasts on reverse engineering and binary patching.

Do You Need Your Software Patched?

In case you are faced with a need to patch your own software, feel free to contact me.

Note that reverse engineering, binary patching and augmentation is a paid service. Because of that I will prioritize B2B requests.

Conclusion

My reasoning behind recording these long screencasts was to demonstrate the process of reverse engineering in its full length. Technically I had to do it twice: first to learn how to do it, and second - to record it. And even though the recording part seems quite long, it doesn't even come close to the amount of time that it took to research it first. Thus, I don't think I will ever do the same in a live stream. Well, unless you want to watch me stammer over my mistakes for 8 hours or more. 😂

In despite of that, I love doing reverse engineering. It is a very rewarding job, which I can probably call my hobby.

If you enjoyed watching and reading this blog post ... then you are as weird as me.

OK, kidding. Thanks for watching!

And happy RE'ing!

Related Articles