Статья
Версия для печати
Обсудить на форуме
Функция IoCompletеRequest с ее кодом на С.


Эта небольшая статья посвящена функции IoCompleteRequest, функции, с помощью которой заканчиваются все запросы ввода-вывода. Предполагается, что читатель уже знаком с внутренней организацией драйверов операционных систем направления Windows NT.

Описанию работы данной функции посвящено много статей, но никто не приводит ее код (во всяком случае автор не видел, кроме кода в проекте ReactOS), все просто описывают завершение ввода-вывода словами. С подобным описанием вы можете ознакомиться в статье "Secrets of the Universe Revealed! - How NT Handles I/O Completion" на сайте www.osronline.com (очень рекомендуемый для посещения сайт), эта же статья входит в IFSDK под названием Filter Driver Discussion Paper, желательно ознакомиться с этими статьями перед чтением данной статьи. Также очень полезно ознакомиться с возможными вариантами завершения запросов вввода-вывода, приведенными в книге W.Oney "Programming WDM" (классическая книга, имеется на данном сайте), также описание завершения ввода-вывода есть на сайте Microsoft в Knowledge Base, и, конечно, в DDK.

Я считаю, что в дополнение к великолепному описанию в вышеприведенных источниках неплохо увидеть код, поэтому я исследовал ассемблерный листинг функций, связанных с IoCompleteRequest. Дизассемблирование ядра для системы с архитектурой IA-32 было приведено при помощи дизассемблера IDA Pro, дизассемблерный листинг приведен в конце.

Необходимо отметить, что функция IoCompleteRequest определена как макрос
Код:
#define IoCompleteRequest(a,b)  
        IofCompleteRequest(a,b)

А IofCompleteRequest осуществляет безусловный переход на функцию, адрес которой находится в глобальной переменной ядра _pIopfCompleteRequest
Код:
NTKERNELAPI
VOID
FASTCALL IofCompleteRequest(PIRP pIrp, USHORT PriorityBoost)
{
__asm  jmp[_pIofCompleteRequest];
}

Подобный вызов функции, вероятно, был сделан с целью легкой замены одной функции завершения на другую, например, запущенный DriverVerifier заменяет стандартную функцию завершения на свою функцию IovSpecialIrpCompleteRequest, для проверки корректного завершения запроса ввода-вывода.

На моей системе Windows 2000 Professional SP2, без запущенного DriverVerifier, в переменной _pIofCompleteRequest находится адрес функции IopfCompleteRequest, соответственно, ее и исследуем.
 
Ниже приведен код функции IopfCompleteRequest на языке C, комментарии приведены после кода, можете сразу прочитать комментарии - в них основная цель этой заметки (сразу оговорюсь: приведенный листинг - это не дословный перевод ассемблерного листинга, некоторая часть кода была продублирована, чтобы не писать много операторов goto; в комментариях приведены номера соответствующих строк или имена меток(label) ассемблерного листинга, приведенного в конце статьи)
Код:
1.	void IopfCompleteRequest(PIRP pIrp, CCHAR PriorityBoost)
2. {
3. CHAR StackCount;
4. CHAR PendingRetuned;
5. PDEVICE_OBJECT pDeviceObject;
6. PCHAR AuxiliaryBuffer;
7. PFILE_OBJECT OriginalFileObject;
8. ULONG  Information;
9. struct _IO_STACK_LOCATION *CurrentStackLocation, *PrevStackLocation;
10.
11. //.text:0041F739
12.
13. if((pIrp->CurrentLocation > (pIrp->StackCount+1)) || (Irp->Type != 6))
14. KeBugCheckEx(44, pIrp, 0CCAh,0,0);
15.
16. //.text:0041F76F
17. if( ++pIrp->CurrentLocation > (pIrp->StackCount+1))
18. goto after_loop;
19.
20. PrevStackLocation = pIrp->Overlay.CurrentStackLocation;
21. CurrentStackLocation = ++(pIrp->Overlay.CurrentStackLocation);
22.
23. /////////////////////////////////////////////////////////////////////////
24. // Begin of main loop
25. /////////////////////////////////////////////////////////////////////////
26. {
27. loop:
28. //.text:0041F779
29. PendingRetuned = PrevStackLocation->Control & SL_PENDING_RETURNED;
30. //.text:0041F77E
31. pIrp->PendingRetuned = PendingRetuned;
32. //.text:0041F786
33. if(pIrp->IoStatus.Status < 0)
34. {
35. if(SL_INVOKE_ON_ERROR & (pIrp->Overlay.CurrentStackLocation-1)->Control)
36. {
37. //.text:0041F791 loc_41F791:
38. PrevStackLocation = pIrp->Overlay.CurrentStackLocation-1;
39. PrevStackLocation->MinorFunction = 0;
40. PrevStackLocation->Flags = 0;
41. PrevStackLocation->Control = 0;
42. PrevStackLocation->Parameters.Argument1 = 0;
43. PrevStackLocation->Parameters.Argument2 = 0;
44. PrevStackLocation->Parameters.Argument3 = 0;
45. PrevStackLocation->Parameters.Argument4 = 0;
46. PrevStackLocation->DeviceObject = 0;
47. PrevStackLocation->FileObject = 0;
48.
49. StackCount = pIrp->StackCount;
50. ++StackCount;
51. if((StackCount+1) != Irp->CurrentLocation)
52. pDeviceObject = pIrp->Overlay.CurrentStackLocation->DeviceObject;
53. else
54. pDeviceObject = NULL;
55.
56. if(STATUS_MORE_PROCESSING_REQUIRED == PrevStackLocation->CompletionRoutine(pDeviceObject,pIrp,PrevStackLocation->Context))
57. return;
58. }
59. }
60. else if(SL_INVOKE_ON_SUCCESS & (pIrp->Overlay.CurrentStackLocation-1)->Control)
61. {
62. PrevStackLocation = pIrp->Overlay.CurrentStackLocation-1;
63. PrevStackLocation->MinorFunction = 0;
64. PrevStackLocation->Flags = 0;
65. PrevStackLocation->Control = 0;
66. PrevStackLocation->Parameters.Argument1 = 0;
67. PrevStackLocation->Parameters.Argument2 = 0;
68. PrevStackLocation->Parameters.Argument3 = 0;
69. PrevStackLocation->Parameters.Argument4 = 0;
70. PrevStackLocation->DeviceObject = 0;
71. PrevStackLocation->FileObject = 0;
72.
73. StackCount = pIrp->StackCount;
74. ++StackCount;
75. if((StackCount+1) != Irp->CurrentLocation)
76. pDeviceObject = pIrp->Overlay.CurrentStackLocation->DeviceObject;
77. else
78. pDeviceObject = NULL;
79.
80. if(STATUS_MORE_PROCESSING_REQUIRED == PrevStackLocation->CompletionRoutine(pDeviceObject,pIrp,PrevStackLocation->Context))
81. return;
82. }
83. else if(pIrp->IoStatus.Status >= 0)
84. {
85. //loc_41F796:
86. if(!pIrp->Cancel || (SL_INVOKE_ON_CANCEL & (pIrp->Overlay.CurrentStackLocation-1)->Control))
87. {
88. //loc_41F839:
89. if(!((pIrp->Overlay.CurrentStackLocation-1)->Control & SL_PENDING_RETURNED))
90. {
91. if(pIrp->CurrentLocation < pIrp->StackCount)
92. pIrp->Overlay.CurrentStackLocation->Control &= 1;//set SL_PENDING_RETURNED
93. }
94. }
95. //loc_41F849:
96. PrevStackLocation = pIrp->Overlay.CurrentStackLocation-1;
97. PrevStackLocation->MinorFunction = 0;
98. PrevStackLocation->Flags = 0;
99. PrevStackLocation->Control = 0;
100. PrevStackLocation->Parameters.Argument1 = 0;
101. PrevStackLocation->Parameters.Argument2 = 0;
102. PrevStackLocation->Parameters.Argument3 = 0;
103. PrevStackLocation->Parameters.Argument4 = 0;
104. PrevStackLocation->DeviceObject = 0;
105. PrevStackLocation->FileObject = 0;
106. }
107.
108. //.text:0041F7DA loc_41F7DA
109. CurrentLocation = ++pIrp->Overlay.CurrentStackLocation;
110. ++pIrp->CurrentLocation;
111. if(pIrp->CurrentLocation<=(pIrp->StackCount+1))
112. goto loop;
113. }
114. /////////////////////////////////////////////////////////////////////////
115. // End of main loop
116. /////////////////////////////////////////////////////////////////////////
117.
118. after_loop:
119. //.text:0041F7F3
120. if(pIrp->Flags & IRP_ASSOCIATED_IRP)
121. {
122. PIRP MaterIrp = pIrp->MasterIrp;
123. --(pIrp->MasterIrp->IrpCount);
124. pIrp->Thread = pIrp->MasterIrp->Thread;
125. IopFreeIrpAndMdls(pIrp);
126. if(pIrp->MasterIrp->IrpCount != 1)
127. return;
128. IofCompleteRequest(MasterIrp,PriorityBoost);
129. return;
130. }
131.
132. //.loc_41F867:   
133. if(pIrp->IoStatus == STATUS_REPARSE)
134. {
135. if(pIrp->IoStatus.Information > 1)
136. {
137. if(IO_REPARSE_TAG_MOUNT_POINT == pIrp->IoStatus.Information)
138. {
139. //.text:0041F87F
140. AuxiliaryBuffer = pIrp->Tail.Overlay.AuxiliaryBuffer;
141. pIrp->Tail.Overlay.AuxiliaryBuffer = NULL;
142. }
143. else
144. {
145. //.loc_41F8DB
146. pIrp->IoStatus = STATUS_IO_REPARSE_TAG_NOT_HANDLED;
147. }
148. }
149. }
150.
151. //.loc_41F888:
152. if( pIrp->Tail.Overlay.AuxiliaryBuffer != NULL)
153. {
154. ExFreePool(pIrp->Tail.Overlay.AuxiliaryBuffer);
155. pIrp->Tail.Overlay.AuxiliaryBuffer = NULL;
156. }
157. //.loc_41F898:
158. if(!(pIrp->Flags & (RP_CLOSE_OPERATION | IRP_PAGING_IO)))
159. {
160. //loc_41F915
161. PMDL pMdl = pIrp->MdlAddress;
162. while(pMdl != NULL)
163. {
164. MmUnlockPages(pMdl);
165. pMdl = pMdl->Next
166. }
167. //loc_41F926:
168. if((pIrp->Flags & IRP_DEFER_IO_COMPLETION) && !pIrp->PendingReturned)
169. {
170. if(pIrp->IoStatus.Status & STATUS_REPARSE)
171. {
172. if(pIrp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT)
173. {
174. pIrp->Tail.Overlay.AuxiliaryBuffer = AuxiliaryBuffer;
175. }
176. }
177. return;
178. }
179. }
180. else if(!(pIrp->Flags & (IRP_CLOSE_OPERATION | IRP_INPUT_OPERATION)))
181. {
182. //loc_41F8E9
183. KeInitializeApc(&pIrp->Tail.Apc,pIrp->Tail.Overlay.Thread,pIrp->ApcEnvironment,IopCompletePageWrite,0,0,0,0);
184. KeInsertQueueApc(&pIrp->Tail.Apc,0,0,PriroityBoost);
185. return;
186. }
187. else
188. {
189. //.text:0041F8A7
190.
191. pIrp->UserIosb.Status = pIrp->IoStatus.Status;
192. pIrp->UserIosb.Information = pIrp->IoSatus.Information;
193.
194. KeSetEvent(pIrp->UserEvent, PriorityBoost);
195. //.text:0041F8C8
196. if(pIrp->Flags & IRP_INPUT_OPERATION)
197. IoFreeIrp(pIrp);
198.
199. return;
200. }
201. //loc_41F956
202.
203. OriginalFileObject = pIrp->Overlay.OriginalFileObject;
204. Information = pIrp->IoStatus.Information;
205.
206. if(pIrp->Cancel)
207. {
208. //loc_41F995
209. KIRQL OldIrql;
210. OldIrql = KeRaiseIrqlToDpcLevel();
211. if( NULL == pIrp->Tail.Overlay.Thread)
212. {
213. //loc_41F9E2
214. KfLowerIrql(OldIrql);
215. IopDropIrp(pIrp, pIrp->Overlay.OriginalFileObject);
216. return;
217. }
218. KeInitializeApc(&pIrp->Tail.Apc,pIrp->Tail.Overlay.Thread,pIrp->ApcEnvironment,IopCompleteRequest,IopAbortRequest,0,0,0);
219. KeInsertQueueApc(&pIrp->Tail.Apc,OriginalFileObject,Information,PrirorityBoost);
220. KfLowerIrql(OldIrql);
221. return;
222. }
223. //.text:0041F964
224. KeInitializeApc(&pIrp->Tail.Apc,pIrp->Tail.Overlay.Thread,pIrp->ApcEnvironment,IopCompleteRequest,IopAbortRequest,0,0,0);
225. KeInsertQueueApc(&pIrp->Tail.Apc,OriginalFileObject,Information,PrirorityBoost);
226. return;
227. }

Теперь пройдемся по коду. Функция принимает указатель на пакет ввода-вывода, который надо завершить и насколько поднять приоритет потока. Строки 13, 14 - проверка входных параметров, строка 28 - начало цикла, в котором проводится раскрутка стека запроса ввода-вывода, с вызовом зарегистрированных функций завершения ввода-вывода, это так называемая первая стадия завершения ввода-вывода. Как видно из строчек 56, 80 в которых происходит вызов функций завершения, если функция вернет STATUS_MORE_PROCESSING_REQUIRED, произойдет выход из функции IopfCompleteRequest без осуществления второй стадии завершения, то есть без установки APC в очередь потока, сделавшего запрос.

После раскрутки стека в строчках 28-112 функция IopfCompleteRequest принимает решение о том, что делать с пакетом Irp, заметьте - она может сама вызвать IoFreeIrp или IopDropIrp явно или путем установки APC с функцией IopCompleteRequest, которая также вызовет IoFreeIrp, все это приведет к уничтожению Irp и освобождению занятой памяти, единственный вариант избежать уничтожения Irp системой - это
  • Возвратить STATUS_MORE_PROCESSING_REQUIRED из зарегистрированной функции завершения ввода-вывода. Строки 56, 80.
  • Создание Irp с флагами IRP_CLOSE_OPERATION или IRP_PAGING_IO и отсутствующим флагом IRP_INPUT_OPERATION. Строки 158, 180, 196.
  • Создание Irp с флагом IRP_DEFER_IO_COMPLETION необходимо, чтобы этот Irp не запендили, то есть не отложили его отработку, возвратив STATUS_PENDING.

По некоторым сведениям, флаг IRP_DEFER_IO_COMPLETION любят ставить функции, вызываемые из режима пользователя.

Из приведенного выше списка и анализа кода ясно, что гарантию неуничтожения Irp может дать только возврат STATUS_MORE_PROCESSING_REQUIRED из зарегистрированной функции завершения ввода-вывода, попытка самостоятельного уничтожения созданного вами же Irp в большинстве случаев приведет к BSOD (тут полезно посмотреть на способы завершения запросов ввода-вывода, приведенных в книге W. Oney). Заметьте, что в подавляющем большинстве случаев для уничтожения Irp ставится APC в очередь потока, сделавшего запрос, вне зависимости от того, является запрос синхронным или нет. Для синхронного запроса (то есть полностью идущего в контексте потока, сделавшего запрос - именно такой запрос я называю синхронным, в других источниках встречаются другие интерпретации) после установки APC в очередь, при помощи KeInsertQueueApc, сразу будет вызвана процедура очистки очереди APC из функции KeInsertQueueApc (сама поставила в очередь - сама инициировала очистку очереди), то есть последовательность выполнения потока не нарушится - после выхода из IopfCompleteRequest пакет запроса ввода-вывода уже будет уничтожен в функции IopCompleteRequest. Для асинхронных запросов APC будут вызваны сразу после того, как планировщик запланирует поток, в очереди которого они находятся, на выполнение, переключит контекст и начнется понижение уровня IRQL с DISPATCH_LEVEL до PASSIVE_LEVEL, APC будут вызваны на APC_LEVEL.

В заключение отмечу, что память под структуру KAPC выделяется из памяти, выделенной для Irp, что означает частичное разрушение нижней части Irp.

В строчках 120-129 происходит уничтожение ассоцированных IRP и завершение Master Irp после уничтожения всех потомков, из этого кода видно, почему W.Oney не рекомендует использовать ассоциированные IRP - слишком запутана процедура их уничтожения.

Более подробный анализ я оставляю для читателя, также как и проверку правильности проделанной автором работы - между моментом, когда автор дизассемблировал и исследовал функцию IopfCompleteRequest и написал соответствующий код на С, прошло достаточно много времени, некоторые детали могли быть упущены из виду.

В заключение ассемблерный листинг, комментарии в нем сделаны как в стиле С и С++(то есть через /* */ и //), так и через принятую в ассемблере точку с запятой.
Код:
.text:0041F72C @IopfCompleteRequest@8 proc near        ; CODE XREF: @IovCompleteRequest@8+A4p
.text:0041F72C                                         ; @IovSpecialIrpCompleteRequest@8+C1p
.text:0041F72C                                         ; DATA XREF: ...
.text:0041F72C
.text:0041F72C var_C           = dword ptr -0Ch
.text:0041F72C var_8           = dword ptr -8
.text:0041F72C var_2           = byte ptr -2
.text:0041F72C var_1           = byte ptr -1
.text:0041F72C
.text:0041F72C                 push    ebp         
.text:0041F72D                 mov     ebp, esp
.text:0041F72F                 sub     esp, 0Ch
.text:0041F732                 push    ebx           
.text:0041F733                 push    esi
.text:0041F734                 mov     esi, ecx      // ecx = pIrp  edx = PriorityBoost
.text:0041F736                 xor     ebx, ebx      // ebx = 0
.text:0041F738                 push    edi           
                                                     /* stack from up to bottom
                                                        /*000*/    ebp
                                                        /*004*/     0            <-ebp
                                                        /*010*/    ebx
                                                        /*014*/    esi
                                                        /*018*/    edi
                                                     /* 
                                                       registers:
                                                       ebp points to local data
                                                       esi = ecx = pIrp
                                                       edx = PriorityBoost   
                                                      */
.text:0041F739                 mov     [ebp+var_1], dl  // [ebp+var1] = PriorityBoost
.text:0041F73C                 mov     al, [esi+22h]    // al = pIrp->StackCount
.text:0041F73F                 mov     [ebp+var_8], ebx // [ebp+var_8] = 0
.text:0041F742                 inc     al               // ++al, see .text:0041F73C
.text:0041F744                 cmp     [esi+23h], al    // [esi+23h]=pIrp->CurrentLocation if(pIrp->CurrentLocation > al)
.text:0041F747                 jg      short loc_41F74F // if greater  {goto KeBugCheckEx} else
.text:0041F749                 cmp     word ptr [esi], 6// if (pIrp->Type == 6)   
.text:0041F74D                 jz      short loc_41F75E // if equal {goto loc_41F75E} else {goto KeBugCheckEx}
.text:0041F74F
.text:0041F74F loc_41F74F:                             ; CODE XREF: @IopfCompleteRequest@8+1Bj
.text:0041F74F                 push    ebx
.text:0041F750                 push    ebx
.text:0041F751                 push    0CCAh
.text:0041F756                 push    esi
.text:0041F757                 push    44h
.text:0041F759                 call    _KeBugCheckEx@20
.text:0041F75E
.text:0041F75E loc_41F75E:                             ; CODE XREF: @IopfCompleteRequest@8+21j
.text:0041F75E                 mov     edi, [esi+60h]  // edi = pIrp->Overlay.CurrentStackLocation
.text:0041F761                 mov     dl, [esi+22h]   // dl = pIrp->StackCount
.text:0041F764                 inc     byte ptr [esi+23h] // ++pIrp->CurrentLocation
.text:0041F767                 mov     cl, [esi+23h]     //cl = pIrp->CurrentLocation
.text:0041F76A                 inc     dl                //++dl, see .text:0041F761         
.text:0041F76C                 lea     eax, [edi+24h]    // eax = pIrp->Overlay.CurrentStackLocation+1
.text:0041F76F                 cmp     cl, dl            // if( cl == dl)
.text:0041F771                 mov     [esi+60h], eax    // pIrp->Overlay.CurrentStackLocation = pIrp->Overlay.CurrentStackLocation+1
.text:0041F774                 jg      short loc_41F7F3 
.text:0041F776                 add     edi, 3 //edi = ((PCHAR)(pIrp->Overlay.CurrentStackLocation-1))+3
.text:0041F779
///////////////////////////////////////////////////////////////////////
// Begin of loop_1(see End of loop_1). Go through all stacks and call Completion functions.
// esi = pIrp
// edi = ((PCHAR)(pIrp->Overlay.CurrentStackLocation-1))+3
// ebx = 0
///////////////////////////////////////////////////////////////////////
.text:0041F779 loc_41F779:                             ; CODE XREF: @IopfCompleteRequest@8+C5j
.text:0041F779                 mov     cl, [edi]      // cl = (pIrp->Overlay.CurrentStackLocation-1)->Control
.text:0041F77B                 mov     edx, [esi+18h] //edx = pIrp->IoStatus;
.text:0041F77E                 and     cl, 1          //cl = ((pIrp->Overlay.CurrentStackLocation-1)->Control & SL_PENDING_RETURNED)
.text:0041F781                 cmp     edx, ebx       //pIrp->IoStatus.Status == 0
.text:0041F783                 mov     [esi+21h], cl  //IoMarkIrpPending(pIrp)
.text:0041F786                 jl      short loc_41F791    //in loop_1, pIrp->IoStatus.Status != STATUSS_SUCCESS
.text:0041F788                 test    byte ptr [edi], 40h //SL_INVOKE_ON_SUCCESS & (pIrp->Overlay.CurrentStackLocation-1)->Control
.text:0041F78B                 jnz     short loc_41F7A8    //invoke on success
.text:0041F78D                 cmp     edx, ebx         
.text:0041F78F                 jge     short loc_41F796 //in loop_1
.text:0041F791
.text:0041F791 loc_41F791:                             ; CODE XREF: @IopfCompleteRequest@8+5Aj
.text:0041F791                 test    byte ptr [edi], 80h //SL_INVOKE_ON_ERROR & (pIrp->Overlay.CurrentStackLocation-1)->Control
.text:0041F794                 jnz     short loc_41F7A8    //in loop_1
.text:0041F796
.text:0041F796 loc_41F796:                             ; CODE XREF: @IopfCompleteRequest@8+63j
.text:0041F796                 cmp     [esi+24h], bl
.text:0041F799                 jz      loc_41F839          //some work and go to loc_41F7DA in loop_1
.text:0041F79F                 test    byte ptr [edi], 20h //SL_INVOKE_ON_CANCEL & (pIrp->Overlay.CurrentStackLocation-1)->Control
.text:0041F7A2                 jz      loc_41F839          //some work and go to loc_41F7DA in loop_1
.text:0041F7A8
.text:0041F7A8 loc_41F7A8:                             ; CODE XREF: @IopfCompleteRequest@8+5Fj
.text:0041F7A8                                         ; @IopfCompleteRequest@8+68j
// ebx = 0
// edi = &((pIrp->Overlay.CurrentStackLocation-1)->Control)
.text:0041F7A8                 mov     [edi-2], bl
.text:0041F7AB                 mov     [edi-1], bl
.text:0041F7AE                 mov     [edi], bl
.text:0041F7B0                 mov     [edi+1], ebx
.text:0041F7B3                 mov     [edi+5], ebx
.text:0041F7B6                 mov     [edi+9], ebx
.text:0041F7B9                 mov     [edi+0Dh], ebx
.text:0041F7BC                 mov     [edi+15h], ebx
.text:0041F7BF                 mov     al, [esi+22h]//pIrp->StackCount;
.text:0041F7C2                 inc     al
.text:0041F7C4                 cmp     [esi+23h], al
// if(Irp->CurrentLocation != (Irp->StackCount+1)) go to loc_41F82F
.text:0041F7C7                 jnz     short loc_41F82F//set eax to pIrp->Overlay.CurrentStackLocation->DeviceObject, and go to loc_41F7CB in loop_1
.text:0041F7C9                 xor     eax, eax        //DeviceObject = NULL;  Irp->CurrentLocation == (Irp->StackCount+1)
.text:0041F7CB
.text:0041F7CB loc_41F7CB:                             ; CODE XREF: @IopfCompleteRequest@8+109j
.text:0041F7CB                 push    dword ptr [edi+1Dh] // push (pIrp->Overlay.CurrentStackLocation-1)->Context
.text:0041F7CE                 push    esi                 // push pIrp
.text:0041F7CF                 push    eax                 // push pIrp->Overlay.CurrentStackLocation->DeviceObject or NULL, see .text:0041F7C7
.text:0041F7D0                 call    dword ptr [edi+19h] // call (pIrp->Overlay.CurrentStackLocation-1)->CompletionRoutine ,see .text:0041F776
.text:0041F7D3                 cmp     eax, 0C0000016h   // STATUS_MORE_PROCESSING_REQUIRED
.text:0041F7D8                 jz      short loc_41F82A  // return
.text:0041F7DA
.text:0041F7DA loc_41F7DA:                             ; CODE XREF: @IopfCompleteRequest@8+10Bj
.text:0041F7DA                                         ; @IopfCompleteRequest@8+134j
.text:0041F7DA                 mov     dl, [esi+22h]   // dl = pIrp->StackCount
.text:0041F7DD                 add     dword ptr [esi+60h], 24h  //++pIrp->Overlay.CurrentStackLocation
.text:0041F7E1                 mov     eax, [esi+60h]
.text:0041F7E4                 add     edi, 24h       //((PCHAR)(pIrp->Overlay.CurrentStackLocation-1))+3
.text:0041F7E7                 inc     byte ptr [esi+23h]
.text:0041F7EA                 mov     cl, [esi+23h]  //pIrp->CurrentLocation
.text:0041F7ED                 inc     dl
.text:0041F7EF                 cmp     cl, dl   // cl == pIrp->CurrentLocation, dl == pIrp->StackCount+1
.text:0041F7F1                 jle     short loc_41F779
////////////////////////////////////////////////////////////////////////////////////////////
//End of loop_1
////////////////////////////////////////////////////////////////////////////////////////////
.text:0041F7F3
.text:0041F7F3 loc_41F7F3:                             ; CODE XREF: @IopfCompleteRequest@8+48j
.text:0041F7F3                 test    byte ptr [esi+8], 8 // pIrp->Flags & IRP_ASSOCIATED_IRP
.text:0041F7F7                 jz      short loc_41F867   //process normal IRP
 //complete associated Irp and return
.text:0041F7F9                 mov     edi, [esi+0Ch]
.text:0041F7FC                 lea     eax, [edi+0Ch] //&pIrp->MasterIrp->IrpCount
.text:0041F7FF                 mov     [ebp+var_8], eax
.text:0041F802                 mov     eax, 0FFFFFFFFh //-1
.text:0041F807                 mov     ecx, [ebp+var_8]//&pIrp->MasterIrp->IrpCount
.text:0041F80A                 xadd    [ecx], eax      //--(pIrp->MasterIrp->IrpCount)
.text:0041F80D                 mov     ebx, eax        //pIrp->MasterIrp->IrpCount
.text:0041F80F                 mov     eax, [edi+50h]  //pIrp->MasterIrp->Thread
.text:0041F812                 push    esi             //pIrp
.text:0041F813                 mov     [esi+50h], eax  //pIrp->Thread = pIrp->MasterIrp->Thread
.text:0041F816                 call    _IopFreeIrpAndMdls@4
.text:0041F81B                 cmp     ebx, 1
.text:0041F81E                 jnz     short loc_41F82A  //return
.text:0041F820                 mov     dl, [ebp+var_1]   //PriorityBoost
.text:0041F823                 mov     ecx, edi
.text:0041F825                 call    @IofCompleteRequest@8
.text:0041F82A
.text:0041F82A loc_41F82A:                             ; CODE XREF: @IopfCompleteRequest@8+ACj
.text:0041F82A                                         ; @IopfCompleteRequest@8+F2j ...
.text:0041F82A                 pop     edi
.text:0041F82B                 pop     esi
.text:0041F82C                 pop     ebx
.text:0041F82D                 leave
.text:0041F82E                 retn
.text:0041F82F ; ---------------------------------------------------------------------------
.text:0041F82F
.text:0041F82F loc_41F82F:                             ; CODE XREF: @IopfCompleteRequest@8+9Bj
.text:0041F82F                 mov     eax, [esi+60h]  //pIrp->Overlay.CurrentStackLocation
.text:0041F832                 mov     eax, [eax+14h]  //eax = pIrp->Overlay.CurrentStackLocation->DeviceObject
.text:0041F835                 jmp     short loc_41F7CB// goto loop_1
.text:0041F837 ; ---------------------------------------------------------------------------
.text:0041F837                 jmp     short loc_41F7DA
.text:0041F839 ; ---------------------------------------------------------------------------
.text:0041F839
.text:0041F839 loc_41F839:                             ; CODE XREF: @IopfCompleteRequest@8+6Dj
.text:0041F839                                         ; @IopfCompleteRequest@8+76j
.text:0041F839                 cmp     cl, bl
.text:0041F83B                 jz      short loc_41F849
.text:0041F83D                 mov     cl, [esi+23h]
.text:0041F840                 cmp     cl, [esi+22h]
.text:0041F843                 jg      short loc_41F849
.text:0041F845                 or      byte ptr [eax+3], 1
.text:0041F849
.text:0041F849 loc_41F849:                             ; CODE XREF: @IopfCompleteRequest@8+10Fj
.text:0041F849                                         ; @IopfCompleteRequest@8+117j
.text:0041F849                 mov     [edi-2], bl
.text:0041F84C                 mov     [edi-1], bl
.text:0041F84F                 mov     [edi], bl
.text:0041F851                 mov     [edi+1], ebx
.text:0041F854                 mov     [edi+5], ebx
.text:0041F857                 mov     [edi+9], ebx
.text:0041F85A                 mov     [edi+0Dh], ebx
.text:0041F85D                 mov     [edi+15h], ebx
.text:0041F860                 jmp     loc_41F7DA  //go to loop_1
.text:0041F865 ; ---------------------------------------------------------------------------
.text:0041F865                 jmp     short loc_41F82A  //return, we never will be here!
.text:0041F867 ; ---------------------------------------------------------------------------
.text:0041F867
// go from .text:0041F7F7
.text:0041F867 loc_41F867:                             ; CODE XREF: @IopfCompleteRequest@8+CBj
// check for Reparse Point (Volume Mounted to directory)
.text:0041F867                 cmp     dword ptr [esi+18h], 104h //pIrp->IoStatus == STATUS_REPARSE
.text:0041F86E                 jnz     short loc_41F888
.text:0041F870                 mov     eax, [esi+1Ch] // pIrp->IoStatus.Information
.text:0041F873                 cmp     eax, 1
.text:0041F876                 jbe     short loc_41F888
.text:0041F878                 cmp     eax, 0A0000003h //IO_REPARSE_TAG_MOUNT_POINT
.text:0041F87D                 jnz     short loc_41F8DB
.text:0041F87F                 mov     eax, [esi+54h]
.text:0041F882                 mov     [esi+54h], ebx
.text:0041F885                 mov     [ebp+var_8], eax
.text:0041F888
.text:0041F888 loc_41F888:                             ; CODE XREF: @IopfCompleteRequest@8+142j
.text:0041F888                                         ; @IopfCompleteRequest@8+14Aj ...
.text:0041F888                 mov     eax, [esi+54h] //
.text:0041F88B                 cmp     eax, ebx
.text:0041F88D                 jz      short loc_41F898
.text:0041F88F                 push    eax
.text:0041F890                 call    _ExFreePool@4
.text:0041F895                 mov     [esi+54h], ebx
.text:0041F898
.text:0041F898 loc_41F898:                             ; CODE XREF: @IopfCompleteRequest@8+161j
.text:0041F898                 mov     eax, [esi+8]
.text:0041F89B                 test    ax, 402h // IRP_CLOSE_OPERATION | IRP_PAGING_IO
.text:0041F89F                 jz      short loc_41F915//possible go to KeInsertQueueApc
.text:0041F8A1                 test    ax, 440h // IRP_CLOSE_OPERATION | IRP_INPUT_OPERATION
.text:0041F8A5                 jz      short loc_41F8E9// go to KeInsertQueueApc
.text:0041F8A7                 mov     ecx, [esi+18h]  // ecx = pIrp->IoStatus.Status
.text:0041F8AA                 and     eax, 40h
.text:0041F8AD                 mov     edi, eax  //edi = pIrp->Flags & IRP_INPUT_OPERATION
.text:0041F8AF                 mov     eax, [esi+28h] //eax = pIrp->UserIosb
.text:0041F8B2                 push    ebx
.text:0041F8B3                 mov     [eax], ecx     // pIrp->UserIosb.Status = pIrp->IoStatus.Status
.text:0041F8B5                 mov     ecx, [esi+1Ch] // ecx = pIrp->IoSatus.Information
.text:0041F8B8                 mov     [eax+4], ecx   // pIrp->UserIosb.Information = pIrp->IoSatus.Information
.text:0041F8BB                 movsx   eax, [ebp+var_1]// PriorityBoost
.text:0041F8BF                 push    eax
.text:0041F8C0                 push    dword ptr [esi+2Ch]
.text:0041F8C3                 call    _KeSetEvent@12
.text:0041F8C8                 cmp     edi, ebx
.text:0041F8CA                 jz      loc_41F82A   //return
.text:0041F8D0                 push    esi
.text:0041F8D1                 call    _IoFreeIrp@4
.text:0041F8D6                 jmp     loc_41F82A   //return
.text:0041F8DB ; ---------------------------------------------------------------------------
.text:0041F8DB
.text:0041F8DB loc_41F8DB:                             ; CODE XREF: @IopfCompleteRequest@8+151j
.text:0041F8DB                 mov     dword ptr [esi+18h], 0C0000279h //STATUS_IO_REPARSE_TAG_NOT_HANDLED
.text:0041F8E2                 jmp     short loc_41F888
.text:0041F8E4 ; ---------------------------------------------------------------------------
.text:0041F8E4                 jmp     loc_41F82A  //return
.text:0041F8E9 ; ---------------------------------------------------------------------------
.text:0041F8E9
.text:0041F8E9 loc_41F8E9:                             ; CODE XREF: @IopfCompleteRequest@8+179j
.text:0041F8E9                 movsx   eax, byte ptr [esi+26h] //pIrp->ApcEnvironment
.text:0041F8ED                 push    ebx
.text:0041F8EE                 push    ebx
.text:0041F8EF                 push    ebx
.text:0041F8F0                 push    ebx
.text:0041F8F1                 push    offset _IopCompletePageWrite@20
.text:0041F8F6                 push    eax
.text:0041F8F7                 push    dword ptr [esi+50h]
.text:0041F8FA                 lea     edi, [esi+40h]
.text:0041F8FD                 push    edi
.text:0041F8FE                 call    _KeInitializeApc@32
.text:0041F903                 movsx   eax, [ebp+var_1]
.text:0041F907                 push    eax
.text:0041F908                 push    ebx
.text:0041F909                 push    ebx
.text:0041F90A
.text:0041F90A loc_41F90A:                             ; CODE XREF: @IopfCompleteRequest@8+25Fj
.text:0041F90A                 push    edi
.text:0041F90B                 call    _KeInsertQueueApc@16
.text:0041F910                 jmp     loc_41F82A  //return
.text:0041F915 ; ---------------------------------------------------------------------------
.text:0041F915
.text:0041F915 loc_41F915:                             ; CODE XREF: @IopfCompleteRequest@8+173j
.text:0041F915                 mov     edi, [esi+4]    //pIrp->MdlAddress
.text:0041F918
.text:0041F918 loc_41F918:                             ; CODE XREF: @IopfCompleteRequest@8+1F8j
.text:0041F918                 cmp     edi, ebx        // if pIrp->MdlAddress == 0
.text:0041F91A                 jz      short loc_41F926
.text:0041F91C                 push    edi
.text:0041F91D                 call    _MmUnlockPages@4// MmUnlockPages(pIrp->MdlAddress)
.text:0041F922                 mov     edi, [edi]      // edi = pIrp->MdlAddress.Next
.text:0041F924                 jmp     short loc_41F918
.text:0041F926 ; ---------------------------------------------------------------------------
.text:0041F926
.text:0041F926 loc_41F926:                             ; CODE XREF: @IopfCompleteRequest@8+1EEj
.text:0041F926                 test    byte ptr [esi+9], 8//pIrp->Flags & IRP_DEFER_IO_COMPLETION
.text:0041F92A                 jz      short loc_41F956  // go to KeInsertQueueApc
.text:0041F92C                 cmp     [esi+21h], bl     //PendingRetuned
.text:0041F92F                 jnz     short loc_41F956  // pIrp->PendingRetuned == TRUE, go to KeInsertQueueApc
.text:0041F931                 cmp     dword ptr [esi+18h], 104h //STATUS_REPARSE
.text:0041F938                 jnz     loc_41F82A  //return
.text:0041F93E                 cmp     dword ptr [esi+1Ch], 0A0000003h
.text:0041F945                 jnz     loc_41F82A  //return
.text:0041F94B                 mov     eax, [ebp+var_8]
.text:0041F94E                 mov     [esi+54h], eax
.text:0041F951                 jmp     loc_41F82A  //return
.text:0041F956 ; ---------------------------------------------------------------------------
.text:0041F956
.text:0041F956 loc_41F956:                             ; CODE XREF: @IopfCompleteRequest@8+1FEj
.text:0041F956                                         ; @IopfCompleteRequest@8+203j
.text:0041F956                 mov     edi, [esi+64h]  //edi = pIrp->Overlay.OriginalFileObject
.text:0041F959                 cmp     [esi+24h], bl   // pIrp->Cancel
.text:0041F95C                 mov     eax, [esi+50h]  //eax = pIrp->Tail.Overlay.Thread
.text:0041F95F                 mov     [ebp+var_C], edi //pIrp->Overlay.OriginalFileObject
.text:0041F962                 jnz     short loc_41F995
.text:0041F964                 movsx   ecx, byte ptr [esi+26h]//ecx = pIrp->ApcEnvironment
.text:0041F968                 push    ebx
.text:0041F969                 push    ebx
.text:0041F96A                 push    ebx
.text:0041F96B                 push    offset _IopAbortRequest@4
.text:0041F970                 push    offset _IopCompleteRequest@20
.text:0041F975                 lea     edi, [esi+40h]   //&pIrp->Tail.Apc
.text:0041F978                 push    ecx
.text:0041F979                 push    eax
.text:0041F97A                 push    edi
.text:0041F97B                 call    _KeInitializeApc@32
.text:0041F980                 movsx   eax, [ebp+var_1]
.text:0041F984                 push    eax
.text:0041F985                 push    [ebp+var_8]
.text:0041F988                 push    [ebp+var_C]
.text:0041F98B                 jmp     loc_41F90A //InsertQueueApc
.text:0041F990 ; ---------------------------------------------------------------------------
.text:0041F990                 jmp     loc_41F82A //return
.text:0041F995 ; ---------------------------------------------------------------------------
.text:0041F995
.text:0041F995 loc_41F995:                             ; CODE XREF: @IopfCompleteRequest@8+236j
.text:0041F995                 call    ds:__imp__KeRaiseIrqlToDpcLevel@0
.text:0041F99B                 mov     cl, al//OldIrql
.text:0041F99D                 mov     eax, [esi+50h]//eax = pIrp->Tail.Overlay.Thread
/* ebx == 0*/
.text:0041F9A0                 cmp     eax, ebx
.text:0041F9A2                 mov     [ebp+var_2], cl
.text:0041F9A5                 jz      short loc_41F9E2//IoDropIrp if pIrp->Tail.Overlay.Thread == NULL
.text:0041F9A7                 movsx   ecx, byte ptr [esi+26h]
.text:0041F9AB                 push    ebx
.text:0041F9AC                 push    ebx
.text:0041F9AD                 push    ebx
.text:0041F9AE                 push    offset _IopAbortRequest@4
.text:0041F9B3                 push    offset _IopCompleteRequest@20
.text:0041F9B8                 lea     edi, [esi+40h]
.text:0041F9BB                 push    ecx
.text:0041F9BC                 push    eax
.text:0041F9BD                 push    edi
.text:0041F9BE                 call    _KeInitializeApc@32
.text:0041F9C3                 movsx   eax, [ebp+var_1]
.text:0041F9C7                 push    eax
.text:0041F9C8                 push    [ebp+var_8]
.text:0041F9CB                 push    [ebp+var_C]
.text:0041F9CE                 push    edi
.text:0041F9CF                 call    _KeInsertQueueApc@16
.text:0041F9D4                 mov     cl, [ebp+var_2]
.text:0041F9D7                 call    ds:__imp_@KfLowerIrql@4
.text:0041F9DD                 jmp     loc_41F82A //return
.text:0041F9E2 ; ---------------------------------------------------------------------------
.text:0041F9E2
.text:0041F9E2 loc_41F9E2:                             ; CODE XREF: @IopfCompleteRequest@8+279j
.text:0041F9E2                 call    ds:__imp_@KfLowerIrql@4
.text:0041F9E8                 push    edi
.text:0041F9E9                 push    esi
.text:0041F9EA                 call    _IopDropIrp@8
.text:0041F9EF                 jmp     loc_41F82A //return
.text:0041F9EF @IopfCompleteRequest@8 endp

Автор осознает, что в его работе неизбежно содержатся ошибки и неточности, поэтому с благодарностью примет замечания и исправления, которые можно оставить на форуме этого сайта.

SlavaI 
09.06.2003.
Odintsovo.  Moscow region.  Russia.
Версия для печати
Обсудить на форуме