IntroductionThis Windows file monitoring system aims at providing security to files in a Windows environment. I was in a need to design an application which monitors file open, close, and save operations on Windows and restricts the user from accessing a subset of file types until this utility is installed. This was achieved by hooking Windows file related APIs and then preprocessing file open, save, and close operations in Windows as per the requirement. The preprocessing may be encryption of files, corrupting the file's header section, etc. If this utility is installed on the system, then the file, initially in the encrypted format, would first be decrypted before being opened, and then would again be encrypted when the file is closed or saved. This would help prevent the file from being accessed anywhere else where this utility is not installed, thereby providing security to the file. I found a few good applications like AvaFind, FileMon, etc. performing file monitoring functionality. But, these applications use system drivers to achieve their goals. Because of the complexities involved in writing driver programs, I tried to achieve the same through Win32 user level programming. I have achieved this by hooking the Out of the various ways available for hooking Windows APIs, I chose the method of "Hooking by altering the Import Address Table (IAT)" of all the processes running on the system. The DLL containing the code to change the IAT is injected into the address space of the target process (the process in which the DLL is to be injected), by creating a remote thread in the address space of that process using the Windows API Injecting DLLs by remote threads is well documented in Jeffrey Richter's article "Load Your 32-bit DLL into Another Process's Address Space Using INJLIB". Injecting DLLs has by far been the most widely used concept, with the greatest advantage of getting hold over the process, once your DLL is within its address space. But, this method has a disadvantage of the DLL not being injected into the target process in case kernel32.dll does not get loaded at its well known preferred load address. Hence, the method of injecting a DLL is based on the sole assumption that the load addresses of Kernel32.dll remain same for both the processes. Design and ImplementationComing back to the original problem... The first step I performed was to create HookAPI.dll, which contains the code to hook Windows APIs, and then this DLL is injected in all the running processes on the system. Once injected into the target process, HookAPI.dll changes the IAT of the process and all of its loaded modules. HookAPI.dll contains a function called Here are the logical steps of a replacing cycle:
Hide Shrink Copy Code void GetIAList() { HMODULE hMods[1024]; TCHAR szLibFile[MAX_PATH]; HANDLE hProcess = GetCurrentProcess(); HMODULE hModule = GetModuleHandle(TEXT("HookAPI.dll")); GetModuleFileName(hModule,szLibFile,sizeof(szLibFile)); DWORD cbNeeded = 0; multimap <CString,void*> m_mapOld; multimap <CString,void*> :: iterator m_AcIter; PROC pfnNewAddress = NULL; unsigned int i = 0; PROC* ppfn = NULL; CString str; ULONG ulSize = 0; if( EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) { for ( i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ ) { TCHAR szModName[MAX_PATH]; // Get the full path to the module's file. if ( GetModuleFileNameEx( hProcess, hMods[i], szModName, sizeof(szModName))) { // We must skip the IAT of HookAPI.dll // from being modified as it contains // the wrapper functions for Windows AOIs being hooked. if(_tcscmp(szModName,szLibFile) == 0) { i++; } } // Get the address of the module's import section PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR) ImageDirectoryEntryToData(hMods[i], TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize); if(NULL != pImportDesc) { while (pImportDesc->Name) { PSTR pszModName = (PSTR)((PBYTE) hMods[i] + pImportDesc->Name); CString strModName = pszModName; // Get caller's IAT PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA) ( (PBYTE) hMods[i] + pImportDesc->FirstThunk ); while (pThunk->u1.AddressOfData) { // Get the address of the function address ppfn = (PROC*) &pThunk->u1.AddressOfData; str.Format(_T("%s:%x"),strModName,*ppfn); // Store the dll name and address of the function from the IAT // into a map in the form ("KERNEL32.dll:<address of CreateFile>", // <address that contains the address of CreateFile in IAT>). // The map contains the entries in the form // ("KERNEL32.dll:0x110023",0x707462) // ("KERNEL32.dll:0x110045",0x707234) // ("KERNEL32.dll:0x110074",0x402462) // ... m_mapOld.insert( func_Pair( str, ppfn ) ); pThunk++; } pImportDesc++; } } } } // Traverse the map to hook the appropriate function. for(m_AcIter = m_mapOld.begin() ; m_AcIter != m_mapOld.end() ; m_AcIter++) { // pfnNewAddress = GetNewAddress(m_AcIter -> first); // m_AcIter -> first is a string that gives all the informatino // about the Windows API to be hooked like the name of the DLL // in which the function is actually present, its address in that DLL // and its address in IAT. // GetNewAddress should be implemented in such a way that it should return // the address of the wrapper function for Windows API implemented in HookAPI.dll if(pfnNewAddress != NULL) { PROC* pfnOldAddress = (PROC*)m_AcIter -> second; MEMORY_BASIC_INFORMATION mbi = {0}; VirtualQuery( pfnOldAddress, &mbi, sizeof(MEMORY_BASIC_INFORMATION) ); VirtualProtect( mbi.BaseAddress,mbi.RegionSize,PAGE_EXECUTE_READWRITE, &mbi.Protect); // Replace the origional address of API with the address of corresponding // wrapper function *pfnOldAddress = *pfnNewAddress; DWORD dwOldProtect = 0; VirtualProtect( mbi.BaseAddress, mbi.RegionSize, mbi.Protect, &dwOldProtect ); } } } Once this DLL is designed, the next job is to create Injector.exe which injects the hooking DLL, HookAPI.dll, in all the running processes, by using Hide Copy Code // Get the path of DLL to be injected TCHAR pszLibFile[MAX_PATH]; GetModuleFileName(NULL,pszLibFile,sizeof(szLibFile)); _tcscpy(_tcsrchr(pszLibFile,TEXT('\\')) + 1,TEXT("HookAPI.dll"));
Hide Shrink Copy Code void InjectIntoExistingProcesses(PCWSTR pszLibFile) { BOOL fOk=FALSE; PWSTR pszLibFileRemote = NULL; int cch = 1+lstrlenW(pszLibFile); int cb = (cch + sizeof(WCHAR))*sizeof(WCHAR); DWORD aProcesses[1024], cbNeeded, cProcesses; EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded); cProcesses = cbNeeded / sizeof(DWORD); // Get process handle for each running process. for (int i = 0; i < cProcesses; i++) { HANDLE hRunningProcess = OpenProcess( PROCESS_ALL_ACCESS,FALSE, aProcesses[i] ); pszLibFileRemote = (PWSTR)VirtualAllocEx(hCurrentProcess,NULL,cb, MEM_COMMIT,PAGE_READWRITE); SIZE_T nBytes = 0; WriteProcessMemory(hCurrentProcess, pszLibFileRemote,(PVOID) pszLibFile,cb,&nBytes ); LPTHREAD_START_ROUTINE pfnThreadRtn = ( LPTHREAD_START_ROUTINE ) GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW"); CreateRemoteThread(hCurrentProcess,NULL,0, pfnThreadRtn,pszLibFileRemote,0,NULL); if (pszLibFileRemote != NULL) { VirtualFreeEx(hCurrentProcess,pszLibFileRemote,0,MEM_RELEASE); } if (hRunningProcess != NULL) { CloseHandle(hRunningProcess ); } } } When HookAPI.dll hooks the Issues with the first run of this utilityInitially, all the files on the system are neither in encrypted form nor in decrypted form. This utility requires that all the concerned files (files belonging to a particular subset of file types) on the system should be in encrypted form before they are opened. Hence, this encryption should be done at the time of installation of this utility. One way to do this, in case a particular noise pattern is defined for corrupting the file headers, is to check whether this noise pattern exists in the file. If yes, remove the noise, i.e., decrypt the file and proceed in the fashion mentioned above. If no, it shows that this is the first run and no preprocessing is needed. Another approach is to find all the files on the system belonging to a particular subset of file types the utility is intended to process, and encrypt them all at the time of installing this utility. References
LicenseThis article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL) Share |
Windows File Monitoring System Using Windows API Hooking
猜你喜欢
转载自blog.csdn.net/jiangbb8686/article/details/89424750
今日推荐
周排行