Search This Blog

Showing posts with label windows internals. Show all posts
Showing posts with label windows internals. Show all posts

Wednesday, May 30, 2012

CreateRemoteThread. Bypass Windows 7 Session Separation

Internet is full of programmers' forums and those forums are full with questions about CreateRemoteThread Windows API function not working on Windows 7 (when trying to inject a DLL). Those posts made by lucky people, somehow, redirect you to the MSDN page dedicated to this API, which says: "Terminal Services isolates each terminal session by design. Therefore, CreateRemoteThread fails if the target process is in a different session than the calling process." and, basically, means - start the process from your injector as suspended, inject your DLL and then resume the process' main thread. This works... Most of the time... But sometimes you really need to inject your code into a running process. Isn't there a way to do that? Well, there is. As a matter of fact, it is so easy, that I decided not to attach my source code to this article (mainly, because I am too lazy to make it look readable :) ). It appears to be that I am not the only one lazy here :), so I have uploaded the source code.

Let me start as usual, with a note for nerds in order to avoid meaningless comments and stupid discussions. 
The code provided within the article is for example purposes only. Error checks have been omitted on purpose. Yes, there may be another, probably even better, way of doing this. No, manual DLL mapping is not better unless you have plenty of time and nothing to do with it.

All others, let's get to business :)


Opening the Victim Process

This is the easiest part. At this stage you will see whether you are able to inject your code or not (in case of a system process, for example). Nothing unusual here - you simply invoke the good old OpenProcess API

HANDLE WINAPI OpenProcess(
       DWORD dwDesiredAccess, /* in our case PROCESS_ALL_ACCESS */
       BOOL  bInheritHandle, /* no need, so FALSE */
       DWORD dwProcessId /* self explanatory enough */
);

which opens the process specified by dwProcessId and returns a handle to that process, unless, you have no sufficient rights to access that process.


Reading the Shellcode

What you usually see in the examples of shellcode over the internet, is an unsigned char array of hexadecimal values somewhere in the C code. Helps to keep the amount of files smaller, but is not really comfortable to deal with. I decided to store the shellcode in a separate binary file, produced with FASM (Flat Assembler):

use32
   ; offset of the LoadLibraryA address within the shellcode
   dd    func
   ; save all registers
   push  eax ebx ecx edx ebp edi esi
   ; get your EIP
   call  next
next:
   pop   eax
   mov   ebx, eax
   ; get the address of the DLL name
   mov   eax, string - next
   ; do this to avoid possible negative values (due to sign extend)
   movzx eax, al
   add   eax, ebx
   ; pass it to the LoadLibraryA API
   push  eax
   ; get the address of the LoadLibraryA function
   mov   eax, func - next
   movzx eax, al
   add   eax, ebx
   mov   eax, [eax]
   ; call LoadLibraryA
   call  eax
   ; restore registers
   pop   esi edi ebp edx ecx ebx eax
   ; return
   ret
func     dd 0x12345678 ; placeholder for the address
string:

Compiling this code with FASM.EXE will produce a raw binary file, where all offsets are 0 - based. There are some parts in the code above, that may require some additional explanation (for example, why does it not end with ExitThread()). I am aware of this and I will provide you with the explanation a little bit later.

For now, allocate an unsigned char buffer for your shellcode. Make this buffer large enough to contain the shellcode and the name of the DLL (my assumption is, that you passed that name as a command line parameter to your injector). with it's terminating zero.

Once you have read the shellcode into that buffer - append the name of the DLL (which may be a full path to the DLL) to the end of the shellcode with, for example, memcpy() function. Half done with it. Now we still have to "tell" the shellcode where the LoadLibraryA API function is located in memory. Fortunately, the load address randomization in Windows is far from being perfect (addresses  of loaded modules may vary between subsequent reboots, but are the same for all processes). This means that, just as in usual DLL injection, we obtain the address of this API in our process by calling good old GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA") and save it to the "func" variable of the shellcode. Due to the fact that our shellcode may vary in size from time to time (that depends on the needs), we saved the offset to that variable in the first four bytes of the shellcode, which eliminates the need to hardcode the offset. Simply do the following:

*(unsigned int*)(shellcode_ptr + *(int*)(shellcode_ptr)) = (unsigned int)LoadLibraryA_address;

Our shellcode is ready now.


"Create remote thread" without CreateRemoteThread()

As the title of this paragraph suggests - we are not going to use the CreateRemoteThread(). In fact, we are not going to create any thread in the victim process (well, the injected DLL may, but the shellcode won't).


Code Injection

Surely, we need to move our shellcode into the victim process' address space in order to load or library. We are doing it in the same manner, as we would copy the name of the DLL in regular DLL injection procedure:
  1. Allocate memory in the remote process with
    LPVOID WINAPI VirtualAllocEx(
       HANDLE hProcess, /* the handle we obtained with OpenProcess */
       LPVOID lpAddress, /* preferred address; may be NULL */
       SIZE_T dwSize, /* size of the allocation in bytes */
       DWORD  flAllocationType, /* MEM_COMMIT */
       DWORD  flProtect /* PAGE_EXECUTE_READWRITE */
    );
    This function returns the address of the allocation in the address space of the victim process or NULL if it fails.
  2. Copy the shellcode into the buffer we've just allocated in the address space of the victim process:
    BOOL WINAPI WriteProcessMemory(
       HANDLE   hProcess, /* same handle as above */
       LPVOID   lpBaseAddress, /* address of the allocation */
       LPCVOID  lpBuffer, /* address of the local buffer with the shellcode */
       SIZE_T   nSize, /* size of the shellcode together with the appended                                 NULL-terminated string */
  3.    SIZE_T   *lpNumberOfBytesWritten /* if this is zero - check your code */
    );
    If the return value of this function is non zero - we have successfully copied our shellcode into the victim process' address space. It may also be a good idea to check the value returned in the lpNumberOfBytesWritten.

Make It Run
So, we have copied our shell code. The only thing left, is to make it run, but we cannot use the CreateRemoteThread() API... Solution is a bit more complicated.

First of all, we have to suspend all threads of the victim process. In general, suspending only one thread is enough, but, as we cannot know for sure what is going on there, we should suspend them all. There is no specific API that would provide us with the list of threads for a specified process, instead, we have to create a snapshot with CreateToolhelp32Snapshot, which provides us with the list of all currently running threads of all processes running in the system:

HANDLE WINAPI CreateToolhelp32Snapshot(
   DWORD dwFlags, /* TH32CS_SNAPTHREAD = 0x00000004 */
   DWORD th32ProcessID /* in this case may be 0 */
);

This function returns the handle to the snapshot, which contains information on all present threads. Once we have this, we "iterate through the list" with Thread32First and Thread32Next API functions:

BOOL WINAPI Thread32First(
   HANDLE hSnapshot, /* the handle to the snapshot */
   LPTHREADENTRY32 lpte /* pointer to the THREADENTRY32 structure */
);

The Thread32Next has the same prototype as Thread32First.

typedef struct tagTHREADENTRY32{
   DWORD dwSize; /* size of this struct; you have to initialize this field before use */
   DWORD cntUsage; 
   DWORD th32ThreadID; /* use this value to open thread for suspension */
   DWORD th32OwnerProcessID; /* compare this value against the PID of the victim 
                              to filter out threads of other processes */
   LONG  tpBasePri;
   LONG  tpDeltaPri;
   DWORD dwFlags;
} THREADENTRY32, *PTHREADENTRY32;

For each THREADENTRY32 with matching th32OwnerProcessID, open it with OpenThread() and suspend with SuspendThread:

HANDLE WINAPI OpenThread(
   DWORD dwDesiredAccess, /* THREAD_ALL_ACCESS */
   BOOL  bInheritHandle, /* FALSE */
   DWORD dwThreadId /* th32ThreadID field of THREADENTRY32 structure */
);

and

DWORD WINAPI SuspendThread(
   HANDLE hThread, /* Obtained by OpenThread() */
);

Don't forget to CloseHandle(openedThread) :)

Take the first thread, once it is opened (actually, you can do that with any thread that belongs to the victim process) and suspended, and get its CONTEXT (see "Community Additions" here) using the GetThreadContext API:

BOOL WINAPI GetThreadContext(
   HANDLE    hThread, /* handle to the thread */
   LPCONTEXT lpContext /* pointer to the CONTEXT structure */
);

Now, when all the threads of the victim process are suspended, we are may do our job. The idea is to redirect the execution flow of this thread to our shellcode, but make it in such a way, that the shellcode would return to where the suspended thread currently is. This is not a problem at all, as we have the CONTEXT of the thread. The following code does that just fine:

/* "push" current EIP of the thread onto its stack, so that the ret instruction in the shellcode returns the execution flow to this address (which is somewhere in WaitForSingleObject for suspended threads) */
ctx.Esp -= sizeof(unsigned int);
WriteProcessMemory(victimProcessHandle, 
                   (LPVOID)ctx.Esp, 
                   (LPCVOID)&ctx.Eip,
                   sizeof(unsigned int),
                   &bytesWritten);
/* Set the EIP to our injected shellcode; do not forget to skip the first four bytes */
ctx.Eip = remoteAddress + sizeof(unsigned int);

Almost there. All we have to do now, is resume the previously suspended threads in the same manner (iterating with Thread32First and Thread32Next with the same snapshot handle).

Don't forget to close the victim process' handle with CloseHandle() ;)


Shellcode

After all this, the execution flow in the selected thread of the victim process reaches our shellcode, which source code should be pretty clear now. It simply calls the LoadLibraryA() API function with the name/path of the DLL we want to inject.

One important note - it is a bad practice to do anything "serious" inside the DllMain() function. My suggestion is - create a new thread in DllMain() and do all the job there, so that it may return safely.

Hope this article was helpful.

Have fun injecting and see you at the next.




Tuesday, March 6, 2012

Faking KERNEL32.DLL - an Amateur Sandbox

As a part of my work (read "fun") of maintaining this blog, I am constantly checking the statistic information on traffic sources and keywords (it's nice to know that people are getting here via Google) in order to see whether my readers are getting what they are looking for (personally, I see no reason in simply "streaming my consciousness to the masses" as this is not the point of this blog). Sometimes, it gives an idea of what is missing but still related to system and low level programming.

A couple of days ago, I saw that someone was looking for a way to load and use fake KERNEL32.dll and I realized that this information has not yet been covered here. There is no source code for this article as I am a bit short on time to write it, but I will do my best to provide as much information as possible so, those who would want to try it would have no problem doing that.


KERNEL32.DLL
First notable thing about KERNEL32.dll is that it is always loaded, regardless of whether a running executable imports anything from it (this is briefly covered here). Same as NTDLL.dll (well, KERNEL32.dll imports from it). This library provides interfaces for interaction with deeper levels of "user land" part of the operating system for the running executable and some of other dynamic link libraries loaded into process' memory. 

Knowing all that, the first thought may be: "how are we going to fake it if all the rest depends on it?". The solution is easier than one could think at first. However, we should keep in mind, that some programs may import from NTDLL.dll directly, bypassing the KERNEL32.dll (which used to happen quite often in the world of malware), meaning that once you faked KERNEL32.dll, you may have to fake NTDLL,as well.


Preparations
We should start with writing a good old simple DLL/code injector. It is easier to dissect the victim process from inside. This is the simplest part and it is covered in this and this posts of this blog. Roughly saying, the injector should be able to create a victim process in suspended state by passing the CREATE_SUSPENDED process creation flag to CreateProcess API.

Writing the code or the DLL we are going to inject is a harder task as this code is intended to perform the tasks described below in order of execution.

Load Fake KERNEL32.dll
Let's assume, that we already have a ready to use fake KERNEL32.dll (we'll get back to creation of fake dll a bit later). This is quite simple - call LoadLibrary function from your code. One thing worth mentioning is that MSDN is not suggesting to use LoadLibrary in your DllMain function. Therefore, if you decide to use DLL Injection instead of code injection, then better use the approach described in "Advanced DLL Injection" article. 

Fake KERNEL32.dll should simply import all API's from the original one. Don't be mistaken - import, not forward it's exports at least as long as we are talking about API functions, but you may safely forward exported objects and variables to the original one.

Resolve Victim's Imports
By the time we get our code/DLL running inside the suspended victim process, all of it's imports should already have been resolved. What we still have to do, is to replace all API addresses exported from the original KERNEL32.dll with corresponding addresses in our fake one.

Here is a link to Microsoft's specifications of MS PE and MS COFF file formats - would be useful digging through imports and export.

Hide the Original KERNEL32.dll
While performing the aforementioned actions may be enough in case of a regular application, we should take some precautions in case of malicious code. My suggestion is to hide the original KERNEL32.dll by replacing its entry in the list of LDR_MODULE structures in PEB with the one describing our fake KERNEL32.dll, just like we would hide an injected DLL in the "Hiding Injected DLL in Windows" article.


Creation of Fake KERNEL32.dll
This may sound scary, but there is no need to worry (at least not too much). All that we need in order to create one, is a C compiler (or whatever high level language you prefer) and any assembler (I use FASM as usual).

Dump KERNEL32.dll to ASM Source
No, of course we do not have to disassemble the whole DLL and dump it to a corresponding Assembly source. Instead, what we have to do, is write a small application in high level language (you may try to do it in Assembly if you want) that would parse the export table of the original KERNEL32.dll and create a set of Assembly source files: one for code, one for data (if needed), one for import and one for export sections.

Want it or not, but the application has to generate a bit of Assembly code for at least transferring the execution flow to an API function in the original KERNEL32.dll. For example, if we have no interest in, let's say, ExitProcess, then our fake ExitProcess should look similar to this:

fake_ExitProcess:
   ; As we are not tracing/logging this function, we simply let the
   ; original ExitProcess shoot
   jmp dword [real_ExitProcess]

However, the code would be different for APIs of interest. For example, the CreateFileA API would be implemented like this:

fake_CreateFileA:
   ; We pass control to a fake CreateFileA, which is implemented in
   ; a separate DLL imported by our fake KERNEL32.dll
   ; Parameters are already on the stack, so we simply jump.
   ; Don't forget to declare the fake function as STDCALL 
   ; (remember #define WINAPI __declspec(stdcall) ? )
   jmp dword [our_CreateFileA]

The Assembly source file containing code for the import section would then contain the following:

section '.idata' import data readable writable
   library original, 'kernel32.dll',\            ;Import original KERNEL32.dll
           fake,     'our_dll_with_fake_api.dll' ;Import a DLL with fake APIs

   import original,\
      real_ExitProcess, 'ExitProcess'

   import fake,\
      our_CreateFileA, 'whatever you call it here'


Now, finally, we get to the export section's code:

section '.edata' export data readable
   export 'KERNEL32.dll',\              ;FASM does not care about what you type here, 
                                        ;so let's be fake to the end and pretend 
                                        ;to be KERNEL32.dll
      fake_ExitProcess, 'ExitProcess',\
      fake_CreateFileA, 'CreateFileA'


Finally the main source file, the one that would assemble all the rest together:

format PE DLL at 0x10000000

include 'code.asm'
include 'import.asm'
include 'export.asm'

section '.reloc' fixups data discardable

compile it with FASM and you have your fake KERNEL32.dll.


Implementation of Fake API
As it has been mentioned above, there are some functions we would want to trace. Those should have some custom implementation, preferably in a separate DLL (which would be loaded by Windows loader at the time it resolves our fake KERNEL32.dll's dependencies). Below is a diagram of the interactions between all the modules:
Interactions between modules involved in faking.


And here is an example of such fake API:

HANDLE WINAPI fake_CreateFileA(
                               LPCSTR lpFileName,
                               DWORD dwDesiredAccess,
                               DWORD dwShareMode,
                               LPSECURITY_ATTRIBUTES lpSA,
                               DWORD dwCreationDisposition,
                               DWORD dwFlagsAndAttributes,
                               HANDLE hTemplateFile)
{
   fprintf(log_file, "CreateFileA(list params here)\n", params);
   return CreateFileA(lpFileName, 
                      dwDesiredAccess, 
                      dwShareMode, 
                      lpSA, 
                      dwCreationDisposition,
                      dwFlagsAndAttributes,
                      hTemplateFile);
}

Of course, you may implement addition mechanisms within this DLL, e.g. let it communicate with another application via sockets or pipes, but this is deserves a separate article.


P.S. 
My personal suggestion is to insert more code into each function inside the fake KERNEL32.dll so that it would look more realistic to the victim process (should it try to do anything with it).



Hope this article was useful. 

See you at the next.






Friday, March 2, 2012

Defeating Packers for Static Analysis of Malicious Code

I doubt whether there is anybody in either AV industry or among reverse engineers who does not know what a software packer is (for those who don't - this article may help). Malware research and reverse engineering forums are full of packers' related questions, descriptions thereof, unpacking suggestions and links to both packers and unpackers. In short - people have been doing a lot of precious work on defeating packers and protectors.

However, for those of us who are not afraid of static analysis, there is an easier way (I'd dare to say "generic") to handle packers and protectors and retrieve the unpacked form of the executable (cannot hold my self from adding a note for nerds: no, this does not include reversing virtual machines like Oreans' one. This is up to you). So, the main problem is obtaining the unpacked version of code as all the rest may be well handled from there. What we actually need is a dump of unpacked executable. There are lots of memory dumping programs, but some protectors "know" how to handle them, therefore, this article explains a simple and short way of obtaining such dump without teasing the implemented protections.

Knock Knock
First of all, we need to, let's say, get into the process. There are at least two ways to do that:

  • Use the OpenProcess Windows API with, preferably, PROCESS_ALL_ACCESS and read/write from/to process' memory.
  • Inject our code into the process' memory space (simply a code injection or a DLL injection).
My preference is the second one as you mostly have more power operating from inside.

There are several ways to inject a DLL into another process, e.g. calling LoadLibraryA as a remote thread in the victim process or even this one (my preference is the second one again). This is in deed the easiest part. My personal suggestion would be to create a suspended process, inject your DLL and then resume the main thread of the created process as this provides you with greater flexibility.

Set the Trap
No, I am not referring to 0xCC (trap to debugger). Trap, in this case, means something that would trigger the dumper embedded into the injected DLL and cause it to dump the unpacked image, for example, patch one of the API functions with a jmp instruction, which would redirect the execution flow to where we want. Be careful with this approach, as your patch may be well "overpatched" by the protection mechanism of the target executable. Let me give you a couple of suggestions: never patch the first bytes of the API (I assume this code is not a production code, so you may let it be bound to your version of Windows); patch as deep as possible - meaning leave the kernel32.dll alone and go further to ntdll.dll where possible. 

For example, if your target executable outputs a string to a console, that may be a good idea to patch either WriteConsoleA or WriteConsoleW API  function. However, it may be an even better idea to go deeper and patch WriteConsoleInternal (Win7) and install your notification jump there. Once that API is called - chances are that the executable has been fully unpacked. As an alternative, you may simply create a new thread in your DLL and Sleep it for several milliseconds (or even seconds) and then dump the memory.

You may perform these actions in the DllMain of your injected DLL, on the other hand, you may create a separate procedure for this, but then you'd have to use this approach or something similar.

Dumper Triggered
No matter how (either by the API patch or our thread) the dumper is triggered. Sure thing - we are not going to dump the whole memory allocated by the process. We just need the image. The easiest way of getting the information on ImageBase and SizeOfImage of the target module (usually the main module of the process) is to find the corresponding entry in PEB (you may want to check the "Hiding Injected DLL in Windows" post to get more information on PEB and related structures). However, it is important to mention that you HAVE to be careful with that, as the information in PEB may be altered by the protection scheme of the victim executable. Having found the base address and the size of the image, just write the content of that memory region to a file (make sure to take note of image's base address if you are dumping DLL). Quite simple, isn't it? Well, not really. You have to check for memory protection of every region you are currently going to dump as it may have either PAGE_WRITE or PAGE_EXECUTE access rights only, meaning that you cannot access it for reading. Once done with this, you may either let the program execution to continue or terminate the process.

In addition, it is strongly recommended to suspend all the threads of the process, except the thread our code is running in.

Using Dump
Nothing's easier - load the dump into IDA Pro and see how good it handles it.

P.S. Suspending/Resuming Threads
Suspending threads is a bit annoying as you have to get the IDs of all the threads currently running in the system, then select those with process ID of your process and suspend then. The same procedure is applicable for resuming suspended threads.

First of all CreateToolhelp32Snapshot (MSDN):

HANDLE WINAPI CreateToolhelp32Snapshot(
              DWORD wdFlags,
              DWORD th32ProcessID
       );

You have to specify TH32_SNAPTHREAD as flags in order to get threads information. If the return value is not NULL, the you may proceed with Thread32First:

BOOL WINAPI Thread32First(
            HANDLE          hSnapshot,
            LPTHREADENTRY32 lpte
            );

followed by subsequent calls to Thread32Next (has the same arguments) until the return value is FALSE.

The functions Thread32First and Thread32Next fill the THREADENTRY32 structure which has the following format:

typedef struct tagTHREADENTRY32
{
   DWORD dwSize; /* Should be set to sizeof(THREADENTRY32) prior 
                    to calling Thread32First */
   DWORD cntUsage;
   DWORD th32ThreadID;
   DWORD th32OwnerProcessID;
   LONG  tpBasePri;
   LONG  tpDeltaPri;
   DWORD dwFlags;
} THREADENTRY32, *PTHREADENTRY32;

Fields of interest for you would be the th32OwnerProcessID and the th32ThreadID. Compare the th32OwnerProcessID with the ID of the process (previously obtained with GetCurrentProcessId()) your code is running in. If those values are equal, then you have to open the thread with:

HANDLE WINAPI OpenThread(
              DWORD dwDesiredAccess, /* Would be THREAD_ALL_ACCESS */
              BOOL  bInheritHandle, /* FALSE */
              DWORD dwThreadId      /* th32ThreadID */
              );

Then suspend the thread with:

DWORD WINAPI SuspendThread( HANDLE hThread );

while passing the handle obtained with OpenThread().
You have to resume threads once you have saved the dump by calling:

DWORD WINAPI ResumeThread( HANDLE hThread );

Don't forget to close each thread handle with CloseHandle.


That's it. Hope this post was helpful (at least I used this method a lot).
See you at the next.


Wednesday, February 29, 2012

Vectored Exception Handling for Linux

Source code for this article may be found here.


The title of this article may look weird. In deed, why would someone want to use Vectored Exception Handling in Linux, while this OS provides a perfectly working mechanism - signals? Well, there are several possible answers:

  • Many programmers, who started their career with Windows programming, are getting a bit frustrated when it comes to exception (signal) handling in Linux and keep asking about Linux analogs of Structured or Vectored Exception Handling.
  • It may be interesting to try to extend the existing model.
  • Boredom - as simple as that.
Single Handler vs Chained Handlers
It is a quite common assumption, that Linux signal handling model does not allow multiple handlers for the same signal. Another assumption is that in Linux, signal handlers are not provided with context information. These very assumptions are the main reason those switching from Windows development to Linux are looking for Windows-like solutions.

This assumption is obviously not true and is based on the fact that majority (still) of internet resources only refer to sighandler_t signal(int signum, sighandler_t handler) function. Despite the fact that this function's return value may be used for chaining signal handlers. Needless to mention that sigaction is still (although, this sounds weird) "gaining popularity".

The problem is, however, that implementation of such chaining mechanism must be done by a developer and is not provided by libc .

Winux (Windows to Linux) Method
Let me skip the description of Linux signal handling model as it is covered here (as well as on many online resources) and get straight to the customized implementation of the Vectored Exception handling mechanism.

Despite the fact, that VEH has been with us since Windows XP, it is still not known enough among developers (who tend to think that SEH is the only way), although, it provides more power (and leaves stack for better purposes). VectoredHandlers are "known" across all the threads running in the process and, therefore, saves us some time, as we do not need to register yet another handler when entering a function (however, both things are good in Windows).

The internal implementation of VEH is very simple. The OS maintains a linked list of handlers registered with AddVectoredExceptionHandler API function, which allows to add new handler to either the top of the list or it's tail and returns a handle to the handler. In order to remove certain VectoredHandler, RemoveVectoredExceptionHandler API function should be called.

This way, the intention is to implement these two functions for Linux targeted C code.

Basis - Definitions and Prototypes
Nothing we can do about it - we have to start with some definitions and prototypes:



EXCEPTION_CONTINUE_EXECUTION and EXCEPTION_CONTINUE_SEARCH are defined in Winbase.h and represent the two values that may be returned by VectoredHandler. They, actually, speak for themselves.

EXCEPTION_POINTERS is a structure used to pass pointers to siginfo_t and ucontext_t to the registered pseudo handlers, much like Windows passes  pointers to ExceptionRecord and ContextRecord.

vectored_handler_t - this type represents pointers to our pseudo handlers.

As we need some infrastructure to store information about the registered pseudo handlers, we define the VECTORED_HANDLER_ENTRY structure - a member of a linked list (vector) of VectoredHandlers.


This linked list is represented by head and tail pointers to VECTORED_HANDLER_ENTRY structures.

The AddVectoredExceptionHandler and RemoveVectoredExceptionHandler prototypes are almost identical to those of Windows with minor differences, the most important of which, is the int parameter in AddVectoredExceptionHandler. This parameter is the number of the signal, which the pseudo handler, specified by vectored_handler_t, is intended to handle.

WalkTheVector - this is the actual handler, which will be known to the system. When a new signal is being registered, this function is specified as its handler before a call to sigaction is executed.

SIGNAL_RECORD 
In order to make things simpler, we are not going to handle all possible signals by default, instead, when a new handler is being added to the list, for a signal which has no handler, SIGNAL_RECORD structure is created and added to the list of signal records. It's members contain all the information needed by our real handler - WalkTheVector. This is the way to register signals with the Linux VEH library. When the last handler for a given signal is being removed, the corresponding SIGNAL_RECORD structure is removed from the list of registered signals as well.

Members of the structure:
signum - number of corresponding signal.
old - this structure is only filled if the specified signal already had another (not related to our library) associated handler.
current - this structure, in turn, describes the new handler being installed.

As it has been mentioned above, this library installs the same handler for every signal being registered - WalkTheVector.

It has also been mentioned that registration/unregistration of signals is performed automatically by either AddVectoredExceptionHandler or RemoveVectoredExceptionHandler functions.

Usage
It is as simple to use this library, as it is to use those API functions in Windows (just don't forget to link to it ;-) ).

Here is the working example:


Note for nerds: yes, of course, you have to include <stdio.h> and "veh.h", and include <stdlib.h>, <signal.h>, <ucontext.h> and <sys/ucontext.h> in the "veh.h" and no, this code does not perform any checks, as it is not production code, but a presentation.

And the output of this example looks like this:



Exception Handling Implementation
While in normal situation, in Linux, you typically assign one handler to one signal, in this case, you assign the same handler to any signal that you want to handle:


Once a signal is received (given that it has been registered), it is passed to the WalkTheVector function, which, in turn, iterates through all the added VectoredHandlers until either reaching end of list or encountering a handler that returns EXCEPTION_CONTINUE_EXECUTION, in which case, WalkTheVector peacefully returns or prints an error message and kills the process if no relevant handler was found.

ExceptionRecord and ContextRecord Analogs
Each handler in the list receives this information in EXCEPTION_POINTERS structure, much like in Windows. However, if you are new to Linux, or have never dealt with signals, my suggestion is to take a look at the following two include files: bits/siginfo.h and bits/sigcontext.h (or read this post) as siginfo_t and ucontext_t structures have nothing to do woth EXCEPTION_RECORD and CNOTEXT_RECORD structures in Windows.

That's it for now. I hope this post was helpful or at least interesting.

See you at the next!