Функция IoCompletеRequest с ее кодом на С. - Направления и технологии - Shelek
Эта небольшая статья посвящена функции 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
Information
  • Posted on 01.02.2010 00:53
  • Просмотры: 4386