/// <summary>
/// Trigger the Type Confusion Vulnerability
/// </summary>
/// <param name="pTypeConfusionUserObject">The pointer to TYPE_CONFUSION_USER_OBJECT object</param>
/// <returns>NTSTATUS</returns>
NTSTATUS TriggerTypeConfusion(IN PTYPE_CONFUSION_USER_OBJECT pTypeConfusionUserObject) {
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    PTYPE_CONFUSION_KERNEL_OBJECT pTypeConfusionKernelObject = NULL;

    PAGED_CODE();

    __try {
        // Verify if the buffer resides in User Mode
        ProbeForRead(pTypeConfusionUserObject,
                     sizeof(TYPE_CONFUSION_USER_OBJECT),
                     (ULONG)__alignof(TYPE_CONFUSION_USER_OBJECT));

        // Allocate Pool Memory
        pTypeConfusionKernelObject = (PTYPE_CONFUSION_KERNEL_OBJECT)
                                      ExAllocatePoolWithTag(NonPagedPool,
                                                            sizeof(TYPE_CONFUSION_KERNEL_OBJECT),
                                                            (ULONG)POOL_TAG);

        if (!pTypeConfusionKernelObject) {
            // Unable to allocate Pool Memory with Tag
            DbgPrint("[-] Unable To Allocate Pool Memory\n");

            status = STATUS_NO_MEMORY;
            return status;
        }
        else {
            DbgPrint("[+] Pool Address: 0x%p\n", pTypeConfusionKernelObject);
            DbgPrint("[+] Pool Type: %s\n", STRINGIFY(NonPagedPool));
            DbgPrint("[+] Pool Size: 0x%X\n", sizeof(TYPE_CONFUSION_KERNEL_OBJECT));
            DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG));
        }

        DbgPrint("[+] pTypeConfusionUserObject: 0x%p\n", pTypeConfusionUserObject);
        DbgPrint("[+] pTypeConfusionKernelObject: 0x%p\n", pTypeConfusionKernelObject);
        DbgPrint("[+] pTypeConfusionKernelObject Size: 0x%X\n", sizeof(TYPE_CONFUSION_KERNEL_OBJECT));

        pTypeConfusionKernelObject->objectID = pTypeConfusionUserObject->objectID;
        DbgPrint("[+] pTypeConfusionKernelObject->objectID: 0x%p\n", pTypeConfusionKernelObject->objectID);

        pTypeConfusionKernelObject->objectType = pTypeConfusionUserObject->objectType;
        DbgPrint("[+] pTypeConfusionKernelObject->objectType: 0x%p\n", pTypeConfusionKernelObject->objectType);

        #ifdef SECURE
            // Secure Note: This is secure because the developer is properly setting 'pCallback' 
            // member of the TYPE_CONFUSION_KERNEL_OBJECT structure before passing the pointer to 
            // itself to TypeConfusionObjectInitializer() function as parameter
            pTypeConfusionKernelObject->pCallback = &TypeConfusionObjectCallback;
            status = TypeConfusionObjectInitializer(pTypeConfusionKernelObject);
        #else
            DbgPrint("[+] Triggering Type Confusion\n");

            // Vulnerability Note: This is a vanilla Type Confusion vulnerability due to improper 
            // use of the UNION construct. The developer has not set the 'pCallback' member of the 
            // TYPE_CONFUSION_KERNEL_OBJECT structure before passing the pointer to itself to 
            // TypeConfusionObjectInitializer() function as parameter
            status = TypeConfusionObjectInitializer(pTypeConfusionKernelObject);
        #endif

        DbgPrint("[+] Freeing pTypeConfusionKernelObject Object\n");
        DbgPrint("[+] Pool Address: 0x%p\n", pTypeConfusionKernelObject);
        DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG));

        // Free the allocated Pool Memory
        ExFreePoolWithTag((PVOID)pTypeConfusionKernelObject, (ULONG)POOL_TAG);
        pTypeConfusionKernelObject = NULL;
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        status = GetExceptionCode();
        DbgPrint("[-] Exception Code: 0x%X\n", status);
    }

    return status;
}
/// <summary>
/// Trigger the Type Confusion Vulnerability
/// </summary>
/// <param name="UserTypeConfusionObject">The pointer to USER_TYPE_CONFUSION_OBJECT object</param>
/// <returns>NTSTATUS</returns>
NTSTATUS TriggerTypeConfusion(IN PUSER_TYPE_CONFUSION_OBJECT UserTypeConfusionObject) {
    NTSTATUS Status = STATUS_UNSUCCESSFUL;
    PKERNEL_TYPE_CONFUSION_OBJECT KernelTypeConfusionObject = NULL;

    PAGED_CODE();

    __try {
        // Verify if the buffer resides in user mode
        ProbeForRead(UserTypeConfusionObject,
                     sizeof(USER_TYPE_CONFUSION_OBJECT),
                     (ULONG)__alignof(USER_TYPE_CONFUSION_OBJECT));

        // Allocate Pool chunk
        KernelTypeConfusionObject = (PKERNEL_TYPE_CONFUSION_OBJECT)
                                     ExAllocatePoolWithTag(NonPagedPool,
                                                           sizeof(KERNEL_TYPE_CONFUSION_OBJECT),
                                                           (ULONG)POOL_TAG);

        if (!KernelTypeConfusionObject) {
            // Unable to allocate Pool chunk
            DbgPrint("[-] Unable to allocate Pool chunk\n");

            Status = STATUS_NO_MEMORY;
            return Status;
        }
        else {
            DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG));
            DbgPrint("[+] Pool Type: %s\n", STRINGIFY(NonPagedPool));
            DbgPrint("[+] Pool Size: 0x%X\n", sizeof(KERNEL_TYPE_CONFUSION_OBJECT));
            DbgPrint("[+] Pool Chunk: 0x%p\n", KernelTypeConfusionObject);
        }

        DbgPrint("[+] UserTypeConfusionObject: 0x%p\n", UserTypeConfusionObject);
        DbgPrint("[+] KernelTypeConfusionObject: 0x%p\n", KernelTypeConfusionObject);
        DbgPrint("[+] KernelTypeConfusionObject Size: 0x%X\n", sizeof(KERNEL_TYPE_CONFUSION_OBJECT));

        KernelTypeConfusionObject->ObjectID = UserTypeConfusionObject->ObjectID;
        KernelTypeConfusionObject->ObjectType = UserTypeConfusionObject->ObjectType;

        DbgPrint("[+] KernelTypeConfusionObject->ObjectID: 0x%p\n", KernelTypeConfusionObject->ObjectID);
        DbgPrint("[+] KernelTypeConfusionObject->ObjectType: 0x%p\n", KernelTypeConfusionObject->ObjectType);


#ifdef SECURE
        // Secure Note: This is secure because the developer is properly setting 'Callback'
        // member of the 'KERNEL_TYPE_CONFUSION_OBJECT' structure before passing the pointer
        // of 'KernelTypeConfusionObject' to 'TypeConfusionObjectInitializer()' function as
        // parameter
        KernelTypeConfusionObject->Callback = &TypeConfusionObjectCallback;
        Status = TypeConfusionObjectInitializer(KernelTypeConfusionObject);
#else
        DbgPrint("[+] Triggering Type Confusion\n");

        // Vulnerability Note: This is a vanilla Type Confusion vulnerability due to improper
        // use of the 'UNION' construct. The developer has not set the 'Callback' member of
        // the 'KERNEL_TYPE_CONFUSION_OBJECT' structure before passing the pointer of
        // 'KernelTypeConfusionObject' to 'TypeConfusionObjectInitializer()' function as
        // parameter
        Status = TypeConfusionObjectInitializer(KernelTypeConfusionObject);
#endif

        DbgPrint("[+] Freeing KernelTypeConfusionObject Object\n");
        DbgPrint("[+] Pool Tag: %s\n", STRINGIFY(POOL_TAG));
        DbgPrint("[+] Pool Chunk: 0x%p\n", KernelTypeConfusionObject);

        // Free the allocated Pool chunk
        ExFreePoolWithTag((PVOID)KernelTypeConfusionObject, (ULONG)POOL_TAG);
        KernelTypeConfusionObject = NULL;
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        Status = GetExceptionCode();
        DbgPrint("[-] Exception Code: 0x%X\n", Status);
    }

    return Status;
}