nexmon – Rev 1

Subversion Repositories:
Rev:
/***************************************************************************
 *                                                                         *
 *          ###########   ###########   ##########    ##########           *
 *         ############  ############  ############  ############          *
 *         ##            ##            ##   ##   ##  ##        ##          *
 *         ##            ##            ##   ##   ##  ##        ##          *
 *         ###########   ####  ######  ##   ##   ##  ##    ######          *
 *          ###########  ####  #       ##   ##   ##  ##    #    #          *
 *                   ##  ##    ######  ##   ##   ##  ##    #    #          *
 *                   ##  ##    #       ##   ##   ##  ##    #    #          *
 *         ############  ##### ######  ##   ##   ##  ##### ######          *
 *         ###########    ###########  ##   ##   ##   ##########           *
 *                                                                         *
 *            S E C U R E   M O B I L E   N E T W O R K I N G              *
 *                                                                         *
 * This file is part of NexMon.                                            *
 *                                                                         *
 * Based on:                                                               *
 *                                                                         *
 * This code is based on the ldpreloadhook example by Pau Oliva Fora       *
 * <pofłeslack.org> and the idea of hooking ioctls to fake a monitor mode  *
 * interface, which was presented by Omri Ildis, Yuval Ofir and Ruby       *
 * Feinstein at recon2013.                                                 *
 *                                                                         *
 * Copyright (c) 2016 NexMon Team                                          *
 *                                                                         *
 * NexMon is free software: you can redistribute it and/or modify          *
 * it under the terms of the GNU General Public License as published by    *
 * the Free Software Foundation, either version 3 of the License, or       *
 * (at your option) any later version.                                     *
 *                                                                         *
 * NexMon is distributed in the hope that it will be useful,               *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
 * GNU General Public License for more details.                            *
 *                                                                         *
 * You should have received a copy of the GNU General Public License       *
 * along with NexMon. If not, see <http://www.gnu.org/licenses/>.          *
 *                                                                         *
 **************************************************************************/

#include <stdarg.h>
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/socket.h>
#include <linux/if_arp.h>
#include <linux/sockios.h>
#include <linux/wireless.h>
#include <monitormode.h>
#include <errno.h>
#include <net/if.h>
#include <nexioctls.h>

#define WLC_GET_MONITOR                 107
#define WLC_SET_MONITOR                 108

struct nexio {
    struct ifreq *ifr;
    int sock_rx_ioctl;
    int sock_rx_frame;
    int sock_tx;
};

extern int nex_ioctl(struct nexio *nexio, int cmd, void *buf, int len, bool set);
extern struct nexio *nex_init_ioctl(const char *ifname);

#ifndef RTLD_NEXT
#define RTLD_NEXT ((void *) -1l)
#endif

#define REAL_LIBC RTLD_NEXT

typedef int request_t;

typedef void (*sighandler_t)(int);

static struct nexio *nexio = NULL;

static const char *ifname = "wlan0";

static int (*func_sendto) (int, const void *, size_t, int, const struct sockaddr *, socklen_t) = NULL;
static int (*func_ioctl) (int, request_t, void *) = NULL;
static int (*func_socket) (int, int, int) = NULL;
static int (*func_bind) (int, const struct sockaddr *, int) = NULL;
static int (*func_write) (int, const void *, size_t) = NULL;

static void _libmexmon_init() __attribute__ ((constructor));
static void _libmexmon_init() {
    nexio = nex_init_ioctl(ifname);

    if (! func_ioctl)
        func_ioctl = (int (*) (int, request_t, void *)) dlsym (REAL_LIBC, "ioctl");

    if (! func_socket)
        func_socket = (int (*) (int, int, int)) dlsym (REAL_LIBC, "socket");

    if (! func_bind)
        func_bind = (int (*) (int, const struct sockaddr *, int)) dlsym (REAL_LIBC, "bind");

    if (! func_write)
        func_write = (int (*) (int, const void *, size_t)) dlsym (REAL_LIBC, "write");

    if (! func_sendto)
        func_sendto = (int (*) (int, const void *, size_t, int, const struct sockaddr *, socklen_t)) dlsym (REAL_LIBC, "sendto");
}

int
ioctl(int fd, request_t request, ...)
{
    va_list args;
    void *argp;
    int ret;
    
    va_start (args, request);
    argp = va_arg (args, void *);
    va_end (args);

    ret = func_ioctl(fd, request, argp);
    //if (ret < 0) {
    //    printf("LIBNEXMON: original response: %d, request: 0x%x\n", ret, request);
    //}

    switch (request) {
        case SIOCGIFHWADDR:
            {
                int buf;
                struct ifreq* p_ifr = (struct ifreq *) argp;
                if (!strncmp(p_ifr->ifr_ifrn.ifrn_name, ifname, strlen(ifname))) {
                    nex_ioctl(nexio, WLC_GET_MONITOR, &buf, 4, false);
                    
                    if (buf & MONITOR_IEEE80211) p_ifr->ifr_hwaddr.sa_family = ARPHRD_IEEE80211;
                    else if (buf & MONITOR_RADIOTAP) p_ifr->ifr_hwaddr.sa_family = ARPHRD_IEEE80211_RADIOTAP;
                    else if (buf & MONITOR_DISABLED || buf & MONITOR_LOG_ONLY || buf & MONITOR_DROP_FRM || buf & MONITOR_IPV4_UDP)
                        p_ifr->ifr_hwaddr.sa_family = ARPHRD_ETHER;

                    ret = 0;
                }
            }
            break;

        case SIOCGIWMODE:
            {
                int buf;
                struct iwreq* p_wrq = (struct iwreq*) argp;
                
                if (!strncmp(p_wrq->ifr_ifrn.ifrn_name, ifname, strlen(ifname))) {
                    nex_ioctl(nexio, WLC_GET_MONITOR, &buf, 4, false);

                    if (buf & MONITOR_RADIOTAP || buf & MONITOR_IEEE80211 || buf & MONITOR_LOG_ONLY || buf & MONITOR_DROP_FRM || buf & MONITOR_IPV4_UDP) {
                        p_wrq->u.mode = IW_MODE_MONITOR;
                    }

                    ret = 0;
                }
            }
            break;

        case SIOCSIWMODE:
            {
                int buf;
                struct iwreq* p_wrq = (struct iwreq*) argp;

                if (!strncmp(p_wrq->ifr_ifrn.ifrn_name, ifname, strlen(ifname))) {
                    if (p_wrq->u.mode == IW_MODE_MONITOR) {
                        buf = MONITOR_RADIOTAP;
                    } else {
                        buf = MONITOR_DISABLED;
                    }

                    ret = nex_ioctl(nexio, WLC_SET_MONITOR, &buf, 4, true);
                }
            }
            break;

        case SIOCSIWFREQ: // set channel/frequency (Hz)
            {
                //if (ret < 0)
                    //printf("LIBNEXMON: SIOCSIWFREQ not implemented\n");
            }
            break;

        case SIOCGIWFREQ: // get channel/frequency (Hz)
            {
                //if (ret < 0)
                    //printf("LIBNEXMON: SIOCGIWFREQ not implemented\n");
            }
            break;
    }
    return ret;
}

void
hexdump(const char *desc, const void *addr, int len)
{
    int i;
    unsigned char buff[17];
    unsigned char *pc = (unsigned char*)addr;

    // Output description if given.
    if (desc != 0)
        printf ("%s:\n", desc);

    // Process every byte in the data.
    for (i = 0; i < len; i++) {
        // Multiple of 16 means new line (with line offset).

        if ((i % 16) == 0) {
            // Just don't print ASCII for the zeroth line.
            if (i != 0)
                printf ("  %s\n", buff);

            // Output the offset.
            printf ("  %04x ", i);
        }

        // Now the hex code for the specific character.
        printf (" %02x", pc[i]);

        // And store a printable ASCII character for later.
        if ((pc[i] < 0x20) || (pc[i] > 0x7e))
            buff[i % 16] = '.';
        else
            buff[i % 16] = pc[i];
        buff[(i % 16) + 1] = '\0';
    }

    // Pad out last line if not exactly 16 characters.
    while ((i % 16) != 0) {
        printf ("   ");
        i++;
    }

    // And print the final ASCII bit.
    printf ("  %s\n", buff);
}

static char sock_types[][16] = { 
    "SOCK_STREAM", 
    "SOCK_DGRAM", 
    "SOCK_RAW", 
    "SOCK_RDM", 
    "SOCK_SEQPACKET",
};

static char domain_types[][16] = { 
    "AF_UNSPEC", 
    "AF_UNIX", 
    "AF_INET", 
    "AF_AX25", 
    "AF_IPX", 
    "AF_APPLETALK", 
    "AF_NETROM", 
    "AF_BRIDGE",
    "AF_ATMPVC",
    "AF_X25",
    "AF_INET6",
    "AF_ROSE",
    "AF_DECnet",
    "AF_NETBEUI",
    "AF_SECURITY",
    "AF_KEY",
    "AF_NETLINK",
    "AF_PACKET",
    "AF_ASH",
    "AF_ECONET",
    "AF_ATMSVC",
    "AF_RDS",
    "AF_SNA",
    "AF_IRDA",
    "AF_PPPOX",
    "AF_WANPIPE",
    "AF_LLC",
    "AF_IB",
    "AF_MPLS",
    "AF_CAN",
    "AF_TIPC",
    "AF_BLUETOOTH",
    "AF_IUCV",
    "AF_RXRPC",
    "AF_ISDN",
    "AF_PHONET",
    "AF_IEEE802154",
    "AF_CAIF",
    "AF_ALG",
    "AF_NFC",
    "AF_VSOCK",
    "AF_KCM",
    "AF_QIPCRTR",
    "AF_SMC"
};

int socket_to_type[100] = { 0 };
char bound_to_correct_if[100] = { 0 };

int
socket(int domain, int type, int protocol)
{
    int ret;

    ret = func_socket(domain, type, protocol);

    // save the socket type
    if (ret < sizeof(socket_to_type)/sizeof(socket_to_type[0]))
        socket_to_type[ret] = type;

    //if ((type - 1 < sizeof(sock_types)/sizeof(sock_types[0])) && (domain - 1 < sizeof(domain_types)/sizeof(domain_types[0])))
    //    printf("LIBNEXMON: %d = %s(%s(%d), %s(%d), %d)\n", ret, __FUNCTION__, domain_types[domain], domain, sock_types[type - 1], type, protocol);

    return ret;
}

int
bind(int sockfd, const struct sockaddr *addr, int addrlen)
{
    int ret;
    struct sockaddr_ll *sll = (struct sockaddr_ll *) addr;

    ret = func_bind(sockfd, addr, addrlen);

    char sll_ifname[IF_NAMESIZE] = { 0 };
    if_indextoname(sll->sll_ifindex, sll_ifname);

    if ((sockfd < sizeof(bound_to_correct_if)/sizeof(bound_to_correct_if[0])) && !strncmp(ifname, sll_ifname, sizeof(ifname)))
        bound_to_correct_if[sockfd] = 1;

    //printf("LIBNEXMON: %d = %s(%d, 0x%p, %d) sll_ifindex=%d ifname=%s\n", ret, __FUNCTION__, sockfd, addr, addrlen, sll->sll_ifindex, sll_ifname);

    return ret;    
}

struct inject_frame {
    unsigned short len;
    unsigned char pad;
    unsigned char type;
    char data[];
};

ssize_t
write(int fd, const void *buf, size_t count)
{
    ssize_t ret;

    // check if the user wants to write on a raw socket
    if ((fd > 2) && (fd < sizeof(socket_to_type)/sizeof(socket_to_type[0])) && (socket_to_type[fd] == SOCK_RAW) && (bound_to_correct_if[fd] == 1)) {
        struct inject_frame *buf_dup = (struct inject_frame *) malloc(count + sizeof(struct inject_frame));

        buf_dup->len = count + sizeof(struct inject_frame);
        buf_dup->pad = 0;
        buf_dup->type = 1;
        memcpy(buf_dup->data, buf, count);

        nex_ioctl(nexio, NEX_INJECT_FRAME, buf_dup, count + sizeof(struct inject_frame), true);

        free(buf_dup);

        ret = count;
    } else {
        // otherwise write the regular frame to the socket
        ret = func_write(fd, buf, count);
    }

    return ret;
}

ssize_t
sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)
{
    ssize_t ret;

    // check if the user wants to write on a raw socket
    if ((sockfd > 2) && (sockfd < sizeof(socket_to_type)/sizeof(socket_to_type[0])) && (socket_to_type[sockfd] == SOCK_RAW) && (bound_to_correct_if[sockfd] == 1)) {
        struct inject_frame *buf_dup = (struct inject_frame *) malloc(len + sizeof(struct inject_frame));

        buf_dup->len = len + sizeof(struct inject_frame);
        buf_dup->pad = 0;
        buf_dup->type = 1;
        memcpy(buf_dup->data, buf, len);

        nex_ioctl(nexio, NEX_INJECT_FRAME, buf_dup, len + sizeof(struct inject_frame), true);

        free(buf_dup);

        ret = len;
    } else {
        // otherwise write the regular frame to the socket
        ret = func_sendto(sockfd, buf, len, flags, dest_addr, addrlen);
    }

    return ret;
}