GetImageConfigInformation call is returning false

The GetImageConfigInformation Windows API call is returning false for me.
Anyone know what I'm doing wrong? This function doesn't seem documented very well, so I'm not sure what the possible reasons for failure are.

I am using MinGW [g++ (GCC) 7.1.0].
I am compiling with: g++ -Wall main.cpp -limagehlp -o main.exe

The output of my program is:
main.exe loaded
GetImageConfigInformation failed, error 13

Error Code 13 is "Invalid Data".

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
///
/// Compile and link with:  g++ -Wall main.cpp -limagehlp -o main.exe
///

#include <iostream>
#include <string>
#include <cstdint>

#include <windows.h>
#include <imagehlp.h> 

int main()
{  
    std::string image_name = "main.exe";
    
    LOADED_IMAGE loaded_image;  
    bool win_ret = MapAndLoad(
        image_name.c_str(),  // file name of the image (executable or DLL)
        nullptr,       // if null, search path rules set using SearchPath function apply
        &loaded_image, // ptr to LOADED_IMAGE
        false,         // is .dll?
        true           // is read-only?
    );
       
    if (!win_ret)
    {
        int err = GetLastError();
        std::cout << "MapAndLoad failed, error " << err << '\n';
        return 1;
    }
    else
    {
        std::cout << image_name << " loaded\n";
    }
    
    IMAGE_LOAD_CONFIG_DIRECTORY64 image_config_info;
    
    win_ret = GetImageConfigInformation(&loaded_image, &image_config_info);
    
    if (!win_ret)
    {
        int err = GetLastError();
        std::cout << "GetImageConfigInformation failed, error " << err << '\n';
        return 2;
    }
    else
    {
        std::cout << "Image Config Information loaded\n";
    }
    
    return 0;
}
Last edited on
> IMAGE_LOAD_CONFIG_DIRECTORY64 image_config_info;
A couple of thoughts.

I thought in general you left of the 32/64 suffix, and relied instead on compilation flags to select the right structure based on the kind of build being performed.
https://docs.microsoft.com/en-gb/windows/win32/api/winnt/ns-winnt-_image_load_config_directory32

Also, initialising the .size member might be an idea.
M$ often uses the .size member to figure out which actual declaration is being used across multiple versions which have added various members in different versions.
Thank you for the very fast reply! :)

You are correct, it still compiles without the "64" struct name suffix, I will remember that. (I am compiling 64-bit, Windows 10.)

From your suggestion, have now tried:
1
2
    IMAGE_LOAD_CONFIG_DIRECTORY image_config_info = {};
    image_config_info.Size = sizeof(image_config_info);

1
2
    IMAGE_LOAD_CONFIG_DIRECTORY image_config_info = {};
    image_config_info.Size = 64;

and
1
2
    IMAGE_LOAD_CONFIG_DIRECTORY image_config_info = {};
    image_config_info.Size = 32;


but all still cause the error code to be 13.

Edit:
Also, this fails as well, same error code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int main()
{  
    std::string image_name = "accesschk64.exe"; //"main.exe";
    
    PLOADED_IMAGE p_loaded_image = ImageLoad(image_name.c_str(), nullptr);
    if (!p_loaded_image)
    {
        std::cout << "ImageLoad error " << GetLastError() << std::endl;
        return 1;
    }

    IMAGE_LOAD_CONFIG_DIRECTORY image_config_info;
    //image_config_info.Size = 64 ;//sizeof(image_config_info);
    bool win_ret = GetImageConfigInformation(p_loaded_image, &image_config_info);
    
    if (!win_ret)
    {
        int err = GetLastError();
        std::cout << "GetImageConfigInformation failed, error " << err << '\n';
        return 2;
    }
    else
    {
        std::cout << "Image Config Information loaded\n";
    }
    
    // TODO: Cleanup resources
    
    return 0;
}


Note that I also found this "example" in a search,
https://elogeel.wordpress.com/2010/11/07/thread-scheduling-priorities-and-affinities/
In this example, .Size is not set. But of course that doesn't mean it shouldn't be set... but it seems to make no difference whether it is or isn't.

Edit 2:
I'm starting to think this is some sort of version compatibility issue.

You can see what's currently on the MSDN page, https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-_image_load_config_directory64
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64 {
  DWORD                            Size;
  DWORD                            TimeDateStamp;
  WORD                             MajorVersion;
  WORD                             MinorVersion;
  DWORD                            GlobalFlagsClear;
  DWORD                            GlobalFlagsSet;
  DWORD                            CriticalSectionDefaultTimeout;
  ULONGLONG                        DeCommitFreeBlockThreshold;
  ULONGLONG                        DeCommitTotalFreeThreshold;
  ULONGLONG                        LockPrefixTable;
  ULONGLONG                        MaximumAllocationSize;
  ULONGLONG                        VirtualMemoryThreshold;
  ULONGLONG                        ProcessAffinityMask;
  DWORD                            ProcessHeapFlags;
  WORD                             CSDVersion;
  WORD                             DependentLoadFlags;
  ULONGLONG                        EditList;
  ULONGLONG                        SecurityCookie;
  ULONGLONG                        SEHandlerTable;
  ULONGLONG                        SEHandlerCount;
  ULONGLONG                        GuardCFCheckFunctionPointer;
  ULONGLONG                        GuardCFDispatchFunctionPointer;
  ULONGLONG                        GuardCFFunctionTable;
  ULONGLONG                        GuardCFFunctionCount;
  DWORD                            GuardFlags;
  IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity;
  ULONGLONG                        GuardAddressTakenIatEntryTable;
  ULONGLONG                        GuardAddressTakenIatEntryCount;
  ULONGLONG                        GuardLongJumpTargetTable;
  ULONGLONG                        GuardLongJumpTargetCount;
  ULONGLONG                        DynamicValueRelocTable;
  ULONGLONG                        CHPEMetadataPointer;
  ULONGLONG                        GuardRFFailureRoutine;
  ULONGLONG                        GuardRFFailureRoutineFunctionPointer;
  DWORD                            DynamicValueRelocTableOffset;
  WORD                             DynamicValueRelocTableSection;
  WORD                             Reserved2;
  ULONGLONG                        GuardRFVerifyStackPointerFunctionPointer;
  DWORD                            HotPatchTableOffset;
  DWORD                            Reserved3;
  ULONGLONG                        EnclaveConfigurationPointer;
  ULONGLONG                        VolatileMetadataPointer;
} IMAGE_LOAD_CONFIG_DIRECTORY64, *PIMAGE_LOAD_CONFIG_DIRECTORY64;


In my winnt.h file, however, it looks like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    typedef struct {
      DWORD Size;
      DWORD TimeDateStamp;
      WORD MajorVersion;
      WORD MinorVersion;
      DWORD GlobalFlagsClear;
      DWORD GlobalFlagsSet;
      DWORD CriticalSectionDefaultTimeout;
      ULONGLONG DeCommitFreeBlockThreshold;
      ULONGLONG DeCommitTotalFreeThreshold;
      ULONGLONG LockPrefixTable;
      ULONGLONG MaximumAllocationSize;
      ULONGLONG VirtualMemoryThreshold;
      ULONGLONG ProcessAffinityMask;
      DWORD ProcessHeapFlags;
      WORD CSDVersion;
      WORD Reserved1;
      ULONGLONG EditList;
      ULONGLONG SecurityCookie;
      ULONGLONG SEHandlerTable;
      ULONGLONG SEHandlerCount;
    } IMAGE_LOAD_CONFIG_DIRECTORY64,*PIMAGE_LOAD_CONFIG_DIRECTORY64;


So I perhaps do need to fill in Size with something, but nothing I've tried so far as worked.

Edit 3: Actually, I wrote a program to try all .Size values between 0 and sizeof(IMAGE_LOAD_CONFIG_DIRECTORY) * 10, and none of those values worked. So it's not just an issue with size.

Edit 4: I can't read Chinese, but the same error happens in the program from this link: https://bbs.csdn.net/topics/200087305 (fixed for modern C++ below)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <windows.h>
#include <imagehlp.h>
#include <time.h>

using std::cout;
 
int main() {
    OPENFILENAME    ofn;
    TCHAR            szFileName[MAX_PATH];
    LOADED_IMAGE    loadedImage;
    BOOL            bRet;
    IMAGE_LOAD_CONFIG_DIRECTORY     imageLoadedConfig;
     
        memset(&ofn, 0, sizeof(ofn));
        memset(szFileName, 0, sizeof(szFileName));
     
    ofn.lStructSize = sizeof(ofn);
    ofn.lpstrFilter = TEXT("Executable Files(*.exe)\0*.exe\0DLL Files(*.dll)\0*.dllAll Files(*.*)\0*.*\0\0");
    ofn.lpstrFile = szFileName;
    ofn.nMaxFile = MAX_PATH;
 
    GetOpenFileName(&ofn);
 
    bRet = MapAndLoad(szFileName, NULL, &loadedImage, FALSE, TRUE);
    if(bRet == FALSE) {
        cout << "Error Ocuure in MapAndLoad\n";
    }
 
    bRet = GetImageConfigInformation(&loadedImage, &imageLoadedConfig);
    if(bRet == FALSE) {
        cout << "error ocuure in GetImageConfigInformation: "  << GetLastError() << '\n';
    }
         
    UnMapAndLoad(&loadedImage);
     
    return 0;
}

g++ -Wall main2.cpp -limagehlp -lcomdlg32 -o main2.exe


Edit 5: To top it off, the following program produces error 87 (invalid parameter) in Visual Studio 2017, but error 13 if compiled with g++.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#pragma comment(lib, "Imagehlp.lib") 

#include <iostream>
#include <windows.h>
#include <imagehlp.h>
#include <time.h>

using std::cout;

int main() {

	LOADED_IMAGE    loadedImage;
	BOOL            bRet;
	IMAGE_LOAD_CONFIG_DIRECTORY     imageLoadedConfig;

	const char* filename = "test.exe";

	bRet = MapAndLoad(filename, NULL, &loadedImage, FALSE, TRUE);
	if (bRet == FALSE) {
		cout << "Error Ocuure in MapAndLoad\n";
	}

	bRet = GetImageConfigInformation(&loadedImage, &imageLoadedConfig);
	if (bRet == FALSE) {
		cout << "error ocuure in GetImageConfigInformation: " << GetLastError() << '\n';
	}

	UnMapAndLoad(&loadedImage);

	return 0;
}


And apparently MapAndLoad isn't compatible with Unicode so that's funny too.
Last edited on
Topic archived. No new replies allowed.