Author Topic: manually map a dll  (Read 419 times)

0 Members and 1 Guest are viewing this topic.

ZOldDude

  • The Unknown Rank!
  • Administrator
  • MasstKer
  • *
  • *
  • Posts: 20809
  • Old School TKC
    • View Profile
    • Admin
manually map a dll
« on: February 18, 2016, 05:55:15 am »
Code: [Select]
//         ManualMap - by Darawk
//        Featured @ www.RealmGX.com & www.Darawk.com
//
//   The purpose of ManualMap is to "manually map" a dll
//   module into a remote process's address space.  This
//   means that instead of just manipulating the remote
//   process into calling the LoadLibrary function, we
//   have our own emulation of what LoadLibrary does
//   without all those annoying detectability issues ^^.
//   The advantage of this method over using something
//   like my CloakDll function, is that this method never
//   has to call a function like LoadLibrary inside the
//   remote process.  Since LoadLibrary can be hooked,
//   the dll   could still be caught at the injection stage.
//   Or possibly also through the weakness I discussed in
//   the comment header of that file, which is not present
//   when using this technique.
#include <windows.h>
#include <tlhelp32.h>
#include <shlwapi.h>

#pragma comment(lib, "shlwapi.lib")

#define IMAGE_DIRECTORY_ENTRY_IMPORT 1
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5

//   Pietrek's macro
//
//   MakePtr is a macro that allows you to easily add to values (including
//   pointers) together without dealing with C's pointer arithmetic.  It
//   essentially treats the last two parameters as DWORDs.  The first
//   parameter is used to typecast the result to the appropriate pointer type.
#define MakePtr( cast, ptr, addValue ) (cast)( (DWORD_PTR)(ptr) + (DWORD_PTR)(addValue))

//   This one is mine, but obviously..."adapted" from matt's original idea =p
#define MakeDelta(cast, x, y) (cast) ( (DWORD_PTR)(x) - (DWORD_PTR)(y))

bool MapRemoteModule(unsigned long, char *);

unsigned long GetProcessIdByName(char *);
HMODULE GetRemoteModuleHandle(unsigned long, char *);
FARPROC GetRemoteProcAddress(unsigned long, char *, char *);

bool FixImports(unsigned long, void *, IMAGE_NT_HEADERS *, IMAGE_IMPORT_DESCRIPTOR *);
bool FixRelocs(void *, void *, IMAGE_NT_HEADERS *, IMAGE_BASE_RELOCATION *, unsigned int);
bool MapSections(HANDLE, void *, void *, IMAGE_NT_HEADERS *);

PIMAGE_SECTION_HEADER GetEnclosingSectionHeader(DWORD, PIMAGE_NT_HEADERS);
LPVOID GetPtrFromRVA(DWORD, PIMAGE_NT_HEADERS, PBYTE);

//   Stub that calls the Dll from within the remote process.
//   This is necessary because a DllMain function takes 3
//   arguments, and CreateRemoteThread can pass only 1.
__declspec(naked) void DllCall_stub(HMODULE hMod)
{
   _asm
   {
      push 0
      push 1
      push [esp+0Ch]      //   Pointer to the hMod argument
        mov eax, 0xDEADBEEF   //   Patch this in with the real value at run-time

      call eax         //   MSVC++ doesn't like direct absolute calls, so we have to be
                     //   clever about it.

      ret               //   Don't have to clean up the stack because the calling function
                     //   is just going to call ExitThread() immediately after this
                     //   function returns.
   }
}

//   Marker for the end of the DllCall_stub function
__declspec(naked) void DC_stubend(void) { }   

int main(int argc, char **argv)
{
   //   Just my test values...Cmdline.dll is a plugin that comes with
   //   Olly Debug 1.10
   MapRemoteModule(GetProcessIdByName("notepad.exe"), "Cmdline.dll");
   return 0;
}

bool MapRemoteModule(unsigned long pId, char *module)
{
   IMAGE_DOS_HEADER *dosHd;
   IMAGE_NT_HEADERS *ntHd;

   HANDLE hFile = CreateFile(module,
      GENERIC_READ,
      FILE_SHARE_READ | FILE_SHARE_WRITE,
      NULL,
      OPEN_EXISTING,
      FILE_ATTRIBUTE_NORMAL,
      NULL);

   if(hFile == INVALID_HANDLE_VALUE)
      return false;

   unsigned int fSize;

   if(GetFileAttributes(module) & FILE_ATTRIBUTE_COMPRESSED)
      fSize = GetCompressedFileSize(module, NULL);
   else
      fSize = GetFileSize(hFile, NULL);

   unsigned char *dllBin = new unsigned char[fSize];
   unsigned int nBytes;

   ReadFile(hFile, dllBin, fSize, (LPDWORD)&nBytes, FALSE);
   CloseHandle(hFile);

   //   Every PE file contains a little DOS stub for backwards compatibility
   //   it's only real relevance is that it contains a pointer to the actual
   //   PE header.
   dosHd = MakePtr(IMAGE_DOS_HEADER *, dllBin, 0);

   //   Make sure we got a valid DOS header
   if(dosHd->e_magic != IMAGE_DOS_SIGNATURE)
   {
      delete dllBin;
      return false;
   }

   //   Get the real PE header from the DOS stub header
   ntHd = MakePtr(IMAGE_NT_HEADERS *, dllBin, dosHd->e_lfanew);

   //   Verify the PE header
   if(ntHd->Signature != IMAGE_NT_SIGNATURE)
   {
      delete dllBin;
      return false;
   }

   HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pId);

   if(!hProcess)
      return false;

   //   Allocate space for the module in the remote process
   void *moduleBase = VirtualAllocEx(hProcess,
      NULL,
      ntHd->OptionalHeader.SizeOfImage,
      MEM_COMMIT | MEM_RESERVE,
      PAGE_EXECUTE_READWRITE);

   //   Make sure we got the memory space we wanted
   if(!moduleBase)
      return false;

   //   Allocate space for our stub
   void *stubBase = VirtualAllocEx(hProcess,
      NULL,
      MakeDelta(SIZE_T, DC_stubend, DllCall_stub),
      MEM_COMMIT | MEM_RESERVE,
      PAGE_EXECUTE_READWRITE);

   //   Make sure we got the memory space we wanted
   if(!stubBase)
      return false;

   //   Fix up the import table of the new module
   IMAGE_IMPORT_DESCRIPTOR *impDesc = (IMAGE_IMPORT_DESCRIPTOR *)GetPtrFromRVA(
      (DWORD)(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress),
      ntHd,
      (PBYTE)dllBin);

   if(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size)
      FixImports(pId,
         (unsigned char *)dllBin,
         ntHd,
         impDesc);
   
   //   Fix "base relocations" of the new module.  Base relocations are places
   //   in the module that use absolute addresses to reference data.  Since
   //   the base address of the module can be different at different times,
   //   the base relocation data is necessary to make the module loadable
   //   at any address.
   IMAGE_BASE_RELOCATION *reloc = (IMAGE_BASE_RELOCATION *)GetPtrFromRVA(
      (DWORD)(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress),
      ntHd,
      (PBYTE)dllBin);

   if(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size)
      FixRelocs(dllBin,
         moduleBase,
         ntHd,
         reloc,
         ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);

   //   Write the PE header into the remote process's memory space
   WriteProcessMemory(hProcess,
      moduleBase,
      dllBin,
      ntHd->FileHeader.SizeOfOptionalHeader + sizeof(ntHd->FileHeader) + sizeof(ntHd->Signature),
      (SIZE_T *)&nBytes);

   //   Map the sections into the remote process(they need to be aligned
   //   along their virtual addresses)
   MapSections(hProcess, moduleBase, dllBin, ntHd);
   
   //   Change the page protection on the DllCall_stub function from PAGE_EXECUTE_READ
   //   to PAGE_EXECUTE_READWRITE, so we can patch it.
   VirtualProtect((LPVOID)DllCall_stub,
      MakeDelta(SIZE_T, DC_stubend, DllCall_stub),
      PAGE_EXECUTE_READWRITE,
      (DWORD *)&nBytes);

   //   Patch the stub so it calls the correct address
   *MakePtr(unsigned long *, DllCall_stub, 9) =
      MakePtr(unsigned long, moduleBase, ntHd->OptionalHeader.AddressOfEntryPoint);


   //   Write the stub into the remote process
   WriteProcessMemory(hProcess,
      stubBase,
      (LPVOID)DllCall_stub,
      MakeDelta(SIZE_T, DC_stubend, DllCall_stub),
      (SIZE_T *)&nBytes);

   //   Execute our stub in the remote process
   CreateRemoteThread(hProcess,
      NULL,
      0,
      (LPTHREAD_START_ROUTINE)stubBase,
      moduleBase,      //   Pass the base address of the module as the argument to the stub.
                  //   All a module handle is, is the base address of the module(except
                  //   in windows CE), so we're really passing a handle to the module
                  //   so that it can refer to itself, create dialogs, etc..
      0,
      NULL);

   delete dllBin;
   return true;
}

bool MapSections(HANDLE hProcess, void *moduleBase, void *dllBin, IMAGE_NT_HEADERS *ntHd)
{
   IMAGE_SECTION_HEADER *header = IMAGE_FIRST_SECTION(ntHd);
   unsigned int nBytes = 0;
   unsigned int virtualSize = 0;
   unsigned int n = 0;

   //   Loop through the list of sections
   for(unsigned int i = 0; ntHd->FileHeader.NumberOfSections; i++)
   {
      //   Once we've reached the SizeOfImage, the rest of the sections
      //   don't need to be mapped, if there are any.
      if(nBytes >= ntHd->OptionalHeader.SizeOfImage)
         break;
     
      WriteProcessMemory(hProcess,
         MakePtr(LPVOID, moduleBase, header->VirtualAddress),
         MakePtr(LPCVOID, dllBin, header->PointerToRawData),
         header->SizeOfRawData,
         (LPDWORD)&n);

      virtualSize = header->VirtualAddress;
      header++;
      virtualSize = header->VirtualAddress - virtualSize;
      nBytes += virtualSize;

      //   Set the proper page protections for this section.
      //   This really could be skipped, but it's not that
      //   hard to implement and it makes it more like a
      //   real loader.
      VirtualProtectEx(hProcess,
         MakePtr(LPVOID, moduleBase, header->VirtualAddress),
         virtualSize,
         header->Characteristics & 0x00FFFFFF,
         NULL);
   }

   return true;
}

bool FixImports(unsigned long pId, void *base, IMAGE_NT_HEADERS *ntHd, IMAGE_IMPORT_DESCRIPTOR *impDesc)
{
   char *module;

   //   Loop through all the required modules
   while((module = (char *)GetPtrFromRVA((DWORD)(impDesc->Name), ntHd, (PBYTE)base)))
   {
      //   If the library is already loaded(like kernel32.dll or ntdll.dll) LoadLibrary will
      //   just return the handle to that module.
        HMODULE localMod = LoadLibrary(module);

      //   If the module isn't loaded in the remote process, we recursively call the
      //   module mapping code.  This has the added benefit of ensuring that any of
      //   the current modules dependencies will be just as invisble as this one.
      if(!GetRemoteModuleHandle(pId, module))
         MapRemoteModule(pId, module);
       
      //   Lookup the first import thunk for this module
      //   NOTE: It is possible this module could forward functions...which is something
      //   that I really should handle.  Maybe i'll add support for forwared functions
      //   a little bit later.
      IMAGE_THUNK_DATA *itd =
         (IMAGE_THUNK_DATA *)GetPtrFromRVA((DWORD)(impDesc->FirstThunk), ntHd, (PBYTE)base);

      while(itd->u1.AddressOfData)
      {
         IMAGE_IMPORT_BY_NAME *iibn;
         iibn = (IMAGE_IMPORT_BY_NAME *)GetPtrFromRVA((DWORD)(itd->u1.AddressOfData), ntHd, (PBYTE)base);

             itd->u1.Function = MakePtr(DWORD, GetRemoteProcAddress(pId,
            module,
            (char *)iibn->Name), 0);

         itd++;
      }       
      impDesc++;
   }
   
   return true;
}

bool FixRelocs(void *base, void *rBase, IMAGE_NT_HEADERS *ntHd, IMAGE_BASE_RELOCATION *reloc, unsigned int size)
{
   unsigned long ImageBase = ntHd->OptionalHeader.ImageBase;
   unsigned int nBytes = 0;

   unsigned long delta = MakeDelta(unsigned long, rBase, ImageBase);

   while(1)
   {
      unsigned long *locBase =
         (unsigned long *)GetPtrFromRVA((DWORD)(reloc->VirtualAddress), ntHd, (PBYTE)base);
      unsigned int numRelocs = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);

      if(nBytes >= size) break;

      unsigned short *locData = MakePtr(unsigned short *, reloc, sizeof(IMAGE_BASE_RELOCATION));
      for(unsigned int i = 0; i < numRelocs; i++)
      {       
         if(((*locData >> 12) & IMAGE_REL_BASED_HIGHLOW))
             *MakePtr(unsigned long *, locBase, (*locData & 0x0FFF)) += delta;

         locData++;
      }

      nBytes += reloc->SizeOfBlock;
      reloc = (IMAGE_BASE_RELOCATION *)locData;
   }

   return true;
}


FARPROC GetRemoteProcAddress(unsigned long pId, char *module, char *func)
{
   HMODULE remoteMod = GetRemoteModuleHandle(pId, module);
   HMODULE localMod = GetModuleHandle(module);

   //   Account for potential differences in base address
   //   of modules in different processes.
   unsigned long delta = MakeDelta(unsigned long, remoteMod, localMod);
   return MakePtr(FARPROC, GetProcAddress(localMod, func), delta);
}

unsigned long GetProcessIdByName(char *process)
{
   PROCESSENTRY32 pe;
   HANDLE thSnapshot;
   BOOL retval, ProcFound = false;

   thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

   if(thSnapshot == INVALID_HANDLE_VALUE)
   {
      MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
      return false;
   }

   pe.dwSize = sizeof(PROCESSENTRY32);

    retval = Process32First(thSnapshot, &pe);

   while(retval)
   {
      if(StrStrI(pe.szExeFile, process) )
      {
         ProcFound = true;
         break;
      }

      retval    = Process32Next(thSnapshot,&pe);
      pe.dwSize = sizeof(PROCESSENTRY32);
   }

   return pe.th32ProcessID;
}

HMODULE GetRemoteModuleHandle(unsigned long pId, char *module)
{
   MODULEENTRY32 modEntry;
   HANDLE tlh = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pId);

   modEntry.dwSize = sizeof(MODULEENTRY32);
    Module32First(tlh, &modEntry);

   do
   {
      if(!stricmp(modEntry.szModule, module))
         return modEntry.hModule;
      modEntry.dwSize = sizeof(MODULEENTRY32);
   }
   while(Module32Next(tlh, &modEntry));

   return NULL;
}

//   Matt Pietrek's function
PIMAGE_SECTION_HEADER GetEnclosingSectionHeader(DWORD rva, PIMAGE_NT_HEADERS pNTHeader)
{
    PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
    unsigned int i;
   
    for ( i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++ )
    {
      // This 3 line idiocy is because Watcom's linker actually sets the
      // Misc.VirtualSize field to 0.  (!!! - Retards....!!!)
      DWORD size = section->Misc.VirtualSize;
      if ( 0 == size )
         size = section->SizeOfRawData;
         
        // Is the RVA within this section?
        if ( (rva >= section->VirtualAddress) &&
             (rva < (section->VirtualAddress + size)))
            return section;
    }
   
    return 0;
}

//   This function is also Pietrek's
LPVOID GetPtrFromRVA( DWORD rva, IMAGE_NT_HEADERS *pNTHeader, PBYTE imageBase )
{
   PIMAGE_SECTION_HEADER pSectionHdr;
   INT delta;
     
   pSectionHdr = GetEnclosingSectionHeader( rva, pNTHeader );
   if ( !pSectionHdr )
      return 0;

   delta = (INT)(pSectionHdr->VirtualAddress-pSectionHdr->PointerToRawData);
   return (PVOID) ( imageBase + rva - delta );
}


*While we crash and burn, small, low tech, agrarian societies such as the Hmong in the mountains of Laos will continue on without so much as blinking an eye.*

ZOldDude

  • The Unknown Rank!
  • Administrator
  • MasstKer
  • *
  • *
  • Posts: 20809
  • Old School TKC
    • View Profile
    • Admin
Re: manually map a dll
« Reply #1 on: February 18, 2016, 05:57:48 am »
Code: [Select]
//      GetProcAddress2 - by Darawk
//        Featured @ www.RealmGX.com & www.Darawk.com
//   
//   GetProcAddress2 is essentially identical to the
//   windows API function GetProcAddress, with one
//   key difference.  GetProcAddress2 does not check
//   to make sure the module handle that's passed to
//   it is in the loaded modules list.  GetProcAddress2
//   is designed to be used in conjunction with ManualMap
//   or CloakDll.  It allows you to access functions that
//   have been exported from a dll loaded by ManualMap or
//   cloaked by CloakDll.  This functionality is necessary
//   for plugin-based applications and late-binding functions.
#include <windows.h>

#define IMAGE_DIRECTORY_ENTRY_EXPORT 0

//   Pietrek's macro
//
//   MakePtr is a macro that allows you to easily add to values (including
//   pointers) together without dealing with C's pointer arithmetic.  It
//   essentially treats the last two parameters as DWORDs.  The first
//   parameter is used to typecast the result to the appropriate pointer type.
#define MakePtr( cast, ptr, addValue ) (cast)( (DWORD_PTR)(ptr) + (DWORD_PTR)(addValue))

//   This one is mine, but obviously..."adapted" from matt's original idea =p
#define MakeDelta(cast, x, y) (cast) ( (DWORD_PTR)(x) - (DWORD_PTR)(y))

//   My modified version of pietrek's function, to work with PE files that have
//   already been mapped into memory.
LPVOID GetPtrFromRVA( DWORD, IMAGE_NT_HEADERS *, PBYTE, bool);

FARPROC GetProcAddress2(HMODULE hMod, char *func)
{
   IMAGE_DOS_HEADER *dosHd;
   IMAGE_NT_HEADERS *ntHd;
   IMAGE_EXPORT_DIRECTORY *ied;
   char **names;
   unsigned short *ordinals;
   FARPROC *funcs;

   //   Make sure we got a valid pointer
   if(!hMod || hMod == INVALID_HANDLE_VALUE)
      return NULL;

   dosHd = (IMAGE_DOS_HEADER *)hMod;

    //   Verify the DOS header
   if(dosHd->e_magic != IMAGE_DOS_SIGNATURE)
      return NULL;

   ntHd = MakePtr(IMAGE_NT_HEADERS *, hMod, dosHd->e_lfanew);

   //   Verify the NT header
   if(ntHd->Signature != IMAGE_NT_SIGNATURE)
      return NULL;

    ied = (IMAGE_EXPORT_DIRECTORY *)GetPtrFromRVA((DWORD)(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress),
      ntHd,
      (PBYTE)hMod, true);
   
   names = (char **)GetPtrFromRVA(ied->AddressOfNames, ntHd, (PBYTE)hMod, true);
   ordinals = (unsigned short *)GetPtrFromRVA(ied->AddressOfNameOrdinals, ntHd, (PBYTE)hMod, true);
   funcs = (FARPROC *)GetPtrFromRVA(ied->AddressOfFunctions, ntHd, (PBYTE)hMod, true);

   unsigned int i;
   for(i = 0; i < ied->NumberOfNames; i++)
      if(!stricmp((char *)GetPtrFromRVA((DWORD)names[i], ntHd, (PBYTE)hMod, true), func))
         break;

   if(i >= ied->NumberOfNames)
      return NULL;

    return MakePtr(FARPROC, hMod, funcs[ordinals[i]]);
}

//   Matt Pietrek's function
PIMAGE_SECTION_HEADER GetEnclosingSectionHeader(DWORD rva, PIMAGE_NT_HEADERS pNTHeader)
{
    PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
    unsigned int i;
   
    for ( i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++ )
    {
      // This 3 line idiocy is because Watcom's linker actually sets the
      // Misc.VirtualSize field to 0.  (!!! - Retards....!!!)
      DWORD size = section->Misc.VirtualSize;
      if ( 0 == size )
         size = section->SizeOfRawData;
         
        // Is the RVA within this section?
        if ( (rva >= section->VirtualAddress) &&
             (rva < (section->VirtualAddress + size)))
            return section;
    }
   
    return 0;
}

unsigned long GetMappedSectionOffset(IMAGE_NT_HEADERS *ntHd, IMAGE_SECTION_HEADER *seHd, void *base)
{
   IMAGE_SECTION_HEADER *section = IMAGE_FIRST_SECTION(ntHd);
   unsigned int i;
   unsigned long offset = MakeDelta(unsigned long, section, base);

   for(i = 0; i < ntHd->FileHeader.NumberOfSections; i++, section++)
   {
      if(section->Name == seHd->Name)
      {
         offset = MakeDelta(unsigned long, section->VirtualAddress, section->PointerToRawData);
         break;
      }

      //offset += (section->SizeOfRawData > ntHd->OptionalHeader.SectionAlignment ?
      //   section->SizeOfRawData - ntHd->OptionalHeader.SectionAlignment :
      //   ntHd->OptionalHeader.SectionAlignment - section->SizeOfRawData);
   }

   return offset;
}

//   This function is also Pietrek's
LPVOID GetPtrFromRVA( DWORD rva, IMAGE_NT_HEADERS *pNTHeader, PBYTE imageBase, bool mapped )
{
   PIMAGE_SECTION_HEADER pSectionHdr;
   INT delta;
   unsigned long offset = 0;

   pSectionHdr = GetEnclosingSectionHeader( rva, pNTHeader );

   if(mapped)
      offset = GetMappedSectionOffset(pNTHeader, pSectionHdr, imageBase);

   if ( !pSectionHdr )
      return 0;

   delta = (INT)(pSectionHdr->VirtualAddress-pSectionHdr->PointerToRawData);
   return (PVOID) ( imageBase + rva - delta + offset);
}

*While we crash and burn, small, low tech, agrarian societies such as the Hmong in the mountains of Laos will continue on without so much as blinking an eye.*

ZOldDude

  • The Unknown Rank!
  • Administrator
  • MasstKer
  • *
  • *
  • Posts: 20809
  • Old School TKC
    • View Profile
    • Admin
Re: manually map a dll
« Reply #2 on: February 18, 2016, 06:00:02 am »
Code: [Select]
//              CloakDll - by Darawk
//        Featured @ www.RealmGX.com & www.Darawk.com
//
//   The purpose of CloakDll is to allow the user to hide any loaded
//   module from the windows API.  It works by accessing the modules
//   list stored in the PEB, and subsequently unlinking the module
//   in question from all 4 of the doubly-linked lists that it's a
//   node of.  It then zeroes out the structure and the path/file
//   name of the module in memory.  So that even if the memory where
//   the data about this module used to reside is scanned there will
//   still be no conclusive evidence of it's existence.  At present
//   there is only one weakness that I have found in this method.
//   I'll describe how it may still be possible to discover at least
//   that a module has been hidden, after a brief introduction to how
//   the GetModuleHandle function works.
//
//   *The following information is not documented by Microsoft.  This
//    information consists of my findings while reverse-engineering
//    these functions and some of them may be incorrect and/or
//    subject to change at any time(and is almost definitely different
//    in different versions of windows, and maybe even in different
//    service packs).  I've tried to make my code as version independant
//    as possible but certain parts of it may not work on older versions
//    of windows.  I've tested it on XP SP2 and there i'll guarantee
//    that it works, but on any other versions of windows, it's anyone's
//    guess.*
//
//   GetModuleHandle eventually calls GetModuleHandleExW, which in
//   turn accesses the native API function GetDllHandle, which calls
//   GetDllHandleEx.  And it's not until here, that we actually see
//   anything even begin to look up information about loaded modules.
//   Whenever GetModuleHandle is called, it saves the address of the
//   last ModuleInfoNode structure that it found in a global variable
//   inside of ntdll.  This global variable is the first thing
//   checked on all subsequent calls to GetModuleHandle.  If the
//   handle being requested is not the one that was requested the last
//   time GetDllHandleEx calls the LdrpCheckForLoadedDll function.
//   LdrpCheckForLoadedDll begins by converting the first letter of the
//   module name being requested to uppercase, decrementing it by 1 and
//   AND'ing it with 0x1F.  This effectively creates a 0-based index
//   beginning with the letter 'A'.  The purpose of this is so that
//   the module can first be looked up in a hash table.  The hash table
//   consists entirely of LIST_ENTRY structures.  One for each letter
//   'A' through 'Z'.  The LIST_ENTRY structure points to the first
//   and last modules loaded that begin with the letter assigned to
//   that entry in the hash table.  The Flink member being the first
//   loaded beginning with that letter, and the Blink member being the
//   last.  The code scans through this list until it finds the module
//   that it's looking for.  On the off-chance that it doesn't find it
//   there, or if the boolean argument UseLdrpHashTable is set to false
//   it will begin going through one of the other three lists.  If, at
//   this point it still doesn't find it, it will admit defeat and return
//   0 for the module handle.
//
//   Weakness:  The global variable inside ntdll that caches the pointer
//   to the last module looked up could be used to at least detect the
//   fact that a module has been hidden.  The LdrUnloadDll() function
//   will set this value to 0 when it unloads a module, so if the cache
//   variable points to an empty structure, the only logical conclusion
//   would be a hidden module somewhere in the process.  This could be
//   resolved by using the static address of this variable and simply
//   zeroing it out.  However, this would make the code specific to only
//   one version of windows.  You could also scan the address space of
//   ntdll for any occurences of the base address(aka module handle)
//   of the module you're hiding.  However, this would be slow and it
//   would clutter up the CloakDll_stub function, because it'd have to
//   all be done manually.  And i'd have to either use a static base
//   address for ntdll...which would probably work on most versions
//   of windows, however I really don't like using static addresses.
//   Or i'd have to manually locate it by writing my own unicode
//   string comparison code, to lookup ntdll in the list by it's name.
//   Realistically though anyone trying to detect this way would run
//   into the same problem.  That their code would not be version
//   independant.  So, it's unlikely to see any largescale deployment
//   of such a technique.  However, anyone who would like to solve
//   this problem themselves is perfectly free, and encouraged to do
//   so.

#include <windows.h>
#include <winnt.h>
#include <tlhelp32.h>
#include <shlwapi.h>


#pragma comment(lib, "shlwapi.lib")

#define UPPERCASE(x) if((x) >= 'a' && (x) <= 'z') (x) -= 'a' - 'A'
#define UNLINK(x) (x).Blink->Flink = (x).Flink; \
   (x).Flink->Blink = (x).Blink;
   
#pragma pack(push, 1)

typedef struct _UNICODE_STRING {
  USHORT  Length;
  USHORT  MaximumLength;
  PWSTR  Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

typedef struct _ModuleInfoNode
{
   LIST_ENTRY LoadOrder;
   LIST_ENTRY InitOrder;
   LIST_ENTRY MemoryOrder;
   HMODULE baseAddress;      //   Base address AKA module handle
   unsigned long entryPoint;
   unsigned int size;         //   Size of the modules image
   UNICODE_STRING fullPath;
   UNICODE_STRING name;
   unsigned long flags;
   unsigned short LoadCount;
   unsigned short TlsIndex;
   LIST_ENTRY HashTable;   //   A linked list of any other modules that have the same first letter
   unsigned long timestamp;
} ModuleInfoNode, *pModuleInfoNode;

typedef struct _ProcessModuleInfo
{
   unsigned int size;         //   Size of a ModuleInfo node?
   unsigned int initialized;
   HANDLE SsHandle;
   LIST_ENTRY LoadOrder;
   LIST_ENTRY InitOrder;
   LIST_ENTRY MemoryOrder;
} ProcessModuleInfo, *pProcessModuleInfo;


#pragma pack(pop)

bool CloakDll_stub(HMODULE);
void CD_stubend();

bool CloakDll(char *, char *);
unsigned long GetProcessIdFromProcname(char *);
HMODULE GetRemoteModuleHandle(unsigned long, char *);


int main(int argc, char **argv)
{
   CloakDll("notepad.exe", "kernel32.dll");
   return 0;
}

bool CloakDll(char *process, char *dllName)
{
   PathStripPath(dllName);

   unsigned long procId;
   procId = GetProcessIdFromProcname(process);
   HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procId);

   //   Calculate the length of the stub by subtracting it's address
   //   from the beginning of the function directly ahead of it.
   //
   //   NOTE: If the compiler compiles the functions in a different
   //   order than they appear in the code, this will not work as
   //   it's supposed to.  However, most compilers won't do that.
   unsigned int stubLen = (unsigned long)CD_stubend - (unsigned long)CloakDll_stub;

   //   Allocate space for the CloakDll_stub function
   void *stubAddress = VirtualAllocEx(hProcess,
      NULL,
      stubLen,
      MEM_RESERVE | MEM_COMMIT,
      PAGE_EXECUTE_READWRITE);

   //   Write the stub's code to the page we allocated for it
   WriteProcessMemory(hProcess, stubAddress, CloakDll_stub, stubLen, NULL);

   HMODULE hMod = GetRemoteModuleHandle(procId, dllName);

   //   Create a thread in the remote process to execute our code
   CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)stubAddress, hMod, 0, NULL);

   //   Clean up after ourselves, so as to leave as little impact as possible
   //   on the remote process
   VirtualFreeEx(hProcess, stubAddress, stubLen, MEM_RELEASE);
   return true;
}

bool CloakDll_stub(HMODULE hMod)
{
   ProcessModuleInfo *pmInfo;
   ModuleInfoNode *module;

   _asm
   {
      mov eax, fs:[18h]      // TEB
      mov eax, [eax + 30h]   // PEB
      mov eax, [eax + 0Ch]   // PROCESS_MODULE_INFO
      mov pmInfo, eax
   }

    module = (ModuleInfoNode *)(pmInfo->LoadOrder.Flink);
   
   while(module->baseAddress && module->baseAddress != hMod)
      module = (ModuleInfoNode *)(module->LoadOrder.Flink);

   if(!module->baseAddress)
      return false;

   //   Remove the module entry from the list here
   ///////////////////////////////////////////////////   
   //   Unlink from the load order list
   UNLINK(module->LoadOrder);
   //   Unlink from the init order list
   UNLINK(module->InitOrder);
   //   Unlink from the memory order list
   UNLINK(module->MemoryOrder);
   //   Unlink from the hash table
   UNLINK(module->HashTable);

   //   Erase all traces that it was ever there
   ///////////////////////////////////////////////////

   //   This code will pretty much always be optimized into a rep stosb/stosd pair
   //   so it shouldn't cause problems for relocation.
   //   Zero out the module name
   memset(module->fullPath.Buffer, 0, module->fullPath.Length);
   //   Zero out the memory of this module's node
   memset(module, 0, sizeof(ModuleInfoNode));   

   return true;
}

__declspec(naked) void CD_stubend() { }

unsigned long GetProcessIdFromProcname(char *procName)
{
   PROCESSENTRY32 pe;
   HANDLE thSnapshot;
   BOOL retval, ProcFound = false;

   thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

   if(thSnapshot == INVALID_HANDLE_VALUE)
   {
      MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
      return false;
   }

   pe.dwSize = sizeof(PROCESSENTRY32);

    retval = Process32First(thSnapshot, &pe);

   while(retval)
   {
      if(StrStrI(pe.szExeFile, procName) )
      {
         ProcFound = true;
         break;
      }

      retval    = Process32Next(thSnapshot,&pe);
      pe.dwSize = sizeof(PROCESSENTRY32);
   }

   return pe.th32ProcessID;
}

HMODULE GetRemoteModuleHandle(unsigned long pId, char *module)
{
   MODULEENTRY32 modEntry;
   HANDLE tlh = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pId);

   modEntry.dwSize = sizeof(MODULEENTRY32);
    Module32First(tlh, &modEntry);

   do
   {
      if(!stricmp(modEntry.szModule, module))
         return modEntry.hModule;
      modEntry.dwSize = sizeof(MODULEENTRY32);
   }
   while(Module32Next(tlh, &modEntry));

   return NULL;
}

*While we crash and burn, small, low tech, agrarian societies such as the Hmong in the mountains of Laos will continue on without so much as blinking an eye.*