内核模式:如何逐行读取 txt 文件?

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

我需要读取 txt 文件的每一行并将这一行作为参数传递给方法。

我找到了这个例子:

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] = '[=10=]';
            DbgPrint("%s\n", buffer);
        }
        ZwClose(handle);
    }

Reference

但这会读取文件的所有内容,而不是逐行读取。

关于如何做到这一点的一些想法?

读取所有文件以缓冲或将其映射为部分。比执行下一个代码:

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;
}

c/c++

上实施 findRN
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;
}

如果你need/want 超快速最有效的实现,在 asm 中执行此操作。例如 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

在 x86 上的代码相同,只是在寄存器名称

中将 r 更改为 e

地图文件:

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;
}