Здравствуйте, De-Bugger, Вы писали:
DB>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>А что тут, собственно, плохого ? Нормальная задача по системному программированию. Даже если студент не напишет полностью корректное решение, то по крайней мере познакомится с перехватом АПИ-функций, поймет, как импорт-экспорт устроены. А на каких тогда примерах их системному программированию обучать ?
DB>Со многим с вами согласен, кроме отцитированного. Поставленная задача в том виде как ее описал топикстартер, действительно очень трудоемкая но и бестолковая одновременно. Ежели и обучать студента методам "перехвата АПИ-функций", то уж явно не на ядренных Nt.., а если и на ядренных Nt.. то уж никак не на NtCreateFile. Если преподаватель толковый, то может дать задание "поэкспериментировать" ну например с NtCreateKey. Это на порядок проще и понять и отладить и поиграться. А дать задание, не имеющей практической пользы в дальнейшем, но потратив полезное время на подпорки с костылями, нежели чем на основную тему задания — ядреного перехвата, это извините, перебор.
Согласен. В первом варианте моего предыдущего сообщения была фраза "хотя я лично считаю эту задачу слишком сложной". Выкинул я ее из-за того, что не знаю деталей — может, это группа, где именно крутых системщиков готовят
Доброго времени суток всем еще раз! Поговорил с преподом, он разрешил перехватывать вместо NtXxx-функций обычные(CreateFile, WriteFile и т.п.). Вот код dll-библиотеки:
// dllmain.cpp: определяет точку входа для приложения DLL.
#include "stdafx.h"
#include <Tlhelp32.h>
#include <string.h>
#include <stdlib.h>
#include <Winternl.h>
#include <Dbghelp.h>
#pragma comment(lib, "Dbghelp.lib")
#pragma pack(push)
#pragma pack(1)
struct far_jmp
{
BYTE PushOp;
PVOID PushArg;
BYTE RetOp;
};
#pragma pack(pop)
HANDLE CurrProc;
far_jmp OldOpenFile, JmpOpenFile;
PVOID AdrOpenFile;
far_jmp OldCreateFile, JmpCreateFile;
PVOID AdrCreateFile;
far_jmp OldNtDeleteFile, JmpNtDeleteFile;
PVOID AdrNtDeleteFile;
far_jmp OldWriteFile, JmpWriteFile;
PVOID AdrWriteFile;
far_jmp OldReadFile, JmpReadFile;
PVOID AdrReadFile;
HANDLE hLog;
HANDLE mutex;
CRITICAL_SECTION cs;
void WriteLogString(const TCHAR * str)
{
DWORD dwBytesWritten = 0;
WriteFile(hLog, str, lstrlen(str) * sizeof(TCHAR), &dwBytesWritten, NULL);
WriteFile(hLog, L"\r\n", lstrlen(L"\r\n") * sizeof(TCHAR), &dwBytesWritten, NULL);
}
HANDLE WINAPI NewCreateFile(LPCTSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile)
{
EnterCriticalSection(&cs);
DWORD Written;
WriteProcessMemory(GetCurrentProcess(), AdrCreateFile, &OldCreateFile, sizeof(far_jmp), &Written);
HANDLE ret = CreateFile(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
WriteLogString(lpFileName);
WriteProcessMemory(GetCurrentProcess(), AdrCreateFile, &JmpCreateFile, sizeof(far_jmp), &Written);
LeaveCriticalSection(&cs);
return ret;
}
BOOL WINAPI NewWriteFile(HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped)
{
EnterCriticalSection(&cs);
DWORD Written;
WriteProcessMemory(GetCurrentProcess(), AdrWriteFile, &OldWriteFile, sizeof(far_jmp), &Written);
BOOL ret = WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
WriteLogString(L"WriteFile");
WriteProcessMemory(GetCurrentProcess(), AdrWriteFile, &JmpWriteFile, sizeof(far_jmp), &Written);
LeaveCriticalSection(&cs);
return ret;
}
BOOL WINAPI NewReadFile(HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped)
{
EnterCriticalSection(&cs);
DWORD Written;
WriteProcessMemory(GetCurrentProcess(), AdrReadFile, &OldReadFile, sizeof(far_jmp), &Written);
BOOL ret = ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
WriteLogString(L"ReadFile");
WriteProcessMemory(GetCurrentProcess(), AdrReadFile, &JmpReadFile, sizeof(far_jmp), &Written);
LeaveCriticalSection(&cs);
return ret;
}
void SetHook(LPCSTR procName, LPCWSTR libName, PVOID procHandler, PVOID * procAdr, far_jmp * old_header, far_jmp * new_header)
{
DWORD Written;
*procAdr = GetProcAddress(GetModuleHandle(libName), procName);
if (*procAdr == 0)
{
MessageBox(0, 0, 0, 0);
return;
}
new_header->PushOp = 0x68;
new_header->PushArg = procHandler;
new_header->RetOp = 0xC3;
ReadProcessMemory(GetCurrentProcess(), *procAdr, old_header, sizeof(far_jmp), &Written);
WriteProcessMemory(GetCurrentProcess(), *procAdr, new_header, sizeof(far_jmp), &Written);
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
DWORD Written;
unsigned char bom[] = {0xFF, 0xFE};
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hLog = CreateFile(L"c:\\log.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
WriteFile(hLog, bom, 2, &Written, NULL);
InitializeCriticalSection(&cs);
SetHook("CreateFileW", L"kernel32.dll", NewCreateFile, &AdrCreateFile, &OldCreateFile, &JmpCreateFile);
SetHook("ReadFile", L"kernel32.dll", NewReadFile, &AdrReadFile, &OldReadFile, &JmpReadFile);
SetHook("WriteFile", L"kernel32.dll", NewWriteFile, &AdrWriteFile, &OldWriteFile, &JmpWriteFile);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
CloseHandle(hLog);
DeleteCriticalSection(&cs);
//CloseHandle(mutex);
//WriteProcessMemory(GetCurrentProcess(), AdrNtOpenFile, &OldNtOpenFile, sizeof(far_jmp), &Written);
break;
}
return TRUE;
}
Вроде как все работало, пока не начал писать информацию о вызовах в лог-файл(это делается с помощью ф-ции WriteLogString). Почему-то при подгрузке этой библиотеки, например, в стандартный Блокнот лог-файл после некоторых действий получает вид:
C:\Windows\Fonts\staticcache.datWriteFile
WriteFile
C:\Users\Сергей\AppData\Roaming\Dropbox\shellext\l\4c979f96WriteFile
WriteFile
WriteFile
WriteFile
WriteFile
WriteFile
WriteFile
WriteFile
WriteFile
\\.\PIPE\srvsvcWriteFile
WriteFile
C:\WriteFile
WriteFile
C:\Users\Сергей\AppData\Local\Microsoft\Windows\Caches\cversions.1.dbWriteFile
WriteFile
C:\Users\Сергей\AppData\Local\Microsoft\Windows\Caches\{AFBF9F1A-8EE8-4C77-AF34-C647E37CA0D9}.1.ver0x000000000000001f.dbWriteFile
WriteFile
C:\Users\desktop.iniWriteFile
WriteFile
ReadFileWriteFile
WriteFile
C:\UsersWriteFile
.............
.............
и т.д.
т.е. периодически нет переносов строки, которые должны быть. Сначала я подумал, что это происходит из-за того, что моя библиотека была непотокобезопасна(хотя что-то я сомневаюсь в многопоточности Блокнота), но после добавления критических секций в функции перехвата ситуация не поменялась.
Из-за чего это может быть и как это можно исправить?
M>Из-за чего это может быть и как это можно исправить?
WriteLogString вызванный из вашего обработчика CreateFile вначале переходит в ваш обработчик WriteFile'а и только потом вызывает оригинал, отсюда спецэффекты
А код хуков все равно не потокобезопасный
Здравствуйте, ononim, Вы писали:
M>>Из-за чего это может быть и как это можно исправить?
O>WriteLogString вызванный из вашего обработчика CreateFile вначале переходит в ваш обработчик WriteFile'а и только потом вызывает оригинал, отсюда спецэффекты
O>А код хуков все равно не потокобезопасный
о! точно! спасибо огромное, попробую поковыряться в этом направлении