Introduction
In this tutorial I will discuss various ways of making a window non-closeable. This can come in handy in a variety of cases. Perhaps you would like to display an inspirational quote in a window, “Just because you are unique, does not mean you are useful”, for example. Most users would close this window before really having a chance to think about these words of wisdom. Making the window non-closeable helps solve this problem. Or perhaps you would like to remind a co-worker that there is more to life than work, so send him a game (like “Kill Bunnies With Your Genitalia II”) and make it so it won’t close, thus reminding him that there are always alternatives to working yourself to death.
You can download the files for this tutorial here.
Types Of Windows
Because Windows has different types of windows, accomplishing this feat is slightly different, depending on which method was used to create the window. There are basically three types of windows; A normal window, A dialog box, A dialog that is acting as the main window. I will explain these three cases separately, as the process is different for each. I have included a binary representing all three types. Let’s start with…
A Normal Window
If you open an app in Olly and do a search for All intermodular calls and see “RegisterClass” or “RegisterClassEx” (providing the app is not packed), then you can assume that this is a probably normal window (meaning not a dialog box). I have included the file “Guru.exe” in this download that uses this type of window. It basically just creates a window and displays a helpful message in it:
Loading the app in Olly and doing a search for intermodular calls gives us the following:
Notice that there is a RegisterClassExA. That’s what we want. Double click:
And here we see the call to RegisteClassExA. Notice right before the call is a PUSH EAX. Getting help on RegisterClasExA will help with that:
So RegisterClassExA takes one argument- a pointer to a WNDCLASSEX structure. The preceding PUSH EAX was this pointer. Here is what the API has to say about WNDCLASSEX:
typedef struct _WNDCLASSEX {
UINT cbSize;
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HANDLE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
HICON hIconSm;
} WNDCLASSEX;
One thing you should know is that if your app calls RegisterClass instead of RegisterClassExA, the WNDCLASS structure will be used instead of the WNDCLASSEX structure. The only difference between the two (that we care about) is the the ExA version starts with a cbSize element, whereas the WNDCLASS does not have this element.
The element of he WNDCLASSEX structure we want is the ‘style’ element, which is the second argument (the first in WNDCLASS). Let’s see this structure for ourselves. Set a BP on the PUSH EAX at address 40109D and re-start the app:
We can see that the argument is pWndClassEx and is equal to 0018FF44. We can also look in the status window and see that in fact EAX is equal to this:
Now, look over at the stack. We can see the start of the WNDCLASSEX structure beginning at stack address 18FF44:
Here, the first argument is 0×30, which is the cbSize argument. So we know the size of this WNDCLASSEX structure is 0×30 bytes. Now single step over the PUSH EAX statement:
and notice that this pointer has been pushed on to the stack:
So, here is our first argument (we don’t care about it):
And here is the style argument and the pointer to WndProc. I added the pointer to WndProc because sometimes you want to find where the main WndProc is and this is a good way to do it (though that’s material for another tutorial!).
We can see that the style is set to 3. This is the default look of the window and means ‘show me a standard window, with all the standard stuff’. Now what we want to do is change this and add a simple command to it that Windows uses to grey out the close button. The constant is CS_NOCLOSE and it disables the Close command on the System menu. CS_NOCLOSE is equal to 0×200. Generally, when you want to combine attributes you OR them together, so that’s what we need to do here. We need to OR 0×03 with 0×200 which equals 0×203. Right-click on the stack line at address 18FF48 and choose ‘modify’:
Now let’s change this to our new attribute setting:
and click OK. We now have our new setting on the stack:
Go ahead and run the app:
and you will notice that you may no longer close this window. Added to the fact that the window can not be covered by another window, it certainly makes it’s point. Of course, the user can always minimize it, but that icon just sits there… calling out…wanting to be opened…
If we want to patch this binary to always do this, we simply need to find where this style value of 3 is being pushed on to the stack and replace it with a 0×203. Looking up a couple lines we can clearly see the culprit:
So patching this line to MOV [LOCAL.11], 203 will patch the app for good .
A Dialog Box As Main
Sometimes apps are set up where the main screen is in fact a dialog box. This is helpful in that you can allow Windows to handle a lot of the overhead having to do with buttons, edit boxes etc. Go ahead and load “Helpful.exe” into Olly. Run it and you will see a dialog box:
Notice that clicking the CLOSE button or the ‘X’ on the title bar both close the dialog.
Doing a search in intermodular calls shows that this app has a RegisterClass (RegisterClassExA), so we know it sets up it’s own window (as opposed to a true dialog opened by another window which will not have a register class, as we will see…):
We will start the same way we did with the previous example. Go to the RegisterClassExA and place a BP on it and re-start the app:
Now look at the stack window:
Notice that most everything is the same, except this time there is an argument called “DLGCLASS”. This is to tell windows that this dialog should be our main program window and to send messages to it just like a normal window.
Go ahead and modify the stack and turn the 3 into a 203 so we can grey out the close button:
You can also patch the instruction at address 401203 to always load in 203 as our value:
Typically with dialog boxes there is a button that will close the dialog along with the normal ‘X’ on the title bar. Sometimes it’s called ‘OK’ or ‘Cancel’, or in our case it’s called ‘Close’:
What we need to do is get rid of the functionality that allows the dialog to be closed by a button. The easiest way to do this is to find the DestroyWindow call by looking in our intermodular calls again:
Notice that right before the DestroyWindow call, there is a JNZ instruction that allows the program to skip this call.
If a button is pressed that sends a quit message, this call will not jump and DestroyWindow will be called. So what we want to do is make it ALWAYS jump so that DestroyWindow is never called:
Here, I just hit the space bar on the line and changed the JNZ to a JMP. Now, any button on the dialog that tries to close the dialog window through a button will fail, as it will always jump over the call to DestroyWindow. Go ahead and try it and you will notice that the close button does nothing and the ‘X’ in the title bar is greyed out
A Standard Dialog Box
A standard dialog box is usually called from another window (think of the “Are you sure” dialogs with the OK and CANCEL button). Though this is the norm, they do not always have to be called from another window. The “Helpful2.exe” binary simply opens a dialog with no parent, though the techniques on this dialog will work for dialogs called from another window as well. Go ahead and run the app:
You will notice that it looks almost the same as the last one, except this time there’s a menu added:
I wanted to add this to show you how to defeat menu items as well. Loading the app in Olly is where you’ll notice the difference though:
There is very little code. Notice that a window is not created like it was in the last two examples. There is no WNDCLASS and no call to RegisterClass. This looks more like the code you would see in a bigger app when the app decides to open a dialog box. Because there is a parent window already created, you do no have to go through the process of creating a whole new one from scratch.
If you do a search for intemodular calls you will notice that there is no RegisterClass, so changing the WNDCLASS structure to add a NOCLOSE attribute is out of the question:
Fortunately, there is a very simple way to stop not only the ‘X’ in the title bar, but also any child that tries to close the window, including buttons and menu items. Even though this binary does not have a RegisterClass, it does have an EndDialog. EndDialog is called whenever the program wants to close a standard dialog window. All we have to do is make sure this method is never called.
Looking at intermodular calls window, double click on EndDialog:
Just like in the last example, there is a JNZ right before the call to EndDialog that, if equal, will allow falling through to the EndDialog call. What we want o do is simply change this JNZ to a JMP like we did in the last example:
Go ahead and run the app and you will notice the dialog cannot be closed.
-Now go out and do some good.
R4ndom
July 11th, 2012 on 1:51 pm
Hey R4ndom, good stuff with everything you posted!
Justt two things. I saw this typo: “..The element of he WNDCLASSEX..”
Also a more technical Question: can you explain why you chose to OR 0×03 and 0×200? I see where the hex numbers come from, i am asking more of why OR and not ADD or AND..
thanks
July 11th, 2012 on 3:47 pm
Per the Windows API for WndClassEX:
“Specifies the class style(s). Styles can be combined by using the bitwise OR (|) operator.”
So I guess it;s just the way Microsoft wanted it, and so it shall be.
July 15th, 2012 on 7:48 am
What if i go to taskbar and rightclick => Close?
July 15th, 2012 on 4:39 pm
Good question.
June 27th, 2013 on 9:46 am
Appreciating the commitment you put into your blog and detailed information you provide.
It’s awesome to come across a blog every once in a while that isn’t the
same unwanted rehashed material. Fantastic read!
I’ve bookmarked your site and I’m adding your RSS feeds to my Google account.