Disable LFH on Windows?

I want to disable LFH for an application that I am trying to debug. I can rebuild and redeploy the application, but I cannot attach the debugger or install any gflags.

What's a good way to disable LFH with these restrictions? Maybe there is an attribute that I can change on the executable itself? Or some startup code that I can add to the program?

+3


source to share


4 answers


On Vista and Win7, I think you can disable the low fragmentation heap on a per-executable basis with the Application Compatibility Toolkit.

In XP, the documentation suggests you don't get LFH by default . This is probably your C ++ runtime library (which you didn't name) that includes it. And it cannot be turned off after being turned on. So check the documentation for your particular runtime library to see if you can tell it not to include LFH, or if another version of the runtime library you can link from doesn't include it.



See also this thread on the Microsoft forums

+2


source


You can use the tool gflags.exe

that is included in the WDK (possibly also the SDK via the Windows Debug Package) to manipulate a subset of the gflags in the PE header of the executable image. Just go to the "Image File" tab in "gflags.exe".

As pointed out by jcopenha in a comment, it looks like gflags.exe does not manipulate the PE header of the file (I relied on information from Windows Internal Docs, Fifth Edition in Chapter 9, Heap Debugging Capabilities) - apparently it only manipulates the registry key Options image file ".

However, it may be possible to set (or clear) the gflags bit for a specific executable in an image - see docs for a IMAGE_LOAD_CONFIG_DIRECTORY

framework
; in particular fields GlobalFlagsClear

and GlobalFlagsSet

:

  • GlobalFlagsClear - Global flags that control system behavior. See Gflags.exe for more information.
  • GlobalFlagsSet - Global flags that control system behavior. See Gflags.exe for more information.

You can reset these fields with dumpbin

(or link /dump

) with a parameter /loadconfig

:

C:\temp>dumpbin /loadconfig test.exe
Microsoft (R) COFF/PE Dumper Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file test.exe

File Type: EXECUTABLE IMAGE

  Section contains the following load config:

            00000048 size
                   0 time date stamp
                0.00 Version
                   0 GlobalFlags Clear
                   0 GlobalFlags Set             // <=======
                   0 Critical Section Default Timeout

 // remainder of dump snipped...

      



You can get RVA

in the "Load Configuration Directory" with dumpbin /headers

:

C:\temp>dumpbin /headers test.exe
Microsoft (R) COFF/PE Dumper Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file test.exe

// ...

OPTIONAL HEADER VALUES

// ...

           142B0 [      40] RVA [size] of Load Configuration Directory
//         ^^^^^            ^^^
// ...

      

As a point of interest, parameter /loadconfig

and /headers

does not agree with the size of the structure (for the record, it looks like the information /header

is incorrect)

Unfortunately, I don't know of a PE editor that directly supports these fields - you probably have to use the hex editor (or the PE editor's hex edit function) to change these fields. The RVA structure IMAGE_LOAD_CONFIG_DIRECTORY

should help you find it in a hex editor.

I believe that setting one or more of the heap debug flags in the image header (maybe any of them, but you might need to experiment) will disable the fragmentation heap. But I have not tested whether the bits in these fields are actually being set. If you try this, please let us know how it works.

+1


source


Based on Michael Burr's comment above about an IMAGE_LOAD_CONFIG_DIRECTORY containing a GlobalFlagSet, I wrote the following code to demonstrate that a proper GlobalFlag disables a bunch of low fragmentation. One of the caveats about writing your own IMAGE_LOAD_CONFIG_DIRECTORY at compile time is that it disables SafeSEH.

// editloadconfig.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>

#include <tchar.h>
#include <stdio.h>


/*
typedef struct {
    DWORD   Size;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   GlobalFlagsClear;
    DWORD   GlobalFlagsSet;
    DWORD   CriticalSectionDefaultTimeout;
    DWORD   DeCommitFreeBlockThreshold;
    DWORD   DeCommitTotalFreeThreshold;
    DWORD   LockPrefixTable;            // VA
    DWORD   MaximumAllocationSize;
    DWORD   VirtualMemoryThreshold;
    DWORD   ProcessHeapFlags;
    DWORD   ProcessAffinityMask;
    WORD    CSDVersion;
    WORD    Reserved1;
    DWORD   EditList;                   // VA
    DWORD   SecurityCookie;             // VA
    DWORD   SEHandlerTable;             // VA
    DWORD   SEHandlerCount;
} IMAGE_LOAD_CONFIG_DIRECTORY32, *PIMAGE_LOAD_CONFIG_DIRECTORY32;
*/


extern "C" 
IMAGE_LOAD_CONFIG_DIRECTORY _load_config_used = { 0x48, 0, 0, 0,0, 0x00000020/*enable heap free checking*/};
// change the last value to 0 to not enable any globalflags


#define HEAP_STANDARD 0
#define HEAP_LAL 1
#define HEAP_LFH 2
#define SIZE 100

int _tmain(int argc, _TCHAR* argv[])
{
   BOOL bResult;
   HANDLE hHeap;
   ULONG HeapInformation;
   void* allocb[0x12+1];


   // based on "Understanding the LFH" paper at
   // http://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=5&ved=0CE0QFjAE&url=http%3A%2F%2Fillmatics.com%2FUnderstanding_the_LFH.pdf&ei=GlBvT9yrMKHy0gGHpLnaBg&usg=AFQjCNGsvVtl54X7MWGyWYqiSrsdTBrbXQ
   int i = 0;
   for(i = 0; i < 0x12; i++) 
   { 
        printf("Allocation 0x%02x for 0x%02x bytes\n", i, SIZE); 
        allocb[i] = HeapAlloc(GetProcessHeap(), 0x0, SIZE); 
   }

   printf("Allocation 0x%02x for 0x%02x bytes\n", i++, SIZE); 
   printf("\tFirst serviced by the LFH\n"); 
   allocb[i] = HeapAlloc(GetProcessHeap(), 0x0, SIZE);
   // LFH is now activated so the query below will return 0 or 2.

   // sample code from MSDN for querying heap information
   //
   // Get a handle to the default process heap.
   //
   hHeap = GetProcessHeap();
   if (hHeap == NULL) {
       _tprintf(TEXT("Failed to retrieve default process heap with LastError %d.\n"),
                GetLastError());
       return 1;
   }

   //
   // Query heap features that are enabled.
   //
   bResult = HeapQueryInformation(hHeap,
                                  HeapCompatibilityInformation,
                                  &HeapInformation,
                                  sizeof(HeapInformation),
                                  NULL);
   if (bResult == FALSE) {
       _tprintf(TEXT("Failed to retrieve heap features with LastError %d.\n"),
                GetLastError());
       return 1;
   }

   //
   // Print results of the query.
   //
   _tprintf(TEXT("HeapCompatibilityInformation is %d.\n"), HeapInformation);
   switch(HeapInformation)
   {
   case HEAP_STANDARD:
       _tprintf(TEXT("The default process heap is a standard heap.\n"));
       break;
   case HEAP_LAL:
       _tprintf(TEXT("The default process heap supports look-aside lists.\n"));
       break;
   case HEAP_LFH:
       _tprintf(TEXT("The default process heap has the low-fragmentation ") \
                TEXT("heap enabled.\n"));
       break;
   default:
       _tprintf(TEXT("Unrecognized HeapInformation reported for the default ") \
                TEXT("process heap.\n"));
       break;
    }

   return 0; 
}

      

+1


source


The easiest way, if you cannot change the configuration on the machine, is to set the heap information.

http://msdn.microsoft.com/en-us/library/windows/desktop/aa366705(v=vs.85).aspx

I believe you can disable a bunch of LFHs programmatically this way, although I haven't tried that.

0


source







All Articles