Всех приветствую! Поставил себе задачу, реализовать механизм перехвата функций для работы с файлами(копирование, создание, удаление и др.). Для этого накидал следующий код: Код (Text): library Hook; uses Windows, advApiHook; {$R *.res} const MutexName='__API_HOOK'; var SH:HHOOK = 0; CopyFileNextHook: function (lpExistingFileName, lpNewFileName: PChar; bFailIfExists: BOOL): BOOL; stdcall; //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ function CopyFileHookProc(lpExistingFileName, lpNewFileName: PChar; bFailIfExists: BOOL): BOOL; stdcall; begin MessageBox(0, 'Функция: CopyFile', 'Позволить ?', MB_YESNO or MB_ICONQUESTION); end; function MsgProc(code:DWORD;wParam,lparam:DWORD):DWORD;stdcall; begin CallNextHookEx(SH,code,wParam,lparam); end; procedure SetWindowsHook(e:Boolean); stdcall; var M:THandle; begin if e then begin m:=CreateMutex(0,false,MutexName); if m=0 then exit; SH:=SetWindowsHookEx(WH_GETMESSAGE,@MsgProc,HInstance,0); end else UnhookWindowsHookEx(sh); end; procedure HandleEvents(reason: integer); begin case reason of DLL_PROCESS_ATTACH: begin SetWindowsHook(true); HookProc('kernel32.dll', 'CopyFileW', @CopyFileHookProc, @CopyFileNextHook); end; DLL_PROCESS_DETACH: begin SetWindowsHook(false); UnhookCode(@CopyFileNextHook); end; end; end; // HandleEvents(DLL_PROCESS_DETACH); begin DllProc := @HandleEvents; MessageBox(0, 'Запускаем дллку', 'Позволить ?', MB_YESNO or MB_ICONQUESTION); HandleEvents(DLL_PROCESS_ATTACH); /// CopyFile('C:\test.txt','C:\test1.txt',true); end. end. Все работает нормально, перехватывает функции, да вот не задача, не перехватываются функции в самой винде, тоесть в explorer'е. Может Винда пользуетя другими функциями или еще есть какие ньюансы. Помогите пожалуста советом или примером. P.S. Перехватывал функцию SHFileOperation, ни каких реакций.
CopyFileA? Хук то вообще устанавливается? NtCreateFile,NtWriteFile,NtDeleteFile,NtSetInformationFile в помощь. Хотя несколько геморройно имхо
Спасибо за совет, попробовал в Google. Работает. Я извеняюсь, а ссылчка на онову книжку в электроном варианте не подскажешь? А то Google не показывает.
В винде винапи юзермодные нужно перехватывать юникодовские(W), так как "A" является переходником на W и перехватывая CreteFileW ты автоматом перехватишь CreateFileA, кстати заметил, что не для всех API это так... Подозреваю что в эксплорере юзаются варинат именно CreateFileW, но проверять лениво
Чтобы не быть голословным, примерчик из kernel32.dll функция CreateFileA Код (Text): .text:7C801A24 ; HANDLE __stdcall CreateFileA(LPCSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile) .text:7C801A24 public CreateFileA .text:7C801A24 CreateFileA proc near ; CODE XREF: OpenFile+10Dp .text:7C801A24 ; _lcreat+25p ... .text:7C801A24 .text:7C801A24 lpFileName = dword ptr 8 .text:7C801A24 dwDesiredAccess = dword ptr 0Ch .text:7C801A24 dwShareMode = dword ptr 10h .text:7C801A24 lpSecurityAttributes= dword ptr 14h .text:7C801A24 dwCreationDisposition= dword ptr 18h .text:7C801A24 dwFlagsAndAttributes= dword ptr 1Ch .text:7C801A24 hTemplateFile = dword ptr 20h .text:7C801A24 .text:7C801A24 mov edi, edi .text:7C801A26 push ebp .text:7C801A27 mov ebp, esp .text:7C801A29 push [ebp+lpFileName] .text:7C801A2C call sub_7C80E2A4 .text:7C801A31 test eax, eax .text:7C801A33 jz short loc_7C801A53 .text:7C801A35 push [ebp+hTemplateFile] ; hTemplateFile .text:7C801A38 push [ebp+dwFlagsAndAttributes] ; dwFlagsAndAttributes .text:7C801A3B push [ebp+dwCreationDisposition] ; dwCreationDisposition .text:7C801A3E push [ebp+lpSecurityAttributes] ; lpSecurityAttributes .text:7C801A41 push [ebp+dwShareMode] ; dwShareMode .text:7C801A44 push [ebp+dwDesiredAccess] ; dwDesiredAccess .text:7C801A47 push dword ptr [eax+4] ; lpFileName .text:7C801A4A call CreateFileW ; Вот тут прыжок на нащу юникод функцию .text:7C801A4F .text:7C801A4F loc_7C801A4F: ; CODE XREF: CreateFileA+32j .text:7C801A4F pop ebp .text:7C801A50 retn 1Ch .text:7C801A53 ; --------------------------------------------------------------------------- .text:7C801A53 .text:7C801A53 loc_7C801A53: ; CODE XREF: CreateFileA+Fj .text:7C801A53 or eax, 0FFFFFFFFh .text:7C801A56 jmp short loc_7C801A4F .text:7C801A56 CreateFileA endp P.S глянул у себя exolrer на XP S2 он использует только юникод вызовы, в том числе обращается к файлам именно через CreateFileW Собственно развернутый ответ, на поставленный вопрос
lamer2k, на сколько я знаю последние буквы A и W в конце Апи-функции означают в каком контексте рассматривать парамметры передаваемые ей, как данные типа AnsiString или WideString, более ни какой зависимости не замечал. Но факт, остается фактом в винде, то бишь в эксплорере они не перехватываются.
Епта у нас есть функция Код (Text): BOOL HaveBrainW(UNICODE , DWORD, BOOL) { ... тут много кода ... return XXX } BOOL HaveBrainA(ANSI, DWORD, BOOL) { тут производится перекодировка в юникод строк энсии ANSI->UNICODE // и вызов функции юникодной return HaveBrainW(UNICODE, DWORD, BOOL) } ты перехватываешь HaveBrainA, а не HaveBrainW и те программы котрые обращаются на прямую к HaveBrainW обходят твой хук.
Не понял о чем это lamer2k, но я узнал что надо перехватывать функции NtXXX. Может кто знает где о таких почитать?
FreeManCPM не всегда. например, CreateProcessA -> CreateProcessInternalA CreateProcessW -> CreateProcessInternalW а дальше все уходит куда-то в неэкспортируемые функции kernel32. так что тут A не переходник для W. аналогичная ситуация с MessageBox и некоторыми другими
Лучше посмотреть код в диасме и точно узнать, что хукать, а ТС матчасть учить, а потом сюда, задавать вопросы ИМХО.
А я скажу что хукать, Windows XP пользуется функциями NtCreateFile, NtOpenFile и т.д. lamer2k, не понял кому это ты сказал, но помойму форум это то место где делятся своим опытом на задаваемые вопросы. А если опыта нет то и поверхностно отвечать не надо!
не всегда. например, CreateProcessA -> CreateProcessInternalA CreateProcessW -> CreateProcessInternalW Иногда вообще наоборот, хотя сейчас ен вспомню имя той АПИ, но как-то в отладчике увидел (в смысле W -> A)
Coffein, насколько я понимаю цель стоит просто перехватить все обращения к файловой системе из 3го кольца. Как-то тоже немного страдал этим, могу поделиться измышлениями: 1. Все CreateFile рано или поздно упрутся в NtCreateFile, ОpenFile в NtOpenFile, CreateFileMapping в NtOpenSection, хотя перед CreateFileMapping всё равно вызывается NtCreateFile или NtOpenFile. Т.е. достаточно перехватить NtCreateFile и NtOpenFile. 2. Если мы хотим устанавливать свои обработчики NtCreateFile и NtOpenFile, то располагаться они должны в адресном пространстве контролируемого процесса. 3. Для того, чтобы контролировать доступ к файлу мы должны ВСЕ процессы в системе снабдить обработчиками NtCreateFile и NtOpenFile, т.е. мы должны встроить во все существующие процессы механизм внедрения вышеуказанных обработчиков во ВСЕ порождаемые процессы. При создании процесса ОС выполняет выделение памяти под внутренние структуры процесса, его сегмент кода и данных, а также формирует главный поток процесса в состоянии SUSPENSED. Для детектирования порождения дочернего процесса будем пользоваться функцией NtResumeThread, которую родительский процесс вызывает для запуска главного потока дочернего процесса. Условимся в программе использовать только функции экспортируемые из ntdll.dll, т.к. другие библиотеки на момент внедрения в процесс обработчиков NtCreateFile и NtOpenFile могут быть не загружены. Да и вообще, приложение может использовать только функции ntdll (ну ещё kernel.dll, но не факт, хотя функции из kernel.dll и используются самим загрузчиком Windows, и, по логике вещей, если для загрузки приложения используется стандартный загрузчик Windows, то kernel.dll должна быть обязательно спроецирована в память процесса). Всё вышеизложенное реализовано в маленькой программке со следующим алгоритмом: 1. Получаем список адресов всех используемых функций программы. Т.к. будут использоваться функции только из ntdll, то можно смело предположить, что во ВСЕХ приложениях адреса этих функций будут одними и теми же. Запихиваем эти адреса в структуру, которую будем внедрять во все процессы. Обработчики NtCreateFile и NtOpenFile внедрённые в процессы будут пользоваться для вызова системных функций адресами, сохранёнными в этой структуре. 2. Получаем список ВСЕХ доступных процессов в системе. Это будут только пользовательские процессы. Если необходимо контролировать обращение к NtCreateFile и NtOpenFile из системных процессов, то необходимо поднять себе привелегии до уровня "SeDebugPrivilege". 3. Читаем конфигурационный файл, в котором содержится список файлов, обращение к которым отследить надо. Считаем CRC для полного имени каждого файла - именно по СRC строки пути к файлу и будем определять надо или не надо отказать в доступе к файлу. Полученный результат - тоже в эту структуру. 4. Для каждого процесса из полученных на шаге (1) выполняем: 4.1 Открываем его (NtOpenProcess) с атрибутами PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_WRITE 4.2 Выделям память под структуру, содержащуюю адреса функций и список отслеживаемых файлов. 4.3 Выделям память под функцию расчёта алгоритма CRC (NtAllocateVirtualMemory с атрибутом PAGE_READWRITE) 4.4 Записываем в эту память тело функции расчёта CRC (NtWriteVirtualMemory). 4.5 Останавливаем все потоки процесса (т.к. в процессе внедрения какойто из потоков может попытаться вызвать NtCreateFile или NtOpenFile, что с большой долей вероятности приведёт к "абнормал терминэйшн"). 4.6 Выделям память и записываем в процесс процедуры обработки NtCreateFile, NtOpenFile и NtResumeThread. Здесь необходимо обратить внимание на то, что функции обработчиков (если только они не написаны на чистом ASM должны быть объявлены со спецификатором __declspec(naked), чтобы предотвратить запихивание в тело функции стандартного пролога и эпилога). 4.7 После записи в процесс необходимо в каждую функцию-обработчик (NtCreateFile, NtOpenFile и NtResumeThread) внести адрес структуры с адресами функций и списком проверяемых файлов, размещённой в целевом процессе. Возможно не самое элегантное решение, но другого я не нашёл. 4.8 Стартуем все остановленные потоки процесса. 4.9 Закрываем процесс. Если мы всё сделали правильно, то мы получаем все процессы (кроме системных), с установленными обработчиками NtCreateFile, NtOpenFile и NtResumeThread. При порождении других процессов (например создании процесса FAR из процесса Explorer) во вновь порождаемые процессы будут автоматически внедряться вышерассмотренные обработчики, и ни один пользовательский процесс не сможет открыть какой бы то ни было файл в обход наших обработчиков NtCreateFile и NtOpenFile. Для упрощения отладки рекомендую сначала заражать свой процесс и ставить точки останова NtCreateFile, NtOpenFile в ntdll. Вот полезные ссылки: http://www.wasm.ru/article.php?article=apihook_1 http://www.wasm.ru/article.php?article=apihook_3 Как приаттачить исходники к посту я не догадался, поэтому если захочешь их поиметь - напиши почтовый адрес - вышлю. Для начала рекомендую ознакомиться с прилагаемыми статьями Ms-rem'а