4

All Portable Executable files that I've found with zero imports in the Import Address Table have not functioned. I also know that while .NET files often do not have the typical OS imports, they must still import either _CorExeMain or RHBinder__ShimExeMain.

Lastly, even packed files, while they will not have the main modules' imports, will still have imports necessary to start and unpack the file. Is it possible for a .exe PE file to have absolutely zero imports but still run and perform any useful function on a machine?

Please note: I am not talking about DLL files which are used by other executables for their function exports. I am talking about a standalone .exe file.

  • I'm still not clear - do you mean a program that uses no imported functions at all? Without APIs, you can't even print on the screen. Then it becomes a question of how you define "useful". Alternatively, all Crinkler-packed files have an empty import table, yet do many amazing things, by parsing memory structures to find the loader, and then resolving the imports at runtime. – peter ferrie Jun 30 '17 at 20:11
  • Yes, programs can easily lookup the base address of "kernel32.dll" from the PEB. Then walk the PE header and export directory and dynamically lookup function addresses. – Will Aug 13 '17 at 6:58
11

Although blabb's answer shows an executable without any imports, I'm assuming OP was asking about a more functional executable, and not as a theoretical exercise of that level.

I can think of four types of reasonable, useable executable file types that may not have any imports:

  1. An executable that does not require any OS APIs.

    This is somewhat similar to blabb's answer, but coming up with a more realistic example. Coming up with an executable that makes some kind of complex calculation might be an example. Still, this does not seem like the kind of executable OP is looking for.

  2. An executable that fulfils its function by using the default loaded libraries.

    Different OSes have different default libraries, and this might not be always possible, but on windows for example ntdll.dll and kernel32.dll are always loaded into a process, and additional libraries may also be loaded, depending on PE file flags. Some of this is even done by the kernel before most of the PE file format (and the import directory specifically) are processed, other libraries are loaded by the loader automatically or by other library dependencies. An executable may use those available APIs without having any imports, however some additional work to manually resolve APIs will be needed.

  3. An executable that resolves it's own imports based on default loaded libraries.

    Using those available APIs from previously mentioned libraries, an executable can implement it's own API search and even library loading code without actually importing the required APIs. This is what some packers do. Specifically, those implementing their own GetProcAddr functionality on windows, or using GetProcAddr and LoadLibrary to dynamically load APIs with an empty import table.

  4. An executable that directly implements syscalls to use OS services.

    This possibility is the most complex and fragile, as implementing syscalls directly is difficult and may change between OS updates without prior warnings. Basically, most APIs end up with a syscall instruction that transfers control to the kernel, where the requested operation is actually carried out by the kernel. An executable can issues those directly whenever an OS service is required.

  • I don't really see the difference between 2 and 3. (Though I generally agree with what you said and voted up.) – conio Jun 27 '17 at 2:20
  • I split up "only using available APIs" and "Loading additional libraries". Naturally, most of those differences are kinda similar and only slightly differ. Thanks for the upvote :) – NirIzr Jun 27 '17 at 2:24
6
void main (void)
{
    __asm
    {
        retn
    }
}

compiled and linked using

cl /nologo /W4 /Ox /analyze noimpo.cpp /link /DEBUG:NONE /RELEASE /ENTRY:main /INCREMENTAL:NO /FIXED /SUBSYSTEM:windows /ALIGN:128 /DRIVER

will create a working PE file

**edit **

// win 7 sp1 32 bit machine and ewdk 1703 cl.exe
unsigned long long time = 0xdeadbeefdeadbeef;
__declspec(naked) void main (void)
{   
    __asm
    {
        push OFFSET time
        call ntqst      
        retn
    }   
    ntqst:
    __asm
    {
        mov eax,107h
        mov edx , 7ffe0300h
        call dword ptr ds:[edx]
        retn 4
    }
}

running under debugger to see if it really does some thing useful

cdb -c "g @$exentry;dq 400380 l1;pc;p;dq 400380 l1;.formats qwo(400380);.time;q" noimpo.exe | grep -i quit -B 16

00400380  deadbeef`deadbeef <----- marker

00400380  01d2ef24`40afa83a <----- actual result

Evaluate expression: < result from .formats 
xxxxxxxxxxxxxxxxxxxxxxxxx
  Time:             Tue Jun 27 14:33:33.028 2017 
xxxxxxxxxxxxxxxxxxxxxxxxx

result from .time command

Debug session time: Tue Jun 27 14:33:33.028 2017 
xxx
quit:
  • 1
    I appreciate the response and the knowledge is useful, however, I think you missed the part of this sentence: ". Is it possible for a .exe PE file to have absolutely zero imports but still run and perform any useful function on a machine?" 'anything useful.' – the_endian Jun 26 '17 at 23:16
  • if you think querying system time is useful you have it in the edit – blabb Jun 27 '17 at 9:31
4

Yes, it is possible but may depend on the OS you're trying to run it on. From the TinyPE page by Alexander Sotirov:

Unfortunately the 97 byte PE file does not work on Windows 2000. This is because the loader tries to call a function from KERNEL32, but KERNEL32.DLL is not loaded. All other versions of Windows load it automatically, but on Windows 2000 we have to make sure that KERNEL32.DLL is listed in the import table of the executable. Executing a PE file with no imports is not possible.

So, if you use XP or above you can rely on kernel32 being in memory and use its functions. I suspect (but did not check) that even on Windows 2000 the ntdll.dll is mapped by the kernel, so you may be able to use it to do useful work (e.g. LdrLoadDll to load other DLLs and LdrGetProcedureAddress to resolve functions).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.