首页
社区
课程
招聘
[分享]NtSockets -ring3 直接与驱动通信实现sockets
2022-3-22 23:28 17260

[分享]NtSockets -ring3 直接与驱动通信实现sockets

2022-3-22 23:28
17260

NtSockets - 直接与驱动通信实现sockets

最近在研究syscall相关的技术,无意中发现了这个NtSockets(只使用NtCreateFile和NtDeviceIoControlFile 函数,直接操作afd.sys驱动实现socket),感谢作者@x86matthew

 

原文链接 NTSockets - Downloading a file via HTTP using the NtCreateFile and NtDeviceIoControlFile syscalls

项目的bug和不足

作者只实现了TCP-client的代码,并且x86下测试通过,但是在x64模式下连接到服务端时出现了错误。


解决x64环境下connect中的bug

1. 推测问题

根据函数的返回状态 0xc000000d 可知是参数错误。

 

 

根据代码

1
NtDeviceIoControlFile(pSocketData->hSocket, pSocketData->hStatusEvent, NULL, NULL, &IoStatusBlock, dwIoControlCode, (void*)pData, dwLength, bOutputBlock, sizeof(bOutputBlock));

可以推测应该是传入的pData和dwLength出现了错误,根据调用关系

1
2
3
4
5
6
7
8
9
10
11
12
13
struct NTSockets_ConnectDataStruct NTSockets_ConnectData;
NTSockets_ConnectData.dwUnknown1 = 0;
NTSockets_ConnectData.dwUnknown2 = 0;
NTSockets_ConnectData.dwUnknown3 = 0;
NTSockets_ConnectData.SockAddr.sin_family = AF_INET;
NTSockets_ConnectData.SockAddr.sin_addr.s_addr = dwConnectAddr;
NTSockets_ConnectData.SockAddr.sin_port = wConnectPort;
ULONG sz = sizeof(NTSockets_ConnectData);
if (NTSockets_SocketDriverMsg(pSocketData, 0x00012007, (BYTE*)&NTSockets_ConnectData, sz, NULL) != 0)
{
    // error
    return 1;
}

那么问题就出在结构体NTSockets_ConnectDataStruct上。

1
2
3
4
5
6
7
struct NTSockets_ConnectDataStruct
{
    ULONG dwUnknown1;
    ULONG dwUnknown2;
    ULONG dwUnknown3;
    struct sockaddr_in SockAddr;
};

2. 证实猜测

随便在网上找了个TCP-Client的代码,选择x64模式,在connect上下断点,当在connect断下来后,再在NtDeviceIoControlFile上下断点,再运行。

 

可以看到有几次触发断点

1
2
3
4
5
6
dwIoControlCode
0x01207b      mswsock.dll!SockGetInformation()    Unknown
0x0120bf      mswsock.dll!WSPSetSockOpt()            Unknown
0x012003      mswsock.dll!WSPBind()                Unknown
0x012047      mswsock.dll!SockSetHandleContext()    Unknown
0x012007     mswsock.dll!SockDoConnectReal()        Unknown

这里我们只关心 dwIoControlCode为0x012007 的调用。

 

通过对比参数可以找到参数以及大小。

1
2
3
4
5
6
size 0x28
0x000000D8606FEE40  00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
                                            |AFIN |port |---IP---|
0x000000D8606FEE50  30 ef 6f 60 d8 00 00 00 02 00 00 50 7f 00 00 01
                    |------ZERO8----------|
0x000000D8606FEE60  00 00 00 00 00 00 00 00

而NtSockets代码参数是

1
2
3
4
5
size 0x1c
                                                        |AFIN |port
0x0000002EE86FD9F8  00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 50
                    |---IP---|  |------ZERO8----------|
0x0000002EE86FDA08  c0 a8 0a 75 00 00 00 00 00 00 00 00

3.解决办法

重新定义下NTSockets_ConnectDataStruct结构体就可以了。

1
2
3
4
5
6
7
struct NTSockets_ConnectDataStruct
{
    SIZE_T dwUnknown1;
    SIZE_T dwUnknown2;
    SIZE_T dwUnknown3;
    struct sockaddr_in SockAddr;
};

SIZE_T x86下是ULONG 在x64下是ULONGLONG。


增加对UDP的支持

先来看看TCP的细节

根据代码可以看出TCP创建句柄跟bExtendedAttributes有关。所以我们关注下这个参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
NTSTATUS NTAPI NtCreateFile     (     PHANDLE      FileHandle,
        ACCESS_MASK      DesiredAccess,
        POBJECT_ATTRIBUTES      ObjectAttributes,
        PIO_STATUS_BLOCK      IoStatusBlock,
        PLARGE_INTEGER      AllocateSize,
        ULONG      FileAttributes,
        ULONG      ShareAccess,
        ULONG      CreateDisposition,
        ULONG      CreateOptions,
        PVOID      EaBuffer,
        ULONG      EaLength
    )    
 
dwStatus = NtCreateFile(&hSocket, 0xC0140000, &ObjectAttributes, &IoStatusBlock, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 1, 0, &bExtendedAttributes, sizeof(bExtendedAttributes));

在socket函数下断点,断下来后在NtCreateFile函数下断点。堆栈情况如下

1
2
3
4
5
6
7
0x000000EC37FCEE40  0000000000000000  ........
0x000000EC37FCEE48  004f004400000000  ....D.O.
0x000000EC37FCEE50  000000ec00000003  ....ì...
0x000000EC37FCEE58  000000ec00000003  ....ì...
0x000000EC37FCEE60  000000ec00000000  ....ì...
0x000000EC37FCEE68  000000ec37fcef60  `ïü7ì...
0x000000EC37FCEE70  002e006b00000039  9...k...

这是x64下的情况,去除前4个参数(利用寄存器传参),以上是第5-11参数。
这里我们只关注 后两个参数

1
2
3
4
5
6
7
8
0x000000EC37FCEE68  000000ec37fcef60  `ïü7ì...  EaBuffer
0x000000EC37FCEE70  002e006b00000039  9...k...  EaLength
 
EaBuffer:
0x000000EC37FCEF60  00 00 00 00 00 0f 1e 00 41 66 64 4f 70 65 6e 50  ........AfdOpenP
0x000000EC37FCEF70  61 63 6b 65 74 58 58 00 00 00 00 00 00 00 00 00  acketXX.........
0x000000EC37FCEF80  02 00 00 00 01 00 00 00 06 00 00 00 00 00 00 00  ................
0x000000EC37FCEF90  08 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

对比NtSockets的EaBuffer

1
2
3
4
5
6
7
BYTE bExtendedAttributes[] =
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1E, 0x00, 0x41, 0x66, 0x64, 0x4F, 0x70, 0x65, 0x6E, 0x50,
        0x61, 0x63, 0x6B, 0x65, 0x74, 0x58, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x60, 0xEF, 0x3D, 0x47, 0xFE
    };

我解惑的数据和作者给出的有些出入,不过不影响使用。

截获UDP的EaBuffer

直接将socket的参数调整成UDP的。还是在socket断下来以后,给NtCreateFile下断点,以下是udp的堆栈情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
0x000000B698EFF308  0000000000000000  ........
0x000000B698EFF310  0000000000000000  ........
0x000000B698EFF318  004f004400000000  ....D.O.
0x000000B698EFF320  000000b600000003  ....¶...
0x000000B698EFF328  000000b600000003  ....¶...
0x000000B698EFF330  000000b600000000  ....¶...
0x000000B698EFF338  000000b698eff430  0ô...
0x000000B698EFF340  002e006b00000039  9...k...
 
EaBuffer:
0x000000B698EFF430  00 00 00 00 00 0f 1e 00 41 66 64 4f 70 65 6e 50  ........AfdOpenP
0x000000B698EFF440  61 63 6b 65 74 58 58 00 11 00 00 00 00 00 00 00  acketXX.........
0x000000B698EFF450  02 00 00 00 02 00 00 00 11 00 00 00 00 00 00 00  ................
0x000000B698EFF460  08 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

只要替换NtSockets中的bExtendedAttributes数组就可以产生UDP的连接。

最终代码

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
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
#include <stdio.h>
#include <Windows.h>
 
 
#pragma warning(suppress : 4996)
#pragma warning(disable : 4996)
#define _CRT_SECURE_NO_WARNINGS 1
struct IO_STATUS_BLOCK
{
    union
    {
        DWORD Status;
        PVOID Pointer;
    };
 
    DWORD* Information;
};
 
struct UNICODE_STRING
{
    USHORT Length;
    USHORT MaximumLength;
    PWSTR Buffer;
};
 
struct OBJECT_ATTRIBUTES
{
    ULONG Length;
    HANDLE RootDirectory;
    struct UNICODE_STRING* ObjectName;
    ULONG Attributes;
    PVOID SecurityDescriptor;
    PVOID SecurityQualityOfService;
};
 
struct FILE_FULL_EA_INFORMATION
{
    ULONG     NextEntryOffset;
    UCHAR      Flags;
    UCHAR   EaNameLength;
    USHORT     EaValueLength;
    CHAR     EaName[1];
};
 
 
 
 
struct NTSockets_ConnectDataStruct
{
    SIZE_T dwUnknown1;
    SIZE_T dwUnknown2;
    SIZE_T dwUnknown3;
    struct sockaddr_in SockAddr;
};
 
struct NTSockets_BindDataStruct
{
    DWORD dwUnknown1;
    struct sockaddr_in SockAddr;
};
 
struct NTSockets_DataBufferStruct
{
    DWORD dwDataLength;
    BYTE* pData;
};
 
struct NTSockets_SendRecvDataStruct
{
    struct NTSockets_DataBufferStruct* pBufferList;
    DWORD dwBufferCount;
    DWORD dwUnknown1;
    DWORD dwUnknown2;
};
 
struct NTSockets_SocketDataStruct
{
    HANDLE hSocket;
    HANDLE hStatusEvent;
};
 
struct DNSClient_HeaderStruct
{
    WORD wTransID;
    WORD wFlags;
    WORD wQuestionCount;
    WORD wAnswerRecordCount;
    WORD wAuthorityRecordCount;
    WORD wAdditionalRecordCount;
};
 
struct DNSClient_RequestQueryDetailsStruct
{
    WORD wType;
    WORD wClass;
};
 
struct DNSClient_ResponseAnswerHeaderStruct
{
    WORD wName;
    WORD wType;
    WORD wClass;
    WORD wTTL[2];
    WORD wLength;
};
 
DWORD(NTAPI* NtDeviceIoControlFile)(HANDLE FileHandle, HANDLE Event, VOID* ApcRoutine, PVOID ApcContext, struct IO_STATUS_BLOCK* IoStatusBlock, ULONG IoControlCode, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength);
DWORD(NTAPI* NtCreateFile)(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, struct OBJECT_ATTRIBUTES* ObjectAttributes, struct IO_STATUS_BLOCK* IoStatusBlock, LARGE_INTEGER* AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength);
 
DWORD NTSockets_CreateTcpSocket(struct NTSockets_SocketDataStruct* pSocketData,int bTcp)
{
    struct IO_STATUS_BLOCK IoStatusBlock;
    HANDLE hEvent = NULL;
    HANDLE hSocket = NULL;
    struct OBJECT_ATTRIBUTES ObjectAttributes;
    struct NTSockets_SocketDataStruct SocketData;
    struct UNICODE_STRING ObjectFilePath;
    DWORD dwStatus = 0;
 
        /* tcp extended attr
        0x0000003395EFF130  00 00 00 00 00 0f 1e 00 41 66 64 4f 70 65 6e 50  ........AfdOpenP
        0x0000003395EFF140  61 63 6b 65 74 58 58 00 00 00 00 00 00 00 00 00  acketXX.........
        0x0000003395EFF150  02 00 00 00 01 00 00 00 06 00 00 00 00 00 00 00  ................
        0x0000003395EFF160  08 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        */
 
    /*  udp
        0x000000506EF3F040  00 00 00 00 00 0f 1e 00 41 66 64 4f 70 65 6e 50  ........AfdOpenP
        0x000000506EF3F050  61 63 6b 65 74 58 58 00 11 00 00 00 00 00 00 00  acketXX.........
        0x000000506EF3F060  02 00 00 00 02 00 00 00 11 00 00 00 00 00 00 00  ................
        0x000000506EF3F070  08 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
    */
 
 
    BYTE bEaUdp[] =
    {
        0x00,0x00,0x00,0x00,0x00,0x0f,0x1e,0x00,0x41,0x66,0x64,0x4f,0x70,0x65,0x6e,0x50,
        0x61,0x63,0x6b,0x65,0x74,0x58,0x58,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x08,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    };
 
 
    BYTE bExtendedAttributes[] =
    {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1E, 0x00, 0x41, 0x66, 0x64, 0x4F, 0x70, 0x65, 0x6E, 0x50,
        0x61, 0x63, 0x6B, 0x65, 0x74, 0x58, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x60, 0xEF, 0x3D, 0x47, 0xFE
    };
    printf("[*] NTSockets_CreateTcpSocket:: is %s !\n",bTcp ? "TCP" : "UDP");
    struct FILE_FULL_EA_INFORMATION* ffe;
    ffe = (struct FILE_FULL_EA_INFORMATION*)bTcp ? bExtendedAttributes : bEaUdp;
 
    // create status event
    hEvent = CreateEvent(NULL, 0, 0, NULL);
    if (hEvent == NULL)
    {
        // error
        return 1;
    }
 
    // set afd endpoint path
    memset((void*)&ObjectFilePath, 0, sizeof(ObjectFilePath));
    ObjectFilePath.Buffer = L"\\Device\\Afd\\Endpoint";
    ObjectFilePath.Length = wcslen(ObjectFilePath.Buffer) * sizeof(wchar_t);
    ObjectFilePath.MaximumLength = ObjectFilePath.Length;
 
    // initialise object attributes
    memset((void*)&ObjectAttributes, 0, sizeof(ObjectAttributes));
    ObjectAttributes.Length = sizeof(ObjectAttributes);
    ObjectAttributes.ObjectName = &ObjectFilePath;
    ObjectAttributes.Attributes = 0x40;
 
    // create socket handle
    IoStatusBlock.Status = 0;
    IoStatusBlock.Information = NULL;
    dwStatus = NtCreateFile(&hSocket, 0xC0140000, &ObjectAttributes, &IoStatusBlock, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 1, 0, ffe, sizeof(bExtendedAttributes));
    if (dwStatus != 0)
    {
        // error
        CloseHandle(hEvent);
 
        return 1;
    }
 
    // initialise SocketData object
    memset((void*)&SocketData, 0, sizeof(SocketData));
    SocketData.hSocket = hSocket;
    SocketData.hStatusEvent = hEvent;
 
    // store socket data
    memcpy((void*)pSocketData, (void*)&SocketData, sizeof(SocketData));
 
    return 0;
}
 
DWORD NTSockets_SocketDriverMsg(struct NTSockets_SocketDataStruct* pSocketData, DWORD dwIoControlCode, BYTE* pData, DWORD dwLength, DWORD* pdwOutputInformation)
{
    struct IO_STATUS_BLOCK IoStatusBlock;
    DWORD dwStatus = 0;
    BYTE bOutputBlock[0x10];
 
    // reset status event
    ResetEvent(pSocketData->hStatusEvent);
 
    // send device control request
    IoStatusBlock.Status = 0;
    IoStatusBlock.Information = NULL;
    dwStatus = NtDeviceIoControlFile(pSocketData->hSocket, pSocketData->hStatusEvent, NULL, NULL, &IoStatusBlock, dwIoControlCode, (void*)pData, dwLength, bOutputBlock, sizeof(bOutputBlock));
    if (dwStatus == STATUS_PENDING)
    {
        // response pending - wait for event
        if (WaitForSingleObject(pSocketData->hStatusEvent, -1) != WAIT_OBJECT_0)
        {
            // error
            return 1;
        }
 
        // complete - get final status code
        dwStatus = IoStatusBlock.Status;
    }
 
    // check for errors
    if (dwStatus != 0)
    {
        // error
        return 1;
    }
 
    if (pdwOutputInformation != NULL)
    {
        // store output info
        *pdwOutputInformation = (DWORD)IoStatusBlock.Information;
    }
 
    return 0;
}
 
DWORD NTSockets_ConvertIP(char* pIP, DWORD* pdwAddr)
{
    char szCurrOctet[8];
    DWORD dwCurrOctetIndex = 0;
    DWORD dwCompletedOctetCount = 0;
    char* pCurrByte = NULL;
    DWORD dwEndOfOctet = 0;
    DWORD dwEndOfString = 0;
    DWORD dwOctet = 0;
    BYTE bOctets[4];
    DWORD dwAddr = 0;
 
    // read IP string
    memset(szCurrOctet, 0, sizeof(szCurrOctet));
    dwCurrOctetIndex = 0;
    pCurrByte = pIP;
    for (;;)
    {
        // process current character
        dwEndOfOctet = 0;
        if (*pCurrByte == '\0')
        {
            // end of string
            dwEndOfOctet = 1;
            dwEndOfString = 1;
        }
        else if (*pCurrByte == '.')
        {
            // end of octet
            dwEndOfOctet = 1;
        }
        else
        {
            // ensure this character is a number
            if (*pCurrByte >= '0' && *pCurrByte <= '9')
            {
                if (dwCurrOctetIndex > 2)
                {
                    // invalid ip
                    return 1;
                }
 
                // store current character
                szCurrOctet[dwCurrOctetIndex] = *pCurrByte;
                dwCurrOctetIndex++;
            }
            else
            {
                // invalid ip
                return 1;
            }
        }
 
        // check if the current octet is complete
        if (dwEndOfOctet != 0)
        {
            if (dwCurrOctetIndex == 0)
            {
                // invalid ip
                return 1;
            }
 
            // convert octet string to integer
            dwOctet = atoi(szCurrOctet);
            if (dwOctet > 255)
            {
                // invalid ip
                return 1;
            }
 
            // already read 4 octets
            if (dwCompletedOctetCount >= 4)
            {
                // invalid ip
                return 1;
            }
 
            // store current octet
            bOctets[dwCompletedOctetCount] = (BYTE)dwOctet;
 
            // current octet complete
            dwCompletedOctetCount++;
 
            if (dwEndOfString != 0)
            {
                // end of string
                break;
            }
 
            // reset szCurrOctet string
            memset(szCurrOctet, 0, sizeof(szCurrOctet));
            dwCurrOctetIndex = 0;
        }
 
        // move to the next character
        pCurrByte++;
    }
 
    // ensure 4 octets were found
    if (dwCompletedOctetCount != 4)
    {
        // invalid string
        return 1;
    }
 
    // store octets in dword value
    memcpy((void*)&dwAddr, bOctets, 4);
 
    // store value
    *pdwAddr = dwAddr;
 
    return 0;
}
 
WORD NTSockets_Swap16BitByteOrder(WORD wValue)
{
    WORD wNewValue = 0;
 
    // swap byte order - this assumes we are running on an x86-based chip
    //*(BYTE*)((DWORD)&wNewValue + 0) = *(BYTE*)((DWORD)&wValue + 1);
    //*(BYTE*)((DWORD)&wNewValue + 1) = *(BYTE*)((DWORD)&wValue + 0);
    *(((BYTE*)&wNewValue) + 0) = *(((BYTE*)&wValue) + 1);
    *(((BYTE*)&wNewValue) + 1) = *(((BYTE*)&wValue) + 0);
 
 
    return wNewValue;
}
 
DWORD NTSockets_Connect(struct NTSockets_SocketDataStruct* pSocketData, char* pIP, WORD wPort)
{
    struct NTSockets_BindDataStruct NTSockets_BindData;
    struct NTSockets_ConnectDataStruct NTSockets_ConnectData;
    WORD wConnectPort = 0;
    DWORD dwConnectAddr = 0;
 
    // bind to local port
    memset((void*)&NTSockets_BindData, 0, sizeof(NTSockets_BindData));
    NTSockets_BindData.dwUnknown1 = 2;
    NTSockets_BindData.SockAddr.sin_family = AF_INET;
    NTSockets_BindData.SockAddr.sin_addr.s_addr = INADDR_ANY;
    NTSockets_BindData.SockAddr.sin_port = 0;
    if (NTSockets_SocketDriverMsg(pSocketData, 0x00012003, (BYTE*)&NTSockets_BindData, sizeof(NTSockets_BindData), NULL) != 0)
    {
        // error
        return 1;
    }
 
    // read connection ip
    if (NTSockets_ConvertIP(pIP, &dwConnectAddr) != 0)
    {
        // error
        return 1;
    }
 
    // use network byte order for connection port
 
 
//    wConnectPort = htons(wPort);
    wConnectPort = NTSockets_Swap16BitByteOrder(wPort);
 
    // connect to remote port
    memset((void*)&NTSockets_ConnectData, 0, sizeof(NTSockets_ConnectData));
    NTSockets_ConnectData.dwUnknown1 = 0;
    NTSockets_ConnectData.dwUnknown2 = 0;
    NTSockets_ConnectData.dwUnknown3 = 0;
    NTSockets_ConnectData.SockAddr.sin_family = AF_INET;
    NTSockets_ConnectData.SockAddr.sin_addr.s_addr = dwConnectAddr;
    NTSockets_ConnectData.SockAddr.sin_port = wConnectPort;
    ULONG sz = sizeof(NTSockets_ConnectData);
    if (NTSockets_SocketDriverMsg(pSocketData, 0x00012007, (BYTE*)&NTSockets_ConnectData, sz, NULL) != 0)
    {
        // error
        return 1;
    }
 
    return 0;
}
 
DWORD NTSockets_Send(struct NTSockets_SocketDataStruct* pSocketData, BYTE* pData, DWORD dwLength)
{
    struct NTSockets_SendRecvDataStruct NTSockets_SendRecvData;
    struct NTSockets_DataBufferStruct NTSockets_DataBuffer;
    DWORD dwBytesSent = 0;
    BYTE* pCurrSendPtr = NULL;
    DWORD dwBytesRemaining = 0;
 
    // set initial values
    pCurrSendPtr = pData;
    dwBytesRemaining = dwLength;
 
    // send data
    for (;;)
    {
        if (dwBytesRemaining == 0)
        {
            // finished
            break;
        }
 
        // set data buffer values
        memset((void*)&NTSockets_DataBuffer, 0, sizeof(NTSockets_DataBuffer));
        NTSockets_DataBuffer.dwDataLength = dwBytesRemaining;
        NTSockets_DataBuffer.pData = pCurrSendPtr;
 
        // send current block
        memset((void*)&NTSockets_SendRecvData, 0, sizeof(NTSockets_SendRecvData));
        NTSockets_SendRecvData.pBufferList = &NTSockets_DataBuffer;
        NTSockets_SendRecvData.dwBufferCount = 1;
        NTSockets_SendRecvData.dwUnknown1 = 0;
        NTSockets_SendRecvData.dwUnknown2 = 0;
        if (NTSockets_SocketDriverMsg(pSocketData, 0x0001201F, (BYTE*)&NTSockets_SendRecvData, sizeof(NTSockets_SendRecvData), &dwBytesSent) != 0)
        {
            // error
            return 1;
        }
 
        if (dwBytesSent == 0)
        {
            // socket disconnected
            return 1;
        }
 
        // update values
        pCurrSendPtr += dwBytesSent;
        dwBytesRemaining -= dwBytesSent;
    }
 
    return 0;
}
 
int NTSockets_Recv(struct NTSockets_SocketDataStruct* pSocketData, BYTE* pData, DWORD dwLength)
{
    struct NTSockets_SendRecvDataStruct NTSockets_SendRecvData;
    struct NTSockets_DataBufferStruct NTSockets_DataBuffer;
 
    DWORD dwBytesReceived = 0;
 
 
 
 
    // set data buffer values
    memset((void*)&NTSockets_DataBuffer, 0, sizeof(NTSockets_DataBuffer));
    NTSockets_DataBuffer.dwDataLength = dwLength;
    NTSockets_DataBuffer.pData = pData;
 
    // recv current block
    memset((void*)&NTSockets_SendRecvData, 0, sizeof(NTSockets_SendRecvData));
    NTSockets_SendRecvData.pBufferList = &NTSockets_DataBuffer;
    NTSockets_SendRecvData.dwBufferCount = 1;
    NTSockets_SendRecvData.dwUnknown1 = 0;
    NTSockets_SendRecvData.dwUnknown2 = 0x20;
    if (NTSockets_SocketDriverMsg(pSocketData, 0x00012017, (BYTE*)&NTSockets_SendRecvData, sizeof(NTSockets_SendRecvData), &dwBytesReceived) != 0)
    {
        // error
        return -1;
    }
 
 
 
    return dwBytesReceived;
}
 
DWORD NTSockets_CloseSocket(struct NTSockets_SocketDataStruct* pSocketData)
{
    // close handles
    CloseHandle(pSocketData->hSocket);
    CloseHandle(pSocketData->hStatusEvent);
 
    return 0;
}
 
DWORD DNSClient_Query(char* pDNSClient_IP, char* pTargetHost, char* pOutput, DWORD dwOutputMaxLength)
{
    struct NTSockets_SocketDataStruct SocketData;
    struct DNSClient_HeaderStruct DNSClient_RequestHeader;
    struct DNSClient_RequestQueryDetailsStruct DNSClient_RequestQueryDetails;
    struct DNSClient_HeaderStruct* pDNSClient_ResponseHeader = NULL;
    struct DNSClient_ResponseAnswerHeaderStruct* pDNSClient_ResponseAnswerHeader = NULL;
    DWORD dwIpAddrIndex = 0;
    DWORD dwFoundRecord = 0;
    DWORD dwCurrAnswerEntryStartIndex = 0;
    DWORD dwHostLength = 0;
    DWORD dwCurrLabelLength = 0;
    WORD wRequestLength = 0;
    WORD wResponseLength = 0;
    WORD wBlockLength = 0;
    WORD wAnswerCount = 0;
    BYTE bIP[4];
    BYTE bResponseBuffer[4096];
    char szConvertedHost[1024];
    char* pCurrDot = NULL;
    char szIP[32];
 
    // convert target host name to dns format
    memset(szConvertedHost, 0, sizeof(szConvertedHost));
    _snprintf_s(szConvertedHost, sizeof(szConvertedHost) - 1, -1, ".%s", pTargetHost);
    dwHostLength = strlen(szConvertedHost) + 1;
    for (DWORD i = 0; i < dwHostLength; i++)
    {
        // process domain labels
        if (szConvertedHost[i] == '.' || szConvertedHost[i] == '\0')
        {
            // check if a previous separator exists
            if (pCurrDot != NULL)
            {
                // calculate current label length
                dwCurrLabelLength = (DWORD)(&szConvertedHost[i] - pCurrDot);
                dwCurrLabelLength--;
                if (dwCurrLabelLength == 0 || dwCurrLabelLength >= 64)
                {
                    return 1;
                }
 
                // insert label length
                *pCurrDot = (char)dwCurrLabelLength;
            }
 
            // store current dot position
            pCurrDot = &szConvertedHost[i];
        }
    }
 
    // create socket handle
    if (NTSockets_CreateTcpSocket(&SocketData,1) != 0)
    {
        // error
        return 1;
    }
 
    // connect to DNS server
    if (NTSockets_Connect(&SocketData, pDNSClient_IP, 53) != 0)
    {
        // error
        NTSockets_CloseSocket(&SocketData);
 
        return 1;
    }
 
    // calculate request length
    wRequestLength = sizeof(struct DNSClient_HeaderStruct) + dwHostLength + sizeof(DNSClient_RequestQueryDetails);
    wBlockLength = NTSockets_Swap16BitByteOrder(wRequestLength);
 
    // set request header details
    memset((void*)&DNSClient_RequestHeader, 0, sizeof(DNSClient_RequestHeader));
    DNSClient_RequestHeader.wTransID = NTSockets_Swap16BitByteOrder(1);
    DNSClient_RequestHeader.wFlags = NTSockets_Swap16BitByteOrder(0x100);
    DNSClient_RequestHeader.wQuestionCount = NTSockets_Swap16BitByteOrder(1);
 
    // type A dns request
    memset((void*)&DNSClient_RequestQueryDetails, 0, sizeof(DNSClient_RequestQueryDetails));
    DNSClient_RequestQueryDetails.wType = NTSockets_Swap16BitByteOrder(1);
    DNSClient_RequestQueryDetails.wClass = NTSockets_Swap16BitByteOrder(1);
 
    // send request length
    if (NTSockets_Send(&SocketData, (BYTE*)&wBlockLength, sizeof(WORD)) != 0)
    {
        // error
        NTSockets_CloseSocket(&SocketData);
 
        return 1;
    }
 
    // send request header
    if (NTSockets_Send(&SocketData, (BYTE*)&DNSClient_RequestHeader, sizeof(DNSClient_RequestHeader)) != 0)
    {
        // error
        NTSockets_CloseSocket(&SocketData);
 
        return 1;
    }
 
    // send host name
    if (NTSockets_Send(&SocketData, (BYTE*)szConvertedHost, dwHostLength) != 0)
    {
        // error
        NTSockets_CloseSocket(&SocketData);
 
        return 1;
    }
 
    // send host query details
    if (NTSockets_Send(&SocketData, (BYTE*)&DNSClient_RequestQueryDetails, sizeof(DNSClient_RequestQueryDetails)) != 0)
    {
        // error
        NTSockets_CloseSocket(&SocketData);
 
        return 1;
    }
 
    // receive response length
    if (NTSockets_Recv(&SocketData, (BYTE*)&wBlockLength, sizeof(WORD)) != 0)
    {
        // error
        NTSockets_CloseSocket(&SocketData);
 
        return 1;
    }
 
    // swap byte order
    wResponseLength = NTSockets_Swap16BitByteOrder(wBlockLength);
 
    // validate response length
    if (wResponseLength < sizeof(struct DNSClient_HeaderStruct) || wResponseLength > sizeof(bResponseBuffer))
    {
        // error
        NTSockets_CloseSocket(&SocketData);
 
        return 1;
    }
 
    // receive response data
    memset((void*)bResponseBuffer, 0, sizeof(bResponseBuffer));
    if (NTSockets_Recv(&SocketData, bResponseBuffer, wResponseLength) != 0)
    {
        // error
        NTSockets_CloseSocket(&SocketData);
 
        return 1;
    }
 
    // set response header ptr
    pDNSClient_ResponseHeader = (struct DNSClient_HeaderStruct*)bResponseBuffer;
 
    // check flags (expect response, no error)
    if (pDNSClient_ResponseHeader->wFlags != NTSockets_Swap16BitByteOrder(0x8180))
    {
        // error
        NTSockets_CloseSocket(&SocketData);
 
        return 1;
    }
 
    // validate question count
    if (pDNSClient_ResponseHeader->wQuestionCount != NTSockets_Swap16BitByteOrder(1))
    {
        // error
        NTSockets_CloseSocket(&SocketData);
 
        return 1;
    }
 
    // get response answer count
    wAnswerCount = NTSockets_Swap16BitByteOrder(pDNSClient_ResponseHeader->wAnswerRecordCount);
 
    // read DNS response answers
    dwCurrAnswerEntryStartIndex = wRequestLength;
    for (DWORD i = 0; i < (DWORD)wAnswerCount; i++)
    {
        // validate start index
        if ((dwCurrAnswerEntryStartIndex + sizeof(struct DNSClient_ResponseAnswerHeaderStruct)) > (DWORD)wResponseLength)
        {
            // error
            NTSockets_CloseSocket(&SocketData);
 
            return 1;
        }
 
        // get current response answer header ptr
        pDNSClient_ResponseAnswerHeader = (struct DNSClient_ResponseAnswerHeaderStruct*)&bResponseBuffer[dwCurrAnswerEntryStartIndex];
 
        // check if this is a type A record
        if (pDNSClient_ResponseAnswerHeader->wType == NTSockets_Swap16BitByteOrder(1) && pDNSClient_ResponseAnswerHeader->wClass == NTSockets_Swap16BitByteOrder(1))
        {
            // ensure value length is 4 (ipv4 addr)
            if (pDNSClient_ResponseAnswerHeader->wLength != NTSockets_Swap16BitByteOrder(4))
            {
                // error
                NTSockets_CloseSocket(&SocketData);
 
                return 1;
            }
 
            // validate ip addr index
            dwIpAddrIndex = dwCurrAnswerEntryStartIndex + sizeof(struct DNSClient_ResponseAnswerHeaderStruct);
            if ((dwIpAddrIndex + 4) > (DWORD)wResponseLength)
            {
                // error
                NTSockets_CloseSocket(&SocketData);
 
                return 1;
            }
 
            // store IP addr
            memcpy((void*)bIP, (void*)&bResponseBuffer[dwIpAddrIndex], 4);
 
            // set flag
            dwFoundRecord = 1;
 
            break;
        }
        else
        {
            // check next entry
            dwCurrAnswerEntryStartIndex += sizeof(struct DNSClient_ResponseAnswerHeaderStruct);
            dwCurrAnswerEntryStartIndex += NTSockets_Swap16BitByteOrder(pDNSClient_ResponseAnswerHeader->wLength);
        }
    }
 
    // close socket
    NTSockets_CloseSocket(&SocketData);
 
    // ensure a valid record was found
    if (dwFoundRecord == 0)
    {
        return 1;
    }
 
    // generate IP string
    memset(szIP, 0, sizeof(szIP));
    _snprintf_s(szIP, sizeof(szIP) - 1, -1, "%u.%u.%u.%u", bIP[0], bIP[1], bIP[2], bIP[3]);
 
    // store value
    strncpy_s(pOutput,32, szIP, dwOutputMaxLength);
 
    return 0;
}
 
 
int main(int argc, char* argv[])
{
    char* szIP = "127.0.0.1";
    unsigned int dwPort = 80;
    char buffer[1024] = "hello pediy.com !";
    struct NTSockets_SocketDataStruct SocketData;
 
    // get NtDeviceIoControlFile function ptr
    NtDeviceIoControlFile = (unsigned long(__stdcall*)(void*, void*, void*, void*, struct IO_STATUS_BLOCK*, unsigned long, void*, unsigned long, void*, unsigned long))GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtDeviceIoControlFile");
    if (NtDeviceIoControlFile == NULL)
    {
        return 1;
    }
 
    // get NtCreateFile function ptr
    NtCreateFile = (unsigned long(__stdcall*)(void**, unsigned long, struct OBJECT_ATTRIBUTES*, struct IO_STATUS_BLOCK*, union _LARGE_INTEGER*, unsigned long, unsigned long, unsigned long, unsigned long, void*, unsigned long))GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtCreateFile");
    if (NtCreateFile == NULL)
    {
        return 1;
    }
 
    // create socket handle
    printf("create socket !\n");
    if (NTSockets_CreateTcpSocket(&SocketData,1) != 0)
    {
        // error
        printf("Error: Failed to create TCP socket\n");
 
        return 1;
    }
 
    // connect to server
    printf("connect to server !\n");
    if (NTSockets_Connect(&SocketData, szIP, (WORD)dwPort) != 0)
    {
        // error
        printf("Error: Failed to connect to server\n");
        NTSockets_CloseSocket(&SocketData);
 
        return 1;
    }
    //send
    printf("send ... !\n");
    if (NTSockets_Send(&SocketData, (BYTE*)buffer, strlen(buffer)) != 0)
    {
        // error
        printf("Error: Failed to send data to server\n");
        NTSockets_CloseSocket(&SocketData);
 
        return 1;
    }
    //recv
    printf("recv ... !\n");
    memset(buffer, 0, sizeof(buffer));
    if (NTSockets_Recv(&SocketData, (BYTE*)buffer, sizeof(buffer) ) < 0)
    {
        // error
        printf("Error: Failed to read HTTP response header\n");
        NTSockets_CloseSocket(&SocketData);
 
        return 1;
    }
 
    printf("buffer is: %s \n",buffer);
    printf("close socket !\n");
    NTSockets_CloseSocket(&SocketData);
    getchar();
    return 0;
}

vs完整工程见附件。

代码测试

NTSockets-UDP test

 

以上为UDP测试动画。


 

NTSockets-TCP test
以上为TCP测试动画。

 

#未完待续

 

随后附上TCP-Server和UDP-Server的代码实现。敬请期待。。。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2022-5-27 23:21 被zhenwo编辑 ,原因: 完善测试代码
上传的附件:
收藏
点赞10
打赏
分享
打赏 + 50.00雪花
打赏次数 1 雪花 + 50.00
 
赞赏  Editor   +50.00 2022/04/22 恭喜您获得“雪花”奖励,安全圈有你而精彩!
最新回复 (9)
雪    币: 2590
活跃值: (3677)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
syser 2022-3-23 00:33
2
0
64位错误是因为结构体各种 需要更新 自己把这遍流程重新逆下 就能解决
雪    币: 6115
活跃值: (4036)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
黑洛 1 2022-3-24 18:04
3
0
推荐一个项目:https://github.com/MiroKaku/libwsk
雪    币: 26
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
Asphyxia 2022-5-6 11:19
4
0
在执行NTSockets_CreateTcpSocket的
dwStatus = NtCreateFile(&hSocket, 0xC0140000, &ObjectAttributes, &IoStatusBlock, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 1, 0, ffe, sizeof(bExtendedAttributes));
       if (dwStatus != 0)
       {
               // error
               printf("[ - ] NtCreateFile : %d\n", dwStatus);
               CloseHandle(hEvent);

               return 1;
       }

输出[ - ] NtCreateFile : -2147483620应该怎么解决呢(x86)
雪    币: 9583
活跃值: (3427)
能力值: ( LV12,RANK:319 )
在线值:
发帖
回帖
粉丝
堂前燕 1 2022-5-10 11:10
5
0
NTSockets_Recv返回值改了,返回值判断的地方却不改0.0;
雪    币: 1537
活跃值: (2837)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
zhenwo 1 2022-5-21 20:56
6
0
堂前燕 NTSockets_Recv返回值改了,返回值判断的地方却不改0.0;
一直没应用到项目中,很多地方还没好好测试。
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
zz77 2022-5-22 10:28
7
0
在MS Win 和 ReactOS 都有源代码
分别位于win2k\private\net\sockets\winsock2\wsp\msafd\ 和 ReactOS\dll\win32\msafd\
与AFD的通讯协议、数据结构及功能函数代码都全的,建议作为参考
期待你的Server代码
雪    币: 504
活跃值: (3056)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wem 2022-5-24 18:01
8
0
cool
雪    币: 1204
活跃值: (1504)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Cohen 2022-8-31 23:42
9
0
有没有检测是否正在连接中的 select (0, udtRead_fds, udtWrite_fds, udtError_fds, 0)
雪    币: 1204
活跃值: (1504)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Cohen 2022-8-31 23:58
10
0
Recv一直在等待接收数据  如何更改成超时返回 我看代码 都是发送AFD 无从下手呀
游客
登录 | 注册 方可回帖
返回