c++winapidriverkernel-mode

Kernel Mode: How read a txt file line by line?


I need read each line of a txt file and pass this line as parameter to a method.

I have found this example:

LARGE_INTEGER      byteOffset;

    ntstatus = ZwCreateFile(&handle,
                            GENERIC_READ,
                            &objAttr, &ioStatusBlock,
                            NULL,
                            FILE_ATTRIBUTE_NORMAL,
                            0,
                            FILE_OPEN, 
                            FILE_SYNCHRONOUS_IO_NONALERT,
                            NULL, 0);
    if(NT_SUCCESS(ntstatus)) {
        byteOffset.LowPart = byteOffset.HighPart = 0;
        ntstatus = ZwReadFile(handle, NULL, NULL, NULL, &ioStatusBlock,
                              buffer, BUFFER_SIZE, &byteOffset, NULL);
        if(NT_SUCCESS(ntstatus)) {
            buffer[BUFFER_SIZE-1] = '\0';
            DbgPrint("%s\n", buffer);
        }
        ZwClose(handle);
    }

Reference

but this read all content of file and not line by line.

Some idea about how do this?


Solution

  • read all file to buffer or map it as section. than execute next code:

    extern "C" PCSTR __fastcall findRN(SIZE_T cb, PCSTR sz);
    
    void processLine(SIZE_T len, PCSTR line)
    {
        DbgPrint("%.*s\n", len, line);
    }
    
    NTSTATUS process(PCSTR buf, SIZE_T cb)
    {
        PCSTR end = buf + cb, line = buf;
    
        while (buf = findRN(end - line, line))
        {
            processLine(buf - line, line);
            line = buf + 2;
        }
    
        if (line != end)
        {
            processLine(end - line, line);
        }
        return 0;
    }
    

    implementation of findRN on c/c++

    PCSTR __fastcall findRN(SIZE_T cb, PCSTR sz)
    {
        if (cb < 2)
        {
            return 0;
        }
    
        cb--;
    
        do 
        {
            if (*sz++ == '\r')
            {
                if (*sz == '\n')
                {
                    return sz - 1;
                }
            }
        } while (--cb);
    
        return 0;
    }
    

    if you need/want ultra fast most effective implementation, do this in asm. for example x64:

    findRN proc
        cmp rcx,1
        ja  @@0
        xor rax,rax
        ret
    @@0:
        mov ax,0a0dh
        xchg rdi,rdx
        dec rcx
    @@1:
        repne scasb
        jne @@2
        cmp [rdi],ah
        jne @@1
    @@2:
        sete al
        dec rdi
        movzx rax,al
        neg rax
        and rax,rdi
        xchg rdi,rdx
        ret
    findRN endp
    

    on x86 code the same, only change r to e in register names

    map file:

    NTSTATUS process(POBJECT_ATTRIBUTES poa)
    {
        HANDLE hFile, hSection = 0;
        IO_STATUS_BLOCK iosb;
        NTSTATUS status = NtOpenFile(&hFile, FILE_GENERIC_READ, poa, &iosb, 
            FILE_SHARE_VALID_FLAGS, FILE_SYNCHRONOUS_IO_NONALERT);
    
        if (0 <= status)
        {
            FILE_STANDARD_INFORMATION fsi;
    
            if (0 <= (status = NtQueryInformationFile(hFile, &iosb, &fsi, sizeof(fsi), FileStandardInformation)))
            {
                if (fsi.EndOfFile.HighPart)
                {
                    status = STATUS_FILE_TOO_LARGE;
                }
                else if (!fsi.EndOfFile.LowPart)
                {
                    status = STATUS_MAPPED_FILE_SIZE_ZERO;
                }
                else
                {
                    status = NtCreateSection(&hSection, SECTION_MAP_READ, 0, 0, PAGE_READONLY, SEC_COMMIT, hFile);
                }
            }
    
            NtClose(hFile);
    
            if (0 <= status)
            {
                PVOID BaseAddress = 0;
                SIZE_T ViewSize = 0;
    
                status = ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, 0,
                    0, 0, &ViewSize, ViewUnmap, 0, PAGE_READONLY);
    
                NtClose(hSection);
    
                if (0 <= status)
                {
                    status = process((PCSTR)BaseAddress, fsi.EndOfFile.LowPart);
                    ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
                }
            }
        }
    
        return status;
    }