DuplicateHandle用法
The DuplicateHandlefunction creates a duplicate handle. The returned duplicate is in the caller's process space.(从当前进程复制句柄到其他进程空间)
示例代码:
1 //ALL of the following code is executed by Process S. 2 //Create a mutex object accessible by Process S. 3 HANDLE hObjProcessS = CreateMutex(NULL, FALSE, NULL); 4 5 //Open a handle to Process T's kernel object. 6 HANDLE hProcessT = OpenProcess(PROCESS_ALL_ACCESS, 7 FALSE, dwProcessIdT); 8 9 //An uninitilized handle relative to Process T. 10 HANDLE hObjProcessT; 11 12 //Give Process T accesss to our mutex object 13 DuplicateHandle(GetCurrentProcess(), 14 hObjProcessS, 15 hProcessT, 16 &hObjProcessT, 0, FALSE, 17 DUPLICATE_SAME_ACCESS); 18 19 //Use some IPC mechanism to get the handle 20 //valuein hOnjProcess S into Process T 21 //We nolonger need to communicate with Process T. 22 //[Mailslot, pipe, share memory, socket. etc.] 23 //传递句柄的值到其他进程 24 CloseHandle(hProcessT); 25 26 //WhenProcess S no longer needs to Use the mutex, 27 //itshould close it. 28 CloseHandle(hObjProcessS);
内核对象的句柄会在新进程中,产生一条记录,并且该内核对象计数增加。
根据引用计数,这里会引出该函数的一种巧妙用法,文件锁定或者叫文件占坑,原理如下:
向系统进程中,复制打开的文件句柄,内核对象在所有引用未删除时不会销毁。
示例代码:
1 #include <windows.h> 2 3 BOOL OccupyFile( LPCTSTR lpFileName ); 4 5 int main() 6 { 7 OccupyFile("c:\\duplicateHandle_Test.txt"); 8 9 return 0; 10 } 11 12 void RaiseToDebugP() 13 { 14 HANDLE hToken; 15 HANDLE hProcess = GetCurrentProcess(); 16 if ( OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken) ) 17 { 18 TOKEN_PRIVILEGES tkp; 19 if ( LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tkp.Privileges[0].Luid) ) 20 { 21 tkp.PrivilegeCount = 1; 22 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 23 24 BOOL bREt = AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, 0) ; 25 } 26 CloseHandle(hToken); 27 } 28 } 29 30 BOOL OccupyFile( LPCTSTR lpFileName ) 31 { 32 BOOL bRet; 33 34 RaiseToDebugP(); 35 36 HANDLE hProcess = OpenProcess( PROCESS_DUP_HANDLE, FALSE, 4); // 4为system pid 37 38 if ( hProcess == NULL ) 39 { 40 hProcess = OpenProcess( PROCESS_DUP_HANDLE, FALSE, 8); // OS-2K is 8 41 42 if ( hProcess == NULL ) 43 return FALSE; 44 } 45 46 HANDLE hFile; 47 HANDLE hTargetHandle; 48 49 hFile = CreateFile( lpFileName, GENERIC_READ, 0, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL, NULL); 50 51 52 if ( hFile == INVALID_HANDLE_VALUE ) 53 { 54 CloseHandle( hProcess ); 55 return FALSE; 56 } 57 58 bRet = DuplicateHandle( GetCurrentProcess(), hFile, hProcess, &hTargetHandle, 59 0, FALSE, DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE); 60 61 CloseHandle( hProcess ); 62 63 return bRet; 64 }
DuplicateHandle()复制句柄函数的用法
很多像我一样的菜鸟起初都不知道DuplicateHandle()的用法和为何要使用DuplicateHandle()函数,现在我在这里总结一下:
BOOL WINAPI DuplicateHandle( __in HANDLE hSourceProcessHandle, __in HANDLE hSourceHandle, __in HANDLE hTargetProcessHandle, __out LPHANDLE lpTargetHandle, __in DWORD dwDesiredAccess, __in BOOL bInheritHandle, __in DWORD dwOptions ); hSourceProcessHandle:源进程内核句柄(即负责传递内核对象句柄的进程句柄)
hSourceHandle:要传递的内核对象句柄
hTargetProcessHandle:目标进程内核句柄
lpTargetHandle:接收内核对象句柄的地址(先随便声明一个HANDLE)
dwDesiredAccess:TargetHandle句柄使用何种访问掩码(这个掩码是在句柄表中的一项)
bInheritHandle:是否拥有继承
dwOptions:当设DUPLICATE_SAME_ACCESS时,表示于源的内核对象所有标志一样,此时wDesiredAccess可标志为0 当设DUPLICATE_CLOSE_SOURCE时,传输完后,关闭源中的内核对象句柄
此函数能否成功调用还要看你是否有足够的权限去操作目标进程
通常目标进程的内核句柄是利用OpenProcess()得到的
HANDLE WINAPI OpenProcess( __in DWORD dwDesiredAccess, __in BOOL bInheritHandle, __in DWORD dwProcessId ); dwDesiredAccess:决定你拥有该进程的操作权限,如果要成功用到则要填PROCESS_ALL_ACCESS或PROCESS_DUP_HANDLE
bInheritHandle:是否可继承
dwProcessId:这个ID可在资源管理器中找到,当然,我不提倡在哪里得到,或者你可以通过进程间通信的方法把PID从目标进程传给源进程
若DuplicateHandle()能成功执行,则利用进程通信把句柄值TargetHandle传给目标进程,让他知道利用该句柄使用内核对象
注意:不要试图在源进程中利用CloseHandle()关闭TargetHandle,因为这个TargetHandle句柄值并不属于源进程的句柄表中的,若错误关闭了,会产生不可预料的结果
好了,只要依照上面的做法,基本是可以正确用到DuplicateHandle()函数的
但很多菜鸟们都不知道为何要用复制句柄函数,我利用进程间通信把句柄传给目标进程不就行了吗?
这样的想法就大错特错了,我们表面上是在复制句柄值,实际上是把该句柄在源进程句柄表中的所有项复制到目标进程的句柄表中,而且使该内核对象的计数器+1了,如果只是简单的只传句柄值,目标进程的句柄表中是不会有所增加的
顺便一提,句柄表是各进程用来记录该进程的内核对象的.