系统消息 发表于 2019-9-22 18:12:55

【C++】VC生成PE文件脱离C库的同时支持C艹的全局变量初始化和析构

本帖最后由 系统消息 于 2019-9-22 18:59 编辑

原帖链接:【C++】VC生成PE文件脱离C库的同时支持C艹的全局变量初始化和析构 https://www.0xaa55.com/thread-25869-1-1.html
(出处: 技术宅的结界,转载请保留出处。)

平常我们用VC生成的PE(比如exe、dll等)文件,都是依赖各种CRT和STL运行库的,关键是每个VC都各自依赖一个不同的版本。另外使用静态C库的话,生成的exe、dll文件又很大。对于我们基本上全用WinAPI写程序来说,基本上是不需要使用到C库的,脱离C库的方法网上是有很多,原理就是程序不去调用C库提供的函数,包含主函数(main、wmain、WinMain、wWinMain、DllMain)都不能使用(使用自定义入口代替)。当我们使用脱离C库后会发现,如果我们是用C语言写程序还好,C艹有一些语法会隐式的涉及到CRT函数调用(比如new、delete、异常等),这些都有一定的解决方法,自定义入口之后,还会发现C艹的动态初始化机制失效了(比如全局变量初始化为一个函数的返回值,带构造函数和析构函数的全局对象),这方面网上很少见到有资料提到,不过我在偶然间发现了CRT的实现原理。
编译自动生成全局变量动态初始化的函数地址会放到 .CRT$XCA 节和 .CRT$XCZ 之间,所以我们可以在进入自定义入口时马上把这些节中的所有初始化函数按顺序挨个调用一遍,就可以实现脱离C库的同时支持全局变量动态初始化,不过我们还要在考虑C艹对象存在析构函数的现象,全局对象在程序启动时调用了构造函数,那么同理在程序退出之前需要调用析构函数,还有静态局部变量虽然是延迟初始化机制(当第一次执行到初始化代码时执行,下次再执行到时跳过初始化代码),但它同样得保证在程序结束之前安全的执行析构函数(并且保证先构造的一定要后析构)。对编译器生成的全局对象初始化代码反汇编跟踪下来发现,原来VC是通过在构造函数执行成功后,再把析构函数的地址注册到atexit函数,当程序调用exit退出时(标准的main返回后也会调用exit函数),exit会按倒序执行所有atexit注册的退出函数。因此我们要脱离C库的话,是绝对不能使用CRT提供的atexit和exit的,不过我们自己重写一个atexit函数替换掉CRT的atexit,并且自己保证在程序退出前按倒序执行所有析构函数(比如exe在调用ExitProcess之前执行全局析构,dll在入口函数参数为DLL_PROCESS_DETACH时执行全局析构)。
附加中提供的 rawcppinit.h 和 rawcppinit.c,即为裸C艹初始化库(开发者可以根据自己需要来选择在合适的时机分别调用 _initrawcpp 和 _uninitrawcpp 来初始化和析构全局对象),main.cpp 是测试Demo源码,要看测试Demo运行结果请运行test.bat(而不是test.exe,bat会在exe结束后暂停,方便你看结果)。

Ayala 发表于 2019-9-22 21:30:31

c++版本大点就大点吧 更新太频繁了 如果为了追求小 直接用c更好些

唐凌 发表于 2019-9-23 00:27:40

不是很懂你们C艹,反正用wdk写exe dll的话直接就依赖msvcrt.dll,就算用标准库也能全平台兼容,也就是_s的安全函数用起来蛋疼,不兼容xp而已。

系统消息 发表于 2019-9-23 21:54:59

tangptr@126.com 发表于 2019-9-23 00:27
不是很懂你们C艹,反正用wdk写exe dll的话直接就依赖msvcrt.dll,就算用标准库也能全平台兼容,也就是_s的 ...

有时候连msvcrt.dll也不想依赖,就适合用我这套机制了

系统消息 发表于 2019-9-23 21:57:03

Ayala 发表于 2019-9-22 21:30
c++版本大点就大点吧 更新太频繁了 如果为了追求小 直接用c更好些

怎么说呢?主要是有很多dll,我完全是封装的API或自己写的算法,完全用不到C库。

Ayala 发表于 2019-9-25 21:22:25

系统消息 发表于 2019-9-23 21:54
有时候连msvcrt.dll也不想依赖,就适合用我这套机制了

静态链接可以单函数链接。我写shellcode都不想用user32.dll呢,c++的 safecrt更新太频繁了 自己实现维护成本有点高。不过适合开发pe系统下的工具还是很赞的

系统消息 发表于 2019-9-26 23:22:19

Ayala 发表于 2019-9-25 21:22
静态链接可以单函数链接。我写shellcode都不想用user32.dll呢,c++的 safecrt更新太频繁了 自己实现维护 ...

可以把crt函数链接到ntdll上,再结合我这个初始化就完美了

Ayala 发表于 2019-9-29 20:58:08

系统消息 发表于 2019-9-26 23:22
可以把crt函数链接到ntdll上,再结合我这个初始化就完美了

ntdll里可没有c++的safecrt 只有几个vc的基本crt函数

系统消息 发表于 2019-9-30 17:25:09

Ayala 发表于 2019-9-29 20:58
ntdll里可没有c++的safecrt 只有几个vc的基本crt函数

Win10的ntdll倒是有_s函数,不过我还是更倾向于使用n版函数(比如snprintf代替sprint_s)。
页: [1]
查看完整版本: 【C++】VC生成PE文件脱离C库的同时支持C艹的全局变量初始化和析构