【水·技术】浅谈Windows 10 Build 9879的磁盘清理的System Compression-Windows,技术,清理-远景论坛-微软极客社区

PS:估计看完这篇文章的巨神们可能会认为我这个帖子有些微不足道,既然这样,就当我来水经验好了

 

PS:感谢@不离不弃的包子,@zifeityzyicq和@ART-Master ,没有他们,我也没有办法水经验

 

PS:以下正文开始

 

 

SystemCompression.jpg

 

 

 

说到Windows 10 Build 9879的新特性,磁盘清理的System Compression肯定会被注意到;我昨天试了一下,效果超级棒(C盘增加了10GB空闲空间);但这引起了我的好奇心,我的直觉告诉我,应该是NTFS压缩,但是,当我随便看一个系统盘下的文件的属性时让我目瞪口呆

 

 

NTOSKRNL.png

 

 

 

以上是ntoskrnl.exe的属性截图,NTFS压缩竟然不勾选,而且看占用和大小这两栏数字,明显发现是压缩过的

 

……“这种黑科技,微软是怎么做到的?”……我的疑惑越来越大,最终准备用IDA反汇编cleanmgr.exe

 

 

但是反编译后,发现cleanmgr.exe没有内建清理列表;但是一个注册表键“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches”给予了我灵感,我想这应该就是cleanmgr的清理列表,事实打开注册表也的确如此。浏览System Compression子键,如图

 

 

Regedit_1.png

 

 

 

一般的人估计觉得这里没有什么特别的就走了,但是,我却发现了不同。我马上把(默认)这个值的GUID放进注册表编辑器的搜索选项,结果发现System Compression是调用WofDsCln.dll实现的。于是我准备去SysWOW64去找这个文件(因为32位IDA不能反汇编64位PE文件),但是没有找到;我去远景求助,感谢包子君把32位的WofDsCln.dll发给我

 

当我求助的时候,也没有忘记用7zip查看WofDsCln.dll的内容,粗略看了看,调用的一个函数引起了我的注意,那就是DeviceIOControl和GetCompressedFileSizeW;我去问zifeityzyicq,他告诉我估计是NTFS压缩的新算法,看看传入DeviceIOControl的是什么参数。

 

一会儿QQ新消息来了,原来是包子把文件发来了,万岁!我终于可以放大招了

 

粗略的用IDA看了看,也了解了System Compression的原理(在最后会说明),本来想写个Demo的(非常感谢ART-Master的指导,虽然最后没有写出来,我觉得很愧疚),结果代码Debug出错,出错代

 

码是0x00000157(也就是请提供Provider);遂我只好放弃了(抱歉)

 

顺便把反汇编后的主要操作的C++伪代码贴一下

  1. char __fastcall CompressFile(void *a1, const WCHAR *a2, void *a3, unsigned __int16 *a4, struct _WIN32_FIND_DATAW *a5, struct _COMPRESS_STATS *a6)
  • {
  •   char v6; // zf@1
  •   unsigned int v8; // ecx@3
  •   int v9; // eax@3
  •   char v10; // bl@6
  •   unsigned __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
  •   HANDLE FileSizeHigh; // [sp+24h] [bp-1Ch]@1
  •   int OutBuffer; // [sp+28h] [bp-18h]@13
  •   int v26; // [sp+2Ch] [bp-14h]@16
  •   int v27; // [sp+30h] [bp-10h]@16
  •   unsigned __int32 v28; // [sp+34h] [bp-Ch]@16
  •   int v29; // [sp+38h] [bp-8h]@16
  •   v6 = (*(_BYTE *)a3 & 0x10) == 0;
  •   lpFileName = a2;
  •   FileSizeHigh = a1;
  •   if ( !v6 )
  •     return 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让我们这群小白拜读,感激不尽

 

谢谢,Mouri_Naruto写于2014年12月21日

来源URL:http://bbs.pcbeta.com/forum.php?mod=viewthread&tid=1567726&extra=page%3D1%26filter%3Dtypeid%26typeid%3D1210%26typeid%3D1210