What to expect from KoroIRC 0.4

January 15th, 2009

Since I started this blog, which was kind of supposed to be the KoroIRC developer blog, I went on many ramblings about random stuff, but never actually took the time to talk about the main subject. This is what I do today.

Changes in this version

Here I will talk a little about what will change and what will not.

Modularity

In version 0.3, the source code of the main executable contained about three big categories of code:

  1. User interface code: This is the code that manages the windows, switchbar, pane, all the settings dialogs, etc. Everything you can see or interact with is here.
  2. IRC code: This is what manages the actual connections, parses the protocol and notifies the user interface. Also, all CTCP, DCC and Identity management is here.
  3. Helper and “glue” code:This is all the code that does common tasks. Initialization, custom memory management, string parsing, threads, etc. This part was very big.

Of course, all of it was compiled into a giant monolithic executable that has everything embedded in it. Therefore, the goal for this version is to try and make KoroIRC 0.4 more modular.

In order to achieve this goal, the main executable code has been split into many parts. First, all the common code has been made into a new library, kirccore.dll. This also allows the other executables and DLLs to reuse that code too, reducing them in code size. Most of the extraneous functions of KoroIRC are in the process of being moved to plugins (.kpl files), with kircapi.dll as their “call gate” into the main executable code. As such, it is possible to have a super minimalist, no-frills KoroIRC installation in only three files:

I shall also take the occasion to mention that KoroIRC can be used as a portable application since its very birth. The installer is provided merely as a convenience. If KoroIRC finds an INI file in the same folder as itself, it will use it for loading/saving settings.

Operating system requirements

In version 0.3, I had three separate builds to maintain: an Unicode build, an ANSI build and an x64 build. This was all magically hidden to the user by the installer, which automatically installed the right one.

Back in 2005, when I started version 0.3, I still knew a bunch of people stuck with old computers, still on Windows 98. So it was only natural to support these old operating systems, since they were still used. However, having to support them often meant a lot of glue code, such as loading stuff with LoadLibrary / GetProcAddress and having an “alternate code path” if the functionality was not present. This increased code size and complexity a lot, and limited my choice of APIs to use.

Thankfully, these days everybody uses Windows XP or Windows Vista now, so I think it is safe to remove support for the old operating systems. So version 0.4 will only support Windows 2000 and higher, and the code is being cleaned of old code paths. A good example of this is in the updater code, where I could just stick a call to CheckTokenMembership — which is only available starting with Windows 2000 — instead of having to manually loop through the groups in the token.

User interface changes

There won’t be much major user interface changes for this version. But there is one thing worthy of noting. I’m currently in the process of replacing all message boxes with much more user-friendlier task dialogs instead. The very cool thing is that it works in Windows 2000 and Windows XP too! And, since I’m doing that, I’ve also started using string table resources.

Also, I’m working hard in order to have High-DPI support. KoroIRC 0.3 only had that partially, which is why the executable wasn’t marked as “DPI-aware” under Windows Vista. I’m working hard to remove all remaining hardcoded sizes (which are often for bitmaps or icons) and making sure everything scales well no matter the size. Also, this is an area I’m dogfooding much, as I myself run at 120DPI on my new LCD monitor.

Also, for all those who complained that it was imposible to hide the lower pane, this version won’t have the possibility to hide it either, sorry. However, know that I heard you and that it is definitely planned for the following version, along with a slew of other user interface changes.

Tools

I have also added my own crash reporter. Yeah, I know this reeks of NIH, especially when Microsoft has Windows Error Reporting, but there are hard entry conditions on WER, and also my own crash reporting tool allows to collect additional information from the user before sending the dump file.

I have also added a “Files” pane as an optional plugin, which is merely an embedding of a shell folder right into the lower pane. It is very useful to be able to drag and drop files to send them to somebody real fast, without having to switch windows.

I plan to redo the user interface of the DCC Information Tool. For those who didn’t know, every time you receive a file by DCC, KoroIRC stores additional information from the DCC into an alternate data stream of the file. This tool allows you to see that stored information.

Status

I have much done, enough to say that KoroIRC 0.4 is already significantly different from version 0.3. However, there is still much work to be done in all areas, so I’d say it’s at about 50% done.

Why is development so slow?

The short answer is: because I’m not paid to do it. The long answer is that coding is an activity best done at night, and also needs long times of having nothing to do in order to be properly set in motion.

Thing is, with school and work being much more demanding than before, I simply do not have as much free time as I’d like to, and when I get some, I don’t necessarily feel like coding much. Back in 2004, I had whole months free, with nothing better to do than sleeping in the day and coding in the night, and thus KoroIRC 0.2 was born in about four months of concentrated efforts.

Sadly, this is not the case anymore, and sometimes months can pass without me writing a single line of code on KoroIRC. This is why it takes so much time to release new versions now.

How to bring back regular window captions in Windows Live Messenger 9

January 14th, 2009

I hate skinned applications. Hate them, with a burning passion. The only thing I hate more are skinned applications that “try” to look native but spectacularly fail on anything else but the default theme.

Now, it ain’t so bad when applications restrict that to their client area. It is still useless and disrespectful of my settings, but at least it’s contained. But more and more apps take bolder steps at spitting in the face of my settings — hint: I set them that way for a reason, because I like it that way — and, sadly, Microsoft is no exception to this.

Windows Live Messenger is a big culprit in this case. Up until Wave 3, even though it defaulted to using custom window captions, a simple “Show the menu bar” would bring the regular ones back. But, as it seems to be the fashion these days, that possibility was removed. That, and they also now impose ClearType usage, even if you explicitly disabled it. Not that important now, since LCD screens are everywhere, but my old CRT monitor only broke 6 months ago.

But if you played a little with WLM9, you notice it reverts to regular window captions in certain cases, like if you maximize a window. A little poking around in WinDbg quickly shows that it’s just using window regions to do its bidding. That, along with a friend that showed me that under Aero Glass, it actually just lets the window manager do its job and uses regular captions, was more than enough to tip me off that something could be done very easily about this problem.

My first try was to try and block the SetWindowRgn call outright. I basically overwrite the code for that function in the process’ memory with the assembly equivalent of this:

int HookSetWindowRgn(HWND hWnd, HRGN hRgn, BOOL bRedraw)
{
    if (hRgn)
        DeleteObject(hRgn);
    return 1;
}

There are multiple problems with this approach. First, since WLM hides the whole caption and window borders, it has to handle WM_NCHITTEST in order to allow window resizing from within its client area. Since it also still thinks the caption and borders are hidden, it does not handle these cases, and as such, returns HTBOTTOM when the cursor is on the window caption. Also, the theming system in UxTheme.dll also calls this function — why it does not call NtUserSetWindowRgn directly is beyond me — in order to have those round window corners, and this “fix” disables that too.

My second and final solution came upon noticing that when WLM itself decides to show these captions, they work properly, and also the pseudo-caption inside the client area disapprears, too. If there was a way to trick WLM into thinking one of the “show the caption” conditions is met, it would by itself comply and show it without additional work. I first tried to hook the IsZoomed function directly to make it always return TRUE, but again it caused problems with UxTheme.dll.

I started by looking for calls to SetWindowRgn in all of WLM’s binaries. One of these files is UxCore.dll. Now, the fun part with exporting C++ classes or functions directly with __declspec(dllexport) is that all the decorated names are kept intact, which is very handy for reverse engineering like this since they contain full parameters and return type information. It did not take much time to find the UXFramelessManager class, which is responsible for hiding or showing the window caption, and handling everything that is associated with it. That class has a method called UpdateFrame, which does the work of determining if a window region needs to be set, and setting or clearing it as needed.

The UpdateFrame method checks that at least one of these three conditions is met:

  • The window is maximized
  • Aero Glass is enabled
  • High Contrast Mode is enabled

If that is the case, it will set a NULL region for the window and not do any custom handling of the WM_NCHITTEST message. So, I figured, let’s make it think the window is always maximized! The code that does this check is:

7033e028  push  dword ptr [esi+8]
7033e02b  shr   eax,13h
7033e02e  and   al,1
7033e030  mov   byte ptr [ebp-1],al
7033e033  call  dword ptr [__imp__IsZoomed@4]

The instruction at 7033e028 pushes the HWND of the window on the stack. The next three instructions are interleaved code that does something else, probably due to agressive compiler optimization settings, then the call is done at 7033e033. So all we need to do is to change the code to just always assume IsZoomed returned TRUE, padding as appropriate with NOPs:

7033e028  nop
7033e029  nop
7033e02a  nop
7033e02b  shr   eax,13h
7033e02e  and   al,1
7033e030  mov   byte ptr [ebp-1],al
7033e033  mov   eax,1
7033e038  nop

All that was needed was to patch that new stream of instructions at the right file offset in UxCore.dll:

0003D428 -> 90 90 90 C1 E8 13 24 01 88 45 FF B8 01 00 00 00 90

Upon starting WLM, I had my window captions indeed:

WLM9 conversation window with regular window caption

(Yes, I went back to Windows Classic, despite my claims to the contrary.)

There is still a bug with this though. It it not apparent under Windows Classic, but UxTheme.dll causes problems again, albeit a minor one this time. Basically, UpdateFrame will still call SetWindowRgn on window creation with a NULL region, clearing the one set by UxTheme.dll. This is the code that does it:

7033e141  push   1
7033e143  push   ebx
7033e144  push   dword ptr [esi+8]
7033e147  call   dword ptr [__imp__SetWindowRgn@12]

Note that EBX is zeroed out at the beginning of the function, so this code is the equivalent of:

SetWindowRgn(m_hWnd,NULL,TRUE);

All we have to do is to replace that whole code sequence with NOPs again. I won’t present the code here, but directly the bytes to patch in the file:

0003D541 -> 90 90 90 90 90 90 90 90 90 90 90 90

Once this is patched, WLM will have regular window captions, with no glitch (that I found yet). It is sad though, that I had to resort to patching code for such a trivial matter, especially that older versions of WLM allowed this, so they actually had to remove code to make it not-work…

All code addresses and listings comes from UxCore.dll version 14.0.8050.1202 in the WLM installation directory. Make sure you have that exact same version before patching the file, of course.

Update: This also works with UxCore.dll version 14.0.8064.206, as none of the offsets have changed.

Update #2: As of version 14.0.8117.0416, the offsets and surrounding code have changed. Here are the updated patch instructions:

0003D195 -> 90 90 90 C1 E8 13 24 01 88 45 FF EB 04 90 90 90 90 31 C0 EB 16
0003D2AE -> 90 90 90 90 90 90 EB 04 90 90 90 90

I have also fixed it to not crash under ASLR anymore.

Getting around the manifest check in the C Runtime DLL

September 23rd, 2008

Today’s article is again about my “archnemesis”, the Visual Studio 2005/2008 CRT. As I mentioned in a previous article, this CRT will refuse to load if it’s not loaded with a manifest, and today I document how it checks that, and then, how to bypass it. This can be very useful, for example, to get MSVCR80.DLL to load under WINE.

The core of the manifest checking is in the _check_manifest function, which is located in crtlib.c in the CRT source. As the name suggests, this code is only linked in when compiling a DLL version of the CRT.

Here is what the code does:

  1. First, it checks for the presence of the FindActCtxSectionStringW function in KERNEL32.DLL. If this step fails (i.e. GetProcAddress returns NULL), then it assumes that the OS it’s running on does not support Fusion, and returns with success.
  2. Then, it checks if both of MSCOREE.DLL and PGORT90.DLL are loaded in the process’ address space, and if yes, assumes it was loaded for instrumentation and returns success.
  3. It then retrieves the path of where it was loaded and of the system32 directory.
  4. When the paths are retrieved, it checks explicitly that it wasn’t loaded from system32. If it was loaded from there, it immediately returns a failure.
  5. Then, it checks the current activation context with FindActCtxSectionString to check if it was referenced in the manifest. If that isn’t the case, it returns a failure.
  6. It then makes sure it was loaded from under the WinSxS folder in the Windows directory by doing a string compare of that path and its own path. If that is the case, it returns with success.
  7. This last check happens only if the previous check failed. It will try to find a file called Microsoft.VC80.CRT.manifest (or Microsoft.VC80.DebugCRT.manifest if it’s the debug version) in the same folder from which it was loaded, and if found, will return success.
  8. If it comes here, it assumes that it was wrongfully loaded and returns a failure.

Note that over the course of these checks, it uses multiple fixed-size string buffers. The one that is used to retrive the path of the Windows and the system32 directories is MAX_PATH in size, whereas the others are 8000 characters in size. If any of these buffers overflow at any time, it will just bail out of the checks and return success.

Also, WINE does have an implementation of activation contexts, found here (KERNEL32 wrappers) and here (actual implementation in NTDLL). Except for some reason, it fails to go grab MSVCR80.DLL from the WinSxS directory, instead returning with status 0xc0000135. It’s not that the functionality is not there however, as a quick look into WINE’s source (in loader.c to be exact) shows a neat little function called find_actctx_dll that gets called from find_dll_file.

So, now that you understand how it works, the solution to bypass it becomes very simple.

You can take the long route and recompile your own version of the CRT with the _check_manifest function dummyfied. A quick look at some installed apps on my computer shows that a few apps do it. Firefox has its MOZCRT19.DLL and Winamp has NSCRT.DLL, although the latter is an older version of the CRT.

The previous solution is quite complicated for such a simple detail. Also, if you wish to redistribute the DLL with your application, you have to name it something else than MSVCR80.DLL. So you still have to redistribute it even if you got rid of the manifest check.

Follow me here for a much quickier-and-dirtier hack. Basically, you just have to patch 5 bytes in the DLL file to disable the manifest checking. Disclaimer: I don’t think the EULA allows you to do that, and it would not be a good idea to redistribute those patched DLLs. Do it at your own risk.

I have tested with versions 8.0.50727.1433 and 8.0.50727.3053 of MSVCR80.DLL and it worked well. After that, I was able to drop them into my system32 directory in a WINE install and they would work flawlessly. So, you need to patch the following bytes at the following file offset:

00001D76 -> B8 01 00 00 00 C3

This effectively turns the content of the _check_manifest function into nothing more than a return TRUE.

I hope that this goes to show again that using manifests for the CRT was a really bad idea. It just pushes more people to either statically link to it, compile their own or try to find another way to get over that restriction, all of which are not really beneficial in the long term. It defeats the purpose of DLLs, which was to share code between processes.