首页
社区
课程
招聘
[求助]关于WINDOWS核心编程中句柄方面的一点疑惑?
发表于: 2011-7-16 01:42 8104

[求助]关于WINDOWS核心编程中句柄方面的一点疑惑?

2011-7-16 01:42
8104
核心编程第五版第十章中说的每个文件内核对象都有自己的文件指针。并给出例子:
BYTE pb[10];
DWORD dwNumBytes;
HANDLE hFile1=CreateFile(TEXT("MyFile.dat"),...);//Pointer set to 0
HANDLE hFile2=CreateFile(TEXT("MyFile.dat"),...);//Pointer set to 0
ReadFile(hFile1,pb,10,&dwNumBytes,NULL);//Reads bytes 0--9
ReadFile(hFile2,pb,10,&dwNumBytes,NULL);//Reads bytes 0--9
在这个例子中,使用了两个不同的内核对象来管理同一个文件。由于每个内核对象都有自己的文件指针,用一个文件对象来对文件进行操作不会影响到其他对象的文件指针,因此文件的前10个字节被读取了两次。
这个还比较容易理解:进程创建时,OS会为进程构造一个句柄表,当该进程希望获得一个内核对象句柄或者创建一个内核对象从而获得该对象句柄时,系统会在句柄表中增加一个表项,会把这个返回的句柄放置在进程的句柄表中。
上述代码创建了2个文件内核对象,因此在主调进程的句柄表中会放置两个句柄(hFile1,hFile2),分别对应两个内核对象,也就分别有一个属于自己的文件指针,所以上述结果合理。
接下来对书中代码进行了测试:
#include<iostream>
#include<windows.h>
using namespace std;
int main(int argc,char * argv[])
{
	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	ZeroMemory(&si,sizeof(si));
	si.cb=sizeof(si);
	ZeroMemory(&pi,sizeof(pi));
	CreateProcess(NULL,"notepad.exe 23.txt",NULL,NULL,FALSE,0,NULL,NULL,
		&si,&pi);

	BYTE pb[11]={0};
	DWORD dwNumBytes;
	HANDLE hFile1=CreateFile("12.txt",GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
	HANDLE hFile2=NULL;//=CreateFile("12.txt",GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
    //DuplicateHandle(GetCurrentProcess(),hFile1,pi.hProcess,&hFile2,0,FALSE,DUPLICATE_SAME_ACCESS);//测试1
	DuplicateHandle(GetCurrentProcess(),hFile1,GetCurrentProcess(),&hFile2,0,FALSE,DUPLICATE_SAME_ACCESS);//测试2
	ReadFile(hFile1,pb,10,&dwNumBytes,NULL);
	cout<<pb<<endl;
	ReadFile(hFile2,pb,10,&dwNumBytes,NULL);
	cout<<pb<<endl;
	CloseHandle(hFile1);
	CloseHandle(hFile2);
	system("pause");
	return 0;
}

自己对于测试2的理解:
DuplicataHandle是复制句柄,把源进程中的某个句柄复制到目的进程中,得到了在目的进程中的一个句柄值(当然源进程可以跟目标进程相同---GetCurrentProcess返回的是伪句柄。。。不再讨论),上述代码刚好是源进程句柄跟目标句柄进程相同(都用了GetCurrentProcess得到当前进程的伪句柄--可以只在本进程内使用),然后这个进程的进程句柄表中已经有了这个文件的句柄了,也就是hFile1,现在在把这个文件句柄hFile1复制到这个进程中?首先想到的是多此一举,其实不完全是,起码增加了这个内核对象中的引用计数了,我的意思是既然这个句柄hFile1已经在这个进程句柄表中了,那现在在复制一次是不是应该跟原来的句柄值一样呢?仅仅只是让引用计数从1变成2.然而我调试发现,这里的hFile1!=hFile2,这里比较困惑,按理说应该相等才对吧?毕竟只有一个文件内核对象,而非2个。请问这里该如何理解,谢谢先!
对于测试1的理解:
由于把文件句柄复制到了其他的进程,则其他进程的进程句柄表中势必会有此文件句柄用来表示该文件,但是这个进程并没有因此创建一个文件内核对象(只有文件内核对象才有一个文件指针的),因此何来文件指针呢?更何况后面还读取了10个字节呢?DuplicateHandle只是复制句柄(MSDN的解释没发现其他内容)这里也迷茫了,请大家帮忙理解一下,三克油三克油!!!

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
免费 0
支持
分享
最新回复 (9)
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
2
句柄只是内核对象在句柄表中的索引,索引不同,但是其内容可以是相同的啊,就像指针一样~~
复制句柄操作只是在指定的目标进程的句柄表中找到一个空闲的位置把源句柄指向的对象写入,并返回这个新位置的索引,所以从这个操作上讲,对于测试2,两个句柄的值肯定是不同的,尽管他们指向相同的对象,就好像一个人有两个电话号码一样,你打哪个都能找到它~
对于测试1,你复制之后的hFile2根本不属于当前进程,而句柄是进程相关的,所以这个句柄你只能看(即你知道它的值,甚至可以知道它对应的文件对象的值),但是根本无法使用,使用ReadFile来读取hFile2是不可能成功的,就像我知道你家保险柜里放了多少钱,但是也仅仅是“知道”而已,根本没有权限来使用~~
2011-7-16 07:00
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
3
感谢形象生动加风趣回答!特别说明一下,我家没有保险柜的
你说的测试1只能看到句柄,但是根本无法使用,使用ReadFile来读取hFile2是不可能成功的,这里好像有点问题吧,因为上述代码我测试,确实能读取出来文件中的前10个字节的,从0-9前面10个字节的。
再次翻了一下书对DuplicateHandle的说明:书上说这个函数获得一个进程的句柄表中的一个记录项,然后在另一个进程的句柄表中创建这个记录项的一个副本。请问这里的副本该如何理解呢?

就以如下的例子来分析吧:
假如进程S创建了一个文件内核对象,他的句柄表如下:
                    进程S的句柄表

索引                指向内核对象内存块的指针       访问掩码                     标志
1                           0x00000000                            (不可用)                             不可用
2                          0xF0000020(文件内核对象)         0x????????                   0x00000000
现在利用duplicatehandle复制句柄到进程T中,假如复制到T之前T的句柄表如下:
                   调用DuplicateHandle之前,进程T的句柄表

索引            指向内核对象内存块的指针         访问掩码        标志
1                      0x00000000                             不可用         不可用
2                      0xF0000030                           0x?????            0x00000000

调用DuplicateHandle之后,进程T的句柄表:
索引         指向内核对象内存块的指针                访问掩码           标志
1                  0xF0000020(是文件内核对象的地址吗?)  0x???               0x00000001(1?)
2                 0xF0000030                                         0x???                  0x00000000

以上是核心编程第三章中的一些说明,针对上述说明有一些疑问:
疑问1 :复制的副本就是指指向内核对象内存块的指针?标志怎么变成1了?这个还算是副本吗?已经变化了嘛?
疑问2:仅仅把指向内核对象内存块的指针原模原样的复制到进程T的句柄表中为什么进程T就能访问此文件了。我们从小受的教育就是进程是相互独立的,每个进程有属于自己独立的4G地址空间,哦,抱歉,内核对象不是属于进程的,是属于内核的。那我想问,这里表示的地址:0xF0000020是被内核占用的地址,是逻辑地址还是物理地址呢?既然这个地址被放到了进程的句柄表中,那进程一定会翻译这个地址从而找到文件内核对象的真实物理地址,进而操作文件吧,两个进程的句柄表中都有这个地址0XF0000020,怎么能指向同一个文件内核对象呢?(进程是独立的,同一个地址代表的完全不同意义)请问这里该如何解释呢?谢谢,问题有点长,自己的表达能力不是很强,希望各位不要见怪啊!!!!!!
2011-7-16 14:49
0
雪    币: 27
活跃值: (43)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
你说的测试1只能看到句柄,但是根本无法使用,使用ReadFile来读取hFile2是不可能成功的,这里好像有点问题吧

没问题  ,如果你可以读取,那你比较一下 hFile1 和 hFile2 是否一样

标志怎么变成1了?
这个标志好像是说明句柄来源的,记不清楚了,但使用上是一模一样的,因为访问掩码一样

疑问2:
进程的用户地址空间是不同的,但是用户空间以上的系统空间是共用的,也就是说 2GB以上 大家的内容都是一样的,是逻辑地址,也需要转换成物理地址
2011-7-16 17:49
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
5
我补充一下楼上的。
一、关于hFile2的问题
楼主你在读取之前最好所楼上所说确认一下hFile2的值是不是和hFile1一样,如果一样的话说明只是个巧合,并且可以判断下ReadFile的返回值来判断到底有没有读取成功,这个应该很简单吧?

二、0xF0000020的问题
楼主所举的0xF0000020这个就是文件对象的地址(也就是FileObject,以后你会具体接触到),地址一样当然指向的是同一个对象了嘛。。。这是个逻辑地址,也是个内核地址,所有进程都可以访问

三、标志的问题
在实际中,标志和对象地址是在同一个值中存储的(内核对象的地址总是8字节对齐,所以低位的3个bit总是0,可以用做标志位),在复制句柄的时候这个标志视具体情况可能会有一些改变吧
2011-7-17 08:24
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
6
如你所说,昨天调试才发现确实是hFile2的值跟hFile1一样导致pb的内容相同,已经OK了。第二个问题看了你的解释也明白了,0xF0000020确实是个内核地址,所有进程都可以访问到的,疑惑也就彻底消除了,thanks very much!
2011-7-17 12:10
0
雪    币: 132
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
关于这个函数请教个问题
假如A进程调用了duplicatehandle函数把句柄hfile传递给了进程B,。。进程B怎么使用这个句柄,或者是进程B怎样获得这个句柄。。
2011-8-9 01:32
0
雪    币: 132
活跃值: (214)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
8
进程B是肯定不知道他多了一个句柄的,所以他也没法用,要想使用此句柄,需要进程间通信传递值吧。
2011-8-9 09:24
0
雪    币: 132
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
哦明白了。
2011-8-9 17:43
0
雪    币: 90
活跃值: (91)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
解我一个惑 嘿嘿
2012-3-7 18:44
0
游客
登录 | 注册 方可回帖
返回
//