找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 3678|回复: 8

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

[复制链接]

9

主题

176

回帖

1万

积分

用户组: 真·技术宅

UID
4293
精华
6
威望
441 点
宅币
8670 个
贡献
850 次
宅之契约
0 份
在线时间
338 小时
注册时间
2018-9-19
发表于 2019-9-22 18:12:55 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
本帖最后由 系统消息 于 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结束后暂停,方便你看结果)。

TestRawCppInit.zip

2.42 KB, 阅读权限: 1, 下载次数: 9

裸C艹初始化

回复

使用道具 举报

30

主题

210

回帖

2778

积分

用户组: 版主

UID
1821
精华
7
威望
69 点
宅币
2159 个
贡献
206 次
宅之契约
0 份
在线时间
480 小时
注册时间
2016-7-12
发表于 2019-9-22 21:30:31 | 显示全部楼层
c++版本大点就大点吧 更新太频繁了 如果为了追求小 直接用c更好些
回复 赞! 靠!

使用道具 举报

65

主题

115

回帖

1万

积分

用户组: 超级版主

OS与VM研究学者

UID
1043
精华
35
威望
789 点
宅币
8294 个
贡献
1094 次
宅之契约
0 份
在线时间
2067 小时
注册时间
2015-8-15
发表于 2019-9-23 00:27:40 | 显示全部楼层
不是很懂你们C艹,反正用wdk写exe dll的话直接就依赖msvcrt.dll,就算用标准库也能全平台兼容,也就是_s的安全函数用起来蛋疼,不兼容xp而已。
回复 赞! 靠!

使用道具 举报

9

主题

176

回帖

1万

积分

用户组: 真·技术宅

UID
4293
精华
6
威望
441 点
宅币
8670 个
贡献
850 次
宅之契约
0 份
在线时间
338 小时
注册时间
2018-9-19
 楼主| 发表于 2019-9-23 21:54:59 | 显示全部楼层
tangptr@126.com 发表于 2019-9-23 00:27
不是很懂你们C艹,反正用wdk写exe dll的话直接就依赖msvcrt.dll,就算用标准库也能全平台兼容,也就是_s的 ...

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

使用道具 举报

9

主题

176

回帖

1万

积分

用户组: 真·技术宅

UID
4293
精华
6
威望
441 点
宅币
8670 个
贡献
850 次
宅之契约
0 份
在线时间
338 小时
注册时间
2018-9-19
 楼主| 发表于 2019-9-23 21:57:03 | 显示全部楼层
Ayala 发表于 2019-9-22 21:30
c++版本大点就大点吧 更新太频繁了 如果为了追求小 直接用c更好些

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

使用道具 举报

30

主题

210

回帖

2778

积分

用户组: 版主

UID
1821
精华
7
威望
69 点
宅币
2159 个
贡献
206 次
宅之契约
0 份
在线时间
480 小时
注册时间
2016-7-12
发表于 2019-9-25 21:22:25 | 显示全部楼层
系统消息 发表于 2019-9-23 21:54
有时候连msvcrt.dll也不想依赖,就适合用我这套机制了

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

使用道具 举报

9

主题

176

回帖

1万

积分

用户组: 真·技术宅

UID
4293
精华
6
威望
441 点
宅币
8670 个
贡献
850 次
宅之契约
0 份
在线时间
338 小时
注册时间
2018-9-19
 楼主| 发表于 2019-9-26 23:22:19 | 显示全部楼层
Ayala 发表于 2019-9-25 21:22
静态链接可以单函数链接。我写shellcode都不想用user32.dll呢,c++的 safecrt更新太频繁了 自己实现维护 ...

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

使用道具 举报

30

主题

210

回帖

2778

积分

用户组: 版主

UID
1821
精华
7
威望
69 点
宅币
2159 个
贡献
206 次
宅之契约
0 份
在线时间
480 小时
注册时间
2016-7-12
发表于 2019-9-29 20:58:08 | 显示全部楼层
系统消息 发表于 2019-9-26 23:22
可以把crt函数链接到ntdll上,再结合我这个初始化就完美了

ntdll里可没有c++的safecrt 只有几个vc的基本crt函数
回复 赞! 靠!

使用道具 举报

9

主题

176

回帖

1万

积分

用户组: 真·技术宅

UID
4293
精华
6
威望
441 点
宅币
8670 个
贡献
850 次
宅之契约
0 份
在线时间
338 小时
注册时间
2018-9-19
 楼主| 发表于 2019-9-30 17:25:09 | 显示全部楼层
Ayala 发表于 2019-9-29 20:58
ntdll里可没有c++的safecrt 只有几个vc的基本crt函数

Win10的ntdll倒是有_s函数,不过我还是更倾向于使用n版函数(比如snprintf代替sprint_s)。
回复 赞! 靠!

使用道具 举报

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-4-20 11:04 , Processed in 0.040822 second(s), 33 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表