【水·技术】浅谈Windows 10 Build 9879的磁盘清理的System Compress?
PS:估计看完这篇文章,巨神们可能会觉得我的帖子有些不值一提。在这种情况下,就当是我在水中的经历吧。
PS:感谢@ Buzi、@ zifeityzyicq和@ART-Master,没有他们,我无法体验水。
附言:以下文字开始。
说到Windows 10 Build 9879的新功能,磁盘清理的系统压缩肯定会引起注意。昨天试了一下,效果很棒(驱优艾设计网_在线设计动器C增加了10GB的可用空间);但这引起了我的好奇心。直觉告诉我应该是NTFS压缩。然而,当我漫不经心地看着系统盘下一个文件的属性时,我傻眼了。
上面是ntoskrnl.exe属性的截图。不检查NTFS压缩,通过查看占用率和大小两列可以明显看出是压缩的。
.“微软是怎么做到这个黑科技的?”.我的疑惑越来越大,终于要和IDA一起拆解cleanmgr.exe了。
但是反编译后发现cleanmgr.exe没有内置的清理列表。但是一个注册表项“HKEY本地机器\软件\微软\视窗\当前版本\浏览器\卷缓存”启发了我。我想这应该是cleanmgr的清理列表,注册表打开是真的。浏览系统压缩子项,如图所示
一般人大概觉得这里没什么特别就离开了,但是我发现了区别。我立即将该值的(默认)GUID放入注册表编辑器的搜索选项中,发现系统压缩是通过调用WofDsCln.dll实现的。所以我要去SysWOW64找这个文件(因为32位IDA不能反汇编64位PE文件),但是找不到;我去袁晶求助,感谢包子君送我32 WofDsCln.dll。
当我寻求帮助时,我没有忘记用7zip检查WofDsCln.dll的内容。粗略看了一下,注意到一个叫的函数,就是DeviceIOControl和GetCompressedFileSizeW;我问zifeityzyicq,他告诉我估计是一种新的NTFS压缩算法,看看传入DeviceIOControl的参数是什么。
过了一会儿,新的QQ消息来了。原来是包子发的文件。万岁!我终于可以放大了。
我跟IDA粗略看了一下,也学到了系统压缩的原理(后面会解释)。本来想写一个Demo(非常感谢ART-Master的指导,虽然最后没有写出来,但是感觉很愧疚)。结果,在代码调试和错误生成中出现了错误。
代码0x00000157(即请提供提供者);所以只好放弃(不好意思),反汇编后粘贴主操作的C伪代码。
char _ _ fast call CompressFile(void * a1,const WCHAR *a2,void *a3,无符号__int16 *a4,struct _WIN32_FIND_DATAW *a5,struct _COMPRESS_STATS *a6)
{
char v6//zf@1
无符号int v8//ecx@3
int v9//eax@3
char v10//bl@6
无符号_ _ int8 v11//cf@6
const WCHAR * v12//ecx@7
const WCHAR v13//ax@8
int v14//ecx@9
const wchar _ t * v15//edi@10
DWORD v16//eax@19
HANDLE v17//ecx@21
int v18//edi@24
const WCHAR * lpFileName//[sp 10h] [bp-30h]@1
int v20//[sp 14h] [bp-2Ch]@3
DWORD BytesReturned//[sp 18h] [bp-28h]@13
int v22//[sp 1Ch] [bp-24h]@3
DWORD v23//[sp 20h] [bp-20h]@19
句柄文件大小高;//[sp 24h] [bp-1Ch]@1
int OverFever;//[sp 28h] [bp-18h]@13
int v26//[sp 2Ch] [bp-14h]@16
int v27//[sp 30h] [bp-10h]@16
无符号_ _ int32 v28//[sp 34h] [bp-Ch]@16
int v29//[sp 38h] [bp-8h]@16
V6=(*(_ BYTE *)a30x 10)=0;
lpFileName=a2
FileSizeHigh=a1
if(!v6)
返回1;
V8=*(_ DWORD *)a3 8);
v9=*(_ DWORD *)a3
7);v20 = *((_DWORD *)a3 + 8);
v22 = v9;
if ( v9 > 0 || v9 >= 0 && v8 >= 0x2000 )
{
v12 = a2;
do
{
v13 = *v12;
++v12;
}
while ( v13 );
v14 = v12 - (a2 + 1);
v10 = 1;
if ( (unsigned int)v14 <= 4 || (v15 = &a2[v14 - 4], __wcsicmp(v15, L".exe")) && __wcsicmp(v15, L".dll") )
{
v11 = __CFADD__((*((_DWORD *)a4 + 8))++, 1);
*((_DWORD *)a4 + 9) += v11;
}
if ( DeviceIoControl(FileSizeHigh, 0x90310u, NULL, 0, &OutBuffer, 0x14u, &BytesReturned, NULL)
|| GetLastError() == 234
|| GetLastError() == 122
|| (v29 = 0,
v28 = WofAlgorithm,
OutBuffer = 1,
v26 = 2,
v27 = 1,
!DeviceIoControl(FileSizeHigh, 0x9030Cu, &OutBuffer, 0x14u, NULL, 0, &BytesReturned, NULL))
&& GetLastError() != 344
&& GetLastError() != 317 )
return v10;
v16 = GetCompressedFileSizeW(lpFileName, (LPDWORD)&FileSizeHigh);
v23 = v16;
if ( v16 == -1 )
{
if ( GetLastError() )
{
v16 = 0;
v17 = NULL;
LABEL_24:
v18 = v22;
if ( !v20 )
{
if ( !v22 )
{
v17 = NULL;
v16 = 0;
}
}
v11 = __CFADD__(v20, *((_DWORD *)a4 + 12));
*((_DWORD *)a4 + 12) += v20;
*((_DWORD *)a4 + 13) += v18 + v11;
v11 = __CFADD__(v16, *((_DWORD *)a4 + 16));
*((_DWORD *)a4 + 16) += v16;
*((_DWORD *)a4 + 17) += (char *)v17 + v11;
v11 = __CFADD__((*((_DWORD *)a4 + 2))++, 1);
*((_DWORD *)a4 + 3) += v11;
return v10;
}
v16 = v23;
}
v17 = FileSizeHigh;
goto LABEL_24;
}
v10 = 1;
v11 = __CFADD__((*((_DWORD *)a4 + 10))++, 1);
*((_DWORD *)a4 + 11) += v11;
return v10;
}
总体来说,这个System Compression的原理还是挺搞笑的,那就是把Windows目录和Program Files目录下的所有的EXE和DLL文件采用WofAlgorithm压缩(Wof算法,估计有人会疑问,说白了就是对每个文件进行WIMBoot压缩)
顺便也想说,去MSDN查了查那个IO码,也就是FSCTL_SET_EXTERNAL_BACKING和FSCTL_GET_EXTERNAL_BACKING;最低要求Windows 8.1 Update;但是微软在C++的头文件里写最低要求Win7?莫非是WIMBoot早就在Win7就策划好了?@vb4112 麻烦巨神解答一下
如果有大神可以写出Demo,希望可以Open Source让我们这群小白拜读,感激不尽
更多Windows 10 技巧讨论,请移步至远景论坛 Windows 10版块(http://bbs.pcbeta.com/forum-548-1.html)
精彩评论