NtDll是否真的导出C运行时函数,并且可以在我的应用程序中使用它们吗? [英] Does NtDll really export C runtime functions, and can I use these in my application?

查看:126
本文介绍了NtDll是否真的导出C运行时函数,并且可以在我的应用程序中使用它们吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Windows 10计算机上查看了NtDll导出表,发现它可以导出标准的C运行时函数,例如 memcpy sprintf strlen 等。

I was looking at the NtDll export table on my Windows 10 computer, and I found that it exports standard C runtime functions, like memcpy, sprintf, strlen, etc.

这意味着我可以动态调用它们在运行时通过 LoadLibrary GetProcAddress

Does that mean that I can call them dynamically at runtime through LoadLibrary and GetProcAddress? Is this guaranteed to be the case for every Windows version?

如果是这样,可以完全删除C运行时库(仅使用NtDll的CRT函数)即可。

If so, it is possible to drop the C runtime library altogether (by just using the CRT functions from NtDll), therefore making my program smaller?

推荐答案

绝对没有理由调用这些由NtDll导出的未记录的函数。 Windows将所有必需的C运行时函数导出为标准系统库(即Kernel32)中记录的包装器。如果绝对无法链接到C运行时库 * ,则应调用这些函数。对于内存,您有基本的 HeapAlloc HeapFree (或者也许是 VirtualAlloc VirtualFree ), ZeroMemory FillMemory MoveMemory CopyMemory 等。对于字符串操作,重要的CRT功能都在那里,并带有<$ c前缀$ c> l : lstrlen lstrcat lstrcpy lstrcmp 等。奇怪的人是 wsprintf (及其兄弟 wvsprintf ),它不仅具有不同的前缀,而且不支持浮点值(Windows早期在首次导出这些函数时并没有浮点代码,还有很多其他辅助功能,它们可以复制CRT中的功能,例如 IsCharLower CharLower CharLowerBuff 等。

There is absolutely no reason to call these undocumented functions exported by NtDll. Windows exports all of the essential C runtime functions as documented wrappers from the standard system libraries, namely Kernel32. If you absolutely cannot link to the C Runtime Library*, then you should be calling these functions. For memory, you have the basic HeapAlloc and HeapFree (or perhaps VirtualAlloc and VirtualFree), ZeroMemory, FillMemory, MoveMemory, CopyMemory, etc. For string manipulation, the important CRT functions are all there, prefixed with an l: lstrlen, lstrcat, lstrcpy, lstrcmp, etc. The odd man out is wsprintf (and its brother wvsprintf), which not only has a different prefix but also doesn't support floating-point values (Windows itself had no floating-point code in the early days when these functions were first exported and documented.) There are a variety of other helper functions, too, that replicate functionality in the CRT, like IsCharLower, CharLower, CharLowerBuff, etc.

这是一篇古老的知识库文章,其中记录了一些< a href = https://support.microsoft.com/en-us/kb/99456> C运行时功能的Win32等效项。如果要重新实现CRT的功能,可能还需要其他相关的Win32功能,但这是直接的直接替换。

Here is an old knowledge base article that documents some of the Win32 Equivalents for C Run-Time Functions. There are likely other relevant Win32 functions that you would probably need if you were re-implementing the functionality of the CRT, but these are the direct, drop-in replacements.

其中一些是操作系统的基础结构绝对需要的,任何CRT实现都将在内部调用它们。此类别包括 HeapAlloc HeapFree 之类的东西,它们是操作系统的职责。运行时库仅将它们包装起来,在基本的OS级别详细信息之上提供了一个不错的standard-C接口和一些其他好处。其他功能,例如字符串操作功能,只是围绕内部Windows版本的CRT导出的包装程序(除了它是CRT的真正旧版本,在历史上的某个时候修复了,除了可能已修复的重大安全漏洞外)这些年来)。还有一些几乎完全是多余的,或者似乎是多余的,例如 ZeroMemory MoveMemory ,但实际上已导出以便它们可以可以在没有C运行时库的环境中使用,例如经典的Visual Basic(VB  6)。

Some of these are absolutely required by the infrastructure of the operating system, and would be called internally by any CRT implementation. This category includes things like HeapAlloc and HeapFree, which are the responsibility of the operating system. A runtime library only wraps those, providing a nice standard-C interface and some other niceties on top of the nitty-gritty OS-level details. Others, like the string manipulation functions, are just exported wrappers around an internal Windows version of the CRT (except that it's a really old version of the CRT, fixed back at some time in history, save for possibly major security holes that have gotten patched over the years). Still others are almost completely superfluous, or seem so, like ZeroMemory and MoveMemory, but are actually exported so that they can be used from environments where there is no C Runtime Library, like classic Visual Basic (VB 6).

指出许多简单的 C运行时库函数由Microsoft(和其他供应商)的编译器以 固有函数,并进行了特殊处理。这意味着可以对其进行高度优化。基本上,相关的目标代码是直接在应用程序的二进制文件中以内联方式发出的,从而避免了潜在的昂贵函数调用。允许编译器为一直被调用的 strlen 之类的代码生成内联代码几乎无疑会导致比不必支付调用函数的性能更好的性能。导出的Windows API之一。编译器无法内联 lstrlen ;就像其他函数一样被调用。这使您回到速度和尺寸之间的经典权衡。有时,较小的二进制文件速度更快,但有时并非如此。不必链接CRT会产生较小的二进制文件,因为它使用函数调用而不是内联实现,但在一般情况下可能不会产生更快的代码。

It is also interesting to point out that many of the "simple" C Runtime Library functions are implemented by Microsoft's (and other vendors') compiler as intrinsic functions, with special handling. This means that they can be highly optimized. Basically, the relevant object code is emitted inline, directly in your application's binary, avoiding the need for a potentially expensive function call. Allowing the compiler to generate inlined code for something like strlen, that gets called all the time, will almost undoubtedly lead to better performance than having to pay the cost of a function call to one of the exported Windows APIs. There is no way for the compiler to "inline" lstrlen; it gets called just like any other function. This gets you back to the classic tradeoff between speed and size. Sometimes a smaller binary is faster, but sometimes it's not. Not having to link the CRT will produce a smaller binary, since it uses function calls rather than inline implementations, but probably won't produce faster code in the general case.

* 但是,出于各种原因,您确实应该链接到与编译器捆绑在一起的C运行时库,其中至少包括可以分发的安全更新。通过运行时库的更新版本升级到操作系统的所有版本。您必须有一个非常好的理由,不要使用CRT,例如,如果您要构建世界上最小的可执行文件。而没有这些功能仅是您的第一个障碍。 CRT为您处理了很多您通常不需要考虑的事情,例如启动和运行进程,设置标准C或C ++环境,解析命令行参数,运行静态初始化程序,实现构造函数。和析构函数(如果您正在编写C ++),则支持结构化异常处理(SEH,也用于C ++异常)等等。我已经有了一个简单的C应用程序,可以在不依赖CRT的情况下进行编译,但是花了很多时间,而且我肯定不会推荐它用于任何严重的问题。马修·威尔逊(Matthew Wilson)很久以前写了一篇有关避免视觉的文章C ++运行时库。由于它专注于Visual C ++ 6开发环境,因此它已经过时了,但是很多重要的东西仍然有用。我清楚地记得,Matt Pietrek也是很久以前在《 Microsoft Journal》上写过一篇有关此文章的文章,但是我在网上的任何地方都找不到它的副本(所有链接似乎都死了)。

* However, you really should be linking to the C Runtime Library bundled with your compiler, for a variety of reasons, not the least of which is security updates that can be distributed to all versions of the operating system via updated versions of the runtime libraries. You have to have a really good reason not to use the CRT, such as if you are trying to build the world's smallest executable. And not having these functions available will only be the first of your hurdles. The CRT handles a lot of stuff for you that you don't normally even have to think about, like getting the process up and running, setting up a standard C or C++ environment, parsing the command line arguments, running static initializers, implementing constructors and destructors (if you're writing C++), supporting structured exception handling (SEH, which is used for C++ exceptions, too) and so on. I have gotten a simple C app to compile without a dependency on the CRT, but it took quite a bit of fiddling, and I certainly wouldn't recommend it for anything remotely serious. Matthew Wilson wrote an article a long time ago about Avoiding the Visual C++ Runtime Library. It is largely out of date, because it focuses on the Visual C++ 6 development environment, but a lot of the big picture stuff is still relevant. I distinctly remember that Matt Pietrek wrote an article about this in the Microsoft Journal a long while ago, too, but I can't find a copy of it anywhere online (all the links seem to be dead).

如果您只需要在应用程序中分发C运行时库DLL,则可以考虑静态链接到CRT。这会将代码嵌入到可执行文件中,从而消除了对单独DLL的需求。同样,这会使您的可执行文件肿,但确实使它的部署更简单,而不需要安装程序或ZIP文件。自然,最大的警告是您无法从CRT DLL的增量安全更新中受益;您必须重新编译并重新分发应用程序才能获得这些修复程序。对于没有其他依赖关系的玩具应用程序,我经常选择静态链接。否则,仍然建议使用动态链接。

If your concern is just the need to distribute the C Runtime Library DLL(s) alongside your application, you can consider statically linking to the CRT. This embeds the code into your executable, and eliminates the requirement for the separate DLLs. Again, this bloats your executable, but does make it simpler to deploy without the need for an installer or even a ZIP file. The big caveat of this, naturally, is that you cannot benefit to incremental security updates to the CRT DLLs; you have to recompile and redistribute the application to get those fixes. For toy apps with no other dependencies, I often choose to statically link; otherwise, dynamically linking is still the recommended scenario.

这篇关于NtDll是否真的导出C运行时函数,并且可以在我的应用程序中使用它们吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆