-2

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?

drescherjm
  • 10,365
  • 5
  • 44
  • 64
  • this is an example of what you researched. What have you tried for this problem? – Maddy Oct 12 '17 at 21:24
  • @Mani, this example above read a txt file line by line? certainly no, right? then how do this? some code example etc? –  Oct 12 '17 at 21:36
  • you need read all content of file first (or some chunk if file too large) and yourself parse line ends – RbMm Oct 12 '17 at 21:50
  • 1
    This is a pretty straightforward programming problem, parsing the contents of a buffer into individual lines. You should at least *try* to solve it yourself before asking for help. – Harry Johnston Oct 12 '17 at 22:11
  • 3
    If you are struggling with not small, but *tiny* problems, your code should not run in kernel mode. With that out of the way, if you are indeed using C++, use the `` library. You probably aren't, so you need to update your tags. – IInspectable Oct 12 '17 at 22:33
  • @RbMm, then how find line nº **3** for example? `buffer[3]`? i not understood. –  Oct 12 '17 at 22:47
  • scan for `\r\n` – RbMm Oct 12 '17 at 22:48
  • @RbMm, Normally to read line by line is necessary a **for** loop. –  Oct 12 '17 at 22:56
  • @JoãoPablo - what is **line** ? `ZwReadFile` don't know what is this – RbMm Oct 12 '17 at 23:02
  • @RbMm, until where i know, `ZwReadFile` read all content of file (all lines at once) not line by line. If i'm wrong, say please. –  Oct 12 '17 at 23:42
  • @IInspectable, it is my understanding that it is possible to use C++ in the kernel, but not the C++ runtime. – Harry Johnston Oct 12 '17 at 23:59
  • 5
    There is no way to read just a single line from a file. That's true in user mode as well as kernel mode. What you *can* do is read a chunk of data from the file and then parse it into individual lines. But in this case you will need to do it yourself, since there's no runtime library in the kernel to do it for you. (Well, [there is a runtime library](https://msdn.microsoft.com/library/windows/hardware/ff563638), but it doesn't have that sort of functionality.) Have you considered making your driver user-mode instead of kernel-mode? – Harry Johnston Oct 13 '17 at 00:05
  • @HarryJohnston, my driver is a boot driver, so i need make it in kernel mode. –  Oct 13 '17 at 00:09
  • The code you've just linked to doesn't *actually* read the file one line at a time. When you call `fgets` it reads a chunk of the file into an internal buffer and then searches the buffer until it finds the end of the first line. The first line is returned to the caller, the rest of the data stays in the buffer. When you call `fgets` the second time, it finds the end of the second line in the buffer and returns that. If it runs out of content then it reads more from the file. You can do the same thing. You'll just have to code it yourself, because there's no `fgets` to do it for you. – Harry Johnston Oct 13 '17 at 00:15
  • @HarryJohnston, then you want say that there not exists something similar to `fgets()` (C++) in kernel mode? –  Oct 13 '17 at 00:17
  • No, there isn't. It's not the sort of thing kernel-mode code usually needs. But you can do it yourself. – Harry Johnston Oct 13 '17 at 00:22
  • @HarryJohnston, ok. Then i have must make a **while** loop using `strstr()` searching for `\r\n` as suggested by RbMm. Righ? –  Oct 13 '17 at 00:49
  • @RbMm, could provide a answer with a small explanation and code example please? i not understood fine. –  Oct 13 '17 at 06:13
  • @JoãoPablo Honestly, I think you should learn a bit more about the C language and possibly about programming in general, before trying to write kernel mode code – Jabberwocky Oct 13 '17 at 07:13
  • @HarryJohnston: *"You can use C++, unless you are using C++"* isn't very helpful in making the point, that you can use C++ in kernel mode. If your build tools do not support non-optional parts of the language, then you simply aren't using that language. Case in point being, that if you want to read a file line by line, C++ has the tools to do so. If you cannot use those tools, then you shouldn't tag a question stating the opposite. – IInspectable Oct 13 '17 at 07:24
  • @IInspectable, [FYI, in case you want to comment](https://meta.stackoverflow.com/q/357822/886887). – Harry Johnston Oct 13 '17 at 22:02

1 Answers1

0

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;
}
RbMm
  • 31,280
  • 3
  • 35
  • 56