写这篇分析的目的: 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位的取值有没有其他含义??),所以厚着脸皮贴到此处,请各位前辈不要嗤之以鼻,希望前辈们多多指点晚生,晚生在此拜谢。
|