3
votes

I need to make an exe program that has no import table

iam using C++ i don't use any API even loadlibrary and getprocaddress i get handles to them in runtime

still when i build the application using visual studio 2013 [also tried visual studio 6]

the resulting exe has many imports from kernel32.dll

  • Address Ordinal Name Library

    ------- ------- ---- -------

    0040E000 MultiByteToWideChar KERNEL32

    0040E004 RtlUnwind KERNEL32

    0040E008 HeapAlloc KERNEL32

    0040E00C ExitProcess KERNEL32

    0040E010 TerminateProcess KERNEL32

    0040E014 GetCurrentProcess KERNEL32

    0040E018 GetCommandLineA KERNEL32

    0040E01C GetVersion KERNEL32

    0040E020 RaiseException KERNEL32

    0040E024 HeapFree KERNEL32

    0040E028 HeapReAlloc KERNEL32

    0040E02C HeapSize KERNEL32

    0040E030 HeapDestroy KERNEL32

    0040E034 HeapCreate KERNEL32

    0040E038 VirtualFree KERNEL32

    0040E03C VirtualAlloc KERNEL32

    0040E040 IsBadWritePtr KERNEL32

    0040E044 SetHandleCount KERNEL32

    0040E048 GetStdHandle KERNEL32

    0040E04C GetFileType KERNEL32

    0040E050 GetStartupInfoA KERNEL32

    0040E054 UnhandledExceptionFilter KERNEL32

    0040E058 GetModuleFileNameA KERNEL32

    0040E05C FreeEnvironmentStringsA KERNEL32

    0040E060 FreeEnvironmentStringsW KERNEL32

    0040E064 WideCharToMultiByte KERNEL32

    0040E068 GetEnvironmentStrings KERNEL32

    0040E06C GetEnvironmentStringsW KERNEL32

    0040E070 WriteFile KERNEL32

    0040E074 GetLastError KERNEL32

    0040E078 SetFilePointer KERNEL32

    0040E07C FlushFileBuffers KERNEL32

    0040E080 CloseHandle KERNEL32

    0040E084 SetUnhandledExceptionFilter KERNEL32

    0040E088 IsBadReadPtr KERNEL32

    0040E08C IsBadCodePtr KERNEL32

    0040E090 GetCPInfo KERNEL32

    0040E094 GetACP KERNEL32

    0040E098 GetOEMCP KERNEL32

    0040E09C GetProcAddress KERNEL32

    0040E0A0 LoadLibraryA KERNEL32

    0040E0A4 ReadFile KERNEL32

    0040E0A8 SetStdHandle KERNEL32

    0040E0AC LCMapStringA KERNEL32

    0040E0B0 LCMapStringW KERNEL32

    0040E0B4 GetStringTypeA KERNEL32

    0040E0B8 GetStringTypeW KERNEL32

    0040E0BC ReadConsoleInputA KERNEL32

    0040E0C0 SetConsoleMode KERNEL32

    0040E0C4 GetConsoleMode KERNEL32

    0040E0C8 CreateFileA KERNEL32

i used debug and release option both give the same problem i used multithreaded MD same problem

any ideas

Thanks for your time in advance [Note: my code include some inline assembly]

==================================================================

to reduce the size of the problem. I configured the entry point on the linker option i pointed to main

this helped to reduce the import table to the following

Address Ordinal Name Library

------- ------- ---- -------

00406000 HeapAlloc KERNEL32

00406004 ExitProcess KERNEL32

00406008 TerminateProcess KERNEL32

0040600C GetCurrentProcess KERNEL32

00406010 HeapFree KERNEL32

00406014 VirtualAlloc KERNEL32

00406018 HeapReAlloc KERNEL32

===============================================================

reduced even more

1st - uncheck the include default libraries in linker options

2nd - add MSVCRT.LIB to the linker command

now the import table is

Address Ordinal Name Library

------- ------- ---- -------

00405000 malloc MSVCRT

00405004 exit MSVCRT

00405008 rand MSVCRT

2
In order to start a process in windows requires calls to kernel32.dll. Are you asking how to start a process without that? Even low level filters requires resources from this. Dynamic linking would still use the need of a function table.Ross Bush
i get handle to getprocaddress and loadlibrary on runtime iam not using them in my codeEngEhaB
ok then only loadlib and getprocaddress virtualalloc virtual free then why the other imports!!EngEhaB
I think .def file is for exporting functions not importingEngEhaB
I know that once you loaded a library you loaded it all in memory but iam talking about the import table in the EXE file. i think it doesn't have to include all the APIs from the imported libraryEngEhaB

2 Answers

3
votes

You see all these entries in IAT for kernel32.dll because visual c++ runtime code calls all these functions directly. For example:

#include <Windows.h>    // include prototypes

// note that we need to link with kernel32.dll import library 
// (kernel32.lib) to call its functions directly;
// { Project Properties -> Configuration Properties -> Linker -> Input ->
// Additional dependencies } will contain "kernel32.lib" in the list

int main(int argc, char* argv[]);

int mainCRTStartup()
{
    GetCommandLine(...);   // direct call, so linker will create entry in IAT for kernel32.dll

    ...
    main(argc, argv);      // your main function that linker will search for
    ...
}

Also note that even if you link with kernel32.lib and don't call any of its functions directly (that's the purpose of import library after all) your binary will not even contain IMAGE_IMPORT_DESCRIPTOR for kernel32.dll, so linking with kernel32.lib has absolutely no effect in this case.

Create console application with this code:

int my_entry_point()
{
    return 0;
}

To create exe file with no imports follow these steps:

  1. { Project Properties -> Configuration Properties -> Linker -> Input -> Ignore All Default Libraries -> Yes (/NODEFAULTLIB) }
  2. { Project Properties -> Configuration Properties -> Linker -> Advanced -> Entry Point -> my_entry_point }
  3. { Project Properties -> Configuration Properties -> C/C++ -> Code Generation -> Security Check -> Disable Security Check (/GS-) }

This will tell compiler not to emit calls to security check functions, so linker will not have to resolve them.

Compile your program. Examine it in PE Explorer to make sure it has no imports (DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress is 0).

Note that your program links with kernel32.lib and other import libraries for system dlls (see Linker -> Input -> Additional dependencies). However it has no effect since you don't use CRT and don't call all these functions in your own code.

The interesting thing is that you don't need to import ExitProcess. Windows will immediately call RtlExitUserThread from ntdll.dll when my_entry_point function returns. This call instruction does not use IAT or any other redirection, it is call that will lead us directly to RtlExitUserThread function.

1
votes

Virtually it is not possible to have a Windows executable (well known as Win PE) without an import address table (IAT). But of course, technically it is possible to have an executable with an empty IAT and such an executable will be of no use or will be very difficult to code and maintain.

As we know, a computer program is defined to have at least one output and for that some kind of library dependency will be there. This library dependency is enough to fill the IAT. A C++ program that only uses the function printf() will cause to have a few number of entries in the IAT.

A normal executable will have plenty of entries in the IAT, as you listed. There are guys who do encryption to protect the executable file. They will use a technique known as IAT Mangling. They will considerably reduce the entries that are present in the IAT.

On a practical side, at least, the import table should contain a module entry for "Kernel32.dll" and that entry should contain the sub sections for the "LoadLibrary" and "GetProcAddress" APIs. Knowing how a Windows Loader loads and starts the execution of an executable will help to understand the critical role played by the IAT.

Whenever an executable is going to be loaded by the Loader, among other things it will check the integrity of the IAT. Any mismatch such as missing DLLs, function signature mismatch will cancel the execution of the executable.

There is a series of scholarly article on Win PE by Matt Pietrek. It clearly explains the role played by the IAT. You can read it from here.

By the way, if you are aiming to reduce the size of an executable, have a look at this article on Liposuction Tools.