并且ShFileOperationEx没有在任何dll中导出. 这样就对拦截ShFilerOperationEx带来很

时间:2022-02-04 08:11:34

感化: 监视文件夹和打印机移动,删除, 重定名, 复制操纵. 可以得到源和方针文件名. 可以控制拒绝操纵.

错误谬误: 不能对文件进行控制. 只对Shell文件操纵有效, 对原生Api MoveFile, CopyFile之类的操纵无效.

用法: 从ICopyHook派生一个COM东西, 重载CopyCallbackA和CopyCallbackW, 然后把COM注册到HKRC\Directory\ShellEx\CopyHookHandlers\中去

2. 文件转变通知

感化: 监视一个文件夹下的文件改削(写入, 删除, 重定名), 并可以注册到一个窗口来措置惩罚惩罚通知.

错误谬误: 只是通知, 不成以拒绝操纵. 不能区分是否文件复制操纵还是移动操纵, 不能拿到源文件名. 只对Shell文件操纵有效, 对原生Api MoveFile, CopyFile之类的操纵无效.

用法: SHChangeNotifyRegister 注册一个窗口接收文件转变同; 或者FindFirstChangeNotification 结合FindNextChangeNotification 的方法措置惩罚惩罚.

3.IShellExtInit

感化: 每一个Shell扩展东西创建城市触发IShellExInit::Initialize挪用, 在Shell中, 用户的对文件的复制粘贴操纵, 最终会被解析成文件东西的拖拽操纵, 然后触发拖拽方针东西的Shell扩展东西的挪用. 所以在文件夹和盘符东西上注册一个IShellExtInit可以监视到拖拽到文件夹东西的事件. 也就是可以监视到文件复制或移动到文件夹的操纵. 并且同时可以从IShellExitInit::Initialize中可以获取到源文件名.

错误谬误: 同通知一样, 不能拒绝文件操纵. 只对Shell文件操纵有效, 对原生Api MoveFile, CopyFile之类的操纵无效.

用法: 从IShellExtInit中派生一个COM东西, 重载Initialize, 在Initialize传来的第一个参数是方针目录名, 第二个参数中可以获取所有源文件名, 第三个参数是一个注册表东西句柄.

下面给一段措置惩罚惩罚样例:

HRESULT STDMETHODCALLTYPE CKCopyHook::Initialize(
 
 __in_opt  PCIDLIST_ABSOLUTE pidlFolder,
 
 __in_opt  IDataObject *pdtobj,
 
 __in_opt  HKEY hkeyProgID)
{
 HRESULT ret = E_INVALIDARG;
 if (NtQueryObject == 0)
 {
  NtQueryObject = (PFNtQueryObject)GetProcAddress(LoadLibraryA("ntdll.dll"), "NtQueryObject");
 }

if (NtQueryObject == 0)
  return E_FAIL;

// 获取 hkeyProgID 的名称
 std::auto_ptr<WCHAR> buffer(new WCHAR[4096]);
 DWORD retlen = 0;
 if (NtQueryObject(hkeyProgID, ObjectNameInformation, buffer.get(), 4096, &retlen) > 0)
  return E_INVALIDARG;

POBJECT_NAME_INFORMATION poni = (POBJECT_NAME_INFORMATION)buffer.get();
 poni->Name.Buffer[poni->Name.Length] = 0;

DbgOutPutMessageW(L"[%s] hkeyProgID=0x%x=[%s]", __FUNCTIONW__, hkeyProgID, poni->Name.Buffer);

// 当 hkeyProgID 是 Folder 项时才进行文件措置惩罚惩罚
 if (wcsnicmp(PathFindFileNameW(poni->Name.Buffer), L"Folder", 6) != 0)
  return S_OK;

if (!SHGetPathFromIDListW(pidlFolder, buffer.get()))
  return E_INVALIDARG;

std::wstring DestStr = buffer.get();

ret = E_INVALIDARG;

COleDataObject oledo;
 oledo.Attach(pdtobj, FALSE);
 HGLOBAL  GlobalData;
 GlobalData = oledo.GetGlobalData(CF_HDROP);
 if (GlobalData)
 {
  HDROP hDrop = (HDROP)GlobalLock(GlobalData);
  if (hDrop)
  {
   // 枚举拖拽的源文件
   int nFiles = DragQueryFileW(hDrop, 0xFFFFFFFF, NULL, 0);
   std::vector<std::wstring> SrcStrs;
   for (int i=0; i<nFiles; ++i)
   {
    if (DragQueryFile(hDrop, i, buffer.get(), 4096))
    {
     SrcStrs.push_back(buffer.get());
    }
   }
   
   if (OnCopyFile(SrcStrs, DestStr, 0))
    ret = S_OK;

GlobalUnlock(hDrop);
  }
  GlobalFree(GlobalData);
 }

return ret;
}

4. 文件过滤驱动

感化: 控制所有文件原子操纵

错误谬误: 不能(或者说很难)追踪文件复制, 移动操纵.

用法: 横竖没用, 不写了.

5. API Hooking

感化: 拦截CopyFile, MoveFile等Api, 可以任意控制文件复制操纵, 可以拒绝文件操纵, 也可以在复制前后插入自界说的操纵, 相当灵活.

错误谬误: 麻烦, 相当麻烦, 兼容性差.

用法: Api Hooking的技术这里就不再陈说了.

需要拦截的API相当多, 从kernel32.dll中导出的 MoveFile* CopyFile* 系列函数, Vista之前的系统中, Shell都是使用ShFileOperation进行文件操纵的, ShFileOperation 内部也是挪用kernel32中的这些函数, 所以可以不措置惩罚惩罚ShFileOperation.