.net PublishSingleFile 打包程序提取
- .net PublishSingleFile 打包程序提取
- 提取 Bundle 的常用方法
- 分界线
- 工具
- SingleFileExtractor (低版本)
- SelfContainedExtractor (.NET 5+)
- 定位offset
<PublishSingleFile>true</PublishSingleFile>
该部分内容为AI生成,仅供参考
.NET 的单文件发布模式会将所有应用程序代码、依赖项(包括运行时可能需要的依赖)以及运行时本身(如果选择自包含)都打包到一个单独的可执行文件中。这个可执行文件就像一个"容器"或"压缩包"。
- 运行机制:当运行这个单文件应用程序时,.NET 运行时会根据需要将内部的文件解压到临时目录(例如
%TEMP%\.net\
下特定名称的文件夹)然后加载运行,或者从内存中直接加载(.NET 5+ 更先进的模式)。 corehost
的角色:corehost
(如hostfxr
和hostpolicy
)是 .NET 运行时宿主组件,负责查找和初始化 .NET 运行时,解析依赖关系,并引导应用程序执行。它的主要任务是运行应用程序,
提取 Bundle 的常用方法
以下是更常用的从 .NET 单文件应用程序中提取内容的方法:
-
运行时提取(适用于基于磁盘解压的模式)
这是最简单的方法,尤其适用于 .NET Core 3.x 早期版本的模式。
步骤:- 运行打包好的单文件 EXE 程序。
- 在程序运行期间(切勿关闭程序),打开文件资源管理器。
- 在地址栏输入
%TEMP%
并回车,进入当前用户的临时文件夹。 - 在临时目录中查找类似
.net\你的应用程序名\
或带有随机字符串名称的文件夹。 - 在这个文件夹内,你就可以找到被解压出来的所有程序集(DLL)、配置文件(如
appsettings.json
)、资源文件等。
注意:
- 此方法需要你能成功运行目标程序。
- 程序退出后,操作系统可能会自动清理这些临时文件。
- 对于 .NET 5 及更高版本中使用更高阶模式(内存加载)发布的单文件,此方法可能无效,因为文件不会解压到磁盘。
分界线
工具
SingleFileExtractor (低版本)
(未测试)
Droppers/SingleFileExtractor: A tool for extracting contents (assemblies, configuration, etc.) from a single-file application to a directory, suitable for purposes like malware analysis.
SelfContainedExtractor (.NET 5+)
LukeFZ/SelfContainedExtractor: Standalone extractor for .NET 5+ self-contained executables.
(仅测试.NET 9)
修复offsetStr hex解析bug
https://github.com/LukeFZ/SelfContainedExtractor/blob/master/DotNetSelfContainedExtractor/Program.cs#L26
var parseResult = offsetStr.StartsWith("0x")? int.TryParse(offsetStr, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out offset): int.TryParse(offsetStr, CultureInfo.InvariantCulture, out offset);
==>
var parseResult = offsetStr.StartsWith("0x")? int.TryParse(offsetStr.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out offset): int.TryParse(offsetStr, CultureInfo.InvariantCulture, out offset);
去除Bundle.FindBundleOffset 函数(.net 9不适用,其他版本未知),必须指定参数 [bundle file offset]
定位offset
搜索字符串:“Bundle Header Offset:”,对应源码:https://github.com/dotnet/runtime/blob/main/src/native/corehost/corehost.cpp#L232
bundle_header_offset_ = placeholder__locator_bundle_header_offset;v35 = v71;if ( n7_6 > 7 )v35 = (void **)v71[0];trace::info_1405C81E0(L"Invoking fx resolver [%s] hostfxr_main_bundle_startupinfo", v35);v36 = v59;if ( si128.m128i_i64[1] > 7ui64 )v36 = (void **)v59[0];trace::info_1405C81E0(L"Host path: [%s]", v36);v37 = &v68;if ( n7_5 > 7 )v37 = (__int128 *)v68;trace::info_1405C81E0(L"Dotnet path: [%s]", v37);v38 = v57;if ( *((_QWORD *)&v58 + 1) > 7ui64 )v38 = (void **)v57[0];trace::info_1405C81E0(L"App path: [%s]", v38);trace::info_1405C81E0(L"Bundle Header Offset: [%lld]", bundle_header_offset_);
注意该指针存储的是文件偏移,(使用SelfContainedExtractor 指定参数时 不需要再计算偏移):
.data:00000001407D9CE8 ; __int64 placeholder__locator_bundle_header_offset
.data:00000001407D9CE8 placeholder__locator_bundle_header_offset dq 62C9E26h//示例中为dq 62C9E26h,则参数可指定为0x62C9E26 或者 103587366 (10进制则无需修改SelfContainedExtractor 工具代码)