网络防火墙技术TDI

xp是有TDI的,但是win vista之后就没有了

1736306559033

应用层使用 TCP 协议通信的流程

以下是应用层通过 TCP 协议通信时的典型流程:

  1. 用户模式应用程序调用 WinSock API
  • 应用程序使用 WinSock API(如 socketconnectsendrecv)进行通信。
  • 这些 API 调用会通过 ws2_32.dllmswsock.dll 进入用户模式的网络子系统。
  1. 进入内核模式(afd.sys)
  • afd.sys

    • 用于将用户模式的网络请求转换为内核模式的 IRP(I/O 请求包)。
  1. TDI 层与协议栈交互
  • TDI.sys

    • afd.sys 与 TDI 驱动交互,由TDI接口将数据传递给tcpip.sys
    • TDI 负责将高级协议请求(如打开连接、发送数据)转化为底层协议栈能够理解的操作。

然后TDI过滤驱动会将这个IRP包接着往下传递,根据协议,传递到不同设备,例如Tcp是/Device/tcp

/Device/Tcptcpip.sys 暴露的设备对象名称,因此实际上这些 IRP 是传递给 tcpip.sys

  1. TCP/IP 协议栈(tcpip.sys)
  • tcpip.sys

    • TCP/IP 协议栈实现了具体的 TCP 和 IP 协议功能。

    • 在连接建立时:

      • TCP 三次握手由 tcpip.sys 和网卡驱动协同完成。
    • 在数据传输时:

      • 数据分片、组装,以及错误检测由协议栈处理。
  1. 数据到达网卡(NDIS 驱动层)
  • NDIS(Network Driver Interface Specification)
    • tcpip.sys 将数据传递给 NDIS 驱动层,负责与网卡驱动(如 e1k60x64.sys)通信。
    • 最终,数据通过物理网卡发送到网络中。

6. 返回路径:数据从网卡到应用层

  • 反向过程
    • 数据包从网卡接收后,经过 NDIS 层传递给 tcpip.sys
    • TCP 协议处理包的重组和校验。
    • TDI 层将数据交给 afd.sys
    • 最终数据通过 WinSock API 返回到用户模式应用程序。

套接字操作及触发的IRP

以下是很多是错的,待修改…….

负责的驱动:afd.sys

IRP_MJ_CREATE这个是TDI比较重要的一个点,TDI有两个对象需要创建:

  1. 地址对象:所谓地址对象就是通常我们调用bind函数绑定的本地地址和端口的对象。
  2. 连接对象:所谓连接对象就是我们listen或者connect创建的,用来和远端连接通信的一个对象。

然后就是紧接着会产生一个 TDI_ASSOCIATE_ADDRESS

在这里我们可以对本地的地址对象和连接对象进行绑定

之后才是 TDI_CONNECT , TDI_LISTEN , TDI_SEND 等

从项目中看TDI过滤驱动

参考文章

xue-blood/tdifw: copy of tdifw lib

TDIfw在windows 10 1903的测试-CSDN博客

TCP/IP 在 Windows 下的实现 - blfbuaa - 博客园

TDI网络过滤驱动开发指南-CSDN博客 这个介绍开发的比较全

CodeMachine - Article - TDI Overview 权威介绍TDI

在 Windows 中,TCP 和 UDP 设备接收到的 IRP(I/O 请求包)是由 TDI(Transport Driver Interface)封装的。当创建一个过滤驱动并将其插入到这些设备之上时,可以拦截和修改 TDI 传递给 TCP 和 UDP 驱动的 IRP,这种驱动被称为 TDI 过滤驱动。具体实现请看第二个文章,好理解

现在我们就来在Win10复现一下TDI过滤驱动吧

win10和早期版本还不太一样

例如首先\Device\Tcp已经不在\Driver\Tcpip,现在移动到了\Driver\tdx

高版本的结构长这样

1
2
3
4
5
6
7
8
9
应用程序
|
WinSock DLL (ws2_32.dll)
|
AFD.sys
|
tdx.sys (TDI-to-WSK Adapter)
|
TCPIP.sys

1736248732234

TDI过滤驱动的核心就是对于\\Device\\Tcp\\Device\\Udp以及\\Device\\RawIp三个设备进行过滤,形成设备栈,然后对每个IRP进行处理。

有两种选择,一是创建一个设备然后IoAttach上对应的Tcp,Udp,RawIp设备对象

TDI事件概述

当我们首先来看一下TDI涉及到的事件和IRP有哪些,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

#define IRP_MJ_CREATE 0x00
#define IRP_MJ_CLOSE 0x02
#define IRP_MJ_CLEANUP 0x12
#define IRP_MJ_DEVICE_CONTROL 0x0e
#define IRP_MJ_INTERNAL_DEVICE_CONTROL 0x0f

#define TDI_ASSOCIATE_ADDRESS (0x01)
#define TDI_DISASSOCIATE_ADDRESS (0x02)
#define TDI_CONNECT (0x03)
#define TDI_LISTEN (0x04)
#define TDI_ACCEPT (0x05)
#define TDI_DISCONNECT (0x06)
#define TDI_SEND (0x07)
#define TDI_RECEIVE (0x08)
#define TDI_SEND_DATAGRAM (0x09)
#define TDI_RECEIVE_DATAGRAM (0x0A)
#define TDI_SET_EVENT_HANDLER (0x0B)
#define TDI_QUERY_INFORMATION (0x0C)
#define TDI_SET_INFORMATION (0x0D)
#define TDI_ACTION (0x0E)

#define TDI_EVENT_CONNECT ((USHORT)0) // TDI_IND_CONNECT event handler.
#define TDI_EVENT_DISCONNECT ((USHORT)1) // TDI_IND_DISCONNECT event handler.
#define TDI_EVENT_ERROR ((USHORT)2) // TDI_IND_ERROR event handler.
#define TDI_EVENT_RECEIVE ((USHORT)3) // TDI_IND_RECEIVE event handler.
#define TDI_EVENT_RECEIVE_DATAGRAM ((USHORT)4) // TDI_IND_RECEIVE_DATAGRAM event handler.
#define TDI_EVENT_RECEIVE_EXPEDITED ((USHORT)5) // TDI_IND_RECEIVE_EXPEDITED event handler.
#define TDI_EVENT_SEND_POSSIBLE ((USHORT)6) // TDI_IND_SEND_POSSIBLE event handler

这些事件大致可以分为三类:

  1. 基本的IRP操作,最主要的是用来打开IP,UDP等设备使用,以及传送TDI请求。
  2. TDI请求,这个主要是用户层SOCKET发起请求调用。
  3. TDI事件,这个一般是注册接收网络数据引发的回调函数。

IRP_MJ_CREATE的处理

获取远程连接的Ip和端口

一般来说,对于我们TDI来说一个非常重要的操作就是获取地址;因为bind的时候我们有时候需要让系统选择一个可以使用的地址和端口,因此我们在IRP_MJ_CREATE过滤的时候并不能获取到绑定的地址,需要使用如下方法:

1.设置IRP的完成例程。
2.在完成例程中使用TdiBuildInternalDeviceControlIrp创建一个TDI_QUERY_INFORMATION的IRP。
3.使用TdiBuildQueryInformation设置查询类型为TDI_QUERY_ADDRESS_INFO,并设置完成例程。
4.调用IoCallDriver发起IRP查询请求。
5.这样我们在TDI_QUERY_ADDRESS_INFO的完成例程中就可以获取到绑定的地址了。

具体来说

先创建一个TDI_QUERY_ADDRESS_INFO类型的IRP

1736396967480

在IRP_MJ_CREATE的完成例程,设置之前的Quary_Irp,并设置完成例程函数,然后往下IoCallDriver

1736396849794

最终我们在TDI_QUERY_INFORMATION的IRP拿到了远程连接的IP和端口

1736396925652

TDI_ASSOCIATE_ADDRESS的处理

IRP_MJ_CREATE这个是TDI比较重要的一个点,TDI有两个对象需要创建:

  1. 地址对象:所谓地址对象就是通常我们调用bind函数绑定的本地地址和端口的对象。
  2. 连接对象:所谓连接对象就是我们listen或者connect创建的,用来和远端连接通信的一个对象。

然后就是紧接着会产生一个 TDI_ASSOCIATE_ADDRESS

在这里我们可以对本地的地址对象和连接对象进行绑定

在这个请求中, 我们可以从IrpSp->Parameters中就是我们需要绑定的地址对象

1736502888838

连接对象就是irps->FileObject,可以和地址对象进行绑定

1736503079285

TDI_CONNECT的处理

TDI_CONNECT是用户层发起connect,对于这个请求,我们可以从 IrpSp->Parameters拿到参数 _TDI_REQUEST_KERNEL 结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//IrpSp->Parameters
typedef struct _TDI_REQUEST_KERNEL {
ULONG_PTR RequestFlags;
PTDI_CONNECTION_INFORMATION RequestConnectionInformation;
PTDI_CONNECTION_INFORMATION ReturnConnectionInformation;
PVOID RequestSpecific;
} TDI_REQUEST_KERNEL, *PTDI_REQUEST_KERNEL;

typedef struct _TDI_CONNECTION_INFORMATION {
LONG UserDataLength;
PVOID UserData;
LONG OptionsLength;
PVOID Options;
LONG RemoteAddressLength;
PVOID RemoteAddress;
} TDI_CONNECTION_INFORMATION, *PTDI_CONNECTION_INFORMATION;

从参数RequestConnectionInformation我们可以获取到连接的远程地址。

TDI_SEND

当用户层调用send发送数据包的时候,TDI驱动就会接收到TDI_SEND类型的事件,对于这个请求有两个参数:

  1. IrpSp->Parameters表示发送数据的信息,为TDI_REQUEST_KERNEL_SEND结构。
  2. Irp->MdlAddress表示发送数据的具体内容。
1
2
3
4
struct _TDI_REQUEST_KERNEL_SEND {
ULONG SendLength;
ULONG SendFlags;
} TDI_REQUEST_KERNEL_SEND, *PTDI_REQUEST_KERNEL_SEND;

对于SendFlags可以取如下值:

  • TDI_SEND_EXPEDITED:紧急包,必需放到传输层的头部。
  • TDI_SEND_PARTIAL:只是一部分数据,接下来还会发送数据

其他还有异步发,异步读等,也就是加了个EVENT的

https://blog.csdn.net/xsinlink/article/details/134375333#9__378

可以参考这个

实践环节

本来想在win10测试一下获取本地ip和端口的,也就是拦截IRP_MJ_CREATE,代码如下

头文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#pragma once
extern "C"//存变量
{
#define DebugPrint(...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL,__VA_ARGS__)
#include <ntifs.h>
#include <ntddk.h>
#include <Tdikrnl.h>


extern PVOID* IoDriverObjectType; //外部导入IoDriverObjectType

//设备和驱动名
UNICODE_STRING deviceTcp; //TCP设备名
UNICODE_STRING deviceUdp; //UDP设备名
UNICODE_STRING driverTdx; //TDX驱动名
PDRIVER_OBJECT Tdx_DriverObject=NULL; //TDX驱动对象

PDEVICE_OBJECT TcpObj=NULL; //Tcp设备对象
PDEVICE_OBJECT UdpObj=NULL; //Udp设备对象


// Original_Object用来保存原来的IRP处理例程函数
DRIVER_OBJECT Original_Object;





enum {
FILTER_ALLOW = 1,
FILTER_DENY,
FILTER_PACKET_LOG,
FILTER_PACKET_BAD,
FILTER_DISCONNECT
};

//区分bind和connect,listen
#define TdiTransportAddress "TransportAddress"
#define TdiConnectionContext "ConnectionContext"
#define TDI_TRANSPORT_ADDRESS_LENGTH (sizeof (TdiTransportAddress) - 1)
#define TDI_CONNECTION_CONTEXT_LENGTH (sizeof (TdiConnectionContext) - 1)



struct completion {
PIO_COMPLETION_ROUTINE routine;
PVOID context;
};


#define TdiBuildInternalDeviceControlIrp(IrpSubFunction,DeviceObject,FileObject,Event,IoStatusBlock) \
IoBuildDeviceIoControlRequest (\
0x00000003,\
DeviceObject, \
NULL, \
0, \
NULL, \
0, \
TRUE, \
Event, \
IoStatusBlock)


//用来设置完成例程的附带数据
typedef struct {
PIO_COMPLETION_ROUTINE old_cr; /* old (original) completion routine */
PVOID old_context; /* old (original) parameter for old_cr */
PIO_COMPLETION_ROUTINE new_cr; /* new (replaced) completion routine */
PVOID new_context; /* new (replaced) parameter for new_cr */
PFILE_OBJECT fileobj; /* FileObject from IO_STACK_LOCATION */
PDEVICE_OBJECT new_devobj; /* filter device object */
UCHAR old_control; /* old (original) irps->Control */
} TDI_SKIP_CTX;

//申请非分页内存
#define MEM_TAG 'YCAI'
#define malloc_np(size) ExAllocatePoolWithTag(NonPagedPool, (size), MEM_TAG)

//释放掉非分页内存
#define free(ptr) ExFreePool(ptr)

#define ISO_MAX_ADDR_LENGTH 64


#define TDI_ADDRESS_LENGTH_OSI_TSAP sizeof (TDI_ADDRESS_OSI_TSAP)
#define TA_ADDRESS_MAX (sizeof(TA_ADDRESS) - 1 + TDI_ADDRESS_MAX_LENGTH)
#define TDI_ADDRESS_INFO_MAX (sizeof(TDI_ADDRESS_INFO) - 1 + TDI_ADDRESS_MAX_LENGTH)
#define TDI_ADDRESS_MAX_LENGTH TDI_ADDRESS_LENGTH_OSI_TSAP






typedef struct {
TDI_ADDRESS_INFO* tai; /* address info -- result of TDI_QUERY_ADDRESS_INFO */
PFILE_OBJECT fileobj; /* FileObject from IO_STACK_LOCATION */
} TDI_CREATE_ADDROBJ2_CTX;



}


extern "C"
{
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
VOID DriverUnloadRoutine(IN PDRIVER_OBJECT DriverObject);

//未文档化函数
NTKERNELAPI NTSTATUS ObReferenceObjectByName(
IN PUNICODE_STRING ObjectName,
IN ULONG Attributes,
IN PACCESS_STATE PassedAccessState OPTIONAL,
IN ACCESS_MASK DesiredAccess OPTIONAL,
IN POBJECT_TYPE ObjectType OPTIONAL,
IN KPROCESSOR_MODE AccessMode,
IN OUT PVOID ParseContext OPTIONAL,
OUT PVOID* Object
);

//获取驱动对象
NTSTATUS GetDriverObject();

//获取原来tdx.sys的IRP处理例程
NTSTATUS GetOldIrpMajorFunctions();

//用Hook的方法,劫持掉原来的驱动IRP处理例程函数
NTSTATUS HookTcpUdp();

//通过设备名获取到设备对象
NTSTATUS GetDeviceObjByName(UNICODE_STRING* Unicode_string,PDEVICE_OBJECT* DeviceObj);

//自定义的IRP处理例程函数TdiHookDeviceDispatch
NTSTATUS TdiHookDeviceDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp);

//判断是bind还是listen,connect,并创建回调函数
int tdi_create(PIRP irp, PIO_STACK_LOCATION irps, struct completion* completion);

//IRP_MJ_CREATE完成例程函数
NTSTATUS tdi_create_addrobj_complete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context);

//设置完成例程函数
NTSTATUS tdi_dispatch_complete(PDEVICE_OBJECT devobj, PIRP irp, int filter, PIO_COMPLETION_ROUTINE cr, PVOID context);

//替换掉原来irp完成例程函数的完成例程函数 有点绕
NTSTATUS tdi_skip_complete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context);

//完成例程函数调用结束后都return这玩意
NTSTATUS tdi_generic_complete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context);

//这个是完成TDI_QUERY_INFORMATION这个IRP的完成例程函数
NTSTATUS tdi_create_addrobj_complete2(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context);


unsigned long ntohl(unsigned long netlong)
{
unsigned long result = 0;
((char*)&result)[0] = ((char*)&netlong)[3];
((char*)&result)[1] = ((char*)&netlong)[2];
((char*)&result)[2] = ((char*)&netlong)[1];
((char*)&result)[3] = ((char*)&netlong)[0];
return result;
}

unsigned short ntohs(unsigned short netshort)
{
unsigned short result = 0;
((char*)&result)[0] = ((char*)&netshort)[1];
((char*)&result)[1] = ((char*)&netshort)[0];
return result;
}
}

cpp文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
#include <Ntifs.h>
#include <ntimage.h>
#include <ntstrsafe.h>
#include <Tdikrnl.h>
#define MEM_TAG 'YCAI'
#define malloc_np(size) ExAllocatePoolWithTag(NonPagedPool, (size), MEM_TAG)
#define free(ptr) ExFreePool(ptr)
#define TDI_ADDRESS_MAX_LENGTH TDI_ADDRESS_LENGTH_OSI_TSAP
#define TA_ADDRESS_MAX (sizeof(TA_ADDRESS) - 1 + TDI_ADDRESS_MAX_LENGTH)
#define TDI_ADDRESS_INFO_MAX (sizeof(TDI_ADDRESS_INFO) - 1 + TDI_ADDRESS_MAX_LENGTH)
/* filter result */
enum {
FILTER_ALLOW = 1,
FILTER_DENY,
FILTER_PACKET_LOG,
FILTER_PACKET_BAD,
FILTER_DISCONNECT
};
typedef struct {
PIO_COMPLETION_ROUTINE old_cr; /* old (original) completion routine */
PVOID old_context; /* old (original) parameter for old_cr */
PIO_COMPLETION_ROUTINE new_cr; /* new (replaced) completion routine */
PVOID new_context; /* new (replaced) parameter for new_cr */
PFILE_OBJECT fileobj; /* FileObject from IO_STACK_LOCATION */
PDEVICE_OBJECT new_devobj; /* filter device object */
UCHAR old_control; /* old (original) irps->Control */
} TDI_SKIP_CTX;
struct completion {
PIO_COMPLETION_ROUTINE routine;
PVOID context;
};
typedef struct {
TDI_ADDRESS_INFO* tai; /* address info -- result of TDI_QUERY_ADDRESS_INFO */
PFILE_OBJECT fileobj; /* FileObject from IO_STACK_LOCATION */
} TDI_CREATE_ADDROBJ2_CTX;
struct tdi_obj {
PFILE_OBJECT fileobj, associate_obj;
UCHAR local_addr[TA_ADDRESS_MAX];
};
extern "C"
{
NTKERNELAPI NTSTATUS ObReferenceObjectByName(IN PUNICODE_STRING ObjectName, IN ULONG Attributes, IN PACCESS_STATE PassedAccessState OPTIONAL, IN ACCESS_MASK DesiredAccess OPTIONAL, IN POBJECT_TYPE ObjectType OPTIONAL, IN KPROCESSOR_MODE AccessMode, IN OUT PVOID ParseContext OPTIONAL, OUT PVOID* Object);
VOID DriverUnload(PDRIVER_OBJECT DriverObject);
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegPath);
extern PVOID* IoDriverObjectType;
}

PDEVICE_OBJECT g_tcpfltobj = NULL;
PDEVICE_OBJECT g_udpfltobj = NULL;
PDEVICE_OBJECT g_tcpfltobj6 = NULL;
PDEVICE_OBJECT g_udpfltobj6 = NULL;
DRIVER_OBJECT g_old_DriverObject;
PDRIVER_OBJECT new_DriverObject;
unsigned long ntohl(unsigned long netlong)
{
unsigned long result = 0;
((char*)&result)[0] = ((char*)&netlong)[3];
((char*)&result)[1] = ((char*)&netlong)[2];
((char*)&result)[2] = ((char*)&netlong)[1];
((char*)&result)[3] = ((char*)&netlong)[0];
return result;
}

unsigned short ntohs(unsigned short netshort)
{
unsigned short result = 0;
((char*)&result)[0] = ((char*)&netshort)[1];
((char*)&result)[1] = ((char*)&netshort)[0];
return result;
}


NTSTATUS get_device_object(wchar_t* name, PDEVICE_OBJECT* devobj) {
UNICODE_STRING str;
NTSTATUS status;
PFILE_OBJECT fileobj;

RtlInitUnicodeString(&str, name);

status = IoGetDeviceObjectPointer(&str, FILE_ALL_ACCESS, &fileobj, devobj);
if (status == STATUS_SUCCESS)
ObDereferenceObject(fileobj);

return status;
}


NTSTATUS tdi_skip_complete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) {
TDI_SKIP_CTX* ctx = (TDI_SKIP_CTX*)Context;
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION irps;

if (Irp->IoStatus.Status != STATUS_SUCCESS)
DbgPrint("tdi_skip_complete: status 0x%x\n", Irp->IoStatus.Status);


//这里是回到之前的那一层
Irp->CurrentLocation--;
Irp->Tail.Overlay.CurrentStackLocation--;


irps = IoGetCurrentIrpStackLocation(Irp);

DeviceObject = irps->DeviceObject;//保存一下当前的设备对象

if (ctx->new_cr != NULL) {
// restore fileobject (it's NULL)
irps->FileObject = ctx->fileobj;
// set new device object in irps
irps->DeviceObject = ctx->new_devobj;

// call new completion
status = ctx->new_cr(ctx->new_devobj, Irp, ctx->new_context);//这里是到tdi_create_addrobj_complete 去执行

}
else
status = STATUS_SUCCESS;


// restore routine and context (and even control!)
irps->CompletionRoutine = ctx->old_cr;
irps->Context = ctx->old_context;
irps->Control = ctx->old_control;

// restore device object
irps->DeviceObject = DeviceObject;

Irp->CurrentLocation++;
Irp->Tail.Overlay.CurrentStackLocation++;


if (ctx->old_cr != NULL) {
if (status != STATUS_MORE_PROCESSING_REQUIRED) {
BOOLEAN b_call = FALSE;
if (Irp->Cancel) {
// cancel
if (ctx->old_control & SL_INVOKE_ON_CANCEL)
b_call = TRUE;
}
else {
if (Irp->IoStatus.Status >= STATUS_SUCCESS) {
// success
if (ctx->old_control & SL_INVOKE_ON_SUCCESS)
b_call = TRUE;
}
else {
// error
if (ctx->old_control & SL_INVOKE_ON_ERROR)
b_call = TRUE;
}
}
if (b_call)
status = ctx->old_cr(DeviceObject, Irp, ctx->old_context);//之前老的complete如果有的话
}
else {
irps->Control = ctx->old_control;
}
}

free(ctx);

return status;
}



NTSTATUS tdi_dispatch_complete(PDEVICE_OBJECT devobj, PIRP irp, int filter, PIO_COMPLETION_ROUTINE cr, PVOID context) {
PIO_STACK_LOCATION irps = IoGetCurrentIrpStackLocation(irp);
NTSTATUS status;

if (filter == FILTER_DENY) {
if (irp->IoStatus.Status == STATUS_SUCCESS) {
// change status
status = irp->IoStatus.Status = STATUS_ACCESS_DENIED;
}
else {
// set IRP status unchanged
status = irp->IoStatus.Status;
}

IoCompleteRequest(irp, IO_NO_INCREMENT);
}
else if (filter == FILTER_ALLOW) {

if (cr != NULL) {
// save old completion routine and context
TDI_SKIP_CTX* ctx = (TDI_SKIP_CTX*)malloc_np(sizeof(*ctx));
if (ctx == NULL) {
DbgPrint("tdi_send_irp_to_old_driver: malloc_np\n");

status = irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest(irp, IO_NO_INCREMENT);

return status;
}

ctx->old_cr = irps->CompletionRoutine;
ctx->old_context = irps->Context;
ctx->new_cr = cr;
ctx->new_context = context;
ctx->fileobj = irps->FileObject;
ctx->new_devobj = devobj;

ctx->old_control = irps->Control;

//手动模拟setcomplete
irps->Context = ctx;
irps->CompletionRoutine = (PIO_COMPLETION_ROUTINE)tdi_skip_complete;
irps->Control = SL_INVOKE_ON_ERROR | SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_CANCEL;
//IoSetCompletionRoutine(irp, tdi_skip_complete, ctx, TRUE, TRUE, TRUE);
}
/* call original driver */
status = g_old_DriverObject.MajorFunction[irps->MajorFunction](devobj, irp);
}
else { /* FILTER_UNKNOWN */
status = irp->IoStatus.Status = STATUS_SUCCESS; // ???
IoCompleteRequest(irp, IO_NO_INCREMENT);
}

return status;
}


NTSTATUS tdi_create_addrobj_complete2(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) {
NTSTATUS status;
TDI_CREATE_ADDROBJ2_CTX* ctx = (TDI_CREATE_ADDROBJ2_CTX*)Context;
TA_ADDRESS* addr = ctx->tai->Address.Address;
struct tdi_obj* obj_item = NULL;
unsigned long Ip = ntohl(((TDI_ADDRESS_IP*)(addr->Address))->in_addr);//得到地址
unsigned long* IpAddress = &Ip;
//打印一下ip地址和端口
DbgPrint("tdi_create_addrobj_complete2: IPaddress : %d.%d.%d.%d:%u fileobj0x%llX\n", ((UCHAR*)IpAddress)[3], ((UCHAR*)IpAddress)[2], ((UCHAR*)IpAddress)[1], ((UCHAR*)IpAddress)[0], ntohs(((TDI_ADDRESS_IP*)(addr->Address))->sin_port), ctx->fileobj);

status = STATUS_SUCCESS;
if (Irp->MdlAddress != NULL) {
IoFreeMdl(Irp->MdlAddress);
Irp->MdlAddress = NULL;
}

free(ctx->tai);
free(ctx);

return STATUS_SUCCESS;
}

NTSTATUS tdi_generic_complete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) {

if (Irp->PendingReturned) {
DbgPrint("tdi_generic_complete: PENDING\n");
IoMarkIrpPending(Irp);
}

return STATUS_SUCCESS;
}

NTSTATUS tdi_create_addrobj_complete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) {
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION irps = IoGetCurrentIrpStackLocation(Irp);
PIRP query_irp = (PIRP)Context;
PDEVICE_OBJECT devobj;
TDI_CREATE_ADDROBJ2_CTX* ctx = NULL;
PMDL mdl = NULL;

if (Irp->IoStatus.Status != STATUS_SUCCESS) {
DbgPrint("tdi_create_addrobj_complete: status 0x%x\n", Irp->IoStatus.Status);
status = Irp->IoStatus.Status;
goto done;
}

// query addrobj address:port

ctx = (TDI_CREATE_ADDROBJ2_CTX*)malloc_np(sizeof(TDI_CREATE_ADDROBJ2_CTX));
if (ctx == NULL) {
DbgPrint("tdi_create_addrobj_complete: malloc_np\n");
status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}

ctx->fileobj = irps->FileObject;

ctx->tai = (TDI_ADDRESS_INFO*)malloc_np(TDI_ADDRESS_INFO_MAX);
if (ctx->tai == NULL) {
DbgPrint("tdi_create_addrobj_complete: malloc_np!\n");
status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}

mdl = IoAllocateMdl(ctx->tai, TDI_ADDRESS_INFO_MAX, FALSE, FALSE, NULL);
if (mdl == NULL) {
DbgPrint("tdi_create_addrobj_complete: IoAllocateMdl!\n");
status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
MmBuildMdlForNonPagedPool(mdl);

devobj = DeviceObject;
if (devobj == NULL) {
DbgPrint("tdi_create_addrobj_complete: get_original_devobj!\n");

status = STATUS_INVALID_PARAMETER;
goto done;
}

TdiBuildQueryInformation(query_irp, devobj, irps->FileObject, tdi_create_addrobj_complete2, ctx, TDI_QUERY_ADDRESS_INFO, mdl);

status = IoCallDriver(devobj, query_irp);//这里需要继续往下传
query_irp = NULL;
mdl = NULL;
ctx = NULL;

if (status != STATUS_SUCCESS) {//STATUS_PENDING
DbgPrint("tdi_create_addrobj_complete: IoCallDriver: 0x%x STATUS_PENDING==0x103\n", status);
goto done;
}

status = STATUS_SUCCESS;

done:
// cleanup
if (mdl != NULL)
IoFreeMdl(mdl);

if (ctx != NULL) {
if (ctx->tai != NULL)
free(ctx->tai);
free(ctx);
}

if (query_irp != NULL)
IoCompleteRequest(query_irp, IO_NO_INCREMENT);

Irp->IoStatus.Status = status;

return tdi_generic_complete(DeviceObject, Irp, Context);
}




int tdi_create(PIRP irp, PIO_STACK_LOCATION irps, struct completion* completion) {
FILE_FULL_EA_INFORMATION* ea = (FILE_FULL_EA_INFORMATION*)irp->AssociatedIrp.SystemBuffer;

if (ea != NULL) {
PDEVICE_OBJECT devobj;

devobj = irps->DeviceObject;
if (devobj == NULL) {
DbgPrint("tdi_create: unknown device object 0x%llX!\n", irps->DeviceObject);
return FILTER_DENY;
}

if (ea->EaNameLength == TDI_TRANSPORT_ADDRESS_LENGTH && memcmp(ea->EaName, TdiTransportAddress, TDI_TRANSPORT_ADDRESS_LENGTH) == 0) {//传输
PIRP query_irp;
//搞一个空的irp
query_irp = TdiBuildInternalDeviceControlIrp(TDI_QUERY_INFORMATION, devobj, irps->FileObject, NULL, NULL);
if (query_irp == NULL) {
DbgPrint("tdi_create: TdiBuildInternalDeviceControlIrp\n");
return FILTER_DENY;
}

completion->routine = tdi_create_addrobj_complete;//这里是设置完成的回调
completion->context = query_irp;

}
else if (ea->EaNameLength == TDI_CONNECTION_CONTEXT_LENGTH && memcmp(ea->EaName, TdiConnectionContext, TDI_CONNECTION_CONTEXT_LENGTH) == 0) {//连接

CONNECTION_CONTEXT conn_ctx = *(CONNECTION_CONTEXT*)(ea->EaName + ea->EaNameLength + 1);//这个是链接上下文
}

}

return FILTER_ALLOW;
}

int tdi_connect(PIRP irp, PIO_STACK_LOCATION irps, struct completion* completion) {
PTDI_REQUEST_KERNEL_CONNECT param = (PTDI_REQUEST_KERNEL_CONNECT)(&irps->Parameters);
TA_ADDRESS* remote_addr = ((TRANSPORT_ADDRESS*)(param->RequestConnectionInformation->RemoteAddress))->Address;
unsigned long Ip = ntohl(((TDI_ADDRESS_IP*)(remote_addr->Address))->in_addr);//得到地址
unsigned long* IpAddress = &Ip;

// 监控TCP外连参数 ---在这里处理
DbgPrint("pid:%d tdi_connect: connobj 0x%llX, remote:%d.%d.%d.%d:%u\n",
PsGetCurrentProcessId(),
irps->FileObject,
((UCHAR*)IpAddress)[3], ((UCHAR*)IpAddress)[2], ((UCHAR*)IpAddress)[1], ((UCHAR*)IpAddress)[0],
ntohs(((TDI_ADDRESS_IP*)(remote_addr->Address))->sin_port));


return FILTER_ALLOW;
}
int tdi_associate_address(PIRP irp, PIO_STACK_LOCATION irps, struct completion* completion) {
HANDLE addr_handle = ((TDI_REQUEST_KERNEL_ASSOCIATE*)(&irps->Parameters))->AddressHandle;
PFILE_OBJECT addrobj = NULL;
NTSTATUS status;
int result = FILTER_DENY;

status = ObReferenceObjectByHandle(addr_handle, GENERIC_READ, NULL, KernelMode, (PVOID*)&addrobj, NULL);
if (status != STATUS_SUCCESS) {
DbgPrint("[tdi_fw] tdi_associate_address: ObReferenceObjectByHandle: 0x%x\n", status);
}

DbgPrint("tdi_associate_address: connobj = 0x%llX ---> addrobj = 0x%llX\n", irps->FileObject, addrobj);//这里是绑定本地的transport,只打印不记录

result = FILTER_ALLOW;
if (addrobj != NULL)
ObDereferenceObject(addrobj);

return result;
}

NTSTATUS TdiHookDeviceDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp) {
PIO_STACK_LOCATION irps;
NTSTATUS status;
int result;
struct completion completion = { 0 };
//假装检查一下
if (irp == NULL)
return STATUS_SUCCESS;

irps = IoGetCurrentIrpStackLocation(irp);


if (DeviceObject == g_tcpfltobj || DeviceObject == g_udpfltobj) {//这里过滤TCP和UDP
switch (irps->MajorFunction) {
case IRP_MJ_CREATE:
result = tdi_create(irp, irps, &completion);
status = tdi_dispatch_complete(DeviceObject, irp, result, completion.routine, completion.context);
//DbgPrint("IRP_MJ_CREATE \n");
break;
/*case IRP_MJ_DEVICE_CONTROL:
if (KeGetCurrentIrql() == PASSIVE_LEVEL) {
status = TdiMapUserRequest(DeviceObject, irp, irps);
}else
status = STATUS_NOT_IMPLEMENTED; // set fake status
if (status != STATUS_SUCCESS) {
void *buf = (irps->Parameters.DeviceIoControl.IoControlCode == IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER) ?irps->Parameters.DeviceIoControl.Type3InputBuffer : NULL;
//这里的buf是send的指针,目前不用
// send IRP to original driver
status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW, NULL, NULL);
break;
}*/
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
/* 根据irps->MinorFunction类型进行处理 */
if (irps->MinorFunction == TDI_CONNECT) {
tdi_connect(irp, irps, &completion);
}
else if (irps->MinorFunction == TDI_ASSOCIATE_ADDRESS) {
tdi_associate_address(irp, irps, &completion);
}

status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW, completion.routine, completion.context);
break;
default:
DbgPrint("default \n");
status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW, NULL, NULL);
return status;
}




}
else
status = g_old_DriverObject.MajorFunction[irps->MajorFunction](DeviceObject, irp);//避免二次完成


return status;
}

void HookTcpIp() {

UNICODE_STRING drv_name;
NTSTATUS status;
int i;

//之后用来做过滤的
status = get_device_object(L"\\Device\\Tcp", &g_tcpfltobj);
status = get_device_object(L"\\Device\\Udp", &g_udpfltobj);
//status = get_device_object(L"\\Device\\Tcp6", &g_tcpfltobj6);
//status = get_device_object(L"\\Device\\Udp6", &g_udpfltobj6);
//DbgPrint("Tcp %llX Udp %llX Tcp6 %llX Udp6 %llX \n", g_tcpfltobj, g_udpfltobj, g_tcpfltobj6, g_udpfltobj6);
RtlInitUnicodeString(&drv_name, L"\\Driver\\tdx");//tdx

status = ObReferenceObjectByName(&drv_name, OBJ_CASE_INSENSITIVE, NULL, 0, (POBJECT_TYPE)*IoDriverObjectType, KernelMode, NULL, (PVOID*)&new_DriverObject);
if (status != STATUS_SUCCESS) {
DbgPrint("ObReferenceObjectByName failed \n");
return;
}
ObDereferenceObject(new_DriverObject);//解引用

for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
g_old_DriverObject.MajorFunction[i] = new_DriverObject->MajorFunction[i];
new_DriverObject->MajorFunction[i] = TdiHookDeviceDispatch;//替换方法
}
}





VOID DriverUnload(PDRIVER_OBJECT DriverObject) {
int i;
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
new_DriverObject->MajorFunction[i] = g_old_DriverObject.MajorFunction[i];//还原
DbgPrint("See You !\n");
}


NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegPath) {

DriverObject->DriverUnload = DriverUnload;
HookTcpIp();
return STATUS_SUCCESS;
}

但是拦截不到IRP_MJ_CREATE,就很奇怪

应该是win10不支持了??

所以没再管了。。。。。还是看看远方的WFP吧