NtCreatFile函数的参数传递分析 - zl21 - 程序员网志 - Powered By PHPWind.Net

导读:

写这篇分析的目的: m^mNa8$  
最近在反汇编一个驱动程序时,看到CreateDispacth里面有这么一段操作: F{>Tg lX1f  
;eax=IoGetCurrentIrpLocationStack(Irp) %N~5S5q''  
mov   eax, [ecx+8]           ; eax->Parameters.Create.Option     Ima~JKh  
mov   cx, [ecx+0Ch]           ;eax->Parameters.Create.FileAttributes |/n~;0  
mov   edi, eax Lw @0g  
shr   eax, 18h     ; 右移24位得到CreateOption里面的CreateDisposition参数 qz [ A#z  
                ; 以下是C代码: #08ZSu7M(,  
                ; ULONG disposition GGL%yUtkq  
                ; dispostion=(irpSp->Parameters.Create.Option>>24)&0xff ~yL5  
mov   esi, eax ?{X1/XM!-@  
and   edi, 0FFFFFFh   ; edi=204022 h0X?Z0.  
cmp   esi, 4 _;- '&or{  
…… ` b"LV>  
qu7t%^  
本来我是不知道该代码取的是 CreateDisposition 参数的,是论坛上的一个朋友告诉我的,但是我不知道 win 为什么会这么操作,本着打破沙锅的精神(神经:)),写了分析。 p8n_Bq OJ  
首先来看看在这段代码以前 win 都做了什么: 7-k9Du}]2  
. {]* qz  
**!CreateDispacth zMsLn$tO:  
nt!IopCallDriver `}",TZ0Q  
nt!IopParseDevice m'Cp^s  
nt!ObpLookupObjectName `Y$D.;0  
nt!ObOpenObejctByName }FT/6-"gV  
nt!IopCreateFile mb +d9sTu$  
nt!IoCreateFile T7H~S8(  
nt!NtCreateFile )Am:o  
nt!KiSystemService dM|u3W e  
nt!ZwCreateFile ~U^,V%b,u  
…… q.9l&Ky8  
在 nt!IopparseDevice 中: !mdEjLagf^  
调用 nt!IoGetAttacheDevice ,获得设备栈最顶端的设备对象。调用 IoAllocateIrp 创建 IRP。调用 nt!ObCreateObject 创建文件对象。初始化这个文件对象。该文件对象的 +04 struct _DEVCIE_OBEJCT *DeviceObejct 赋值为通过传入参数找到的那个设备对象。调用 nt!IopCallDriver 将IRP发给设备栈的栈顶。(参考了jiurl的键盘驱动里的一段章节) zX|u7]O  
(Mc[tuUZU  
我不是要抄袭jiurl的大作,我只是想有一个基本的框架。 jWg1r9  
3<^_ Q_#f]  
回到原来的问题,那些参数是怎样传递的??为什么会这样取参数?? ,>;8YZMu  
先来看看 IoAllocateIrp 函数的代码(请出至尊宝典 win2k 的源代码): koA$RwK  
v/{hU"+$6  
代码简单的出乎我的意料: Dy<=lt  
IoAllocateIrp其实什么也不做,他只是一个公共接口函数。 CiuQx 
PIRP kDXXel/  
IoAllocateIrp( "JAK?8 ix  
  IN CCHAR StackSize, ~/eQ82  
  IN BOOLEAN ChargeQuota *C2w?0  
  ) r%0H O7G  
{ .,yH1zkf  
  return (pIoAllocateIrp(StackSize, ChargeQuota)); s%

 
} ETWN'9e  
5MK vsEQ  
extern PIO_ALLOCATE_IRP     pIoAllocateIrp; R*R/C1(pJ  
Cvh DqySi9  
在win2k 源代码中,我找到了两个对 pIoAllocateIrp 的赋值,也就是说有两个 AllocateIrp 函数,他们分别是 PIRP IovAllocateIrp( IN CCHAR StackSize, IN BOOLEAN ChargeQuota) 和 PIRP IopAllocateIrpPrivate( IN CCHAR   StackSize, IN BOOLEAN ChargeQuota),这两个函数的主要功能是检查参数和为 IRP 分配内存空间,最后都会调用同一个函数 IopInitializeIrp 来初始化 Irp ,至于在什么情况下调用 IovAllocateIrp 和 IopAllocateIrpPrivate 函数则不在我的讨论范围里面。 qnzz>(!R  
>&U(q^I  
而 IoInitializeIrp函数也同样出乎了我的意料 yFp+ c  
#define IopInitializeIrp( Irp, PacketSize, StackSize ) {       / -rr{Tl0  
  RtlZeroMemory( (Irp), (PacketSize) );                 / d7>} C 8  
  (Irp)->Type = (CSHORT) IO_TYPE_IRP;                   / }Q"b9HM">t  
  (Irp)->Size = (USHORT) ((PacketSize));                 / {p({2>}  
  (Irp)->StackCount = (CCHAR) ((StackSize));             / 4Ndx8 uV  
  (Irp)->CurrentLocation = (CCHAR) ((StackSize) + 1);       / n@?Mq>V>BT  
  (Irp)->ApcEnvironment = KeGetCurrentApcEnvironment();       / D l^/ IP  
  InitializeListHead (&(Irp)->ThreadListEntry);           / L'XAKoP|  
  (Irp)->Tail.Overlay.CurrentStackLocation =             / %C8%MK>  
    ((PIO_STACK_LOCATION) ((UCHAR *) (Irp) +             / 9zu ,"_  
        sizeof( IRP ) +                           / <8b} W^Kq  
        ( (StackSize) * sizeof( IO_STACK_LOCATION )))); } pE ?Jy  
) 6Ie w3k  
这个函数只填充了部分参数,这些被填充了的参数只与IRP有关系,可是和我想要找的 NtCreateFile 所传入的那些参数则没有太大的关系。 0?POha  
&I/J>V  
看来我是走错了方向了,那么回过头让我从头跟踪一下这些参数的流向: u4X{!"!  
s[k^>0T3  
NTSTATUS 5vyXDq_m~  
NtCreateFile(OUT PHANDLE FileHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes, Jmf*10N  
        OUT PIO_STATUS_BLOCK IoStatusBlock,IN PLARGE_INTEGER AllocationSize OPTIONAL, hLL!+yFQ7  
        IN ULONG FileAttributes,IN ULONG ShareAccess,IN ULONG CreateDisposition,IN ULONG CreateOptions, ?^ZE`!qw  
        IN PVOID EaBuffer OPTIONAL,IN ULONG EaLength {aDY77w8  
        ) 3._]l&F=  
{ :9I}ZJyk  
  // RIvBA 3 lQ  
  // Simply invoke the common I/O file creation routine to do the work. ;1<`,{  
  // U&MUfMH_  
m 
  PAGED_CODE(); CG o#^-5 
4z[w?Vd#  
  return IoCreateFile( FileHandle,DesiredAccess,ObjectAttributes,IoStatusBlock,AllocationSize, A.@ /(_J  
                FileAttributes,ShareAccess,CreateDisposition,CreateOptions, +e:Pwka  
                EaBuffer,EaLength,CreateFileTypeNone,(PVOID)NULL,0 %ychWc k  
                ); LEx9>/a  
} Evo*f5dJ  
在 NtCreateFile中,传入的参数原封不动的被传入 IoCreateFile 函数; ] qP?72>  
在 IoCreateFile中,传入的参数被封装在一个_OPEN_PACKET的结构中: PH+K $  
…… _MG+V#w/  
  //参数检查 5-}[?/ 9  
…… 4- {sp d  
  openPacket.Type = IO_TYPE_OPEN_PACKET; {_2Vzu;|E  
  openPacket.Size = sizeof( OPEN_PACKET ); ;;<*#AZ P  
  openPacket.ParseCheck = 0L; p+@4qw`rS  
  openPacket.AllocationSize = initialAllocationSize; //NtCreateFile(……,IN PLARGE_INTEGER AllocationSize OPTIONAL,,……) J 
  openPacket.CreateOptions = CreateOptions; //NtCreateFile(……,IN ULONG CreateOptions,……) # QJRp  
  openPacket.FileAttributes = (USHORT) FileAttributes; //NtCreateFile(……,IN ULONG FileAttributes,……) 08;.MD|L  
  openPacket.ShareAccess = (USHORT) ShareAccess; //NtCreateFile(……,IN ULONG ShareAccess,……) )],CmM]1  
  openPacket.Disposition = Disposition; //NtCreateFile(……,IN ULONG CreateDisposition,……) "%LH/g  
  openPacket.Override = FALSE; Lt9xUfH)  
  openPacket.QueryOnly = FALSE; H --Nk  
  openPacket.DeleteOnly = FALSE; h -v*F  
  openPacket.Options = Options; ]_HGmz^I  
  openPacket.RelatedFileObject = (PFILE_OBJECT) NULL; p95H^%pt  
  openPacket.CreateFileType = CreateFileType; ;.E=$"wI  
  openPacket.ExtraCreateParameters = ExtraCreateParameters; JoYVeW#  
…… qLFu=Z  
  status = ObOpenObjectByName( ObjectAttributes,(POBJECT_TYPE) NULL,requestorMode, K'w'4  
                      NULL,DesiredAccess,&openPacket,&handle e#%P,{  
                    ); K5]&^$8^  
…… ULH#" rod0  
在传入的参数当中,DesireAccess 和 ObjectAttributes 是调用 ObOpenObejctByName 函数所用到的参数,不在封装之列,而IoStatusBlock 参数则作为单独的结构做处理,这里需要注意的就是 openPacket.Eabuffer 、openPacket.EaLength 和 openPacket.AllocationSize,AllocationSize 参数需要调用 ARGUMENT_PRESENT 宏函数来检验该参数是否为空,然后调用 ProbeForRead 函数做进一步的检查,然后使 initialAllocationSize 指向 AllocationSize,将 initialAllocationSize 封装入 openPacket 中,而 Eabuffer 则同样是调用 ARGUMENT_PRESENT 、ProbeForRead 做参数有效性检查,如果该函数不为空检查通过,则调用 ExAllocatePoolWithQuotaTag 函数为其分配内存空间,然后调用 RtlCopyMemory 函数将Eabuffer 从用户空间拷贝到内核空间。而其余的四个参数 FileAttributes、ShareAccess、Disposition、CreatOption 被原封不动的封装入 OPEN_PACKET 结构中; =e}Vg0YC  
gRV5DN[F#  
在 ObOpenObejctByName 函数中 openPacket 没有被改动过,调用 ObpLookupObjectName 函数; l--W]R  
…… 3%(Z60k  
  Status = ObpLookupObjectName( ObjectCreateInfo.RootDirectory,&CapturedObjectName,ObjectCreateInfo.Attributes, Gu,kj:  
                      ObjectType,AccessMode,ParseContext,ObjectCreateInfo.SecurityQos,NULL, %R9L2V 7,  
                      AccessState,&DirectoryLocked,&ExistingObject F?F!nM:P  
                    ); UiqQ1I2  
…… x!I9E(?#  
在这里,只不过是由 ParseContext 指针指向了OPNE_PACKET结构 H: H d  
同样在 ObpLookupObjectName 函数中 OPEN_PACKET 结构中的内容也没有被改动过,调用 IopParseDevice 函数; }; P8J9_  
…… OA9J*~Ty  
  Status = IopParseDevice( RootDirectory,ObjectType,AccessState,AccessMode,Attributes, JJfLW?`F =  
                  ObjectName,&RemainingName,ParseContext,SecurityQos,&Object /Vpo &QQ  
                  ); A/heOYy  
 
在 IopParseDevice 中首先是调用 IoAllocateIrp 函数来分配一个 IRP,这个在前面已经提过了,接下来便是填充 IRP 了。 9#1zy-r}  
…… u*6_ X-  
  POPEN_PACKET op; =7=0t_E8  
  op=ParseContext; *p`}p"Q  
…… bk|3Wl  
  irp = IopAllocateIrp( deviceObject->StackSize, TRUE ); 2N_q{5  
…… @-( 
  irp->Tail.Overlay.Thread = PsGetCurrentThread(); OP.ZnI"$k  
  irp->RequestorMode = AccessMode; V=&3m9wS"  
  irp->Flags = IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API | IRP_DEFER_IO_COMPLETION; !sDPz4f  
…… D[}9*v&l4  
  irpSp = IoGetNextIrpStackLocation( irp ); KD5_b6f  
  irpSp->Control = 0; P1 
  if (op->CreateFileType == CreateFileTypeNone) { R6d|@  
*&+@  
    irpSp->MajorFunction = IRP_MJ_CREATE; +%8EjnnR*  
    irpSp->Parameters.Create.EaLength = op->EaLength; 8R 
    irpSp->Flags = (UCHAR) op->Options; Vb_NX}U"o  
    if (!(Attributes & OBJ_CASE_INSENSITIVE)) { &Q.45?I  
        irpSp->Flags |= SL_CASE_SENSITIVE; 1YGktS(  
    } H)^eK7  
PR 5 
  } else if (op->CreateFileType == CreateFileTypeNamedPipe) { 2aGjK2]  
Q`S~G):  
    irpSp->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE; %9 SG  
    irpSp->Parameters.CreatePipe.Parameters = op->ExtraCreateParameters; t7;l8W-Z  
Ct >:CoT8  
  } else { u]#` :YP0Q  
@Ql7.G6  
    irpSp->MajorFunction = IRP_MJ_CREATE_MAILSLOT; J 3 D+^  
    irpSp->Parameters.CreateMailslot.Parameters = op->ExtraCreateParameters; @GCG^_#L  
  } ]{  
  irp->Overlay.AllocationSize = op->AllocationSize; [U84 o/QF"  
  irp->AssociatedIrp.SystemBuffer = op->EaBuffer; ~0p v-I  
  irpSp->Parameters.Create.Options = (op->Disposition << 24) | (op->CreateOptions & 0x00ffffff); @KCe 4e  
  irpSp->Parameters.Create.FileAttributes = op->FileAttributes; ~I ,MK  
  irpSp->Parameters.Create.ShareAccess = op->ShareAccess; 0*m6n`gB  
  irpSp->Parameters.Create.SecurityContext = &securityContext; D/V &y${  
$Qz:v6cE  
  irp->UserIosb = &ioStatus; N( bz]F  
  irp->MdlAddress = (PMDL) NULL; p09 i$!  
  irp->PendingReturned = FALSE; *z1v;CxQ  
  irp->Cancel = FALSE; #RMU& 
  irp->UserEvent = (PKEVENT) NULL; ?Sv+6?;TD  
  irp->CancelRoutine = (PDRIVER_CANCEL) NULL; [aPAdj:~w*  
  irp->Tail.Overlay.AuxiliaryBuffer = (PVOID) NULL; .i7/?" 7P)  
…… 4RI)^ 3p  
V RrOEb.@  
找到了,终于被我找到了,我们来看这一句: $tr6flv  
irpSp->Parameters.Create.Options = (op->Disposition << 24) | (op->CreateOptions & 0x00ffffff); x_kq3gu  
}aWHX T  
我想了很长的时间都不解其意(哎,都怪我笨的出奇5555……) U@sOu /u  
.3;ZBK% ,  
首先我们来看看 CreateOption 参数的取值: Ba)dS|X  
#define FILE_DIRECTORY_FILE               0x00000001 P9~/=;O/|  
…… 7' raX  
#define FILE_OPEN_BY_FILE_ID             0x00002000 zXjA5OI  
#define FILE_OPEN_FOR_BACKUP_INTENT         0x00004000 `%By@mE~E  
iGYl};3TQ  
再来看看 Disposition 参数的取值: ys 8(5Oo  
…… /@mUuo  
#define FILE_OPEN               0x00000001 sf}/[EtP  
#define FILE_CREATE               0x00000002 9ttOAR1  
…… {{P{9I1.B  
8}V]h51  
让我们做一个假设,假设Disposition 取值为0x00000002(FILE_CREATE),那么Disposition<<24 的值为 0x02000000,假设 CreateOption 的取值为0x00004000(FILE_OPEN_FOR_BACKUP_INTENT),那么CreateOptions & 0x00ffffff的值为 0x00004000,这样一来(Disposition << 24) | (CreateOptions & 0x00ffffff)的值就为0x02004000,那么irpSp->Parameters.Create.Options 就包含了两个参数,0-3位代表 CreateOption参数,6-7位代表CreateDisposition参数,至于4、5位的取值有没有其他含义,我就不得而知了,还请高人给予赐教。win 这样做的目的除了压缩结构空间外我没有想出太好的理由。 "Rhoibh  
[s 4Q  
接下来就是调用 IopCallDriver 函数了,至此,参数不再传递,代替的是传递 IRP,最后 IRP 会被传递到 CreateDispatch 函数中。 {i V 
z =Nb,B>E  
以上全部来自于泄露的 windows2000 源代码,获此代码如获至宝,只是由于本人整天沉迷于玩乐之中不知刻苦耐劳苦心钻研,以至于代码用时方恨少,只希望前辈将《Windows Nt/2000 泄露源代码情景分析》尽早写出来,以供我等拜读。
时间仓促,只写了这么多,没有动手反汇编分析,总是觉得缺少点什么。
此篇为晚生之初作,本难登大雅之堂,只因一想作为笔记加深印象,二想请各位前辈指点一二(4、5位的取值有没有其他含义??),所以厚着脸皮贴到此处,请各位前辈不要嗤之以鼻,希望前辈们多多指点晚生,晚生在此拜谢。



本文转自
http://blog.zndev.com/blog.php?do=showone&uid=356&type=blog&itemid=323

你可能感兴趣的:(Windows)