构造超小程序

文章目录

  • 构造超小程序
    • 1 编译器-大小优化
    • 2 编译器-移除 C++ 异常
    • 3 链接器-移除所有依赖库
    • 4 移除所有函数依赖
      • _RTC_InitBase() _RTC_Shutdown()
      • __security_cookie __security_check_cookie()
      • __chkstk()
    • 5 链接器-移除清单文件
    • 6 链接器-移除调试信息
    • 7 链接器-关闭随机基址
    • 8 移除异常目录
    • 9 小结
  • 附录
    • 附录1 超小 Hello world 程序

构造超小程序

为了更方便查看编译结果的大小, 可以在 项目属性页>配置属性>生成事件>生成后事件>命令行 添加

powershell -Command "Write-Output 目标大小:%24((Get-Item '$(TargetPath)').Length)"

链接器警告 LINK : 已指定 /LTCG,但不需要生成代码;从链接命令行中移除 /LTCG 以提高链接器性能
可以到 项目属性页>配置属性>链接器>优化>链接时间代码生成 切换 默认配置 来关闭警告

从一个打印 “Hello world!” 的程序开始

#include <print>int main() {std::println("Hello world!");
}

Release 下构建结果大小: 18432B

1 编译器-大小优化

  • 项目属性页>配置属性>C/C++>优化>优化 选 最大优化(优选大小) (/O1)
  • 项目属性页>配置属性>C/C++>优化>优选大小或速度 选 代码大小优先 (/Os)

2 编译器-移除 C++ 异常

通知编译器禁用 C++ 异常

  • 项目属性页>配置属性>C/C++>代码生成>启用C++异常 选 否 (移除 /EH)

通知 C/C++ 库不使用 C++ 异常

  • 项目属性页>配置属性>C/C++>预处理器>预处理器定义 添加 _HAS_EXCEPTIONS=0

3 链接器-移除所有依赖库

  • 项目属性页>配置属性>链接器>输入>附加依赖项 清空, 手动输入下面要依赖的 kernel32.dll
  • 项目属性页>配置属性>链接器>输入>忽略所有默认库 选 是 (/NODEFAULTLIB)

只在代码里用 pragma 添加 /NODEFAULTLIB 并不够, 默认情况下新项目会通过附加依赖项直接指名链接库, 这些库不是通过选项 /DEFAULTLIB 附加的, 用 /NODEFAULTLIB 不能消除依赖

此时链接会报错, 下面来解决链接错误

4 移除所有函数依赖

std::println() 函数依赖 ucrtbase.dll 中的函数, CRT 库相关代码和依赖比较庞大

  • 改用 Windows API WriteConsole 函数 来输出

所用到的函数可以依赖 kernel32.dll

#include <Windows.h>int __stdcall mainCRTStartup(void* teb) {HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);WriteConsoleA(output, "Hello world!\n", 13, NULL, NULL);return 0;
}

现在 Release 大小: 3584B
用 Denpendencies 可以看到导入符号列表现在变得非常干净

_RTC_InitBase() _RTC_Shutdown()

Debug 下默认会开启基本运行时检查, 引入 _RTC_InitBase() 和 _RTC_Shutdown() 两个函数依赖

  • 项目属性页>配置属性>C/C++>代码生成>基本运行时检查 选 默认值 (移除 /RTC)

通常这两个函数随 msvcrt.lib 链接进入程序

__security_cookie __security_check_cookie()

部分函数尾部会被插入 cookie 检查函数, 引入 __security_check_cookie() 函数和 __security_cookie 变量依赖

  • 项目属性页>配置属性>C/C++>代码生成>安全检查 选 禁用安全检查 (/GS-)

通常这两个函数和变量随 msvcrt.lib 链接进入程序, 其中 __security_cookie 定义于 gs_cookie.c 中

__chkstk()

当栈空间占用可能超过 8KB 时(包括局部变量和 _alloca() 调用), 会引入 __chkstk() 函数依赖, 用于提交栈空间
属性页中没有相关配置开关, 需要手动填写选项来控制这个栈空间大小阈值

  • 项目属性页>配置属性>C/C++代码生成>命令行 填 /GsN 其中N是足够大的值

通常该函数在 kernelbase.dll 中导出

5 链接器-移除清单文件

清单文件用于声明系统本程序在启动时请求的资源, 包括请求管理员权限, WIndows版本兼容性, 高 DPI 声明, 视觉主题等, 但现在不需要

  • 项目属性页>配置属性>链接器>清单文件>生成清单 选 否 (/MANIFEST:NO)

.rsrc 节 将被移除

6 链接器-移除调试信息

调试信息用于帮助编译器定位每段机器码在源码文件中的位置, 移除将导致程序无法在源码中设置断点

  • 项目属性页>配置属性>链接器>调试>生成调试信息 选 否 (移除 /DEBUG)

用 /NOCOFFGRPINFO 移除调试目录

  • 项目属性页>配置属性>链接器>命令行 添加 /NOCOFFGRPINFO

7 链接器-关闭随机基址

一些防御技术依赖于随机基址, 关闭后可能导致程序更容易被攻击, 不要在生产环境关闭随机基址
关闭随机基址使得程序默认加载到 0x140000000 处, 可用 /BASE 改变默认基址

  • 项目属性页>配置属性>链接器>高级>固定基址 选 是 (/FIXED)
  • 项目属性页>配置属性>链接器>高级>随机基址 选 否 (/DYNAMICBASE:NO)

Debug 下的 .reloc 节 将被移除, 而 Release 下 .reloc 节本身就被优化合并了

8 移除异常目录

异常目录即 .pdata 节, 可指定当程序跑在某个函数崩溃后,有相对应的异常处理函数可供调用
移除并不会影响程序的正常运行
这篇 Stackoverflow 的回答指出异常目录是强制生成的, 但可以用 CFF Explorer 手动移除异常目录

9 小结

至此我们得到了一个彻底剥离所有基础设施的开发环境
程序大小从 18KB 缩小到 2KB 左右

想问更小的程序? 有的,兄弟😆
本文附录 1 给出一个超小程序, 在只使用 MSVC 工具并且不使用十六进制编辑器的前提下做到了 480B 的大小

附录

附录1 超小 Hello world 程序

C/C++ 生成的代码太长了, 用汇编吧

code
mainCRTStartup proc             ; rcx = PEB; rax = mainCRTStartup; r10, rdx, r8, r9  填函数 1~4 参数; rsp+28h ~ rsp+50h 填函数 5~9 参数mov byte ptr [rsp+38h],14   ; rsp+38h = Length        = 14mov ax,0008hmov qword ptr [rsp+30h],rax ; rsp+30h = Buffer        = "Hello world\n" 覆盖返回地址mov dword ptr [rsp+28h],eax ; rsp+28h = IoStatusBlock = Buffermov r10,qword ptr [rcx+20h]mov r10,qword ptr [r10+28h] ;     r10 = FileHandle    = Peb->ProcessParameter->StandardOutputxor edx,edx                 ;     rdx = Event         = NULLsyscall                     ;      ax = NtWriteFile   = 8ret
mainCRTStartup endp
end

用 /SECTION 先申请一个具有读, 写, 执行的全能节
然后用 /MERGE 将所有节包括代码节和数据节合并

/SECTION:.all,ERW /MERGE:.text=.all /MERGE:.data=.all /MERGE:.rdata=.all

用 /ALIGN 调整节的对齐大小, 默认值 512B 会导致节的尾部留下大量空白, 最小可设为 16 (只有 1 个节时才能非 512B 对齐加载)

/ALIGN:16

用 /BASE 选项设置基址到 0x80000000 用 32 位地址, 方便使用 32 指令节约代码大小

/BASE:0x80000000

新建一个 stub.txt 做 DOS 存根程序, 用 /STUB 使 stub.txt 替换默认的 DOS 头

/STUB:stub.txt

stub.txt 输入以下内容, 顺便在这里存放要输出的字符串

MZ234567Hello world!
012345678901234567890123456789012345678901

NtWriteFile 的 服务号 为 8, 将字符串设置从偏移 8 开始, 方便复用 rax 寄存器
文件以 MZ 起头, 用多余字符填充到刚好 64B 大小来满足链接器对存根程序的要求

程序大小 480B

用十六进制编辑器修改 PE 头还可以让程序更小, 懒得折腾了🐳

程序的PE头其实大部分字段都没有实际功能, 将程序的几个头部进行重叠可以得到更小的程序
Tiny PE 详细讨论了最小程序的构造方法, 得到了 133B 的程序, 文章还提到 97B 的程序, 但链接失效
只是现在 Windows 10 上加载器允许的最小程序大小是 268B
TinyPE on Win10: 268B 消息弹窗
runcalc.asm: 268B 启动附件计算器
smallEXE 收集了一些超小的程序
微软收录的文章 里也有关于最小程序的讨论
snake-qr: 2953B 贪吃蛇

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/899959.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大语言模型开发框架——LangChain

什么是LangChain LangChain是一个开发由语言模型驱动的应用程序的框架&#xff0c;它提供了一套工具、组件和接口&#xff0c;可以简化构建高级语言模型应用程序的过程。利用LangChain可以使应用程序具备两个能力&#xff1a; 上下文感知 将语言模型与上下文&#xff08;提示…

自动化释放linux服务器内存脚本

脚本说明 使用Linux的Cron定时任务结合Shell脚本来实现自动化的内存释放。 脚本用到sync系统命令 sync的作用&#xff1a;sync 是一个 Linux 系统命令&#xff0c;用于将文件系统缓存中的数据强制写入磁盘。 在你执行reboot、poweroff、shutdown命令时&#xff0c;系统会默认执…

Python Websockets库深度解析:构建高效的实时Web应用

引言 在现代Web开发中&#xff0c;实时通信已经成为许多应用的核心需求。无论是聊天应用、在线游戏、金融交易平台还是协作工具&#xff0c;都需要服务器和客户端之间建立持久、双向的通信通道。传统的HTTP协议由于其请求-响应模式&#xff0c;无法有效满足这些实时交互需求。…

【实用技巧】电脑重装后的Office下载和设置

写在前面&#xff1a;本博客仅作记录学习之用&#xff0c;部分图片来自网络&#xff0c;如需引用请注明出处&#xff0c;同时如有侵犯您的权益&#xff0c;请联系删除&#xff01; 文章目录 前言下载设置总结互动致谢参考目录导航 前言 在数字化办公时代&#xff0c;Windows和…

Node.js 技术原理分析系列 —— Node.js 调试能力分析

Node.js 技术原理分析系列 —— Node.js 调试能力分析 Node.js 作为一个强大的 JavaScript 运行时环境,提供了丰富的调试能力,帮助开发者诊断和解决应用程序中的问题。本文将深入分析 Node.js 的调试原理和各种调试技术。 1. Node.js 调试原理 1.1 V8 调试器集成 Node.js…

【图论】最短路径问题总结

一图胜千言 单源最短路径 正权值 朴素Dijkstra dijkstra算法思想是维护一个永久集合U&#xff0c;全部点集合V。 循环n -1次 从源点开始&#xff0c;在未被访问的节点中&#xff0c;选择距离源点最近的节点 t。 以节点 t 为中间节点&#xff0c;更新从起点到其他节点的最短…

【最佳实践】win11使用hyper-v安装ubuntu 22/centos,并配置固定ip,扫坑记录

文章目录 场景查看本机的win11版本启用hyper-vhyper-v安装ubuntu22虚拟机1.准备好个人的 iso文件。2. hyper-v 快速创建3.编辑设置分配内存自定义磁盘位置设置磁盘大小连接网络修改虚拟机名称自定义检查点位置 和智能分页件位置虚拟机第一次连接给ubuntu22配置固定ip遇到过的坑…

自然语言处理(25:(终章Attention 1.)Attention的结构​)

系列文章目录 终章 1&#xff1a;Attention的结构 终章 2&#xff1a;带Attention的seq2seq的实现 终章 3&#xff1a;Attention的评价 终章 4&#xff1a;关于Attention的其他话题 终章 5&#xff1a;Attention的应用 目录 系列文章目录 前言 Attention的结构 一.seq…

Git 命令大全:通俗易懂的指南

Git 命令大全&#xff1a;通俗易懂的指南 Git 是一个功能强大且广泛使用的版本控制系统。对于初学者来说&#xff0c;它可能看起来有些复杂&#xff0c;但了解一些常用的 Git 命令可以帮助你更好地管理代码和协作开发。本文将介绍一些常用的 Git 命令&#xff0c;并解释它们的…

基于yolov11的棉花品种分类检测系统python源码+pytorch模型+评估指标曲线+精美GUI界面

【算法介绍】 基于YOLOv11的棉花品种分类检测系统是一种高效、准确的农作物品种识别工具。该系统利用YOLOv11深度学习模型&#xff0c;能够实现对棉花主要品种&#xff0c;包括树棉&#xff08;G. arboreum&#xff09;、海岛棉&#xff08;G. barbadense&#xff09;、草棉&a…

论文:Generalized Category Discovery with Clustering Assignment Consistency

论文下载&#xff1a; https://arxiv.org/pdf/2310.19210 一、基本原理 该方法包括两个阶段:半监督表示学习和社区检测。在半监督表示学习中&#xff0c;使用了监督对比损失来充分地推导标记信息。此外&#xff0c;由于对比学习方法与协同训练假设一致&#xff0c;研究引入了…

Java高级JVM知识点记录,内存结构,垃圾回收,类文件结构,类加载器

JVM是Java高级部分&#xff0c;深入理解程序的运行及原理&#xff0c;面试中也问的比较多。 JVM是Java程序运行的虚拟机环境&#xff0c;实现了“一次编写&#xff0c;到处运行”。它负责将字节码解释或编译为机器码&#xff0c;管理内存和资源&#xff0c;并提供运行时环境&a…

MySQL 5.7 Online DDL 技术深度解析

14.13.1 在线DDL操作 索引操作主键操作列操作生成列操作外键操作表操作表空间操作分区操作 索引操作 下表概述了对索引操作的在线DDL支持情况。星号表示有附加信息、例外情况或依赖条件。有关详细信息&#xff0c;请参阅语法和使用说明。 操作原地执行重建表允许并发DML仅修…

kafka 报错消息太大解决方案 Broker: Message size too large

kafka-configs.sh --bootstrap-server localhost:9092 \ --alter --entity-type topics \ --entity-name sim_result_zy \ --add-config max.message.bytes10485880 学习营课程

HarmonyOS:ComposeTitleBar 组件自学指南

在日常的鸿蒙应用开发工作中&#xff0c;我们常常会面临构建美观且功能实用的用户界面的挑战。而标题栏作为应用界面的重要组成部分&#xff0c;它不仅承载着展示页面关键信息的重任&#xff0c;还能为用户提供便捷的操作入口。最近在参与的一个项目里&#xff0c;我就深深体会…

前端面试题之CSS中的box属性

前几天在面试中遇到面试官问了一个关于box的属性面试题&#xff0c;平时都是直接AI没有仔细去看过。来说说CSS中的常用box属性&#xff1a; 1. box-sizing box-sizing 属性定义了元素的宽度和高度是否包括内边距&#xff08;padding&#xff09;和边框&#xff08;border&…

前端开发时的内存泄漏问题

目录 &#x1f50d; 什么是内存泄漏&#xff08;Memory Leak&#xff09;&#xff1f;&#x1f6a8; 常见的内存泄漏场景1️⃣ 未清除的定时器&#xff08;setInterval / setTimeout&#xff09;2️⃣ 全局变量&#xff08;变量未正确释放&#xff09;3️⃣ 事件监听未清除4️⃣…

Java 基础-30-单例设计模式:懒汉式与饿汉式

在软件开发中&#xff0c;单例设计模式&#xff08;Singleton Design Pattern&#xff09;是一种常用的设计模式&#xff0c;它确保一个类只有一个实例&#xff0c;并提供一个全局访问点。这种模式通常用于管理共享资源&#xff08;如数据库连接池、线程池等&#xff09;或需要…

为 MinIO AIStor 引入模型上下文协议(MCP)服务器

Anthropic 最近宣布的模型上下文协议 &#xff08;MCP&#xff09; 将改变我们与技术交互的方式。它允许自然语言通信替换许多任务的复杂命令行语法。不仅如此&#xff0c;语言模型还可以总结传统工具的丰富输出&#xff0c;并以人类可读的形式呈现关键信息。MinIO 是世界领先的…

2023年12月电子学会青少年软件编程四级考级真题—新“跳7”游戏

此题可点下方去处查看&#xff0c;支持在线编程&#xff0c;获取源码&#xff1a; 新“跳7”游戏_scratch_少儿编程题库学习中心-嗨信奥https://www.hixinao.com/tiku/scratch/show-5109.html?_shareid3 程序演示可点击下方查看&#xff0c;支持源码查看&#xff1a;新“跳7…