DuplicateHandle GetCurrentProcess 实句柄 伪句柄


GetCurrentProcess得到得到的称之为"伪句柄"
只是一个标识,你可以发现,其实就是返回$FFFFFFFF,
每个进程得句柄都是一样得,只是实用于进程内部得使用.
如果你想得到实际得句柄,在进程间进行通讯,必需要进行转化,
调用DuplicateHandle,注意,得实句柄使用完成以后,你必须要调用CloseHandle去关闭.
其实,你应该明白了为何"伪句柄"得存在,就是使用简单,不用关闭,
不会造成内存泄漏.

同样道理,GetCurrentThread也是伪句柄,其值永远是$FFFFFFFE,只是适用于线程内部得使用.



DuplicateHandle() :

在系统中,对象分两类:核心对象和用户对象.如进程对象,线程对象,文件映射 
对象等就是核心对象;而向窗口,菜单等都是用户对象. 
两者是有差别的,用于标示用户对象的句柄是系统唯一的,也就是说,一个进程 
完全可以对另外一个进程中的用户对象进行操作,比如两个进程间通信的方法之一, 
就是发送消息.正是由于窗口是用户对象,所以句柄是系统唯一,通过FindWindow(), 
得到另外一个进程的窗口句柄,然后用SendMessage(),让hWnd的窗口过程来处理消 
息,实现了进程间的通信.因此,对于用户对象,你根本不用DuplicateHandle(),直接 
把句柄拿来用就行了. 
而核心对象则不一样.核心对象是为了加强系统的稳定性,因此,核心对象句柄是 
进程相关的,在每一个进程中都有一个核心对象表,每一个对象的索引(不完全是)作为内和对象的句柄,从而实现进程相关.同一个对象在不同的进程中可能有不 同的索引,即句柄.对核心对象进行操作时,系统还要进行安全检验,看一下你是否有权来操作这个对象.因此你不能同用户对象一样,直接把句柄拿过来用.比方 说,你想操作另一个进程中的文件映射对象,这个文件映射对象句柄在那个进程中假设是0x000001,但在你的进程中,很有可能0x00000001时表 示另一个核心对象,此时的操作就永远不会成功,甚至会产生灾难性的后果.此时,就有必要用DuplicateHandle().

-----------------------------------------------------------------------------------------------------------------

用DublicateHandle实现文件站坑:

#include <windows.h>

BOOL OccupyFile( LPCTSTR lpFileName );


int main()
{
OccupyFile("c:\\aaa111.txt");

    return 0;
}

void RaiseToDebugP()
{
HANDLE hToken;
HANDLE hProcess = GetCurrentProcess();
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);
}    
}

BOOL OccupyFile( LPCTSTR lpFileName )
{
BOOL    bRet;

RaiseToDebugP();

    HANDLE hProcess = OpenProcess( PROCESS_DUP_HANDLE, FALSE, 4);    // 4为system进程号

    if ( hProcess == NULL )
{
hProcess = OpenProcess( PROCESS_DUP_HANDLE, FALSE, 8);        // 2K下是 8??

if ( hProcess == NULL )
return FALSE;
}

    HANDLE hFile;
HANDLE hTargetHandle;

    hFile = CreateFile( lpFileName, GENERIC_READ, 0, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL, NULL);   


    if ( hFile == INVALID_HANDLE_VALUE )
{
CloseHandle( hProcess );
return FALSE;
}

    bRet = DuplicateHandle( GetCurrentProcess(), hFile, hProcess, &hTargetHandle, 
0, FALSE, DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE);

    CloseHandle( hProcess );

    return bRet;
}

 

The DuplicateHandle function duplicates an object handle.

The duplicate handle refers to the same object as the original handle.

Therefore, any changes to the object are reflected through both handles.

For example, the current file mark for a file handle is always the same

for both handles.

BOOL DuplicateHandle(
  HANDLE hSourceProcessHandle,  // handle to source process
  HANDLE hSourceHandle,         // handle to duplicate
  HANDLE hTargetProcessHandle,  // handle to target process
  LPHANDLE lpTargetHandle,      // duplicate handle
  DWORD dwDesiredAccess,        // requested access
  BOOL bInheritHandle,          // handle inheritance option
  DWORD dwOptions               // optional actions
);
hTargetProcessHandle hSourceHandle,是任意类型的内核对象句柄,而且这个句柄和调用duplicatehandle的进程无关

Handle to the process that is to receive the duplicated handle. The handle must have PROCESS_DUP_HANDLE access.

==============

其实就是把该文件的句柄(真正的句柄)复制给了system进程。

==============

函数比较:

GetCurrentProcess():

GetCurrentProcess得到得到的称之为"伪句柄"
只是一个标识,你可以发现,其实就是返回$FFFFFFFF,
每个进程得句柄都是一样得,只是实用于进程内部得使用.
如果你想得到实际得句柄,在进程间进行通讯,必需要进行转化,
调用DuplicateHandle,注意,得实句柄使用完成以后,你必须要调用CloseHandle去关闭.
其实,你应该明白了为何"伪句柄"得存在,就是使用简单,不用关闭,
不会造成内存泄漏.

同样道理,GetCurrentThread也是伪句柄,其值永远是$FFFFFFFE,只是适用于线程内部得使用.

DuplicateHandle() :

在系统中,对象分两类:核心对象和用户对象.如进程对象,线程对象,文件映射 
对象等就是核心对象;而向窗口,菜单等都是用户对象. 
两者是有差别的,用于标示用户对象的句柄是系统唯一的,也就是说,一个进程 
完全可以对另外一个进程中的用户对象进行操作,比如两个进程间通信的方法之一, 
就是发送消息.正是由于窗口是用户对象,所以句柄是系统唯一,通过FindWindow(), 
得到另外一个进程的窗口句柄,然后用SendMessage(),让hWnd的窗口过程来处理消 
息,实现了进程间的通信.因此,对于用户对象,你根本不用DuplicateHandle(),直接 
把句柄拿来用就行了. 
而核心对象则不一样.核心对象是为了加强系统的稳定性,因此,核心对象句柄是 
进程相关的,在每一个进程中都有一个核心对象表,每一个对象的索引(不完全是)作为内和对象的句柄,从而实现进程相关.同一个对象在不同的进程中可能有不 同的索引,即句柄.对核心对象进行操作时,系统还要进行安全检验,看一下你是否有权来操作这个对象.因此你不能同用户对象一样,直接把句柄拿过来用.比方 说,你想操作另一个进程中的文件映射对象,这个文件映射对象句柄在那个进程中假设是0x000001,但在你的进程中,很有可能0x00000001时表 示另一个核心对象,此时的操作就永远不会成功,甚至会产生灾难性的后果.此时,就有必要用DuplicateHandle().

===========================================

The state of a mutex object is signaled when it is not owned by any thread. The creating thread can use the bInitialOwner flag to request immediate ownership of the mutex. Otherwise, a thread must use one of the wait functions to request ownership. When the mutex's state is signaled, one waiting thread is granted ownership, the mutex's state changes to nonsignaled, and the wait function returns. Only one thread can own a mutex at any given time. The owning thread uses the ReleaseMutex function to release its ownership.

对比一下开源程序的代码

(题外话:

普通的主线程建立子线程的时候通常都是在子线程变为有信号该函数才返回,也就是说在子线程结束运行后就是signaled的了

如下面的代码:

int main(int argc, char* argv[])
{
HANDLE hThread;
DWORD dwThreadId;

// 创建一个线程
hThread = ::CreateThread (
NULL,   // 默认安全属性
NULL,   // 默认堆栈大小
ThreadProc, // 线程入口地址(执行线程的函数)
NULL,   // 传给函数的参数
0,   // 指定线程立即运行
&dwThreadId); // 返回线程的ID号
printf(" Now another thread has been created. ID = %d \n", dwThreadId);

// 等待新线程运行结束
::WaitForSingleObject (hThread, INFINITE);
::CloseHandle (hThread);
return 0;
}

)

///

这是一个开源的软件中的利用互斥对象判断是否运行有另一个本程序的拷贝的方法。。。

bool MyApp::OnInit()
{
// Check if program is already run

HANDLE hMutex;

// Create a mutex with no initial owner.

hMutex = CreateMutex( 
NULL,                       // no security attributes
FALSE,                      // initially not owned
"MutexToProtectDatabase"); // name of mutex

if (hMutex == NULL) 
return false;

/************************************微软已经说得很清楚了,Otherwise, a thread must use one of the wait functions to request ownership. 建立一个内核对象,程序运行结束的时候,不管是自己在程序的最后调用closehandle函数或是由windows替你去做这一切,都会释放内核对象。 因此当你的程序没有运行结束的时候,这一个内核对象是不会被释放的。因此,对象就一直处于无信号的状态。也就说明了这一个程序已经有一个拷贝在运行了

也可以这么说,只有当你的程序运行结束并释放内核对象后,这个你自己命名的内核对象才会消失,这时如果程序再次重新运行,由于该内核对象并没有被初始化,因次下面的代码的判断语句也就不会执行了,因次return语句得不到执行,程序也就不会exit了。
*****************************/
if (WaitForSingleObject(hMutex,0)==WAIT_TIMEOUT)
{
wxMessageBox("Only one copy of allowed!", “", wxOK | wxICON_INFORMATION);
return false;
}

再者由于内核对象是被内核所拥有的,因次内核对象的生存时间(姑且这么说)一般来说都会比程序长一些。

而我们正是利用了内核对象独立与程序的这一点来判断是否已经有一个程序运行。绝对可以说是高明。

说到这里,到底内核对象是什么呢?<programming application >l里面有:

http://hi.baidu.com/wpclub/blog/item/4112ad3f482c5fc67c1e713c.html

WaitForSingleObject

If the function succeeds, the return value indicates the event that caused the function to return. This value can be one of the following.

Value Meaning
WAIT_ABANDONED The specified object is a mutex object that was not released by the thread that owned the mutex object before the owning thread terminated. Ownership of the mutex object is granted to the calling thread, and the mutex is set to nonsignaled.
WAIT_OBJECT_0 The state of the specified object is signaled.
WAIT_TIMEOUT The time-out interval elapsed, and the object's state is nonsignaled.

///

nosignaled表示正在被使用中

又在网上找到的另一个程序:

#include <Windows.h>

int
WINAPI
WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd
)
{
char strAppName[] = "OnlyOne";
HANDLE hMutex = NULL;

 //创建互斥对象
hMutex = CreateMutex(NULL, FALSE, strAppName);
if (hMutex != NULL)
{
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
MessageBox(NULL,TEXT("不是第一次运行这个程序。"),TEXT("OnlyOne"),MB_OK | MB_ICONINFORMATION);
//关闭互斥对象,退出程序
CloseHandle(hMutex);
return (-1);
} else
{
MessageBox(NULL,TEXT("第一次运行这个程序。"),TEXT("OnlyOne"),MB_OK | MB_ICONINFORMATION);
}
} else
{
MessageBox(NULL,TEXT("创建互斥对象失败。"),TEXT("OnlyOne"),MB_OK | MB_ICONINFORMATION);
}
//关闭互斥对象
CloseHandle(hMutex);
return (-1);

======================================

Example Code [C++]

The following example creates a mutex, duplicates a handle to the mutex, and passes it to another thread. Duplicating the handle ensures that the reference count is increased so that the mutex object will not be destroyed until both threads have closed the handle.
#include <windows.h>

DWORD CALLBACK ThreadProc(PVOID pvParam);

int main()
{
HANDLE hMutex = CreateMutex(NULL, FALSE, NULL);
HANDLE hMutexDup, hThread;
DWORD dwThreadId;

    DuplicateHandle(GetCurrentProcess(), 
hMutex, 
GetCurrentProcess(),
&hMutexDup, 
0,
FALSE,
DUPLICATE_SAME_ACCESS);

    hThread = CreateThread(NULL, 0, ThreadProc, 
(LPVOID) hMutexDup, 0, &dwThreadId);

    // Perform work here, closing the handle when finished with the
// mutex. If the reference count is zero, the object is destroyed.
CloseHandle(hMutex);

    // Wait for the worker thread to terminate and clean up.
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
return 0;
}

DWORD CALLBACK ThreadProc(PVOID pvParam)
{
HANDLE hMutex = (HANDLE)pvParam;

    // Perform work here, closing the handle when finished with the
// mutex. If the reference count is zero, the object is destroyed.
CloseHandle(hMutex);
return 0;

}

------------------------------------------------------------------

先来了解一下 DuplicateHandle函数的作用

BOOL DuplicateHandle(
HANDLE hSourceProcessHandle, // handle to the source process
HANDLE hSourceHandle,         // handle to duplicate
HANDLE hTargetProcessHandle, // handle to process to duplicate to
LPHANDLE lpTargetHandle, // pointer to duplicate handle
DWORD dwDesiredAccess,    // access for duplicate handle
BOOL bInheritHandle,      // handle inheritance flag
DWORD dwOptions           // optional actions
)

说明 在指出一个现有系统对象当前句柄的情况下,为那个对象创建一个新句柄。当前句柄可能位于一个不同的进程

如果我们打开想要保护文件,并且不关闭文件句柄,这样文件就无法删除。
那要怎样保证句柄不被关闭呢?当进程退出的时候,即使不关闭句柄,windows系统也会帮你做清理工作,关闭句柄。这时我们可以利用win32 API DuplicateHandle来复制文件句柄到其他进程中,这样即使我们的进程结束了,文件句柄依然还没关闭。文件占坑保护就是利用这个事实来达到保护文件的目的。其他进程我们选哪个呢?csrss.exe system.exe winlogon.exe都可以。

代码如下:

BOOL ProtectFile(
IN LPCTSTR pszFilePath,
IN DWORD dwProcessId,
IN BOOL bFileCanBeRead
)
{
HANDLE hFile;
HANDLE hProcess;

// get the file handle

hFile = CreateFile(
pszFilePath, 
GENERIC_READ, 
(bFileCanBeRead ? FILE_SHARE_READ : 0), 
NULL, 
OPEN_EXISTING, 
FILE_ATTRIBUTE_NORMAL, 
NULL
);
if (hFile == INVALID_HANDLE_VALUE) 
{
return FALSE;
}

// open the process handle

hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, dwProcessId);
if (!hProcess) 
{
CloseHandle(hFile);
return FALSE;
}

// call duplicatehandle

BOOL fOk = DuplicateHandle(
GetCurrentProcess(),              // source process handle
hFile,                                     // source handle
hProcess,                              // target process handle
NULL,                                    // target handle, we don't care it
0,
FALSE,                                   
DUPLICATE_SAME_ACCESS
);

CloseHandle(hFile);
CloseHandle(hProcess);
return fOk;
}                      
类别:默认分类 |  | 添加到搜藏 | 分享到i 贴吧 | 浏览(1075) | 评论 (1)
网友评论
 
发表评论


内 容:
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值