如何在没有导入表的情况下编译C ++ windows exe

时间:2014-04-05 02:33:43

标签: c++ visual-studio visual-c++ compilation compiler-optimization

我需要创建一个没有导入表的exe程序

iam使用C ++我不使用任何API甚至loadlibrary和getprocaddress我在运行时获取句柄

当我使用visual studio 2013构建应用程序时[也尝试过visual studio 6]

生成的exe有很多来自kernel32.dll的导入

  • 地址序号库

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

    0040E000 MultiByteToWideChar KERNEL32

    0040E004 RtlUnwind KERNEL32

    0040E008 HeapAlloc KERNEL32

    <00> 0040E00C ExitProcess KERNEL32

    0040E010 TerminateProcess KERNEL32

    0040E014 GetCurrentProcess KERNEL32

    0040E018 GetCommandLineA KERNEL32

    <00> 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

我使用调试和发布选项都给出了同样的问题 我使用多线程MD同样的问题

任何想法

感谢您提前的时间 [注意:我的代码包含一些内联汇编]

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

减少问题的大小。我在链接器选项i上配置了入口点,指向main

这有助于将导入表减少到以下

地址序号库

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

00406000 HeapAlloc KERNEL32

00406004 ExitProcess KERNEL32

00406008 TerminateProcess KERNEL32

0040600C GetCurrentProcess KERNEL32

00406010 HeapFree KERNEL32

00406014 VirtualAlloc KERNEL32

00406018 HeapReAlloc KERNEL32

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

减少更多

1st - 取消选中链接器选项中的include默认库

2nd - 将MSVCRT.LIB添加到链接器命令

现在导入表是

地址序号库

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

00405000 malloc MSVCRT

00405004退出MSVCRT

00405008 rand MSVCRT

2 个答案:

答案 0 :(得分:2)

您在IAT中看到kernel32.dll的所有这些条目,因为visual c ++运行时代码直接调用所有这些函数。例如:

#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
    ...
}

另请注意,即使您与kernel32.lib链接并且不直接调用其任何函数(毕竟这是导入库的目的),您的二进制文件甚至不会包含{{1}对于kernel32.dll,所以在这种情况下,与kernel32.lib的链接绝对没有效果。

使用以下代码创建控制台应用程序:

IMAGE_IMPORT_DESCRIPTOR

要创建没有导入的exe文件,请按照以下步骤操作:

  1. {项目属性 - &gt;配置属性 - &gt;链接器 - &gt;输入 - &gt;忽略所有默认库 - &gt;是(/ NODEFAULTLIB)}
  2. {项目属性 - &gt;配置属性 - &gt;链接器 - &gt;高级 - &gt;入口点 - &gt; my_entry_point}
  3. {项目属性 - &gt;配置属性 - &gt; C / C ++ - &gt;代码生成 - &gt;安全检查 - &gt;禁用安全检查(/ GS-)}
  4. 这将告诉编译器不要发出对安全检查函数的调用,因此链接器不必解析它们。

    编译您的程序。在PE资源管理器中检查它以确保它没有导入(int my_entry_point() { return 0; } 为0)。

    请注意,您的程序与kernel32.lib和系统dll的其他导入库链接(请参阅链接器 - &gt;输入 - &gt;其他依赖项)。但是它没有任何效果,因为您不使用CRT并且不在您自己的代码中调用所有这些函数。

    有趣的是,您不需要导入DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress。当ExitProcess函数返回时,Windows将立即从ntdll.dll调用RtlExitUserThread。此调用指令不使用IAT或任何其他重定向,调用将直接引导我们my_entry_point函数。

答案 1 :(得分:1)

实际上,如果没有导入地址表(IAT),则无法拥有Windows可执行文件(众所周知的Win PE)。但是,当然,从技术上讲,可能有一个空IAT的可执行文件,这样的可执行文件没有用,或者很难编码和维护。

众所周知,计算机程序被定义为至少有一个输出,因此存在某种类型的库依赖。这个库依赖关系足以填充IAT。只使用函数printf()的C ++程序将导致在IAT中有少量条目。

正如您所列,正常的可执行文件将在IAT中包含大量条目。有人做加密来保护可执行文件。他们将使用一种称为IAT Mangling的技术。它们将大大减少IAT中存在的条目。

实际上,至少,导入表应包含“Kernel32.dll”的模块条目,该条目应包含“LoadLibrary”和“GetProcAddress”API的子部分。了解Windows Loader如何加载并开始执行可执行文件将有助于理解IAT所扮演的关键角色。

每当Loader加载一个可执行文件时,它将检查IAT的完整性。任何不匹配(例如缺少DLL,函数签名不匹配)都将取消可执行文件的执行。

Matt Pietrek撰写了一系列有关Win PE的学术文章。它清楚地解释了IAT所起的作用。您可以从here阅读。

顺便说一句,如果您的目标是缩小可执行文件的大小,请查看有关吸脂工具的this文章。