Search code examples
c++cwinapiportable-executable

Can a portable executable have direct absolute references to external libraries in the code segment, not via IAT?


If I call Win32 API functions from my C++ code like in the following example:

fSuccess = WriteFile( 
  hPipe,                  // pipe handle 
  lpvMessage,             // message 
  cbToWrite,              // message length 
  &cbWritten,             // bytes written 
  NULL);                  // not overlapped 

then the Visual C++ compiler will translate those calls into absolute references to the import address table (IAT) in the data segment. The IAT itself will contain the actual absolute addresses to the external libraries which contains that Win32 API function. In the example above for the WriteFile function this external library is kernel32.dll.

If I modify one entry in the IAT at run-time such that it points to a different library/function, then all of the calls to that function in my original C++ will also change. I would like only some of them to change. Or to make it such that a certain Win32 API function does not even appear in the IAT at all, but it is directly referenced by the code segment.

How can I do that? Can I somehow force the compiler to contain a direct absolute reference to an external library in the code segment, instead of an indirect reference via the IAT?


Solution

  • I would like only some of them to change. Or to make it such that a certain Win32 API function does not even appear in the IAT at all, but it is directly referenced by the code segment.

    How can I do that?

    To do that, you have to access the functions dynamically at run-time using LoadLibrary()/GetModuleHandle() and GetProcAddress() (or your compiler's delay-load wrapper, if it has one), instead of static linking to the functions at compile-time. For example:

    typedef BOOL (WINAPI *LPFN_WRITEFILE)(HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
    LPFN_WRITEFILE lpWriteFile = (LPFN_WRITEFILE) GetProcAddress(GetModuleHandle("kernel32"), "WriteFile");
    fSuccess = lpWriteFile( 
      hPipe,                  // pipe handle 
      lpvMessage,             // message 
      cbToWrite,              // message length 
      &cbWritten,             // bytes written 
      NULL);