Замена функции копирования
От: Strann1k Россия  
Дата: 21.04.07 15:15
Оценка:
Благодарен всем заранее за ответы.
Встала задача об отлове копирования файлов. Решений конечно много: хуки, журнал файловой системы, замена самой функции копированя. Вот я и решил выбрать последний вариант... В 2005 году была опубликована статья Перехват API-функций в Windows NT_2000_XP, вот в ней расказывался метод внедрения DLL в процесс с последующей заменой почти любой функции на свою(храняшуюся в той же dll). Как бы с этим проблем нет, dll внедряется, функции заменяются(Замена нужна бля того, чтобы перед началом копированя показать диалог с запросом пароля, и если пароль верен продолжить копирование), всё как бы работает, если учесть что внедрение происходит в процесс мной написаной программы . Но появилась проблема внедрения в процесс explorer.exe(ибо как я понимаю, за копирование файлов в Windows отвечает именно этот процесс) т.к. этот процесс не содержит .idata.
Вопросы:
1) Что я делаю нетак?
2) Есть ли какие нибудь другие методы отлова и замены копированя файлов?
Код Dll

//------------DLL----------------------

#define _WIN32_WINNT 0x4000

// Dll_for_hook.cpp : Defines the entry point for the DLL application.
//
#define RASSWORD "111"

#include "StdAfx.h"
#include "resource.h"

char szPass[MAX_PATH]; //Буфер для пароля
DWORD adr_i_CopyFileExA;
HINSTANCE hInstance = NULL;

BOOL CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL WINAPI i_CopyFileExA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL,
                               LPVOID lpData OPTIONAL, LPBOOL pbCancel OPTIONAL, DWORD dwCopyFlags );
void InterceptFunctions(void);


BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
                     )
{
    hInstance = (HINSTANCE)hModule;
    if(ul_reason_for_call == DLL_PROCESS_ATTACH)
        InterceptFunctions();
    return TRUE;
}


// Эта функция ищет в таблице импорта - .idata нужный адрес и меняет на
// адрес процедуры-двойника 
void InterceptFunctions(void)
{
  // Начало отображения в памяти процесса
  BYTE *pimage = (BYTE*)GetModuleHandle(NULL); 
  BYTE *pidata;
  // Стандартные структуры описания PE заголовка
  IMAGE_DOS_HEADER *idh;
  IMAGE_OPTIONAL_HEADER *ioh;
  IMAGE_SECTION_HEADER *ish;
  IMAGE_IMPORT_DESCRIPTOR *iid;
  DWORD *isd;  //image_thunk_data dword

  // Получаем указатели на стандартные структуры данных PE заголовка
  idh = (IMAGE_DOS_HEADER*)pimage;
  ioh = (IMAGE_OPTIONAL_HEADER*)(pimage + idh->e_lfanew 
                                 + 4 + sizeof(IMAGE_FILE_HEADER));
  ish = (IMAGE_SECTION_HEADER*)((BYTE*)ioh + sizeof(IMAGE_OPTIONAL_HEADER));
  //если не обнаружен магический код, то у этой программы нет PE заголовка
  if (idh->e_magic != 0x5A4D) 
  {
    MessageBox(NULL, "Not exe hdr", "Error!", 0);
    return;
  }

  //ищем секцию .idata
  for(int i=0; i<16; i++)
    if(strcmp((char*)((ish+ i)->Name) , ".idata") == 0) break;
  if(i==16) 
  {
    MessageBox(NULL, "Unable to find .idata section", "Error!", 0);
    return;
  }

  // Получаем адрес секции .idata(первого элемента IMAGE_IMPORT_DESCRIPTOR)
  iid = (IMAGE_IMPORT_DESCRIPTOR*)(pimage + (ish +i)->VirtualAddress );
  
  // Получаем абсолютный адрес функции для перехвата
  adr_i_CopyFileExA = (DWORD)GetProcAddress(
                        GetModuleHandle("KERNEL32.dll"), "CopyFileExA");
  if(adr_i_CopyFileExA == 0)
  {
    MessageBox(NULL, "Can`t get adr_i_CopyFileExA", "Error!", 0);
    return;
  }

  // В таблице импорта ищем соответствующий элемент для 
  // библиотеки user32.dll
  while(iid->Name)  //до тех пор пока поле структуры не содержит 0
  {
    if(strcmp((char*)(pimage + iid->Name), "KERNEL32.dll") ==0 ) break;
    iid++;
  }

  // Ищем в IMAGE_THUNK_DATA нужный адрес
  isd = (DWORD*)(pimage + iid->FirstThunk);
  while(*isd!=adr_i_CopyFileExA && *isd!=0)  isd++;
  if(*isd == 0)
  {
    MessageBox(NULL, "CopyFileExA not found in .idata", "Error!", 0);
    return;
  }
  
  // Заменяем адрес на свою функцию
  
  DWORD buf =  (DWORD)&i_CopyFileExA;
  DWORD op, writen;
  
  // Обычно страницы в этой области недоступны для записи
  // поэтому принудительно разрешаем запись
  VirtualProtect((void*)(isd),4,PAGE_READWRITE, &op);
  
  // Пишем новый адрес
  WriteProcessMemory(GetCurrentProcess(), (void*)(isd),
                    (void*)&buf,4,&writen);
  //восстанавливаем первоначальную защиту области по записи
  VirtualProtect((void*)(isd),4,op, &op);
  //если записать не удалось – увы, все пошло прахом…
  if(writen!=4)
  {
    MessageBox(NULL, "Unable rewrite address", "Error!", 0);
    return;
  }
}

BOOL CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg){
        case WM_INITDIALOG:
            SetDlgItemText(hDlg, IDC_EDIT1, "Enter_Pass");
        case WM_COMMAND:
            switch(LOWORD(wParam)){
                case IDC_BUTTON1:
                    GetDlgItemText(hDlg, IDC_EDIT1, szPass, MAX_PATH);
                    if(szPass != "111"){ // Знаю что эта стока в данном случае не несёт никакого смысла
                        MessageBox(hDlg, "Пароль не верен, копирование прекращёно", "Error", MB_OK);                    
                        EndDialog(hDlg, TRUE);
                        return false;
                    }
                    else return true;
            }
    }
    return 0;
}

BOOL WINAPI i_CopyFileExA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL,
    LPVOID lpData OPTIONAL, LPBOOL pbCancel OPTIONAL, DWORD dwCopyFlags)
{
      //здесь вы выполняете любые свои действия
    //-----------------------------------------------------------------------------------------------

//    if( !DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc) ) return TRUE;

    //-----------------------------------------------------------------------------------------------
    // вызываем оригинальную функцию через указатель
    MessageBox(NULL, "Пароль не верен, копирование прекращёно", "Error", MB_OK);

    ((BOOL (__stdcall*)(LPCSTR, LPCSTR, LPPROGRESS_ROUTINE, LPVOID, LPBOOL, DWORD))adr_i_CopyFileExA)(lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, pbCancel, dwCopyFlags);
    return TRUE;
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.