• XSS.stack #1 – первый литературный журнал от юзеров форума

Перехват Api. Мониторинг файловой системы.

one_deal

RAID-массив
Пользователь
Регистрация
14.12.2019
Сообщения
58
Реакции
5
Доброго времени суток!

Хочу сделать в своем приложении мониторинг файловой системы:
удаление, перемещение, переименование, копирование файлов и дирректорий.

Хотелось бы узнать две вещи:

- Какие функции надо перехватить?
- В какой процесс внедрить свою длл, и как это проще сделать.

В идеале внедрить свою dll.

Т.е. надо из юзер мода. Без использования драйверов.

Если метод будет палиться антивирусом, не страшно,
главное чтобы корректно работало. ОС Windows 7.

Код:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

type
  TSaveRedir = packed record
    Addr: Pointer;
    Bytes: array[0..4] of Byte;
  end;

type
  PSaveRedir = ^TSaveRedir;

var
  S: TSaveRedir;

procedure RedirectCall(FromAddr, ToAddr: Pointer; SaveRedir: PSaveRedir);
var
  OldProtect: Cardinal;
  NewCode: packed record
    JMP: Byte;
    Distance: Integer;
  end;
begin
  VirtualProtect(FromAddr, 5, PAGE_EXECUTE_READWRITE, OldProtect);
  if Assigned(SaveRedir) then
  begin
    SaveRedir^.Addr := FromAddr;
    Move(FromAddr^, SaveRedir^.Bytes, 5);
  end;
  NewCode.JMP := $E9;
  NewCode.Distance := PChar(ToAddr) - PChar(FromAddr) - 5;
  Move(NewCode, FromAddr^, 5);
  VirtualProtect(FromAddr, 5, OldProtect, OldProtect);
end;

procedure UndoRedirectCall(const SaveRedir: TSaveRedir);
var
  OldProtect: Cardinal;
begin
  VirtualProtect(SaveRedir.Addr, 5, PAGE_EXECUTE_READWRITE, OldProtect);
  Move(SaveRedir.Bytes, SaveRedir.Addr^, 5);
  VirtualProtect(SaveRedir.Addr, 5, OldProtect, OldProtect);
end;

function MyNewMessageBox(Self: TApplication; const Text, Caption: PChar;
  Flags: Longint): Integer;
begin
  ShowMessage('New Messagebox');
  Result := 0;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Application.MessageBox('test', '!!!', MB_OK);
end;

initialization
  RedirectCall(@TApplication.MessageBox, @MyNewMessageBox, @S);

finalization
  UndoRedirectCall(S);

end.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Какие функции надо перехватить?
Все необходимые функции из ntdll.dll, в зависимости от того, какие именно действия нужно мониторить. NtCreateFile, NtOpenFile, NtWriteFile и другие. Но сначала было бы неплохо провести исследование целевого приложения на предмет того, какие функции оно для чего использует. Это удобно сделать с помощью Rohitab API Monitor. Может так сложиться (точнее скорее всего так сложится), что достаточно будет перехвата функций на уровне kernel32.dll, и не морочиться с функциями из ntdll.dll.

В какой процесс внедрить свою длл, и как это проще сделать
Очевидно тот, действия которого нужно мониторить, не?
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
тулз sysinternals
если ты о procmon, то там драйвер вроде как (и это правильный муть к мониторингу).

Еще можно через windows event tracing апи, но они адово сложные, наверное самые сложные из винапи вообще.

Также есть винапи FindFirstChangeNotification / ReadDirectoryChangesW , почитай описание, мб пригодятся.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
если ты о procmon, то там драйвер вроде как (и это правильный муть к мониторингу)
Именно так, причем в последних версиях они поднасрали людям, что сидят на семерках, подписав драйвер по-новому (каким-то хешем, которого по-умолчанию нет). И теперь, чтобы запускать его на семерках надо какую-то там KBшку ставить. Так тупо.
 
Также есть винапи FindFirstChangeNotification / ReadDirectoryChangesW , почитай описание, мб пригодятся.

Я начал с них, эта функция возвращает короткие имена файлов, и из за этого не понятно что происходит.

Может кому пригодится:
Код:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Menus, ComCtrls, ToolWin, StdCtrls;

type
  TForm1 = class(TForm)
    MainMenu1: TMainMenu;
    Menu1: TMenuItem;
    Close1: TMenuItem;
    StatusBar1: TStatusBar;
    ToolBar1: TToolBar;
    ToolButton1: TToolButton;
    Memo1: TMemo;
    Button1: TButton;
    Button2: TButton;
    procedure Close1Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1; 

type
  PFileNotifyInformation = ^TFileNotifyInformation;
  TFileNotifyInformation = record
    NextEntryOffset: DWORD;
    Action: DWORD;
    FileNameLength: DWORD;
    FileName: array [0..MAX_PATH - 1] of WideChar;
  end;

implementation

{$R *.dfm}

procedure TForm1.Close1Click(Sender: TObject);
begin
  Form1.Close;
end; //Close1Click

function GetModuleName: string;
var
  szFileName: array[0..MAX_PATH] of Char;
begin
  FillChar(szFileName, SizeOf(szFileName), #0);
  GetModuleFileName(hInstance, szFileName, MAX_PATH);
  Result := szFileName;
end; //GetModuleName

procedure TForm1.Button1Click(Sender: TObject);
const
  Filter =
  FILE_NOTIFY_CHANGE_FILE_NAME or
            FILE_NOTIFY_CHANGE_DIR_NAME or
            FILE_NOTIFY_CHANGE_ATTRIBUTES or
            FILE_NOTIFY_CHANGE_SIZE or
            FILE_NOTIFY_CHANGE_LAST_WRITE or
            FILE_NOTIFY_CHANGE_LAST_ACCESS or
            FILE_NOTIFY_CHANGE_CREATION or
            FILE_NOTIFY_CHANGE_SECURITY;
var
  Dir: THandle;
  BytesReturned: DWORD;     
  Notify: TFileNotifyInformation;
begin
  Dir := CreateFile('d:\', GENERIC_READ,
    FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
    nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
  if Dir <> INVALID_HANDLE_VALUE then
  try
    while true do
    begin
      Application.ProcessMessages;
      ZeroMemory(@Notify, SizeOf(Notify));
      if ReadDirectoryChangesW(
          Dir,
          @Notify,
          SizeOf(TFileNotifyInformation),
          False,
          Filter,
          @BytesReturned,
          nil,
          nil
      ) then
      begin
        case Notify.Action of
               
          FILE_ACTION_MODIFIED: Memo1.Lines.Add('FILE_ACTION_MODIFIED ' + 'd:\' + Notify.FileName);
         
          FILE_NOTIFY_CHANGE_LAST_WRITE: Memo1.Lines.Add('FILE_NOTIFY_CHANGE_LAST_WRITE ' + Notify.FileName);
          FILE_NOTIFY_CHANGE_FILE_NAME: Memo1.Lines.Add('FILE_NOTIFY_CHANGE_FILE_NAME ' + Notify.FileName);
          FILE_NOTIFY_CHANGE_DIR_NAME: Memo1.Lines.Add('FILE_NOTIFY_CHANGE_DIR_NAME ' + Notify.FileName);
          FILE_NOTIFY_CHANGE_CREATION: Memo1.Lines.Add('FILE_NOTIFY_CHANGE_CREATION ' + Notify.FileName);
          FILE_ACTION_RENAMED_OLD_NAME: Memo1.Lines.Add('Old Name file ' + Notify.FileName);
          FILE_ACTION_RENAMED_NEW_NAME: Memo1.Lines.Add('New Name file ' + Notify.FileName);
            
          //FILE_SHARE_READ: Memo1.Lines.Add('FILE_SHARE_READ' + Notify.FileName);
          //FILE_ACTION_ADDED: Memo1.Lines.Add('FILE_ACTION_ADDED ' + Notify.FileName);
          //FILE_ACTION_REMOVED: Memo1.Lines.Add('FILE_ACTION_REMOVED ' + Notify.FileName);
        end;
        Sleep(500);
      end;
    end;
  finally
    CloseHandle(Dir);
  end;
end; //Button1Click

procedure TForm1.Button2Click(Sender: TObject);
begin
  ShowMessage(ExtractFileName(GetModuleName));
end;

end.

С помощью api monitor выяснил что в процессе explorer.exe надо перехватывать MoveFileExW и DeleteFileW из shell32.dll.

Изначально планировал подгрузить свою dll через ключ реестра AppInit_DLLs.
Т.е. добавить свою длл в AppInit_DLLs, изменить значение LoadAppInit_DLLs в 1, и убрать RequireSignedAppInit_DLLs.

Кажется, этот способ не работает в Windows 7.

Теперь вопрос, как подгрузить свою длл в адрессное пространство explorer.exe?
Подойдет любой способ, даже если палится антивирусами.

Pid процесса определяю так:
Код:
function EnableDebugPrivilege(const Value: Boolean): Boolean;
const
  SE_DEBUG_NAME = 'SeDebugPrivilege';
var
  hToken: THandle;
  tp: TOKEN_PRIVILEGES;
  d: DWORD;
begin
  Result := False;
  if OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, hToken) then
  begin
    tp.PrivilegeCount := 1;
    LookupPrivilegeValue(nil, SE_DEBUG_NAME, tp.Privileges[0].Luid);
    if Value then
      tp.Privileges[0].Attributes := $00000002
    else
      tp.Privileges[0].Attributes := $80000000;
    AdjustTokenPrivileges(hToken, False, tp, SizeOf(TOKEN_PRIVILEGES), nil, d);
    if GetLastError = ERROR_SUCCESS then
    begin
      Result := True;
    end;
    CloseHandle(hToken);
  end;
end;

function DSiGetProcessID(const processName: string; var processID: DWORD): boolean;
  var
    hSnapshot: THandle;
    procEntry: TProcessEntry32;
  begin
    Result := false;
    hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if hSnapshot = 0 then
      Exit;
    try
      procEntry.dwSize := Sizeof(procEntry);
      if not Process32First(hSnapshot, procEntry) then
        Exit;
      repeat
        if AnsiSameText(procEntry.szExeFile, processName) then begin
          processID := procEntry.th32ProcessID;
          Result := true;
          break; // repeat
        end;
      until not Process32Next(hSnapshot, procEntry);
    finally //DSiCloseHandleAndNull(hSnapshot);
    end;
  end; { DSiGetProcessID }

Пробовал эти два способа:
Код:
function InjectDLL(dwPID: DWORD; DLLPath: PWideChar): integer;
var
  dwThreadID: Cardinal;
  hProc, hThread, hKernel: THandle;
  BytesToWrite, BytesWritten: Dword;
  pRemoteBuffer, pLoadLibrary: Pointer;
begin
  hProc := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_QUERY_INFORMATION or PROCESS_VM_OPERATION or PROCESS_VM_WRITE or PROCESS_VM_READ, False, dwPID);
  if hProc = 0 then
    exit;
  try
    BytesToWrite := SizeOf(WideChar)*(Length(DLLPath) + 1);
    pRemoteBuffer := VirtualAllocEx(hProc, nil, BytesToWrite, MEM_COMMIT, PAGE_READWRITE);
    if pRemoteBuffer = nil then
      exit;
    try
      if not WriteProcessMemory(hProc, pRemoteBuffer, DLLPath, BytesToWrite, BytesWritten) then
        exit;
      hKernel := GetModuleHandle('kernel32.dll');
      pLoadLibrary := GetProcAddress(hKernel, 'LoadLibraryW');
      hThread := CreateRemoteThread(hProc, nil, 0, pLoadLibrary, pRemoteBuffer, 0, dwThreadID);
      try
        WaitForSingleObject(hThread, INFINITE);
      finally
        CloseHandle(hThread);
      end;
    finally
      VirtualFreeEx(hProc, pRemoteBuffer, 0, MEM_RELEASE);
    end;
  finally
    CloseHandle(hProc);
  end;
  exit;
end;

{ Внедрение DLL альтернативным способом (без CreateRemoteThread) }
function InjectDllAlt(Process: dword; ModulePath: PChar): boolean;
var
  Context: _CONTEXT;
  hThread: dword;
  ProcessInfo: _PROCESS_BASIC_INFORMATION;
  InjData:  packed record
             OldEip: dword;
             OldEsi: dword;
             AdrLoadLibrary: pointer;
             AdrLibName: pointer;
            end;

  Procedure Injector();
  asm
    pushad
    db $E8              // опкод call short 0
    dd 0                //
    pop eax             // eax - адрес текущей инструкции
    add eax, $12
    mov [eax], esi      // модифицируем операнд dd $00000000
    push [esi + $0C]    // кладем в стек имя DLL
    call [esi + $08]    // call LoadLibraryA
    popad
    mov esi, [esi + $4] // восстанавливаем esi из старого контекста
    dw $25FF            // опкод Jmp dword ptr [00000000h]
    dd $00000000        // модифицируемый операнд
    ret
  end;
 
begin
  Result := false;
  //получаем id процесса
  ZwQueryInformationProcess(Process, ProcessBasicInformation,
                            @ProcessInfo,
                            SizeOf(_PROCESS_BASIC_INFORMATION), nil);
  //открываем первую попавшуюся нить
  hThread := OpenThread(THREAD_ALL_ACCESS, false,
                        SearchProcessThread(ProcessInfo.UniqueProcessId));
  if hThread = 0 then Exit;
  SuspendThread(hThread);
  //сохраняем старый контекст
  Context.ContextFlags := CONTEXT_FULL;
  GetThreadContext(hThread, Context);
  //подготавливаем данные для внедряемого кода
  InjData.OldEip := Context.Eip;
  InjData.OldEsi := Context.Esi;
  InjData.AdrLoadLibrary  := GetProcAddress(GetModuleHandle('kernel32.dll'),
                                            'LoadLibraryA');
  InjData.AdrLibName := InjectString(Process, ModulePath);
  if InjData.AdrLibName = nil then Exit;
  //внедряем данные и устанавливаем ebp контекста
  Context.Esi := dword(InjectMemory(Process, @InjData, SizeOf(InjData)));
  //внедряем код
  Context.Eip := dword(InjectMemory(Process, @Injector, SizeOfProc(@Injector)));
  //устанавливаем новый контекст
  SetThreadContext(hThread, Context);
  ResumeThread(hThread);
  Result := true;
end;

Чето них*я не работает.

В общем проблема, как загрузить свою dll в explorer.exe
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Пожалуйста, обратите внимание, что пользователь заблокирован
подписав драйвер по-новому (каким-то хешем, которого по-умолчанию нет). И теперь, чтобы запускать его на семерках надо какую-то там KBшку ставить. Так тупо.
Так семерку M$ уже не поддерживает, вот видимо и сделали так.
Хз, я юзаю старые версии (2018 года) процмона и прочих , и норм. Для вин2к/ХР можно взять filemon.

Теперь вопрос, как подгрузить свою длл в адрессное пространство explorer.exe?
Подойдет любой способ, даже если палится антивирусами.
AppInit должен работать на семерке , вот на ОС повыше там вроде нет (или обязательная подпись или вырезали, не помню). Ну или инжект обычный.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Так семерку M$ уже не поддерживает, вот видимо и сделали так.
Да понятно, просто часто приходится что-то исследовать или тестить на всех системах, и у меня семерка что-то типо общего знаменателя между всеми вендовыми системами, типа если наисследовал или протестил на семерке, то большая вероятность, что будет работать везде. А необходимость накатывать KBшку семерку раздрожает, приходится использовать старую версию прокмона.
 
Доброго времени суток!

Хочу сделать в своем приложении мониторинг файловой системы:
удаление, перемещение, переименование, копирование файлов и дирректорий.

Хотелось бы узнать две вещи:

- Какие функции надо перехватить?
- В какой процесс внедрить свою длл, и как это проще сделать.

В идеале внедрить свою dll.

Т.е. надо из юзер мода. Без использования драйверов.

Если метод будет палиться антивирусом, не страшно,
главное чтобы корректно работало. ОС Windows 7.

Код:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

type
  TSaveRedir = packed record
    Addr: Pointer;
    Bytes: array[0..4] of Byte;
  end;

type
  PSaveRedir = ^TSaveRedir;

var
  S: TSaveRedir;

procedure RedirectCall(FromAddr, ToAddr: Pointer; SaveRedir: PSaveRedir);
var
  OldProtect: Cardinal;
  NewCode: packed record
    JMP: Byte;
    Distance: Integer;
  end;
begin
  VirtualProtect(FromAddr, 5, PAGE_EXECUTE_READWRITE, OldProtect);
  if Assigned(SaveRedir) then
  begin
    SaveRedir^.Addr := FromAddr;
    Move(FromAddr^, SaveRedir^.Bytes, 5);
  end;
  NewCode.JMP := $E9;
  NewCode.Distance := PChar(ToAddr) - PChar(FromAddr) - 5;
  Move(NewCode, FromAddr^, 5);
  VirtualProtect(FromAddr, 5, OldProtect, OldProtect);
end;

procedure UndoRedirectCall(const SaveRedir: TSaveRedir);
var
  OldProtect: Cardinal;
begin
  VirtualProtect(SaveRedir.Addr, 5, PAGE_EXECUTE_READWRITE, OldProtect);
  Move(SaveRedir.Bytes, SaveRedir.Addr^, 5);
  VirtualProtect(SaveRedir.Addr, 5, OldProtect, OldProtect);
end;

function MyNewMessageBox(Self: TApplication; const Text, Caption: PChar;
  Flags: Longint): Integer;
begin
  ShowMessage('New Messagebox');
  Result := 0;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Application.MessageBox('test', '!!!', MB_OK);
end;

initialization
  RedirectCall(@TApplication.MessageBox, @MyNewMessageBox, @S);

finalization
  UndoRedirectCall(S);

end.
2 пути

1. функи из ntdll (как выше отпейсале)
2. пейсать свою реалезацею монеторенга и по таймеру шерстидь диск
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх