Сбросить дескриптор после ReadFile - PullRequest
0 голосов
/ 26 января 2020

Я пытаюсь открыть файл на windows и проверить, совпадают ли магические байты c с windows PE32. Если я запускаю приведенный ниже код и возвращаюсь непосредственно перед вызовом ReadFile в функции problemFunction, код работает нормально, и он выводит 5a4d в конце основной функции. Однако, если я вернусь после ReadFile вызова в problemFunction, то выйду из проверки dos->e_magic != PIMAGE_DOS_HEADER.

#include <Windows.h>
#include <winternl.h>

void problemFunction(HANDLE *fh) {
    DWORD fileSize = GetFileSize(fh, NULL);
    if (!fileSize) { CloseHandle(fh); exit(1); }

    BYTE* pByte = new BYTE[fileSize];
    DWORD dw;
    ReadFile(*fh, pByte, fileSize, &dw, NULL);
    // could be wrong but i think i need to run SetFilePointer here but not sure on what to do.
    return;
}

int main() {
    const char* filepath = "C:\\windows\\file\\path\\to\\exe";
    HANDLE fh = CreateFileA(filepath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if(fh == INVALID_HANDLE_VALUE) { CloseHandle(fh); exit(1); }

    problemFunction(&fh);

    DWORD fileSize = GetFileSize(fh, NULL);
    if (!fileSize) { CloseHandle(fh); exit(1); }

    BYTE* pByte = new BYTE[fileSize];
    DWORD dw;
    ReadFile(fh, pByte, fileSize, &dw, NULL);

    PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)pByte;

    if (dos->e_magic != IMAGE_DOS_SIGNATURE) { CloseHandle(fh); exit(1); }
    // dos->e_magic should be 5a4d for MZ, windows PE
}

Я предполагаю, что мне нужно сбросить указатель файла после problemFunction вызова чтения с что-то вроде

LONG reset = -sizeof(DWORD);
SetFilePointer(*fh, reset, NULL, FILE_END);

Но я не могу заставить его работать.

Спасибо

1 Ответ

1 голос
/ 27 января 2020

Существует ряд проблем с вашим кодом.

problemFunction() принимает указатель HANDLE* в качестве ввода, но он не разыменовывает этот указатель при передаче его в GetFileSize() или CloseHandle() , Но он разыменовывает указатель при передаче его на ReadFile().

Вы должны компилировать свой код с отключенной проверкой типа STRICT , иначе ваш код не сможет скомпилироваться. Вы всегда должны компилировать с включенным STRICT.

HANDLE - это тип указателя, поэтому нет необходимости передавать его по указателю, если только вы не собираетесь изменять его значение, чего не делает этот код. Таким образом, вы должны изменить problemFunction(), чтобы принимать HANDLE как есть, а не указатель HANDLE*.

Кроме того, GetFileSize() не возвращает 0 в случае сбоя, как предполагает ваш код. На самом деле возвращается INVALID_FILE_SIZE, что равно -1, ie 0XFFFFFFFF как DWORD. Это четко указано в документации :

Если функция завершается ошибкой и lpFileSizeHigh равен NULL, возвращаемое значение равно INVALID_FILE_SIZE. Чтобы получить расширенную информацию об ошибке, вызовите GetLastError.

Но, что наиболее важно, ваш второй вызов ReadFile() внутри main() не читает то, что вы ожидаете, поскольку первый вызов ReadFile() внутри problemFunction() уже прочитал данные (и слил их!), но вы не ищете HANDLE назад к началу файла после того, как прочитали, так что второй вызов ReadFile() может прочитать его снова. Вы правы, что вам нужно использовать SetFilePointer() для этого.

С учетом сказанного, попробуйте что-то вроде этого:

#include <Windows.h>
#include <winternl.h>

bool test(HANDLE fh) {
    DWORD fileSize = GetFileSize(fh, NULL);
    if (fileSize == INVALID_FILE_SIZE) {
        return false;
    }

    BYTE* pByte = new BYTE[fileSize];
    DWORD dw;
    if (!ReadFile(fh, pByte, fileSize, &dw, NULL)) {
        delete[] pByte;
        return false;
    }

    // use pByte as needed...

    delete[] pByte;

    if (SetFilePointer(fh, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
        return false;
    }

    return true;
}

int main() {
    const char* filepath = "C:\\windows\\file\\path\\to\\exe";
    HANDLE fh = CreateFileA(filepath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (fh == INVALID_HANDLE_VALUE) {
        return 1;
    }

    if (!test(fh)) {
        CloseHandle(fh);
        return 1;
    }

    DWORD fileSize = GetFileSize(fh, NULL);
    if (fileSize == INVALID_FILE_SIZE) {
        CloseHandle(fh);
        return 1;
    }

    BYTE* pByte = new BYTE[fileSize];
    DWORD dw;
    if (!ReadFile(fh, pByte, fileSize, &dw, NULL) || dw < sizeof(IMAGE_DOS_HEADER)) {
        CloseHandle(fh);
        return 1;
    }

    PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)pByte;

    if (dos->e_magic != IMAGE_DOS_SIGNATURE) {
        delete[] pByte;
        CloseHandle(fh);
        return 1;
    }

    ...

    delete[] pByte;
    CloseHandle(fh);

    return 0;
}
...