Windows系統中監控檔案複製操作的幾種方式

來源:互聯網
上載者:User

標籤:api函數   sof   狀態   root   rcfile   direct   win32   控制代碼   shc   

http://blog.sina.com.cn/s/blog_4596beaa0100lp4y.html

1. ICopyHook

作用: 監看資料夾和印表機移動,刪除, 重新命名, 複製操作. 可以得到源和目標檔案名. 可以控制拒絕操作.

 

缺點: 不能對檔案進行控制. 只對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.

但是Vista之後的系統, Shell改為調用ShFileOperationEx, ShFilerOperationEx內部並不使用CopyFile, MoveCopy等的函數, 而是使用CreateFile, ReadFile, WriteFile 重疊IO進行檔案操作, 並且ShFileOperationEx沒有在任何dll中匯出. 這樣就對攔截ShFilerOperationEx帶來很大的麻煩.

不過可以利用搜尋特徵代碼的方式從記憶體中, 搜尋到ShFilerOperationEx的地址.

下面這個是32位系統中ShFilerOperationEx的開頭的特徵代碼, 在Shell32.dll記憶體空間中, 32位的Vista, Win7適用 

const BYTE SHFileOperationExCodeMark[] = {
0x8B, 0xFF, 0x55, 0x8B, 0xEC, 0x83, 0xEC, 0x18, 0xA1, 0xFF, 0xFF, 0xFF, 0xFF, 0x33, 0xC5, 0x89,
0x45, 0xFC, 0x8B, 0x45, 0x0C, 0x8B, 0x4D, 0x1C, 0x53, 0x8B, 0x5D, 0x10, 0x56, 0x8B, 0x75, 0x20,
0x57, 0xFF, 0x75, 0x08, 0x89, 0x45, 0xF0, 0x8B, 0x45, 0x14, 0x89, 0x45, 0xEC, 0xBF, 0xFF, 0xFF,
0xFF, 0xFF, 0xE8, 0xFF, 0xFF, 0xFF, 0xFF, 0x85, 0xC0, 0x0F, 0x84, 0xFF, 0xFF, 0xFF, 0xFF, 0x8D,
};

//其中的0xFF的位置跳過比對

https://yq.aliyun.com/wenji/88468摘要: 本文講的是用拷貝鉤子實現對檔案夾的監控, ICopyHook是一個用於建立拷貝鉤子處理常式COM介面,它決定一個檔案夾或者印表機對象是否可以被移動,拷貝,重新命名或刪除。Shell在執行這些操作之前,會調用ICopyHook介面的CopyCallback方法對它們進行

ICopyHook是一個用於建立拷貝鉤子處理常式COM介面,它決定一個檔案夾或者印表機對象是否可以被移動,拷貝,重新命名或刪除。Shell在執行這些操作之前,會調用ICopyHook介面的CopyCallback方法對它們進行驗證。CopyCallback返回一個int值指示Shell是否應該繼續執行這個操作。傳回值IDYES表示繼續,而傳回值IDNO和IDCANCEL則表示終止。

一個檔案夾對象可以安裝多個拷貝鉤子處理常式。如果出現這種情況,Shell會依次調用每個處理常式。只有當每個處理常式都返回IDYES時,Shell才真正執行使用者請求的操作。

拷貝鉤子處理常式的作用是在上述四種操作執行前對它們進行驗證,但是Shell並不會把操作的結果通知給拷貝鉤子處理常式。而windows提供的API函數FindFirstChangeNotification和FindNextChangeNotification卻可以實現這個功能。因此,只有把這種兩種方法結合起來,才能對一個檔案夾的狀態進行完全的監控。

拷貝鉤子處理常式實現並不困難,首先建立一個作為進程內組件的COM對象,它只需要暴露一個ICopyHook介面(當然還有IUnknown)。然後用regsrv32.exe註冊這個COM組件。最後一步是向Shell註冊你的這個拷貝鉤子處理常式,方法是在註冊表HKEY_CLASSES_ROOT\Directory\Shellex\CopyHookHandlers下建立一個名稱任意的sub key,在此sub key中建立一個類型為REG_SZ的項並將你的COM對象的CLSID作為它的預設值就可以了。

下面就是一個拷貝鉤子的實現程式(註:以下代碼經老妖改動並添加了詳細操作過程,在BCB6中成功編譯並通過測試)

1. 從ICopyHook介面建立TCopyHook,從IClassFactory介面建立TClassFactory:

// TCopyHook.h
// TCopyHook類實現了ICopyHook介面,TClassFactory實現了IClassFactory介面
//---------------------------------------------------------------------------
#define NO_WIN32_LEAN_AND_MEAN
#include <shlobj.h>
//---------------------------------------------------------------------------
class TCopyHook: public ICopyHook
{
public:
   TCopyHook():m_refcnt(0) {}
   STDMETHODIMP QueryInterface(REFIID iid,void **ppvObject);
   STDMETHODIMP_(ULONG) AddRef();
   STDMETHODIMP_(ULONG) Release();
   STDMETHODIMP_(UINT) CopyCallback(HWND hwnd, UINT wFunc, UINT wFlags,
       LPCTSTR pszSrcFile, DWORD dwSrcAttribs,
       LPCTSTR pszDestFile, DWORD dwDestAttribs);
private:
   int m_refcnt;
};
//---------------------------------------------------------------------------
class TClassFactory : public IClassFactory
{
public:
   TClassFactory():m_refcnt(0) {}
   STDMETHODIMP QueryInterface(REFIID iid, void **ppvObject);
   STDMETHODIMP_(ULONG) AddRef();
   STDMETHODIMP_(ULONG) Release();
   STDMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject);
   STDMETHODIMP LockServer(BOOL fLock);
private:
   int m_refcnt;
};
// TCopyHook.cpp
// TCopyHook對象和TClassFactory對象的實現檔案
#include <stdio.h>
#include "TCopyHook.h"
//---------------------------------------------------------------------------
extern LONG nLocks;     // 對象計數,用於DllCanUnloadNow
ULONG __stdcall TCopyHook::AddRef()
{
   if(m_refcnt == 0)
     nLocks++;
   m_refcnt++;
   return m_refcnt;
}
//---------------------------------------------------------------------------
ULONG __stdcall TCopyHook::Release()
{
   int nNewCnt = --m_refcnt;
   if(nNewCnt <= 0)
   {
     nLocks--;
     delete this;
   }
   return nNewCnt;
}
//---------------------------------------------------------------------------
HRESULT __stdcall TCopyHook::QueryInterface(REFIID dwIID, void **ppvObject)
{
   if(dwIID == IID_IUnknown)
     *ppvObject = static_cast<IUnknown*>(this);
   else
     if(dwIID == IID_IShellCopyHook)
       *ppvObject = static_cast<ICopyHook*>(this);
     else
       return E_NOINTERFACE;
   reinterpret_cast<IUnknown*>(*ppvObject)->AddRef();
   return S_OK;
}
//---------------------------------------------------------------------------
// 這就是CopyCallback方法,拷貝鉤子的所有功能由它實現。參數的具體值參看MSDN
UINT __stdcall TCopyHook::CopyCallback(HWND hwnd, UINT wFunc, UINT wFlags,
     LPCTSTR pszSrcFile, DWORD dwSrcAttribs,
     LPCTSTR pszDestFile, DWORD dwDestAttribs)
{
   char szMessage[MAX_PATH+14];
   sprintf(szMessage, "對%s進行的操作,是否繼續?", pszSrcFile);
   return MessageBox(NULL, szMessage, "確認", MB_YESNO | MB_ICONEXCLAMATION);
}
//---------------------------------------------------------------------------
ULONG __stdcall TClassFactory::AddRef()
{
   if(m_refcnt==0)
     nLocks++;
   m_refcnt++;
   return m_refcnt;
}
//---------------------------------------------------------------------------
ULONG __stdcall TClassFactory::Release()
{
   int nNewCnt = --m_refcnt;
   if(nNewCnt <= 0)
   {
     nLocks--;
     delete this;
   }
   return nNewCnt;
}
//---------------------------------------------------------------------------
HRESULT __stdcall TClassFactory::QueryInterface(REFIID dwIID, void **ppvObject)
{
   if(dwIID == IID_IUnknown)
     *ppvObject = static_cast<IUnknown*>(this);
   else
     if(dwIID == IID_IClassFactory)
       *ppvObject = static_cast<IClassFactory*>(this);
     else
       return E_NOINTERFACE;
   reinterpret_cast<IUnknown*>(*ppvObject)->AddRef();
   return S_OK;
}
//---------------------------------------------------------------------------
HRESULT __stdcall TClassFactory::CreateInstance(IUnknown* pUnkownOuter,
     REFIID riid, void** ppvObj)
{
   if(pUnkownOuter != NULL)
     return CLASS_E_NOAGGREGATION;
   TCopyHook *pObj = new TCopyHook;
   pObj->AddRef();
   HRESULT hr = pObj->QueryInterface(riid, ppvObj);
   pObj->Release();
   return hr;
}
//---------------------------------------------------------------------------
HRESULT __stdcall TClassFactory::LockServer(BOOL fLock)
{
   if(fLock)
     nLocks++;
   else
     nLocks--;
   return S_OK;
}

以上是雲棲社區小編為您精心準備的的內容,在雲棲社區的部落格、問答、公眾號、人物、課程等欄目也有的相關內容,歡迎繼續使用右上方搜尋按鈕進行搜尋程式 , 拷貝 , return , 鉤子 , 處理 一個 檔案夾拷貝監控、php 鉤子 實現原理、系統鉤子hook監控、windows 鉤子監控視窗、thinkphp 鉤子的實現,以便於您擷取更多的相關知識。

 參考連結:

https://msdn.microsoft.com/en-us/library/cc144063(VS.85).aspx

https://www.codeproject.com/Articles/7309/ICopyHook-implementation

Windows系統中監控檔案複製操作的幾種方式

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.