吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 25364|回复: 10
上一主题 下一主题
收起左侧

[C&C++ 转载] 【技术·水】浅谈Windows10的CompactOS特性

  [复制链接]
跳转到指定楼层
楼主
Mouri_Naruto 发表于 2016-8-16 19:41 回帖奖励
本帖最后由 Mouri_Naruto 于 2016-8-16 19:56 编辑

================================注释开始================================
转载前最好告知楼主一声

感谢不离不弃的包子,zifeityzyicq和ART-Master

本技术贴原名《【水·技术】浅谈Windows 10 Build 9879的磁盘清理的System Compression》
远景地址:http://bbs.pcbeta.com/viewthread-1567726-1-1.html
================================注释结束================================

一:前言

上次,我在远景发布了《【水·技术】浅谈Windows 10 Build 9879的磁盘清理的System Compression》;
虽然文笔稚嫩(可以算黑历史了),但依旧上了远景首页

这个帖子发布了快两年了,这个世界也有了不少变化

Windows10早已从Build 9879进入到了Build 14901;
System Compression也改名为CompactOS;
Windows10下可以使用compact命令行工具;Win7/8/8.1也有Dism++可以帮你;
MSDN也公开了CompactOS的调用方法

在这样的情形下,我打算写个总结帖子

二:CompactOS原理

CompactOS是通过Windows Overlay Filter过滤驱动实现的,该过滤驱动同时也负责WIMBoot的实现

CompactOS在一般人看来如同NTFS压缩和Bitlocker加密一样是透明的
但是CompactOS可以选用压缩率更高的用于压缩WIM文件的算法,你可以使用以下算法

XPRESS4K(WIMBoot压缩算法,CompactOS默认算法;压缩率最低,速度最快)
XPRESS8K
XPRESS16K
LZX(WIM最大压缩;压缩率最高,速度最慢)

于是这也是CompactOS比只使用LZNT压缩算法的NTFS压缩压缩率更高的奥秘所在

三:如何使用CompactOS压缩

第一种途径,你可以通过Windows10开始系统自带的compact命令行工具对文件使用CompactOS压缩

这个用法只适用于Windows 10 Build 10074或更高版本

同时按下键盘上的Win和X键,出现菜单;点击命令提示符(管理员);
接下来弹出用户账户控制对话框,点是就出现了命令提示符窗口。


若安装系统时想对系统文件使用默认CompactOS算法进行全盘压缩,可以执行这样的指令:
DISM /Apply-Image /ImageFile:install.wim /Index:1/ApplyDir:D:\ /compact (D为系统盘符)

如果你要查询你的系统有没有被CompactOS,可以在管理员权限的命令提示符下输入以下命令并回车(在线系统适用)
compact /compactos:query
如果你的系统被CompactOS的话,会显示以下信息:“系统处于压缩状态。它将保持此状态,除非管理员更改它。”

如果你想要进行OSCompact的话,可以在管理员权限的命令提示符下输入以下命令并回车(在线系统适用)
compact /compactos:always

如果你要撤销OSCompact,可以在管理员权限的命令提示符下输入以下命令并回车(在线系统适用)
compact /compactos:never

如果你想单独对一个文件进行CompactOS压缩,那怎么办呢?下面举个例子

如果我要对E:\ToolKit\procexp.exe进行lzx算法的Compact压缩,我可以输入以下命令并回车(在线和离线都可以)。
compact /c /exe:lzx E:\ToolKit\procexp.exe

既然介绍了压缩,那么介绍如何解压也是不可少的。
compact /u /exe E:\ToolKit\procexp.exe

如果你的系统不符合要求,或者不习惯命令提示符操作,推荐使用Dism++。使用方法参考Dism++的相关说明,这里不再叙述。

第二种途径,通过API调用对文件进行CompactOS压缩


你可以通过DeviceIoControl传入相应IO控制码实现对文件的CompactOS压缩

SDK要求Windows 10 Build 10240及之后版本;且使用CompactOS前要
#include <winioctl.h>

而且CompactOS压缩对传入和传出的结构有要求
WOF_EXTERNAL_INFO和FILE_PROVIDER_EXTERNAL_INFO_V1这两个结构的内容要放在一个Buffer内传输
且WOF_EXTERNAL_INFO结构的内容要放在FILE_PROVIDER_EXTERNAL_INFO_V1结构内容的前面


为了方便起见,我定义了一个结构
[C++] 纯文本查看 复制代码
1
2
3
4
5
typedef struct _WOF_FILE_EXTERNAL_BACKING_V1
{
        WOF_EXTERNAL_INFO WofInfo;
        FILE_PROVIDER_EXTERNAL_INFO_V1 FileProviderInfo;
} WOF_FILE_EXTERNAL_BACKING_V1, *PWOF_FILE_EXTERNAL_BACKING_V1;


FSCTL_SET_EXTERNAL_BACKING - 压缩
FSCTL_GET_EXTERNAL_BACKING - 获取压缩信息
FSCTL_DELETE_EXTERNAL_BACKING - 解压缩


PS:CompactOS压缩过的文件,如果以可写方式打开系统会自动解压缩文件(也许微软这么做是为了保证性能)

为了方便起见,我用NativeAPI对CompactOS的调用做了封装

CompactLib.h
[C++] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// CompactLib By Mouri_Naruto
 
#pragma once
 
// Wof压缩算法定义
 
#define FILE_PROVIDER_COMPRESSION_XPRESS4K   (0x00000000)
#define FILE_PROVIDER_COMPRESSION_LZX        (0x00000001)
#define FILE_PROVIDER_COMPRESSION_XPRESS8K   (0x00000002)
#define FILE_PROVIDER_COMPRESSION_XPRESS16K  (0x00000003)
#define FILE_PROVIDER_COMPRESSION_MAXIMUM    (0x00000004)
 
/*
对指定文件执行Wof压缩
*/
HRESULT WINAPI WofCompactFile(
    _In_ HANDLE FileHandle,
    _In_ DWORD CompactAlgorithm
    );
 
/*
对指定文件执行Wof解压缩
*/
HRESULT WINAPI WofUnCompactFile(
    _In_ HANDLE FileHandle
    );
 
/*
获取指定文件的Wof压缩算法
(如果文件未压缩或者执行失败返回 -1,否则为Wof压缩算法定义值)
*/
DWORD WINAPI WofGetFileCompactAlgorithm(
    _In_ HANDLE FileHandle
    );
 
/*
对指定文件执行NTFS压缩
*/
HRESULT WINAPI NTFSCompactFile(
    _In_ HANDLE FileHandle
    );
 
/*
对指定文件执行NTFS解压缩
*/
HRESULT WINAPI NTFSUnCompactFile(
    _In_ HANDLE FileHandle
    );


CompactLib.cpp

[C++] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// CompactLib By Mouri_Naruto
 
#include <Windows.h>
 
#include "CompactLib.h"
 
#ifndef NativeAPI
#define NativeAPI
 
#pragma comment(lib,"ntdll.lib")
 
#define NT_SUCCESS(status) ((NTSTATUS)(status) >= 0)
 
typedef struct _IO_STATUS_BLOCK
{
    union
    {
        NTSTATUS Status;
        PVOID Pointer;
    };
    ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
 
typedef VOID(NTAPI *PIO_APC_ROUTINE)(
    _In_ PVOID ApcContext,
    _In_ PIO_STATUS_BLOCK IoStatusBlock,
    _In_ ULONG Reserved
    );
 
extern "C"
{
    NTSYSCALLAPI NTSTATUS NTAPI NtFsControlFile(
        _In_ HANDLE FileHandle,
        _In_opt_ HANDLE Event,
        _In_opt_ PIO_APC_ROUTINE ApcRoutine,
        _In_opt_ PVOID ApcContext,
        _Out_ PIO_STATUS_BLOCK IoStatusBlock,
        _In_ ULONG FsControlCode,
        _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
        _In_ ULONG InputBufferLength,
        _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
        _In_ ULONG OutputBufferLength
        );
 
    NTSYSAPI ULONG NTAPI RtlNtStatusToDosError(
        _In_ NTSTATUS Status
        );
}
#endif
 
#include <winioctl.h>
 
typedef struct _WOF_FILE_EXTERNAL_BACKING_V1
{
    WOF_EXTERNAL_INFO WofInfo;
    FILE_PROVIDER_EXTERNAL_INFO_V1 FileProviderInfo;
} WOF_FILE_EXTERNAL_BACKING_V1, *PWOF_FILE_EXTERNAL_BACKING_V1;
 
HRESULT WINAPI WofCompactFile(
    _In_ HANDLE FileHandle,
    _In_ DWORD CompactAlgorithm
    )
{
    if (WofGetFileCompactAlgorithm(FileHandle) == CompactAlgorithm)
        return S_OK;
     
    NTSTATUS status;
    IO_STATUS_BLOCK IoStatus = { 0 };
    WOF_FILE_EXTERNAL_BACKING_V1 WofFileInfo = { 0 };
 
    WofFileInfo.WofInfo.Version = WOF_CURRENT_VERSION;
    WofFileInfo.WofInfo.Provider = WOF_PROVIDER_FILE;
    WofFileInfo.FileProviderInfo.Version = FILE_PROVIDER_CURRENT_VERSION;
    WofFileInfo.FileProviderInfo.Algorithm = CompactAlgorithm;
    WofFileInfo.FileProviderInfo.Flags = 0;
 
    status = NtFsControlFile(
        FileHandle, NULL, NULL, NULL, &IoStatus, FSCTL_SET_EXTERNAL_BACKING,
        &WofFileInfo, sizeof(WofFileInfo), NULL, 0);
 
    return RtlNtStatusToDosError(status);
}
 
HRESULT WINAPI WofUnCompactFile(
    _In_ HANDLE FileHandle
    )
{
    NTSTATUS status;
    IO_STATUS_BLOCK IoStatus = { 0 };
 
    status = NtFsControlFile(
        FileHandle, NULL, NULL, NULL, &IoStatus,
        FSCTL_DELETE_EXTERNAL_BACKING, NULL, 0, NULL, 0);
 
    return RtlNtStatusToDosError(status);
}
 
DWORD WINAPI WofGetFileCompactAlgorithm(
    _In_ HANDLE FileHandle
    )
{
    NTSTATUS status;
    IO_STATUS_BLOCK IoStatus = { 0 };
    WOF_FILE_EXTERNAL_BACKING_V1 WofFileInfo = { 0 };
 
    status = NtFsControlFile(
        FileHandle, NULL, NULL, NULL, &IoStatus, FSCTL_GET_EXTERNAL_BACKING,
        NULL, 0, &WofFileInfo, sizeof(WofFileInfo));
 
    return !NT_SUCCESS(status) ? -1 : WofFileInfo.FileProviderInfo.Algorithm;
}
 
HRESULT WINAPI NTFSCompactFile(
    _In_ HANDLE FileHandle
    )
{
    NTSTATUS status;
    IO_STATUS_BLOCK IoStatus = { 0 };
    USHORT Type = COMPRESSION_FORMAT_DEFAULT;
 
    status = NtFsControlFile(
        FileHandle, NULL, NULL, NULL, &IoStatus,
        FSCTL_SET_COMPRESSION, &Type, sizeof(Type), NULL, 0);
 
    return RtlNtStatusToDosError(status);
}
 
HRESULT WINAPI NTFSUnCompactFile(
    _In_ HANDLE FileHandle
    )
{
    NTSTATUS status;
    IO_STATUS_BLOCK IoStatus = { 0 };
    USHORT Type = COMPRESSION_FORMAT_NONE;
 
    status = NtFsControlFile(
        FileHandle, NULL, NULL, NULL, &IoStatus,
        FSCTL_SET_COMPRESSION, &Type, sizeof(Type), NULL, 0);
 
    return RtlNtStatusToDosError(status);
}


四:性能影响和效果

度娘看了看,几乎都表示CompactOS基本上不会影响性能。但CompactOS易产生难整理型文件碎片,在机械硬盘上应注意。

下面附带下个人的体验
由于我使用了LZX算法,于是系统盘比以前腾出了将近一半的空间(原本占用50GB,现在25GB左右)
而且感受不到性能的损失,也许是我的CPU是E3 1230 V2,硬盘是256GB SSD的缘故吧

五:移植CompactOS特性到其他系统

前提条件系统是Windows 7/8/8.1及对应的服务器版本;而且你要使用Windows ADK 10的wofadk.sys

曾经和Dism++作者解决Dism++在Windows Vista下的兼容性问题时
发现Vista下一旦安装了wofadk驱动,bootmgr阶段会报错“启动文件证书无效”

而且你要排除Windows加载wofadk驱动前Windows需要用到的文件

详情可以参考无忧;或者你也可以使用Dism++

附:Windows10 CompactOS排除列表

IDA打开Windows10的compact.exe命令行工具就可以找到了)
[C++] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 文件排除列表
wchar_t *FileExclusionList[] =
{
        L"\\aow.wim",
        L"\\boot\\bcd",
        L"\\boot\\bcd.log",
        L"\\boot\\bootstat.dat",
        L"\\config\\drivers",
        L"\\config\\drivers.log",
        L"\\config\\system",
        L"\\config\\system.log",
        L"\\windows\\bootstat.dat",
        L"\\winload.efi",
        L"\\winload.efi.mui",
        L"\\winload.exe",
        L"\\winload.exe.mui",
        L"\\winresume.efi",
        L"\\winresume.efi.mui",
        L"\\winresume.exe",
        L"\\winresume.exe.mui"
};
 
// 目录排除列表
wchar_t *DirectoryExclusionList[] =
{
        L"\\Backup\\",
        L"\\ManifestCache\\",
        L"\\Manifests\\"
};


感谢阅读,毛利于2016/8/16



发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

沙发
Purewhite 发表于 2016-8-16 22:29
不明觉厉啊。。
3#
dapinggue 发表于 2016-8-16 23:11
4#
lolxzz 发表于 2016-8-18 06:38
5#
os51 发表于 2016-8-18 10:13
6#
 楼主| Mouri_Naruto 发表于 2016-8-18 12:33 |楼主
os51 发表于 2016-8-18 10:13
http://www.52pojie.cn/forum-24-1.html
建议放到这里

建议got,谢谢
7#
gcczm 发表于 2016-8-18 17:23

不明觉厉啊。。
8#
旧城迷梦 发表于 2016-8-18 19:08 来自手机
不明觉厉加1。。。
9#
chenmintian 发表于 2017-5-14 23:00
搜索到了.
谢楼主.
10#
anyta 发表于 2017-12-2 12:44

不明觉厉啊。。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-4-5 21:11

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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