Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > Перехват Native API


Автор: DoZENT 6.1.2007, 13:42
Общая задача: написать что-то вроде FileMon'а, который перехватывает все обращения к любым файлам. Перехватываю api функции сплайсингом. Сначала пробовал с FindFirst, FindNext, но ничего путного не вышло, все-таки они не всегда используются при обращении к файлам. Стал пробовать перехватывать ZwQueryDirectoryFile, но возникла такая куча проблем... У меня есть функции

Код

function TrueZwQueryDirectoryFile (
FileHandle              :dword;
Event                   :dword;
ApcRoutine              :pointer;
ApcContext              :pointer;
var IoStatusBlock       :pointer;
var FileInformation     :pointer;
FileInformationLength   :ULONG;
FileInformationClass    :DWORD;
ReturnSingleEntry       :boolean;
FileName                :PUnicodeString;
RestartScan             :boolean) : NTStatus;stdcall;
var
written : Cardinal;
begin


  WriteProcessMemory (INVALID_HANDLE_VALUE, MbwAdr,
                     @OldMbw, SizeOf(OldCode), Written);

  Result := ZwQueryDirectoryFile (FileHandle, Event, ApcRoutine,ApcContext,
                                  IoStatusBlock, FileInformation,FileInformationLength,
                                  FileInformationClass,ReturnSingleEntry,FileName,RestartScan);



  WriteProcessMemory(INVALID_HANDLE_VALUE, MbwAdr,
                     @JmpMbw, SizeOf(far_jmp), Written);

end;



которая представляет собой "настоящую" функцию. Есть

Код

function NewZwQueryDirectoryFile (
FileHandle              :dword;
Event                   :dword;
ApcRoutine              :pointer;
ApcContext              :pointer;
var IoStatusBlock       :pointer;
var FileInformation     :pointer;
FileInformationLength   :ULONG;
FileInformationClass    :DWORD;
ReturnSingleEntry       :bool;
FileName                :PUnicodeString;
RestartScan             :boolean) : NTStatus;stdcall;
//var
//s : string;
begin

  Result := TrueZwQueryDirectoryFile (FileHandle, Event, ApcRoutine,ApcContext,
                                  IoStatusBlock, FileInformation,FileInformationLength,
                                  FileInformationClass,ReturnSingleEntry,FileName,RestartScan);


end;



которая является "подменной" функцией. Какая-то из них не работает, т.е. вызов api перехватывается, но его подмена не происходит, и процесс, который вызвал ZwQueryDirectoryFile вылетает. В чем дело? 

P.S. есть предположения, что надо записывать какую-то инфу в параметры FileInformation и IoStatusBlock, но какую  smile 

Автор: bartram 6.1.2007, 18:15
DoZENT, Во первых, как ты устанавливаешь перехват? Какие функции для этого используешь и.т.д
Во вторых,
Цитата(DoZENT @  6.1.2007,  13:42 Найти цитируемый пост)
Общая задача: написать что-то вроде FileMon'а

если ты хочешь перехватывать именно ВСЕ обращения то тебе придется писать драйвер smile
В третьих, покажи код DLL которую ты внедряешь в процеесс smile или как ты вообще хук делаешь?

Автор: W4FhLF 6.1.2007, 18:16
Если процесс вылетает значит ошибка в функциях перехвата, т.е. происходит недопустимая операция и исключение. Смотри адрес по которому вылетает, грузи программу в отладчик и изучай, что творится по этому адресу и к какой функции она принадлежит.

Ты внимательно прочёл статью MsRem по перехвату?smile 

На первый взгляд только вот это глаз режет:

Код

Result := ZwQueryDirectoryFile (FileHandle, Event, ApcRoutine,ApcContext,
                                  IoStatusBlock, FileInformation,FileInformationLength,
                                  FileInformationClass,ReturnSingleEntry,FileName,RestartScan);


Вызывай NewZwQueryDirectoryFile. И покажи как перехват ставишь.

Автор: DoZENT 6.1.2007, 19:06
Цитата

Вызывай NewZwQueryDirectoryFile

Наверное ты не понял механизма перехвата. В функции TrueZwQueryDirectoryFile я сначала устанавливаю оригинальный адрес входа в функцию ZwQueryDirectoryFile, потом вызываю ZwQueryDirectoryFile, потом устанавливаю "мой" адрес точки входа, чтобы при вызове этой ф-и вызывалась NewZwQueryDirectoryFile


Перехват делаю так:
Код

Procedure SetHook();
var
 hNTdll: dword;
 Bytes: dword;
begin
  hNTDll := GetModuleHandle('ntdll.dll');
  MbwAdr  := GetProcAddress(hNTdll, 'ZwQueryDirectoryFile');
  ReadProcessMemory(INVALID_HANDLE_VALUE, MbwAdr, @OldMbw, SizeOf(OldCode), Bytes);
  JmpMbw.PuhsOp  := $68;
  JmpMbw.PushArg := @NewZwQueryDirectoryFile;
  JmpMbw.RetOp   := $C3;
  WriteProcessMemory(INVALID_HANDLE_VALUE, MbwAdr, @JmpMbw, SizeOf(far_jmp), Bytes);
end;



Цитата

если ты хочешь перехватывать именно ВСЕ обращения то тебе придется писать драйвер 

Нужно перехватывать обращения, которых хватит для того, чтобы при надобности скрыть файл. Я думаю ZwQueryDirectoryFile будет достаточно

Автор: W4FhLF 6.1.2007, 19:21
Цитата

Наверное ты не понял механизма перехвата. В функции TrueZwQueryDirectoryFile я сначала устанавливаю оригинальный адрес входа в функцию ZwQueryDirectoryFile, потом вызываю ZwQueryDirectoryFile, потом устанавливаю "мой" адрес точки входа, чтобы при вызове этой ф-и вызывалась NewZwQueryDirectoryFile


Этот механизм я уже выучил наизустьsmile Немножечко невнимателен был, поэтому извиняй. Я тебе уже сказал, что делать, нужно отлаживать этот процесс, смотреть где вылеает, смотреть почему, какие исключения, какие ошибки. Я смотрю ты всё делаешь в точности как в статье MsRem, а у него там хватает пробелов, над которыми нужно работать самостоятельно. 


Автор: DoZENT 7.1.2007, 11:42
Цитата

Я тебе уже сказал, что делать, нужно отлаживать этот процесс, смотреть где вылеает, смотреть почему, какие исключения, какие ошибки

Все-таки хотелось бы найти путь попроще. 


есть предположения, что надо записывать какую-то инфу в параметры FileInformation и IoStatusBlock, но какую  smile 

Цитата

у него там хватает пробелов, над которыми нужно работать самостоятельно. 

Я заметил ;) Длл сначала не выгружалась из памяти, MsRem забыл, что для создания хука он создает отдельный поток, поэтому обрабатывать надо не только DLL_PROCESS_DETACH, но и DLL_THREAD_DETACH.

Автор: bartram 7.1.2007, 13:38
Цитата(DoZENT @  7.1.2007,  11:42 Найти цитируемый пост)
Я заметил ;) Длл сначала не выгружалась из памяти, MsRem забыл, что для создания хука он создает отдельный поток, поэтому обрабатывать надо не только DLL_PROCESS_DETACH, но и DLL_THREAD_DETACH.

DLL_THREAD_DETACH обрабатывать не надо.
Цитата(DoZENT @  7.1.2007,  11:42 Найти цитируемый пост)
MsRem забыл, что для создания хука он создает отдельный поток

Где написано что он создает отдельный поток для перехвата?
DoZENT, я использовал его модули для перехвата и работали они безупречно smile
Я перехватывал FindFirst, FindNext и все тоже работало безупречно. Почитай статьи на wasm.ru по перехвату, если что то не понятно, милости просим smile

Автор: W4FhLF 7.1.2007, 15:33
Цитата(DoZENT @  7.1.2007,  11:42 Найти цитируемый пост)
Все-таки хотелось бы найти путь попроще.    


Нет тут пути попроще, нужно отлаживать. 

Цитата(DoZENT @  7.1.2007,  11:42 Найти цитируемый пост)
есть предположения, что надо записывать какую-то инфу в параметры FileInformation и IoStatusBlock, но какую   


Зачем туда что-то класть твоей функции перехватчику? Если без перехвата программа не падает, а с перехватом падает, то эти параметры тут совсем не причём.

Цитата(bartram @  7.1.2007,  13:38 Найти цитируемый пост)
DoZENT, я использовал его модули для перехвата и работали они безупречно Я перехватывал FindFirst, FindNext и все тоже работало безупречно. Почитай статьи на wasm.ru по перехвату, если что то не понятно, милости просим 


К слову, о каких модулях речь? Если advApiHook, то там сплайсинг реализован иначе, чем в примерах к статьям. Кстати, гораздо более удачно. 
И ещё о каких статьях ты говоришь? По перехвату по-моему лучшими статьями на васме являются как раз статьи MsRem, ну можно ещё у Рихера неплохую информацию найти. Статьи 90211 уже достаточно устерели, да и в них нет того, чего бы не было в статьях Рема.


Автор: DoZENT 7.1.2007, 15:39
Цитата

Где написано что он создает отдельный поток для перехвата?

А это что?
Код

CreateThread(nil, 0, @SetGlobalHookProc, nil, 0, TrId)


Цитата

DLL_THREAD_DETACH обрабатывать не надо.

Если его не обрабатывать, то dll не выгружается из памяти. Так было у меня. Даже Delphi при следующей компиляции писала, что не может перезаписать dll, т.к. она используется.

Добавлено @ 15:50 
Цитата

К слову, о каких модулях речь? Если advApiHook, то там сплайсинг реализован иначе, чем в примерах к статьям

Вообще-то я этот модуль не юзал, но надо будет попробовать

Автор: bartram 7.1.2007, 16:09
Цитата(W4FhLF @  7.1.2007,  15:33 Найти цитируемый пост)
Если advApiHook, то там сплайсинг реализован иначе

Я про него и говорю
Цитата(W4FhLF @  7.1.2007,  15:33 Найти цитируемый пост)
И ещё о каких статьях ты говоришь?

О 3х статьях MsRem'a которые на wasm.ru
Цитата(DoZENT @  7.1.2007,  15:39 Найти цитируемый пост)
DLL_THREAD_DETACH

Его не надо обрабатывать, надо обрабатывать DLL_PROCESS_DETACH
Вот пример простого перехвата с использованием AdvApiHook
Код

 procedure LibraryProc (Reason : integer);
begin
  case Reason of
    DLL_PROCESS_ATTACH :
      begin
       HookProc('kernel32.dll', 'ExitProcess', @NewExitProcess, @TrueExitProcess);
      end;

    DLL_PROCESS_DETACH :
//Отсоединение от процесса
// снимаем хук
    begin
     UnhookCode(@TrueExitProcess);
    end;
  end;
end;

begin
  DllProc := LibraryProc;
  DllProc (DLL_PROCESS_ATTACH);
end.




Автор: DoZENT 7.1.2007, 16:20
Цитата

Его не надо обрабатывать, надо обрабатывать DLL_PROCESS_DETACH

Блин. Еще раз. Если обрабатывать ТОЛЬКО его, то dll из памяти У МЕНЯ не выгружается. Я обрабатываю и его и DLL_THREAD_DETACH

Цитата

Вот пример простого перехвата с использованием AdvApiHook

Дык я то же самое делаю, но без этой библиотеки. Попробую ночью ее поюзать, отпишусь.

Автор: bartram 7.1.2007, 21:19
Цитата(DoZENT @  7.1.2007,  16:20 Найти цитируемый пост)
Блин. Еще раз. Если обрабатывать ТОЛЬКО его, то dll из памяти У МЕНЯ не выгружается.

А каким способом ты dll выгружаешь? 

Автор: DoZENT 7.1.2007, 21:29
Цитата

А каким способом ты dll выгружаешь? 

FreeLibrary ест-но

Автор: DoZENT 7.1.2007, 23:21
Цитата

Вот пример простого перехвата с использованием AdvApiHook

Перехватывать я умею и без библиотек. Что делать в "новой" функции smile 

Автор: bartram 8.1.2007, 15:53
Цитата(DoZENT @  7.1.2007,  23:21 Найти цитируемый пост)
Что делать в "новой" функции 

вот:
Код

  var
  TrueExitProcess:function (uExitCode: UINT): Boolean; stdcall;

  //
  function NewExitProcess(uExitCode: UINT):Boolean; stdcall;
  begin
if (MessageBox(0, 'Вы действительно хотите завершить этот процесс?', '', MB_ICONWARNING or MB_YESNO or MB_DEFBUTTON1) = idYes) then
  TrueExitProcess(0);

end;

смекаешь?  smile 

Автор: DoZENT 8.1.2007, 19:15
Цитата

смекаешь?

С ExitProcess и его одним параметром какнить сам разобрался бы. Кто-нибудь может привести ПРИМЕР перехвата ZwQueryDirectoryFile smile  smile  smile 

Автор: bartram 9.1.2007, 14:12
DoZENT, я тебе пример дал, сделай по примеру. Структура описанная тем более у тебя есть. Если что то не получается спрашивай, по коду будет проще понять что у тебя не получается и что ты хочешь сделать smile

Автор: DoZENT 9.1.2007, 16:33
ОК, вот весь код:
Код

library engine;


uses
  Windows;

type
 OldCode = packed record
  One: dword;
  two: word;
 end;

 NTStatus = Cardinal;


far_jmp = packed record
  PuhsOp: byte;
  PushArg: pointer;
  RetOp: byte;
 end;


const
FileDirectoryInformation=1;
FileFullDirectoryInformation=2;
FileBothDirectoryInformation=3;
FileNamesInformation=12;


//Структура записи в FileInformation для FileDirectoryInformation:
type _FILE_DIRECTORY_INFORMATION = packed record 
NextEntryOffset:ULONG;
Unknown:ULONG;
CreationTime,
LastAccessTime,
LastWriteTime,
ChangeTime,
EndOfFile,
AllocationSize:int64; 
FileAttributes:ULONG;
FileNameLength:ULONG; 
FileName:PWideChar;
end;

//для FileFullDirectoryInformation:
type _FILE_FULL_DIRECTORY_INFORMATION = packed record
NextEntryOffset:ULONG;
Unknown:ULONG; 
CreationTime,
LastAccessTime, 
LastWriteTime,
ChangeTime,
EndOfFile,
AllocationSize:int64;
FileAttributes:ULONG; 
FileNameLength:ULONG;
EaInformationLength:ULONG ;
FileName:PWideChar; 
end;

//для FileBothDirectoryInformation:
type _FILE_BOTH_DIRECTORY_INFORMATION = packed record
NextEntryOffset:ULONG;
Unknown:ULONG;
CreationTime,
LastAccessTime,
LastWriteTime, 
ChangeTime,
EndOfFile,
AllocationSize:int64;
FileAttributes:ULONG;
FileNameLength:ULONG;
EaInformationLength:ULONG ;
AlternateNameLength:ULONG;
AlternateName:array[0..11] of WideChar;
FileName:PWideChar; 
end;

//и для FileNamesInformation:
type _FILE_NAMES_INFORMATION = packed record
NextEntryOffset:ULONG;
Unknown:ULONG;
FileNameLength:ULONG;
FileName:PWideChar;
end;

type
PUnicodeString = ^TUnicodeString;
  TUnicodeString = packed record
    Length: Word;
    MaximumLength: Word;
    Buffer: PWideChar;
end;


//нас интересует структура ClientId:
type
PClientID = ^TClientID;
TClientID = packed record
UniqueProcess:cardinal;
UniqueThread:cardinal;
end;

var
 JmpMbw: far_jmp;
 OldMbw : OldCode;
 MbwAdr : pointer;


Function ZwQueryDirectoryFile(FileHandle: dword;
Event: dword;
ApcRoutine: pointer;
ApcContext: pointer;
IoStatusBlock: pointer;
FileInformation: pointer;
FileInformationLength: dword;
FileInformationClass: dword;
ReturnSingleEntry: bool;
FileName: PUnicodeString;
RestartScan: bool): NTStatus;
stdcall; external 'ntdll.dll';

function TrueZwQueryDirectoryFile (
FileHandle              :dword;
Event                   :dword;
ApcRoutine              :pointer;
ApcContext              :pointer;
var IoStatusBlock       :pointer;
var FileInformation     :pointer;
FileInformationLength   :ULONG;
FileInformationClass    :DWORD;
ReturnSingleEntry       :boolean;
FileName                :PUnicodeString;
RestartScan             :boolean) : NTStatus;stdcall;
var
written : Cardinal;
begin


  WriteProcessMemory (INVALID_HANDLE_VALUE, MbwAdr,
                     @OldMbw, SizeOf(OldCode), Written);

  Result := ZwQueryDirectoryFile (FileHandle, Event, ApcRoutine,ApcContext,
                                  IoStatusBlock, FileInformation,FileInformationLength,
                                  FileInformationClass,ReturnSingleEntry,FileName,RestartScan);



  WriteProcessMemory(INVALID_HANDLE_VALUE, MbwAdr,
                     @JmpMbw, SizeOf(far_jmp), Written);

end;



function NewZwQueryDirectoryFile (
FileHandle              :dword;
Event                   :dword;
ApcRoutine              :pointer;
ApcContext              :pointer;
var IoStatusBlock       :pointer;
var FileInformation     :pointer;
FileInformationLength   :ULONG;
FileInformationClass    :DWORD;
ReturnSingleEntry       :bool;
FileName                :PUnicodeString;
RestartScan             :boolean) : NTStatus;stdcall;

begin

  Result := TrueZwQueryDirectoryFile (FileHandle, Event, ApcRoutine,ApcContext,
                                  IoStatusBlock, FileInformation,FileInformationLength,
                                  FileInformationClass,ReturnSingleEntry,FileName,RestartScan);



end;







Procedure SetHook();
var
 hNTdll: dword;
 Bytes: dword;
begin
  hNTDll := GetModuleHandle('ntdll.dll');
  MbwAdr  := GetProcAddress(hNTdll, 'ZwQueryDirectoryFile');
  ReadProcessMemory(INVALID_HANDLE_VALUE, MbwAdr, @OldMbw, SizeOf(OldCode), Bytes);
  JmpMbw.PuhsOp  := $68;
  JmpMbw.PushArg := @NewZwQueryDirectoryFile;
  JmpMbw.RetOp   := $C3;
  WriteProcessMemory(INVALID_HANDLE_VALUE, MbwAdr, @JmpMbw, SizeOf(far_jmp), Bytes);
end;

Procedure Unhook();
var
 Bytes: dword;
begin
  WriteProcessMemory(INVALID_HANDLE_VALUE, MbwAdr, @OldMbw, SizeOf(OldCode), Bytes);
end;


// залепа
Function MessageProc(code : integer; wParam : word;
                    lParam : longint) : longint; stdcall;
begin
 CallNextHookEx(0, Code, wParam, lparam);
 Result := 0;
end;

Procedure SetGlobalHookProc();
begin
 SetWindowsHookEx(WH_GETMESSAGE, @MessageProc, HInstance, 0);
 Sleep(INFINITE);
end;
//

Procedure SetGlobalHook();
var
 hMutex: dword;
 TrId: dword;
begin
 hMutex := CreateMutex(nil, false, 'AdvareHook');
 if GetLastError = 0 then
 CreateThread(nil, 0, @SetGlobalHookProc, nil, 0, TrId) else
 CloseHandle(hMutex);
end;


procedure DLLEntryPoint(dwReason: DWord);
begin
  case dwReason of
    DLL_PROCESS_ATTACH: begin
                          SetGlobalHook();
                          SetHook();
                        end;
    DLL_PROCESS_DETACH: UnHook();
    DLL_THREAD_DETACH : UnHook ();
  end;
end;


begin
 DllProc := @DLLEntryPoint;
 DLLEntryPoint(DLL_PROCESS_ATTACH);
end.




Кое-что подправил, теперь процесс, вызывающий функцию не завершается, но не может найти ни одного файла (например total commander выдает только список дисков, но зайти в них не может).

Автор: drkot 9.1.2007, 16:41
Сори за возможный оффтоп.

DoZENT, а у тебя OutPost случаем не стоит? (из последних версий 4)
А то у меня проблемы с перехватом возникли после очередного обновления. При включенном файрволе при попытке перехвата целевое приложение вылетало с ошибкой. После отключения бока исчезали.

Автор: W4FhLF 9.1.2007, 16:52
Блин, да сколько можно говорить, чтобы ты попробовал отладить процесс? Чё гадать и как дурак тыкать пальцем в небо? Посмотри как и что происходит, локализуй ошибку и исправь её.

Автор: DoZENT 9.1.2007, 17:25
Цитата

DoZENT, а у тебя OutPost случаем не стоит?

Нет, KIS Forever  smile

 
Цитата

Блин, да сколько можно говорить, чтобы ты попробовал отладить процесс? Чё гадать и как дурак тыкать пальцем в небо? Посмотри как и что происходит, локализуй ошибку и исправь её.

Каким образом отлаживать? Если ты имеешь в виду установку прерывания, то на ZwQueryDirectoryFile брейкпойнт на ставится, т.к. это недокументированная ф-я.

Автор: W4FhLF 9.1.2007, 20:17
Цитата(DoZENT @  9.1.2007,  17:25 Найти цитируемый пост)
Каким образом отлаживать? Если ты имеешь в виду установку прерывания, то на ZwQueryDirectoryFile брейкпойнт на ставится, т.к. это недокументированная ф-я.


ZwQueryDirectoryFile является переходником к ядерной функции и экспортируется из ntdll.dll, именно это тебе позволяет перехватывать её таким методом, и именно это позволит отладить этот процесс.
Берёшь любой отладчик, я обычно использую OllyDBG, загружаешь в неё приложение в которое будет проинжектирована твоя dll и в "Опции > Опции отладки > Events" ставишь галку на "Break on new module (DLL)", далее инжектируешь dll в процесс и прерываешься на процедуре DLLEntryPoint, трейсишь установку хуков, смотришь всё ли в порядке, далее ставишь бряк на ZwQueryDirectoryFile(bp ZwQueryDirectoryFile) и пускаешь программу дальше. Когда программа вызовет эту функцию ты прервёшься на её начале, где будет стоять прыжок(push @ZwQueryDirectoryFile / retn) на процедуру NewZwQueryDirectoryFile. Заходишь в эту процедуру, трейсишь и смотришь правильно ли всё происходит, тем самым ты сможешь проконтролировать весь процесс установки перехвата и его срабатывания. 

Автор: DoZENT 9.1.2007, 20:54
Цитата

агружаешь в неё приложение в которое будет проинжектирована твоя dll

Я использую сплайсинг, поэтому dll не будет проинжектированна в процесс. Или я что-то неправильно понимаю?

Автор: dumb 10.1.2007, 06:41
Цитата(DoZENT @  9.1.2007,  20:54 Найти цитируемый пост)
Я использую сплайсинг, поэтому dll не будет проинжектированна в процесс.

как думаешь, зачем у тебя SetWindowsHookEx используется? - как раз для подгрузки dll во все процессы. а подгрузившись, ты уже устанавливаешь хук на ZwQueryDirectoryFile(изменения, вносимые WriteProcessMemory локальны для каждого процесса).

Автор: DoZENT 10.1.2007, 18:04
Цитата

как думаешь, зачем у тебя SetWindowsHookEx используется? - как раз для подгрузки dll во все процессы. а подгрузившись, ты уже устанавливаешь хук на ZwQueryDirectoryFile(изменения, вносимые WriteProcessMemory локальны для каждого процесса).


Почитал MSDN, понял, спасибо  smile Такое вопрос, если внедрение делается одной функцией, тогда зачем тем же автором создавалось такое:

Код

{ Внедрение Dll в процесс }
Function InjectDll(Process: dword; ModulePath: PChar): boolean;
var
  Memory:pointer;
  Code: dword;
  BytesWritten: dword;
  ThreadId: dword;
  hThread: dword;
  hKernel32: dword;
  Inject: packed record
           PushCommand:byte;
           PushArgument:DWORD;
           CallCommand:WORD;
           CallAddr:DWORD;
           PushExitThread:byte;
           ExitThreadArg:dword;
           CallExitThread:word;
           CallExitThreadAddr:DWord;
           AddrLoadLibrary:pointer;
           AddrExitThread:pointer;
           LibraryName:array[0..MAX_PATH] of char;
          end;
begin
  Result := false;
  Memory := VirtualAllocEx(Process, nil, sizeof(Inject),
                           MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  if Memory = nil then Exit;

  Code := dword(Memory);
  //инициализация внедряемого кода:
  Inject.PushCommand    := $68;
  inject.PushArgument   := code + $1E;
  inject.CallCommand    := $15FF;
  inject.CallAddr       := code + $16;
  inject.PushExitThread := $68;
  inject.ExitThreadArg  := 0;
  inject.CallExitThread := $15FF;
  inject.CallExitThreadAddr := code + $1A;
  hKernel32 := GetModuleHandle('kernel32.dll');
  inject.AddrLoadLibrary := GetProcAddress(hKernel32, 'LoadLibraryA');
  inject.AddrExitThread  := GetProcAddress(hKernel32, 'ExitThread');
  lstrcpy(@inject.LibraryName, ModulePath);
  //записать машинный код по зарезервированному адресу
  WriteProcessMemory(Process, Memory, @inject, sizeof(inject), BytesWritten);
  //выполнить машинный код
  hThread := CreateRemoteThread(Process, nil, 0, Memory, nil, 0, ThreadId);
  if hThread = 0 then Exit;
  CloseHandle(hThread);
  Result := True;
end;


?

Автор: DoZENT 10.1.2007, 18:56
Протрассировал процесс, не нашел ничего подозрительного. Хуки расставляются правильно, происходит вызов ZwQueryDirectoryFile, функцией возвращается какое-то числовое значение, и происходит вызов GetLastError... Ладно, буду копаться дальше  smile 

Автор: W4FhLF 10.1.2007, 19:55
Цитата(DoZENT @  10.1.2007,  18:04 Найти цитируемый пост)
если внедрение делается одной функцией, тогда зачем тем же автором создавалось такое:


Это инжектирование DLL в один отдельно взятый процесс. Ну а что делает код и так должно быть понятно.


Автор: dumb 11.1.2007, 04:26
Цитата(DoZENT @  10.1.2007,  18:56 Найти цитируемый пост)
функцией возвращается какое-то числовое значение, и происходит вызов GetLastError

какое значение? что возвращает GetLastError? всегда одни и те же значения?

Автор: MetalFan 11.1.2007, 09:50
Цитата(DoZENT @  9.1.2007,  16:33 Найти цитируемый пост)
Function MessageProc(code : integer; wParam : word;
                    lParam : longint) : longint; stdcall;
begin
 CallNextHookEx(0, Code, wParam, lparam);
 Result := 0;
end;

ммм... не нравится этот момент. а что, если другое приложение так-же поставила глоб.хук на GetMessage?
в MSDN вот что сказано по этому поводу:
Цитата

GetMsgProc Function
....
Return Value
If code is less than zero, the hook procedure must return the value returned by CallNextHookEx. 

If code is greater than or equal to zero, it is highly recommended that you call CallNextHookEx and return the value it returns; otherwise, other applications that have installed WH_GETMESSAGE hooks will not receive hook notifications and may behave incorrectly as a result. If the hook procedure does not call CallNextHookEx, the return value should be zero. 


может это и не то... но все-таки

Автор: dumb 11.1.2007, 10:09
Цитата(MetalFan @  11.1.2007,  09:50 Найти цитируемый пост)
может это и не то... но все-таки

угу, не то. хоть и сделано левой пяткой задней ноги, но на работу ZwQueryDirectoryFile это влияния не оказывает.

Автор: DoZENT 11.1.2007, 11:36
Цитата

может это и не то... но все-таки

Перехват функции осуществляется

Ладно, пойдем другим путем.
Кто-нибудь может привести ПОЛНЫЙ пример работы с библиотекой advApiHook? А то с wasm.ru ни сама библиотека, ни примеры ее использования не скачиваются smile

Автор: W4FhLF 11.1.2007, 15:11
Цитата

Кто-нибудь может привести ПОЛНЫЙ пример работы с библиотекой advApiHook? А то с wasm.ru ни сама библиотека, ни примеры ее использования не скачиваются 


Аттач.

Автор: Girder 11.1.2007, 17:33
Кстати... в факе есть пример использования драйверочков от FileMon smile 

Автор: DoZENT 11.1.2007, 18:55
Спасибо, с библиотекой я уже разобрался. Такой вопрос. Перехватываю ZwQueryDirectoryFile, обрабатываю результаты:

Код

function NewZwQueryDirectoryFile (FileHandle: dword;
                              Event: dword;
                              ApcRoutine: pointer;
                              ApcContext: pointer;
                              IoStatusBlock: pointer;
                              FileInformation: PVOID;
                              FileInformationLength: ULONG;
                              FileInformationClass: dword;
                              ReturnSingleEntry: bool;
                              FileName: PUnicodeString;
                              RestartScan: bool): NTStatus;
                              stdcall;
var
Name : string;
offset : dword;
DirInfo, DirInfo1 : PFILE_DIRECTORY_INFORMATION;
F : TextFile;
FileBothDirectoryInfo, LastFileBothDirectoryInfo : PFILE_BOTH_DIRECTORY_INFORMATION;
begin



  Result := TrueZwQueryDirectoryFile (FileHandle, Event, ApcRoutine, ApcContext,
            IoStatusBlock,FileInformation,FileInformationLength,
            FileInformationClass,ReturnSingleEntry,FileName,RestartScan);

Offset := 0;

if Result = STATUS_SUCCESS then
begin


  if FileInformationClass =  FileBothDirectoryInformation then
  begin
        FileBothDirectoryInfo := nil;
        repeat
          LastFileBothDirectoryInfo := FileBothDirectoryInfo;
         FileBothDirectoryInfo := PFILE_BOTH_DIRECTORY_INFORMATION(pointer(dword(FileInformation)));// + Offset));
         

          //Name := Copy(WideCharToString(FileBothDirectoryInfo.FileName), 1,FileBothDirectoryInfo.FileNameLength div 2); // без этой строчки работает нормально 
  
          Offset := Offset + FileBothDirectoryInfo.NextEntryOffset;
        until FileBothDirectoryInfo.NextEntryOffset = 0;
      end;



end;

end;

Процесс вылетает, если есть строчка 
Код

Name := Copy(WideCharToString(FileBothDirectoryInfo.FileName), 1, FileBothDirectoryInfo.FileNameLength div 2);

 В чем ошибка обработки smile 

Автор: W4FhLF 11.1.2007, 20:03
Ты б справчку по функции Copy и WideCharToString прочёл или посмотрел как она реализована. А потом бы глянул как переводится UNICODE в ASCII. Неверно ты их используешь.

Автор: DoZENT 11.1.2007, 21:59
Код

var
us : PUnicodeString;
         us.Length :=  FileBothDirectoryInfo.FileNameLength div 2;
         us.MaximumLength :=  FileBothDirectoryInfo.FileNameLength div 2;
         us.Buffer := FileBothDirectoryInfo.FileName;

         RtlUnicodeStringToAnsiString (Name, us, true);


Тоже не проходит, причем не выполняется ни одна из этих строк (если хоть одна присутствует, то процесс вылелает)  smile 

Автор: MetalFan 25.1.2007, 17:32
DoZENT, буду сегодня разбираться!
результат, если будет, все еще интересен?

Автор: drkot 25.1.2007, 17:50
Результат всегда интересен.

Автор: MetalFan 26.1.2007, 00:44
мда.
у MS-REM'а видимо спецом ошибочки затесались....
много читал MSDN и понял, что
FileName: PWideChar;
нифига не так,
а вот так:
FileName: WideChar;
ибо в MSDN анлгийским по белому написано:
Код

FileName 
Specifies the first character of the file name string. This is followed in memory by the remainder of the string. 

и еще один косяк в описании структуры...

Автор: Romikgy 26.1.2007, 09:50
MetalFan, имхо ты здесь не прав 

Цитата(MetalFan @  25.1.2007,  23:44 Найти цитируемый пост)
много читал MSDN и понял, что
FileName: PWideChar;
нифига не так,
а вот так:
FileName: WideChar;

не может быть название файла соостоящее из одного символа!

Автор: MetalFan 26.1.2007, 10:42
Romikgy, ;) конечно не может) а кто  сказал, что оно из одного символа.

ладно, вот что у меня вышло,
может кто явные недочеты укажет:

структура
Код

 FILE_BOTH_DIRECTORY_INFORMATION = packed record 
   NextEntryOffset: ULONG;
   Unknown: ULONG; 
   CreationTime,
   LastAccessTime,
   LastWriteTime, 
   ChangeTime,
   EndOfFile,
   AllocationSize: int64; 
   FileAttributes: ULONG; 
   FileNameLength: ULONG; 
   EaInformationLength: ULONG;
   AlternateNameLength: WORD; //здесь 2 байтя, а не 4, как у REM'a
   AlternateName: array [0..11] of WideChar; 
   FileName: WideChar; //и здесь не PWideChar
 end;

сама "перехваченная" функция
Код

   function NewZwQueryDirectoryFile (FileHandle: dword;
                              Event: dword;
                              ApcRoutine: pointer;
                              ApcContext: pointer;
                              IoStatusBlock: pointer;
                              FileInformation: pointer;
                              FileInformationLength: dword;
                              FileInformationClass: dword;
                              ReturnSingleEntry: bool;
                              FileName: PUnicodeString;
                              RestartScan: bool): NTStatus; stdcall;
   var
     lNamePWC: PWideChar;
     lNameW: WideString;

     lPrevPt, lPt: Pointer;
     lNextEntryOffset: ULONG;
     lSz: ULONG;
   begin
     Result := TrueZwQueryDirectoryFile( FileHandle,
                                         Event,
                                         ApcRoutine,
                                         ApcContext,
                                         IoStatusBlock,
                                         FileInformation,
                                         FileInformationLength,
                                         FileInformationClass,
                                         ReturnSingleEntry,
                                         FileName,
                                         RestartScan  );
     if not (FileInformationClass in [ FileDirectoryInformation,
                                  FileFullDirectoryInformation,
                                  FileBothDirectoryInformation,
                                  FileNamesInformation]) or
        (Result = STATUS_NO_SUCH_FILE) or
        (FileInformationLength = 0) then Exit;
     lPt := FileInformation;
     lPrevPt := nil;
     repeat
       lNextEntryOffset := ULONG(lPt^);
       //получаем информацию о имени файла...
       //в зависимости от структуры
       //з.ы. кроме FileBothDirectoryInformation ниразу другие значения не попались
       case FileInformationClass of
         FileDirectoryInformation:
         begin
           lSz := FILE_DIRECTORY_INFORMATION(lPt^).FileNameLength;
           lNamePWC := @FILE_DIRECTORY_INFORMATION(lPt^).FileName;
         end;
         FileFullDirectoryInformation:
         begin
           lSz := FILE_FULL_DIRECTORY_INFORMATION(lPt^).FileNameLength;
           lNamePWC := @FILE_FULL_DIRECTORY_INFORMATION(lPt^).FileName;
         end;
         FileBothDirectoryInformation:
         begin
           lSz := FILE_BOTH_DIRECTORY_INFORMATION(lPt^).FileNameLength;
           lNamePWC := @FILE_BOTH_DIRECTORY_INFORMATION(lPt^).FileName;
         end;
         FileNamesInformation:
         begin
           lSz := FILE_NAMES_INFORMATION(lPt^).FileNameLength;
           lNamePWC := @FILE_NAMES_INFORMATION(lPt^).FileName;
         end;
       end;
       //по скольку lNamePWC не всегда содержит завершающие нули,
       //то сразу использовать нельзя.
       //я сделал вот так, извращенно... 
       SetLength( lNameW, lSz div 2);
       Move( lNamePWC^, lNameW[1], lSz );
       //в lNameW имеем нормальное имя, которое можно отдать не стыдясь на сравнение
       if lstrcmpiW( @gHideFileNameW[1], @lNameW[1] ) = 0 then
       begin //нашли! принимаем решительые меры
         if lPt = FileInformation then
         begin //первая запись
           //этот код протестировать не удалось, возможны косяки
           if lNextEntryOffset <> 0 then
           begin
             lPt := Pointer(ULONG(lPt)+lNextEntryOffset);
             Move( lPt^, FileInformation^, FileInformationLength - lNextEntryOffset );
           end
           else
             Result := STATUS_NO_SUCH_FILE;
         end
         //далее срабатывало правильно
         else
         if lNextEntryOffset <> 0 then
         begin // если серединка
           ULONG(lPrevPt^) := ULONG(lPrevPt^) + lNextEntryOffset;
         end
         else //конетц
         begin
           ULONG(lPrevPt^) := 0;
         end;
         Break; //подменили? выходим из цикла
       end;
       lPrevPt := lPt;
       lPt := Pointer(ULONG(lPt)+lNextEntryOffset);
     until lNextEntryOffset = 0;
   end;


и вообще, часть статьи REM'а содрано слово слово из.. см.аттач
з.ы. уже сам нашел небольшой недочет в коде. точнее отсутсвие кода по одному замечанию из статьи...

Автор: Romikgy 26.1.2007, 11:48
Цитата(MetalFan @  26.1.2007,  09:42 Найти цитируемый пост)
 FileName: WideChar; //и здесь не PWideChar

сомневаюсь я в этом smile

Автор: MetalFan 26.1.2007, 12:55
Romikgy, сомневайся. а в MSDN написано именно так.

Автор: Romikgy 26.1.2007, 13:07
Цитата(MetalFan @  26.1.2007,  11:55 Найти цитируемый пост)
а в MSDN написано именно так.

ссылку можно?

Автор: MetalFan 26.1.2007, 13:17
Romikgy-неверующий! а самому посмотреть? вот ссылка
http://msdn2.microsoft.com/en-us/library/ms791526.aspx, 
кушайте на здоровье) smile 
и вообще, почему сомневаешься? smile  пробовал так, как у REM'а написано и все заработало? или просто посомневаться решил  smile 

Автор: Romikgy 26.1.2007, 13:24
это
Цитата

WCHAR  FileName[1];

не есть это

Цитата(MetalFan @  26.1.2007,  09:42 Найти цитируемый пост)
 FileName: WideChar; //и здесь не PWideChar

это есть вот это
Код


   FileName: array [0..0] of WideChar; 


Цитата(MetalFan @  26.1.2007,  12:17 Найти цитируемый пост)
или просто посомневаться решил

прально сомневался  smile

Добавлено @ 13:25 
Цитата(MetalFan @  26.1.2007,  12:17 Найти цитируемый пост)
Romikgy-неверующий!

угу очень smile 

Автор: MetalFan 26.1.2007, 13:27
Romikgy, а какая разница?! что так 2 байта, что так? ну может чуть удобнее в использовании. но никак не PWideChar, да?

Автор: Romikgy 26.1.2007, 13:28
хотя поидее и твой вариант должен работать
просто я таких объявлений как у тя ни разу не видел

Добавлено @ 13:29 
Цитата(MetalFan @  26.1.2007,  12:27 Найти цитируемый пост)
что так 2 байта, что так?

просто в твоем варианте имхо не красиво и не понятно smile
Цитата(MetalFan @  26.1.2007,  12:27 Найти цитируемый пост)
но никак не PWideChar, да?

да не это

Автор: MetalFan 26.1.2007, 14:06
Romikgy, да, согласен)
array[0..0] будет красивше) только Range Checking не забыть выключить. ну и все-равно контролировать FileNameLength придется, ибо наврядли в конце имени нули будут(сталкнулся с таким).

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)