给个驱动代码吧
// FGHOOK.cpp - main module for VxD FGHOOK
#define DEVICE_MAIN
#include "FGHOOK.h"
Declare_Virtual_Device(FGHOOK)
#undef DEVICE_MAIN
ppIFSFileHookFunc PrevHookProc=NULL; //Previos hook function.
KProtectedFileList protFileList;
KProtectedFileList recycledPathList
//Path of Recycle.
KHandleTable findHTable, openHTable;
KHotKey *pHotKey;
HANDLE hIniFile,hVM;
HANDLE hAppWnd=NULL; //Handle of win32 app.
char iniFilePath[MAX_PATH+1]="";
ParsedPath *pPPath;
BOOL bBusy, bAppReqBusy=FALSE; //bAppReqBusy--win32 app is about be write file.
WORD lastError=FG_ERR_SUCCESS;
UINT maxBakNum=DEF_MAX_BAK_NUM; //max backup file number.
//NOTICE: I don't know whether more than one object files will be linked properly,
//(And I haven't try it.) So I just include other cpp files in the main cpp file.
//This did not cause any problem.
#include "../HookShr/KProtectedFileList.cpp"
#include "../HookShr/HookCom.cpp"
#include "KHandleTable.cpp"
#include "KHotKey.cpp"
///////////////////////////////////////////////////////////////////
//Main interface:
FGHookVM::FGHookVM(VMHANDLE hVM) : VVirtualMachine(hVM) {}
FGHookThread::FGHookThread(THREADHANDLE hThread) : VThread(hThread) {}
BOOL FGHookDevice::OnSysDynamicDeviceInit()
{
#ifdef DEBUG
dout << "Hello from FGHook!" << endl;
#endif
bBusy=FALSE;
if(!(pPPath=(ParsedPath *)malloc(MAX_PATH*sizeof(WCHAR)+sizeof(ParsedPath))))
{
ErrorHandler(FG_ERR_NOT_ENOUGH_MEMORY);
ShellUnloadDevice();
return FALSE;
}
//Add recycled path.
int i;
char recycledPath[MAX_PATH]="A://RECYCLED//*";
for(i=1
i<=32
i++) //Windows supports up to 32 drives.
{
recycledPath[0]=i+'A'-1;
recycledPathList.Add(recycledPath);
}
//intall key board hook:
pHotKey=new KHotKey;
pHotKey->hook();
return TRUE;
}
BOOL FGHookDevice::OnSysDynamicDeviceExit()
{
free(pPPath);
if(PrevHookProc)
IFSMgr_RemoveFileSystemApiHook(HookProc);
delete pHotKey;
#ifdef DEBUG
dout<<"Hook exit."<<endl;
#endif
return TRUE;
}
#ifdef DEBUG
void PrintUni(WCHAR *p, unsigned int len)
{
int i=0;
while(p
&&
i<len)
dout<<(char)p[i++];
dout<<endl;
i=0;
while(p &&
i<len)
dout<<p[i++]<<" ";
dout<<endl;
}
#endif
DWORD FGHookDevice::OnW32DeviceIoControl(PIOCTLPARAMS pDIOCParams)
{
switch(pDIOCParams->dioc_IOCtlCode)
{
case DIOC_OPEN:
//SHELL_Message(pDIOCParams->dioc_hvm,MB_OK,"Device initialize.","FGHook message:",0,0,0);
break;
#ifdef DEBUG
case FG_DIOC_DEBUG:
break;
#endif
case FG_DIOC_INSTALL_HOOK:
#ifdef DEBUG
dout<<"Now install hook..."<<endl;
#endif
if((PrevHookProc=IFSMgr_InstallFileSystemApiHook(HookProc))==NULL)
ErrorHandler(FG_ERR_INSTALL_HOOK_FAIL);
protFileList.bDelBak=(UINT)pDIOCParams->dioc_InBuf &
0x1; //Get del &
write proteciton options.
protFileList.bWriteBak=(((UINT)pDIOCParams->dioc_InBuf &
0x2)== 0x2);
break;
case FG_DIOC_UNINSTALL_HOOK:
if(PrevHookProc &&
IFSMgr_RemoveFileSystemApiHook(HookProc)==0)
PrevHookProc=NULL;
break;
case FG_DIOC_GET_HWND:
hAppWnd=*((HANDLE *)pDIOCParams->dioc_InBuf); //Retrieve hwnd of main window of win32 app.
break;
case FG_DIOC_FLUSH_PROTECTED_FILE_INFO: //==FG_DIOC_READ_PROTECTED_FILE_INFO
//Flush file information by reread from ini file.
protFileList.Empty();
if(pDIOCParams->dioc_InBuf)
strcpy(iniFilePath,(char *)pDIOCParams->dioc_InBuf);
else if(!*iniFilePath) strcpy(iniFilePath, "ProtFile.ini"); //default ini path.
#ifdef DEBUG
dout<<"INI Path:"<<iniFilePath<<endl;
#endif
ReadProtectedFileInfo(iniFilePath);
break;
case FG_DIOC_ADD_PROTECTED_FILE:
//Add new protected file.
protFileList.Add((PROTECTED_FILE *)pDIOCParams->dioc_InBuf);
break;
case FG_DIOC_REMOVE_PROTECTED_FILE:
protFileList.Remove((char *)pDIOCParams->dioc_InBuf);
break;
case FG_DIOC_EXTRA_INFO:
protFileList.bDelBak=(UINT)pDIOCParams->dioc_InBuf &
0x1; //Get del &
write proteciton options.
protFileList.bWriteBak=(((UINT)pDIOCParams->dioc_InBuf &
0x2)== 0x2);
maxBakNum=(UINT)pDIOCParams->dioc_OutBuf;
break;
case FG_SET_DEVICE_BUSY:
bAppReqBusy=(BOOL)pDIOCParams->dioc_InBuf;
break;
}
_asm clc
return 0;
}
VOID FGHookDevice:M_API_Entry(VMHANDLE hVM, CLIENT_STRUCT* pRegs)
{
}
//Hook Procedure: all protection is done though this function.
// Argument : pIFSFunc pfn
// address of the function which will perform this file operation.
// Argument : int fn
// number of the function which will perform this file operation.
// Argument : int CodePage
// current code page.
// Argument : pioreq pir
// It is the parameter to be passed to FSD function pfn.
// In many cases, pir->ir_ppath contain ParsedPath.
int _cdecl HookProc(pIFSFunc pfn, int fn, int Drive, int ResType, int CodePage, pioreq pir)
{
struct _QWORD res;
BOOL bLogHandle=FALSE; //Determine whether to add a handle to handle table(use in IFSFN_OPEN);
//bAppReqBusy: Win32 application of fileguard request busy. bBusy: used to prevent reentry.
if(bAppReqBusy || bBusy)
goto EXIT;
bBusy=TRUE;
if(protFileList.bIsHideOn &&
(fn==IFSFN_FILEATTRIB || fn==IFSFN_DIR || fn==IFSFN_SEARCH || fn==IFSFN_RENAME))
{
//Hide a file:
if(protFileList.IsUnderProtection(Drive, pir->ir_ppath, PT_HIDE))
{
bBusy=FALSE;
return (IFSFN_DIR? ERROR_PATH_NOT_FOUND : ERROR_FILE_NOT_FOUND);
}
}
switch(fn)
{
case IFSFN_DELETE:
{
//do delete protection:
if(!protFileList.bIsDelOn &&
!protFileList.bIsHideOn)
//If there is not protected file has protection type of PT_DELETE or PT_HIDE, skip.
break;
if(DoDeleteProtection(pir, Drive, CodePage)!=ERROR_SUCCESS)
{
bBusy=FALSE;
return pir->ir_error;
}
break;
} //case IFSFN_DELETE
case IFSFN_RENAME:
{
//prevent moving protected file to recycled.
if(!protFileList.bIsDelOn &&
!protFileList.bIsHideOn)
//If there is not protected file has protection type of PT_DELETE or PT_HIDE, skip.
break;
//Is the file being renamed to the recycle?
if(!recycledPathList.IsUnderProtection(Drive, pir->ir_ppath2)
|| DoDeleteProtection(pir, Drive, CodePage)==ERROR_SUCCESS)
break;
bBusy=FALSE;
return pir->ir_error;
} //case IFSFN_RENAME
case IFSFN_OPEN:
{
//If a file is opened with ACTION_REPLACEEXISTING, content of the file will be lost.
//so prevent this.
//And prevent opening hidden file.
//Determine whether or not to log open handle:
PROTECTED_FILE *pProtFile;
if(!(pProtFile=protFileList.IsUnderProtection(Drive, pir->ir_ppath)))
break;
else if(pProtFile->PF_type&(PT_READ|PT_DELETE))
bLogHandle=TRUE;
//determine whether the file is under protection.
if(!(protFileList.bIsHideOn || protFileList.bIsDelOn) || !(pProtFile=protFileList.IsUnderProtection(Drive, pir->ir_ppath, PT_DELETE|PT_HIDE)))
break;
if(!(ACTION_REPLACEEXISTING&pir->ir_options) &&
!(pProtFile->PF_type&PT_HIDE))
//the file is not to be hidden and it is not opened with ACTION_REPLACEEXISTING, skip.
break;
if(pProtFile->PF_type&PT_HIDE)
{
//protect hidden file.
bBusy=FALSE;
pir->ir_error=ERROR_FILE_NOT_FOUND;
return pir->ir_error;
}
else if(!protFileList.bDelBak)
{
//deny file operation.
ShellPostError(FG_ERR_WARNING, FG_WARN_PT_DELETE)
//Send a warning.
bBusy=FALSE;
pir->ir_error=ERROR_ACCESS_DENIED;
return pir->ir_error;
}
//protect the file by rename it to *.BAK .
char pBCSPath[MAX_PATH+1];
UniToBCSPathEx((PUCHAR)pBCSPath,pir->ir_ppath->pp_elements,Drive,MAX_PATH,CodePage,&res);
if(FileRename(pBCSPath)==ERROR_SUCCESS)
{
//The file exists, so recreate it.
WORD error;
BYTE action;
HANDLE h=R0_OpenCreateFile(TRUE,pBCSPath,0,ATTR_NORMAL,ACTION_IFEXISTS_FAIL|ACTION_IFNOTEXISTS_CREATE,0,&error,&action);
R0_CloseFile(h,&error);
}
break;
} //case IFSFN_OPEN
case IFSFN_WRITE:
{
//do write protection.
if(!protFileList.bIsWriteOn)
//If there is not protected file has protection type of PT_WRITE, skip.
break;
//sometimes, a process writes zero bytes only to verify.
if(pir->ir_length==0) break;
//get full path.
int drive=Drive;
if(!GetFullNameByHandle(pir,drive,ResType,CodePage,pPPath, FALSE))
break;
//determine whether the file is under protection.
if(!protFileList.IsUnderProtection(drive, pPPath, PT_WRITE))
break;
if(!protFileList.bWriteBak)
{
//Deny write.
ShellPostError(FG_ERR_WARNING, FG_WARN_PT_WRITE)
//Send a warning.
bBusy=FALSE;
pir->ir_error=ERROR_ACCESS_DENIED;
return pir->ir_error;
}
//protect the file by copying it to the .BAK file.
char pBCSPath[MAX_PATH+1];
UniToBCSPathEx((PUCHAR)pBCSPath,pPPath->pp_elements,Drive,MAX_PATH,CodePage,&res);
if(FileBackupByHandle(pir,drive,ResType,CodePage,pBCSPath)!=ERROR_SUCCESS &&
FileBackup(pBCSPath)!=ERROR_SUCCESS)
{
//if fail to back up the file then deny access.
bBusy=FALSE;
pir->ir_error=ERROR_ACCESS_DENIED;
return pir->ir_error;
}
break;
} //case IFSFN_WRITE
case IFSFN_READ:
{
//prevent process to read protected file.
//Read protection is not on or it is a pagging file.
if(!protFileList.bIsReadOn)
break;
//Get full path.
int drive=Drive;
if(!GetFullNameByHandle(pir,drive,ResType,CodePage,pPPath, FALSE))
break;
//determine whether the file is under protection.
if(!protFileList.IsUnderProtection(drive, pPPath, PT_READ))
break;
//deny read
ShellPostError(FG_ERR_WARNING, FG_WARN_PT_READ)
//Send a warning.
bBusy=FALSE;
pir->ir_error=ERROR_ACCESS_DENIED;
return pir->ir_error;
break;
} //case IFSFN_READ
}
bBusy=FALSE;
EXIT:
int nRetVal=(*PrevHookProc)(pfn,fn,Drive,ResType,CodePage,pir);
//Win32 application of fileguard request busy.
if(bAppReqBusy)
return nRetVal;
//log open handle.
if(bLogHandle)
openHTable.Add(pir->ir_fh, Drive, pir->ir_ppath);
//if find or file is closed, delete the handle in handle table.
if(fn==IFSFN_FINDCLOSE)
findHTable.Delete(pir->ir_fh);
else if(fn==IFSFN_CLOSE &&
pir->ir_flags==CLOSE_FINAL)
openHTable.Delete(pir->ir_fh);
if(!bBusy &&
protFileList.bIsHideOn &&
!nRetVal &&
(fn==IFSFN_FINDNEXT || fn==IFSFN_FINDOPEN))
{
//Hide file in file operation FINDOPEN &
FINDNEXT.
bBusy=TRUE;
int drive=Drive;
_WIN32_FIND_DATA *findData;
//Get search path:
switch(fn)
{
case IFSFN_FINDOPEN:
memcpy(pPPath, pir->ir_ppath, IFSPathSize(pir->ir_ppath)+sizeof(WCHAR));
findHTable.Add(pir->ir_fh, Drive, pPPath);
break;
case IFSFN_FINDNEXT:
if(!GetFullNameByHandle(pir, drive, ResType, CodePage, pPPath, TRUE))
{
bBusy=FALSE;
return nRetVal;
}
break;
}
//Now we will change the search path to file path which is found by FINDOPEN or FINDNEXT.
//get file directory from search path by removing the last component:
pPPath->pp_totalLength-=IFSLastElement(pPPath)->pe_length;
//get full path by adding file name to file directory.
findData=(_WIN32_FIND_DATA *)pir->ir_data;
IFSLastElement(pPPath)->pe_length=wstrlen(findData->cFileName)+sizeof(WCHAR);
memcpy(IFSLastElement(pPPath)->pe_unichars, findData->cFileName, IFSLastElement(pPPath)->pe_length);
StringUpper((WCHAR *)IFSLastElement(pPPath)->pe_unichars, IFSLastElement(pPPath)->pe_length-sizeof(WCHAR));
pPPath->pp_totalLength+=IFSLastElement(pPPath)->pe_length;
*(WCHAR *)((char *)pPPath+pPPath->pp_totalLength)=NULL;
//determine whether the file is under protection.
if(protFileList.IsUnderProtection(drive, pPPath, PT_HIDE))
{
bBusy=FALSE;
//now we are going to hide the protected file...
if(fn==IFSFN_FINDOPEN)
{
//if it is FINDOPEN operation, we should return the next file.
//using IFSMgr_Ring0_FileIO to find the next file.
_WIN32_FIND_DATA_BCS bcsFindData;
BOOL retVal;
retVal=R0_FindNextFile(pir->ir_fh, &bcsFindData, (PWORD)&pir->ir_error);
if(retVal)
{
//if the next file is found, convert _WIN32_FIND_DATA_BCS (the find data return by IFSMgr_Ring0_FileIO) to _WIN32_FIND_DATA ( the find data used by FS_FINDOPEN).
memcpy(pir->ir_data, &bcsFindData, sizeof(_WIN32_FIND_DATA_BCS)-sizeof(bcsFindData.cFileName)-sizeof(bcsFindData.cAlternateFileName));
BCSToUni(((_WIN32_FIND_DATA *)pir->ir_data)->cFileName, bcsFindData.cFileName, strlen((char *)bcsFindData.cFileName), CodePage, &res);
((_WIN32_FIND_DATA *)pir->ir_data)->cFileName[res.ddLower]=0;
BCSToUni(((_WIN32_FIND_DATA *)pir->ir_data)->cAlternateFileName, bcsFindData.cAlternateFileName, strlen((char *)bcsFindData.cAlternateFileName), CodePage, &res);
((_WIN32_FIND_DATA *)pir->ir_data)->cAlternateFileName[res.ddLower]=0;
}
return retVal;
}
else goto EXIT; //if it is FINDNEXT operation, go on to find next file.
}
bBusy=FALSE;
}
return nRetVal;
}
//Protected file on file delete, rename operation.
//Return value: return ERROR_SUCCESS indicates that the protected file has been back up, and
// the file operation can be continue. Otherwise the file operation should stop.
WORD DoDeleteProtection(ioreq *pir, int Drive, int CodePage)
{
struct _QWORD res;
char pBCSPath[MAX_PATH+1];
PROTECTED_FILE *pProtFile;
if(pir->ir_attr&FILE_FLAG_WILDCARDS || pir->ir_attr&FILE_FLAG_HAS_STAR)
{
//Deal with file name with wildcards.
//Convert from ParsedPath to BCS path.
UniToBCSPathEx((PUCHAR)pBCSPath, pir->ir_ppath->pp_elements, Drive, MAX_PATH, CodePage, &res);
//find first file.
_WIN32_FIND_DATA_BCS bcsFindData;
WORD error;
HANDLE hFind;
hFind=R0_FindFirstFile((PCHAR)pBCSPath, pir->ir_attr, &bcsFindData, &error);
CHAR pFindPath[MAX_PATH];
strcpy(pFindPath, pBCSPath);
_strupr(pFindPath);
while(error==ERROR_SUCCESS)
{
//Get full path by adding file name to file directory.
GetDir(pFindPath);
_strupr((PCHAR)bcsFindData.cFileName);
strcat(pFindPath, (PCHAR)bcsFindData.cFileName);
if((pProtFile=protFileList.IsUnderProtection(pFindPath, PT_DELETE|PT_HIDE))!=NULL)
{
if(pProtFile->PF_type&PT_HIDE)
{
//Protect hidden file.
pir->ir_error=ERROR_FILE_NOT_FOUND;
return pir->ir_error;
}
else if(protFileList.bDelBak)
{
//Deny delete.
if(!FileRename(pFindPath)==ERROR_SUCCESS) //Cannot rename the file, so deny access to the file.
return ERROR_ACCESS_DENIED;
}
else
{
//Back up on delete.
pir->ir_error=ERROR_ACCESS_DENIED;
ShellPostError(FG_ERR_WARNING, FG_WARN_PT_DELETE); //Send a warning.
return pir->ir_error;
}
}
//go on to find next file
R0_FindNextFile(hFind, &bcsFindData, &error);
} //while(error==ERROR_SUCCESS)
} //if(pir->ir_attr&FILE_FLAG_WILDCARDS || pir->ir_attr&FILE_FLAG_HAS_STAR)
else if((pProtFile=protFileList.IsUnderProtection(Drive, pir->ir_ppath, PT_DELETE|PT_HIDE))!=NULL)
{
//Deal with file name without wildcards:
if(pProtFile->PF_type&PT_HIDE)
pir->ir_error=ERROR_FILE_NOT_FOUND; //Protect hidden file.
if(!protFileList.bDelBak)
{
//Deny delete
pir->ir_error=ERROR_ACCESS_DENIED;
ShellPostError(FG_ERR_WARNING, FG_WARN_PT_DELETE); //Send a warning.
}
else
{
//Back up on delete.
UniToBCSPathEx((PUCHAR)pBCSPath,pir->ir_ppath->pp_elements,Drive,MAX_PATH,CodePage,&res);
pir->ir_error=FileRename(pBCSPath);
}
return pir->ir_error;
}
return ERROR_SUCCESS;
}
//Append a extension like ".BAK0" or ".BAK1" to the file name.
//(the maximum number appended at the tail depends on MAX_BAK_NUM)
//If every optional back up file name have been used, return FALSE,
//else return TRUE.
//No checking for the parameters. pBCSNewName must be long enough.
BOOL AppendBakExtension(const char *pBCSOldName, char *pBCSNewName)
{
strcpy(pBCSNewName,pBCSOldName);
strcat(pBCSNewName,".BAK1")
//Rename the file.
WORD error;
_WIN32_FIND_DATA_BCS findData;
char i;
for(i='2'
i<='1'+maxBakNum-1
i++)
{
R0_FindFirstFile(pBCSNewName, NULL, &findData, &error);
if(error==ERROR_FILE_NOT_FOUND)
return TRUE;
else
//if the file name has already been used, make some change.
pBCSNewName[strlen(pBCSNewName)-1]=i;
}
return FALSE;
}
//Backup a file by renaming it:
//e.g. "A.txt" to "A.txt.BAK".
WORD FileRename(char *pBCSOldName)
{
char pBCSNewName[MAX_PATH+1];
WORD error;
//Name the bak file.
AppendBakExtension(pBCSOldName, pBCSNewName);
R0_RenameFile(pBCSOldName,pBCSNewName,&error);
return error;
}
// Function name : FileBackupByHandle
// Backup a file identified by pir->ir_fh &
pBCSName.
// Using pir->ir_fh to read from the file.
// if the handle is open with out Generic_Read, this function will fail.
// Only call this function in HookProc.
WORD FileBackupByHandle(pioreq pir,int Drive, int ResType, int CodePage,const char *pBCSName)
{
char pBCSNewName[MAX_PATH+1];
HANDLE hNewFile;
BYTE action;
WORD error, retVal=ERROR_SUCCESS;
ifsreq ifsr;
//Name the bak file.
AppendBakExtension(pBCSName, pBCSNewName);
hNewFile=R0_OpenCreateFile(FALSE, pBCSNewName,OPEN_ACCESS_WRITEONLY | OPEN_SHARE_COMPATIBLE,
ATTR_NORMAL, ACTION_IFEXISTS_TRUNCATE | ACTION_IFNOTEXISTS_CREATE,0 ,&error,&action);
if(error!=ERROR_SUCCESS) return error;
char buf[BUF_LEN+1];
DWORD nBytesRead=0,nBytesWrite=0,offset=0;
memcpy(&ifsr,pir,sizeof(ifsreq));
pIFSFunc readFunc = ifsr.ifs_hndl->hf_read;
while(1)
{
ifsr.ifsir.ir_length=BUF_LEN;
ifsr.ifsir.ir_options=R0_NO_CACHE;
ifsr.ifsir.ir_data=buf;
ifsr.ifsir.ir_pos=offset;
if((*PrevHookProc)(readFunc, IFSFN_READ,Drive, ResType, CodePage,(pioreq) &ifsr)==STATUS_PENDING)
IFSMgr_CompleteAsync((pioreq) &ifsr)
nBytesRead=ifsr.ifsir.ir_length;
if(ifsr.ifsir.ir_error!=ERROR_SUCCESS || !nBytesRead)
{
retVal=ifsr.ifsir.ir_error;
break;
}
nBytesWrite=R0_WriteFile(FALSE,hNewFile,buf,nBytesRead,offset,&error);
if(error!=ERROR_SUCCESS)
{
retVal=error;
break;
}
offset+=nBytesRead;
}
R0_CloseFile(hNewFile,&error);
return retVal;
}
// Function name : FileBackup
// Back up a file identify by pBCSName.
// If the file is currently open by other user with DENY_READ, this function will fail.
WORD FileBackup(char *pBCSName)
{
char pBCSNewName[MAX_PATH+1];
HANDLE hOldFile, hNewFile;
BYTE action;
WORD error, retVal=ERROR_SUCCESS;
//Name the bak file.
AppendBakExtension(pBCSName, pBCSNewName);
hOldFile=R0_OpenCreateFile(FALSE, pBCSName,OPEN_ACCESS_READONLY | OPEN_SHARE_COMPATIBLE,
ATTR_NORMAL, ACTION_IFEXISTS_OPEN | ACTION_IFNOTEXISTS_FAIL ,0 ,&error,&action);
if(error!=ERROR_SUCCESS)
{
return error;
}
hNewFile=R0_OpenCreateFile(FALSE, pBCSNewName,OPEN_ACCESS_WRITEONLY | OPEN_SHARE_COMPATIBLE,
ATTR_NORMAL, ACTION_IFEXISTS_TRUNCATE | ACTION_IFNOTEXISTS_CREATE,0 ,&error,&action);
if(error!=ERROR_SUCCESS) return error;
char buf[BUF_LEN+1];
DWORD nBytesRead=0,nBytesWrite=0,offset=0;
while(1)
{
nBytesRead=R0_ReadFile(FALSE, hOldFile, buf, BUF_LEN, offset, &error);
if(error!=ERROR_SUCCESS || !nBytesRead)
{
retVal=error;
break;
}
nBytesWrite=R0_WriteFile(FALSE,hNewFile,buf,nBytesRead,offset,&error);
if(error!=ERROR_SUCCESS)
{
retVal=error;
break;
}
offset+=nBytesRead;
}
R0_CloseFile(hOldFile, &error);
R0_CloseFile(hNewFile,&error);
return retVal;
}
//Similar to UniToBCSPath(...)
void UniToBCSPathEx(PUCHAR pBCSPath, PathElement* pUniPath, int Drive, DWORD maxLength, int charSet, _QWORD* pResult)
{
//Get driver volume:
pBCSPath[0]=(char)Drive-1+'A';
pBCSPath[1]=':';
UniToBCSPath(pBCSPath+2,pUniPath,maxLength,charSet,pResult);
pBCSPath[pResult->ddLower+2]=NULL;
}
//Get full Canonicalized Path from pir->ir_fh.
BOOL GetFullNameByHandle(pioreq pir,int &Drive, int ResType, int CodePage,path_t pPPath, BOOL bFindHandle)
{
//Search in handle table first.
if((bFindHandle &&
findHTable.Find(pir->ir_fh, Drive, pPPath, MAX_PATH)) || openHTable.Find(pir->ir_fh, Drive, pPPath, MAX_PATH))
return TRUE;
//if not found in handle table, call FS_EnumerateHandle to get file path.
ifsreq ifsr;
memcpy( &ifsr, pir, sizeof(ifsreq));
ifsr.ifsir.ir_flags = bFindHandle ? ENUMH_GETFINDINFO : ENUMH_GETFILENAME;
ifsr.ifsir.ir_ppath = pPPath;
pIFSFunc enumFunc = ifsr.ifs_hndl->hf_misc->hm_func[HM_ENUMHANDLE]; //get address of FS_EnumerateHandle from struct hndlfunc.
if((*PrevHookProc)(enumFunc, IFSFN_ENUMHANDLE, Drive, ResType, CodePage,(pioreq) &ifsr)!= ERROR_SUCCESS) return FALSE;
return TRUE;
}
void SetLastError(WORD errorCode)
{
lastError=errorCode;
}
WORD GetLastError()
{
return lastError;
}
UINT refData;
SHELLMessage_THUNK thunk;
//Gobal error handler for device:
//err: error code. severity: 0 means a fatal error, 1 a minor one.
//return value: 0 ---the moduel where the error occurs must stop processing.
// 1 ---processing can go on.
int ErrorHandler(unsigned int err, int severity/*=1*/)
{
ShellPostError(err,severity);
return 1;
}
//Callback function for user's response of shell_message.
void __stdcall MsgCallBack(DWORD ResponseCode,PVOID Refdata)
{
switch(*((UINT *)Refdata))
{
case ON_MSG_FILE_NOT_FOUND:
if(ResponseCode==IDNO)
ShellUnloadDevice(); //call on FileGuard win32 GUI to stop protection.
break;
}
}
//Read protected file information:
//DO NOT call this function from within HookProc.
BOOL ReadProtectedFileInfo(char *pFileName)
{
//Prevent reentry:
bBusy=TRUE;
HANDLE hIniFile;
WORD error;
BYTE action;
hIniFile=R0_OpenCreateFile(TRUE,pFileName,OPEN_ACCESS_READONLY|OPEN_SHARE_COMPATIBLE|OPEN_FLAGS_COMMIT,ATTR_NORMAL,ACTION_IFEXISTS_OPEN|ACTION_IFNOTEXISTS_FAIL,R0_NO_CACHE,&error,&action);
if(error!=ERROR_SUCCESS)
{
ErrorHandler(FG_ERR_INI_FILE_NOT_FOUND);
return FALSE;
}
//INI file format: each record consist of a '@' followed by length of the path
//(4 char, including a whitespace),a '#' followed by protection type(3 char,
//including a whitespace) and anther '#' followed
//by the path of a file under protection.
const UINT BYTES_TO_READ=MAX_PATH*5;
char buf[BYTES_TO_READ+1];
char path[MAX_PATH+1];
UINT offset=0;
do
{
BYTE nBytesRead=0;
for(int i=0;i<=BYTES_TO_READ;i++) buf=0
nBytesRead=R0_ReadFile(FALSE,hIniFile,buf,BYTES_TO_READ,offset,&error);
if(nBytesRead==0) break;
if(error!=ERROR_SUCCESS)
continue;
UINT pos=0;
//find first '@':
while(*(buf+pos)!='@' &&
pos<=BYTES_TO_READ-1)
pos++;
offset+=pos;
do
{
PROTECTED_FILE protFile;
if(StringToFileInfo(buf+pos, &protFile,path)!=1)
break; //not more record in the string. Go on to read next.
else
{
pos+=(strlen(path)+RECORD_LEN)
offset+=(strlen(path)+RECORD_LEN)
//make sure offset is always pointing to the beginning of a new record.
#ifdef DEBUG
dout <<path<<endl;
#endif
protFileList.Add(&protFile);
}
}
while(1);
}
while(1);
R0_CloseFile(hIniFile,&error);
bBusy=FALSE;
return TRUE;
}
//save protected file information.
//DO NOT call this function from within HookProc.
BOOL SaveProtectedFileInfo(char *pFileName) //debug: unreferrence function.
{
//Prevent reentry:
bBusy=TRUE;
HANDLE hIniFile;
WORD error;
BYTE action;
hIniFile=R0_OpenCreateFile(TRUE,pFileName,OPEN_ACCESS_WRITEONLY|OPEN_SHARE_COMPATIBLE|OPEN_FLAGS_COMMIT,ATTR_NORMAL,ACTION_IFNOTEXISTS_CREATE|ACTION_IFEXISTS_TRUNCATE,R0_NO_CACHE,&error,&action);
if(error!=ERROR_SUCCESS)
{
ErrorHandler(FG_ERR_CANNOT_MAKE);
#ifdef DEBUG
dout << "Save file list: can't open file." << endl;
#endif
return FALSE;
}
//INI file format: each record consist of a '@' followed by length of the path
//(4 char, including a whitespace),a '#' followed by protection type(3 char,
//including a whitespace) and anther '#' followed
//by the path of a file under protection.
PROTECTED_FILE *pProtFile;
char *buf=(char *)malloc(MAX_PATH+15);
UINT offset=0;
if((pProtFile=protFileList.FindFirst())!=NULL)
{
UINT stringLen=sprintf(buf,"@ %3u, %2u,%s/0/n",strlen(pProtFile->PF_pPath),pProtFile->PF_type,pProtFile->PF_pPath);
stringLen++
//add the final char '/0'.
if((stringLen>R0_WriteFile(FALSE, hIniFile, buf, stringLen, offset, &error)) || error!=ERROR_SUCCESS)
{
ErrorHandler(FG_ERR_CANNOT_WRITE_RECORD);
#ifdef DEBUG
dout << "Save file list: can't write an record." << endl;
#endif
}
else offset+=stringLen
//writing success.
}
else //if not item found
{
R0_CloseFile(hIniFile, &error)
free(buf);
return TRUE
}
while((pProtFile=protFileList.FindNext())!=NULL)
{
UINT stringLen=sprintf(buf,"@ %3u, %2u,%s/0/n",strlen(pProtFile->PF_pPath),pProtFile->PF_type,pProtFile->PF_pPath);
stringLen++
//add the final char '/0'.
if((stringLen>R0_WriteFile(FALSE, hIniFile, buf, stringLen, offset, &error)) || error!=ERROR_SUCCESS)
{
ErrorHandler(FG_ERR_CANNOT_WRITE_RECORD);
#ifdef DEBUG
dout << "Save file list: can't write an record." << endl;
#endif
}
else offset+=stringLen
//writing success.
}
R0_CloseFile(hIniFile, &error)
free(buf);
bBusy=FALSE;
return TRUE
//end of list.
}
//call for win32 GUI to stop protection.
BOOL ShellUnloadDevice()
{
if(!hAppWnd)
return FALSE;
return SHELL_PostMessage(hAppWnd, SM_DEVICE_FATAL_ERROR, 0, 0, 0, 0);
}
//Post errer code to win32 app.
BOOL ShellPostError(DWORD err, int severity)
{
if(!hAppWnd)
return FALSE;
return SHELL_PostMessage(hAppWnd, SM_DEVICE_ERROR, (WORD)severity, err, 0, 0); //Error message sended to win32 app.
//wParam is severity, lParam is error code.
}
int wstrlen(unsigned short *uniString)
{
int i = 0;
int len = 0;
while( uniString[i++] != 0 ) len+=2;
return len;
}
//Make characters in a wide character string to upper case.
//Return Value: string length.
int StringUpper(WCHAR *s, int len)
{
int i=-1;
while(++i<=len)
if(s>='a' &&
s<='z')
s-=32;
return i;
}
//Convert BCS path to file system device's Canonicalized Path.
BOOL BCSToFSDPath(FSD_PATH *fp, const char *pBCSPath)
{
fp->ppath=(struct ParsedPath *)malloc((strlen(pBCSPath)+1)*sizeof(WCHAR));
if(!fp->ppath) return FALSE;
fp->flag=0;
fp->drive=pBCSPath[0]-'A'+1; //used first character as drive volume.
//i: index
prefix: prefix in parsed element(pe_length)
elemLength: length of an element;
unsigned int i=3,prefix=4, elemLength=0, totalLenghth=0;
_QWORD res;
do
{
if(*(pBCSPath+i)=='//')
{
BCSToUni((WCHAR *)((char *)fp->ppath+prefix+sizeof(WCHAR)), (PUCHAR)pBCSPath+i-elemLength, elemLength, BCS_OEM, &res);
*(short *)((char*)fp->ppath+prefix)=sizeof(WCHAR)+res.ddLower; //set pe_length.
totalLenghth+=*((char*)fp->ppath+prefix);
prefix+=*((char*)fp->ppath+prefix); //pointing to current '/' (pe_length).
elemLength=0;
i++;
continue;
}
else if(*(pBCSPath+i)=='*')
fp->flag|=FG_FILE_FLAG_HAS_STAR;
else if(*(pBCSPath+i)=='?')
fp->flag|=FG_FILE_FLAG_HAS_QUERYMARK;
elemLength++;
i++;
}
while(*(pBCSPath+i));
BCSToUni((WCHAR *)((char *)fp->ppath+prefix+sizeof(WCHAR)), (PUCHAR)pBCSPath+i-elemLength, elemLength, BCS_OEM, &res);
*(short *)((char*)fp->ppath+prefix)=sizeof(WCHAR)+res.ddLower; //set pe_length for last element.
totalLenghth+=*((char*)fp->ppath+prefix);
fp->ppath->pp_totalLength=2*sizeof(WCHAR)+totalLenghth; //set total length.
fp->ppath->pp_prefixLength=prefix; //pointing to last path element.
*(short *)((char *)fp->ppath+fp->ppath->pp_totalLength)=NULL;
return TRUE;
}
//Compare two parsed element.
BOOL _inline ElementMatch(PathElement *pPattern, PathElement *pMatcher, int flag)
{
if(!(flag&FG_FILE_FLAG_HAS_STAR) &&
pPattern->pe_length!=pMatcher->pe_length) //if pattern has not stars, and lengths don't equal, then match fail.
return FALSE;
return PatternMatch((WCHAR *)pPattern->pe_unichars, (WCHAR *)pMatcher->pe_unichars, pPattern->pe_length/sizeof(WCHAR)-1, pMatcher->pe_length/sizeof(WCHAR)-1);
}
//Compare two FSD_PATH struct.
BOOL _inline FSDPathMatch(FSD_PATH *pPattern, FSD_PATH *pMatcher)
{
//compare path.
if((pPattern->drive!=pMatcher->drive) || (!(pPattern->flag&FG_FILE_FLAG_HAS_STAR) &&
pPattern->ppath->pp_totalLength!=pMatcher->ppath->pp_totalLength))
return FALSE;
PathElement *ppe, *mpe;
ppe=pPattern->ppath->pp_elements;
mpe=pMatcher->ppath->pp_elements;
while(ppe->pe_length)
{
//compare each parsed element.
if(!ElementMatch(ppe, mpe, pPattern->flag))
return FALSE;
ppe=IFSNextElement(ppe);
mpe=IFSNextElement(mpe);
}
return TRUE;
}