-----------------------
  getting the kernel32 image base in C++ - written by malfunction
  -----------------------

This article is about getting the kernel32 image base in C++ without
using any API or inline asm. My code is more or less just a proof of concept,
only useful for those weirdos who want to code a real virus in 100% C++.

The method used here is the very well known attempt to get the return address
of CreateProcess from the stack. Of course, there are many other values
on the stack when my function is called. Thus, I trace back through the whole
stack. Everything must be SEH guarded, of course. To be sure to have the right
image base I compare the name of the export table. I do that for both upper
and lower case because I'm unsure if there might be differences between
some Windows versions.

I tested it successfully on WinXP SP2. I don't if __try / __except make the
code VC++ specific, but I don't care anyway. The code is rather self-explanatory
if you know some C/C++. Have fun.

-------------------------------------------------------


#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <winnt.h>

PIMAGE_DOS_HEADER getKernel32ImageBase(int dummy)
{
   DWORD **stackAddress = (DWORD **)(&dummy - 2);
   DWORD *address;

   while(true)
   {
      address = (DWORD *)((DWORD)*stackAddress & 0xFFFF0000);
      bool found = false;

      while(true)
      {
         __try
         {
            PIMAGE_DOS_HEADER image=(PIMAGE_DOS_HEADER)address;

            if(image->e_magic == IMAGE_DOS_SIGNATURE)
            {
               DWORD *magic=(DWORD *)((BYTE *)image + image->e_lfanew);

               if(*magic == IMAGE_NT_SIGNATURE)
               {
                  PIMAGE_OPTIONAL_HEADER32 optHeader=(PIMAGE_OPTIONAL_HEADER32)
                        ((BYTE *)magic + IMAGE_SIZEOF_FILE_HEADER + 4);

                  DWORD expRVA=optHeader->DataDirectory[0].VirtualAddress;

                  if(expRVA)
                  {
                     PIMAGE_EXPORT_DIRECTORY expDir=(PIMAGE_EXPORT_DIRECTORY)
                        (optHeader->ImageBase + expRVA);


                     DWORD *dllName=(DWORD *)(optHeader->ImageBase + expDir->Name);

                            if(*dllName==0x4E52454B && *(dllName+1)==0x32334C45) // KERNEL32
                        return (PIMAGE_DOS_HEADER)address;

                     if(*dllName==0x6E72656B && *(dllName+1)==0x32336C65) // kernel32
                        return (PIMAGE_DOS_HEADER)address;
                  }
               }
            }
         }
         __except(1)
         {
            break;
         }

         address = (DWORD *)((DWORD)address - 0x00010000);
      }

      stackAddress--;
   }
}

int main(int argc, char *argv[])
{
   PIMAGE_DOS_HEADER address=getKernel32ImageBase(0);

   printf("Kernel32.dll's ImageBase is: \t%08X\n", (DWORD)address);
   getch();

   return 0;
}