ring3层一种占用文件的方法(DuplicateHandle以后,把占用文件的句柄丢给系统进程,导致被占用)
前段时间,一个测试工程师问我关于怎样长时间的占用一个文件,而使别的程序无法再访问这个文件,想起以前很多病毒木马经常劫持hosts文件不放,除非你找到占用文件的程序,并强行结束掉,否则怎么也访问不了hosts文件,病毒通过劫持这个文件来达到劫持你的域名的目的,很有可能你输入了www.baidu.com,访问的却是一个带颜色的网站,并稀里哗啦在后台下了上百个病毒,扯远了,呵呵。
其实sdk里面有个API能够使你在ring3层通过拷贝文件句柄给另外一个进程的方式来达到占用某个文件的目录(ring3层就是应用层),编程实现也不难,不过可能有些用户权限不够,访问不了某些系统进程,这在开始就要有一个提权限的过程了。
提权限的代码如下:
- // -------------------------------------------------------------------------
- // 函数 : RaiseToDebugP
- // 功能 : 提升进程权限到debug权限
- // 返回值 : void
- // 附注 : 该函数就是提升调用进程的权限到DEBUG权限
- // -------------------------------------------------------------------------
- void RaiseToDebugP()
- {
- HANDLE hToken;
- // 获取当前进程句柄
- HANDLE hProcess = GetCurrentProcess();
- // 打开当前进程的Token,就是一个权限令牌,第二个参数可以用TOKEN_ALL_ACCESS
- if (OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
- {
- TOKEN_PRIVILEGES tkp;
- if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tkp.Privileges[0].Luid))
- {
- tkp.PrivilegeCount = 1;
- tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
- //通知系统修改进程权限
- BOOL bREt = AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, 0) ;
- }
- CloseHandle(hToken);
- }
- }
再调用下面的代码之前,先调用上面的函数。
关键地方就是DuplicateHandle这个API的使用,它的具体功能和使用方法大家可以去查MSDN,这里我就不说了,下面的代码有详细的代码说明,关键是首先要找一个系统的常驻进程像system,svchost.exe和system idle process之类的,然后打开一个文件,在把这个文件的句柄拷贝给这个系统进程,这样在自身进程退出之后,某个系统进程仍然持有这个文件的句柄,这样其他的进程再去打开的时候就会被拒绝了。
- // -------------------------------------------------------------------------
- // 函数 : OccupyFile
- // 功能 : 打开一个文件句柄,然后和system进程共享该句柄
- // 返回值 : BOOL
- // 参数 : LPCTSTR lpFileName
- // 附注 :
- // -------------------------------------------------------------------------
- BOOL OccupyFile(LPCTSTR lpFileName)
- {
- BOOL bRet;
- // 提升权限
- RaiseToDebugP();
- // 打开syetem进程,2000下PID是8,没有去看,也许吧,打开的时候必须赋予PROCESS_DUP_HANDLE权限
- HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, 5776); // 4为system进程号
- if (hProcess == NULL)
- {
- hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, 8);
- if (hProcess == NULL)
- return FALSE;
- }
- HANDLE hFile;
- HANDLE hTargetHandle;
- // 创建一个文件,当然这个文件可以是本来就存在的
- hFile = CreateFile(lpFileName, GENERIC_READ | GENERIC_EXECUTE | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if (hFile == INVALID_HANDLE_VALUE)
- {
- // 文件创建或打开失败
- CloseHandle( hProcess );
- return FALSE;
- }
- // 这个是关键的API调用了,复制句柄操作
- // 这里复制句柄的这个API还有些其他的用法,可以获取当前进程或线程的真实句柄
- bRet = DuplicateHandle(GetCurrentProcess(), // 拥有源句柄的那个进程的句柄,这里就是当前进程
- hFile, // 指定对象的句柄,也就是要拷贝的句柄
- hProcess, // 即将拥有新对象句柄的一个进程的句柄,这是是system进程的句柄
- &hTargetHandle, // 指定用于装载新句柄的一个长整型变量
- 0, // 新句柄的安全访问级别
- FALSE, // 是否可以继承
- DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE //
- );
- CloseHandle(hProcess);
- return bRet;
- }
vista下system的进程ID不是4,如果想结束文件被占有,可以使用unlock,pocessxp之类的小工具,vista下面比较奇怪的是,直接用unlock还要重启后才能有效果。
http://blog.csdn.net/magictong/article/details/2944076