Search code examples
c++type-conversionkerneldriver

Type Cast Truncation from HANDLE to ULONG C++


I am getting the warning (treated as error):

Type Cast Pointer Truncation from HANDLE to ULONG

When I try to compile, I understand that the type has a different length as I am compiling ARM64 rather than ARM, therefore I need to change the type or static_cast it, however I receive errors such as "expected (" when changing the line to something like this:

return static_cast<ULONG>PsGetProcessId(current_process); //this gives me invalid conversion type as 
                                                          //there are no brackets around the static cast 
                                                          //because I am returning its value

I add brackets, however there is always a problem and it never seems to work, always "Expected (":

return (static_cast<ULONG>)PsGetProcessId(current_process); //this bracket error 

ORIGINAL CODE BELOW

ULONG memory::get_process_id_by_name(PEPROCESS start_process, const char* process_name)
{
    PLIST_ENTRY active_process_links;
    PEPROCESS current_process = start_process;

    do
    {
        PKPROCESS kproc = (PKPROCESS)current_process;
        PDISPATCHER_HEADER header = (PDISPATCHER_HEADER)kproc;
        LPSTR current_process_name = (LPSTR)((PUCHAR)current_process + IMAGE_FILE_NAME);

        if (header->SignalState == 0 && strcmp(current_process_name, process_name) == 0)
        {   
            return (ULONG)PsGetProcessId(current_process); //warning occurs here
        }

        active_process_links = (PLIST_ENTRY)((PUCHAR)current_process + ACTIVE_PROCESS_LINKS_FLINK);
        current_process = (PEPROCESS)(active_process_links->Flink);
        current_process = (PEPROCESS)((PUCHAR)current_process - ACTIVE_PROCESS_LINKS_FLINK);

    } while (start_process != current_process);

    return 0;
}

Solution

  • The HANDLE type is used to point to an opaque structure.

    It usually stores an index value, but in the winnt.h header file, it is defined as a pointer-length type.

    typedef void *HANDLE;
    

    So the correct approach is to treat the process id as a pointer-length type as well.

    I know you don't like HANDLE, so you can use ULONG_PTR, it has the same length as the pointer type.

    Here is the fixed code:

    ULONG_PTR memory::get_process_id_by_name(PEPROCESS start_process, const char* process_name)
    {
        PLIST_ENTRY active_process_links;
        PEPROCESS current_process = start_process;
    
        do
        {
            PKPROCESS kproc = (PKPROCESS)current_process;
            PDISPATCHER_HEADER header = (PDISPATCHER_HEADER)kproc;
            LPSTR current_process_name = (LPSTR)((PUCHAR)current_process + IMAGE_FILE_NAME);
    
            if (header->SignalState == 0 && strcmp(current_process_name, process_name) == 0)
            {
                return (ULONG_PTR)PsGetProcessId(current_process);
            }
    
            active_process_links = (PLIST_ENTRY)((PUCHAR)current_process + ACTIVE_PROCESS_LINKS_FLINK);
            current_process = (PEPROCESS)(active_process_links->Flink);
            current_process = (PEPROCESS)((PUCHAR)current_process - ACTIVE_PROCESS_LINKS_FLINK);
    
        } while (start_process != current_process);
    
        return 0;
    }
    

    If you have to use ULONG for other reasons, you can refer to @SoronelHaetir's solution.


    Example for comment:

    Before:

    void test()
    {
        ULONG value = (ULONG_PTR)0xFFFFFFFFFFFF;
        UNREFERENCED_PARAMETER(value);
    }
    
    EXTERN_C NTSTATUS DriverEntry(DRIVER_OBJECT *pDriverObject, UNICODE_STRING *pRegistryPath)
    {
        UNREFERENCED_PARAMETER(pDriverObject);
        UNREFERENCED_PARAMETER(pRegistryPath);
        test();
        return STATUS_UNSUCCESSFUL;
    }
    

    Warnings:

    error C2220: the following warning is treated as an error
    warning C4305: 'initializing': truncation from 'ULONG_PTR' to 'ULONG'
    warning C4309: 'initializing': truncation of constant value
    ========== Rebuild All: 0 succeeded, 1 failed, 0 skipped ==========
    

    After:

    #pragma warning(push)
    #pragma warning(disable: 4305)
    #pragma warning(disable: 4309)
    void test()
    {
        ULONG value = (ULONG_PTR)0xFFFFFFFFFFFF;
        UNREFERENCED_PARAMETER(value);
    }
    #pragma warning(pop)
    
    EXTERN_C NTSTATUS DriverEntry(DRIVER_OBJECT *pDriverObject, UNICODE_STRING *pRegistryPath)
    {
        UNREFERENCED_PARAMETER(pDriverObject);
        UNREFERENCED_PARAMETER(pRegistryPath);
        test();
        return STATUS_UNSUCCESSFUL;
    }
    

    No warnings:

    ========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========