Home | Chi sono | Contattami
 

Progr. lineare

Delphi
  Componenti
 
Database
 
Miei articoli

Windows

Miei articoli



 

Eliminazione di un file: arrivare all' api di base
 

2 Novembre 2007 

In questo post mi scollego solo temporaneamente col flusso di byte generato nei post precedenti per annotare una semplice informazione utile per programmi di monitoraggio. A volte mi capita di leggere nei forum la richiesta non rara di intercettare la cancellazione di un file e eventualmente annullarla (o in ogni caso loggare l'evento, etc...). Avrò guardato nei posti sbagliati ma non ho mai trovato qualcuno che abbia dato la risposta a queto semplice quesito (sicuramente ho cercato poco). Comunque la risposta è semplicissima: l'api più bassa che viene chiamata nell'ambito della procedura di eliminazione di un file è l'api Native (esportata da ntdll.dll) NtSetInfomationFile

type

  FILE_INFORMATION_CLASS = (
    FileFiller0,
    FileDirectoryInformation, // 1
    FileFullDirectoryInformation, // 2
    FileBothDirectoryInformation, // 3
    FileBasicInformation, // 4  wdm
    FileStandardInformation, // 5  wdm
    FileInternalInformation, // 6
    FileEaInformation, // 7
    FileAccessInformation, // 8
    FileNameInformation, // 9
    FileRenameInformation, // 10
    FileLinkInformation, // 11
    FileNamesInformation, // 12
    FileDispositionInformation, // 13
    FilePositionInformation, // 14 wdm
    FileFullEaInformation, // 15
    FileModeInformation, // 16
    FileAlignmentInformation, // 17
    FileAllInformation, // 18
    FileAllocationInformation, // 19
    FileEndOfFileInformation, // 20 wdm
    FileAlternateNameInformation, // 21
    FileStreamInformation, // 22
    FilePipeInformation, // 23
    FilePipeLocalInformation, // 24
    FilePipeRemoteInformation, // 25
    FileMailslotQueryInformation, // 26
    FileMailslotSetInformation, // 27
    FileCompressionInformation, // 28
    FileObjectIdInformation, // 29
    FileCompletionInformation, // 30
    FileMoveClusterInformation, // 31
    FileQuotaInformation, // 32
    FileReparsePointInformation, // 33
    FileNetworkOpenInformation, // 34
    FileAttributeTagInformation, // 35
    FileTrackingInformation, // 36
    FileMaximumInformation);

  IO_STATUS_BLOCK = record
    Status: integer;
    Information: Cardinal;
  end;
  PIO_STATUS_BLOCK = ^IO_STATUS_BLOCK;

  //tipologia dell'informazione passata
  //(dato puntato dal parametro FileInformation
  //di NtSetInformationFile)
  FILE_DISPOSITION_INFORMATION = record
    DeleteFile: Boolean; //True se si vuole eliminare il file
  end;
  PFILE_DISPOSITION_INFORMATION = ^FILE_DISPOSITION_INFORMATION;

function  NtSetInformationFile(
    FileHandle : Cardinal; //handle al file
    IoStatusBlock : PIO_STATUS_BLOCK;
    //puntatore al record contenente le informazioni
    //che voglio settare sul file
    FileInformation : Pointer;
    FileInformationLength : Cardinal;
    FileInformationClass : FILE_INFORMATION_CLASS
  ): integer; stdcall; external 'ntdll.dll';

Nel caso di eliminazione di un file, l'api NtSetInformationFile verrà chiamata con i seguenti parametri

1) FileInformation punta ad un record di tipo FILE_DISPOSITION_INFORMATION con il campo DeleteFile settato a True

2) FileInformationClass ha valore FileDispositionInformation (valore 13)

Tutto qui: in un programma che esegue un hook system wide sull'api NtSetInformationFile, basta verificare se ci sono queste impostazioni ed allora significa che si sta effettuando la cancellazione di un file (il primo parametro ossia FileHandle è appunto l'handle a tale file). Per ottenere il nome del file con percorso completo a partire dall'handle si può usare il codice seguente 

type

  OBJECT_INFORMATION_CLASS = (
    ObjectBasicInformation,
    ObjectNameInformation,
    ObjectTypeInformation,
    ObjectAllTypesInformation,
    ObjectHandleInformation);

  PUNICODE_STRING = ^UNICODE_STRING;
  UNICODE_STRING = record
    Length: word;
    MaximumLength: word;
    Buffer: pWideChar;
  end;

  OBJECT_NAME_INFORMATION = record
    Name: UNICODE_STRING;
  end;
  POBJECT_NAME_INFORMATION = ^OBJECT_NAME_INFORMATION;

function NtQueryObject(
    ObjectHandle : Cardinal;
    ObjectInformationClass : OBJECT_INFORMATION_CLASS;
    ObjectInformation : Pointer;
    ObjectInformationLength : Cardinal;
    ReturnLength : pCardinal
  ): Integer; stdcall; external 'ntdll.dll'  

function QueryDosDeviceA(
             lpDeviceName: pAnsiChar;
             lpTargetPath: pAnsiChar;
             ucchMax: Cardinal
             ): Cardinal; stdcall; external 'kernel32.dll'

//dato un handle ad un file o ad una directory, ne resituisce il
//percorso completo
function DirNameFromHandle(dirHandle: THandle): string;
const BUFSIZE = 1024;
var
  pObjectNameInformation: POBJECT_NAME_INFORMATION;//Pointer;
  ObjectNameInformationLength: cardinal;
  NomeDir: string;
  pResponse: cardinal;
  rl: Cardinna;

  devName: string;
  x: Cardinal;
  DrvLetter: char;
  Drv: string;
begin

  GetMem(pObjectNameInformation, 10000);
  NtQueryObject(dirHandle,
                ObjectNameInformation,
                pObjectNameInformation,
                10000,
                @rl);
  NomeDir := WideCharToString(pObjectNameInformation.Name.Buffer);
  Freemem(pObjectNameInformation);

  for DrvLetter:= 'A' to 'Z' do
    begin
      Drv:= DrvLetter+':';
      SetLength(devName, BufSize);
      x:= QueryDosDeviceA(pchar(Drv), pchar(devName), BufSize-1);
      SetLength(devName, x-2);
      if Pos(devName, NomeDir) <> 0 then
        begin
          NomeDir:= StringReplace(NomeDir, devName, Drv, []);
          break;
        end;
    end;

  result := NomeDir;

end;

 L'utilizzo della NtSetInformationFile con i suddetti parametri in caso di cancellazione di un file è argomento trattato nel famoso libro Undocumented Windows Native API di Gary Nebbet. Tuttavia per questo e altre analisi sugli internals di Windows, una fonte di informazione di primaria importanza sono i sorgenti di ReactOS . La versione attuale (3 Novembre 2007) è la 0.3.3. Partendo dall'implementazione della CommandLine (cmd.exe) nella cartella base\shell\cmd, iniziando dal main in cmd.c si passa all'implementazione del comando del in del.c: tale implementazione chiama l'api win32 DeleteFile implementata in dll\win32\kernel32\file\delete.c ; l'implementazione è la seguente

/* $Id: delete.c 21253 2006-03-08 21:33:04Z audit $
 *
 * COPYRIGHT:       See COPYING in the top level directory
 * PROJECT:         ReactOS system libraries
 * FILE:            lib/kernel32/file/delete.c
 * PURPOSE:         Deleting files
 * PROGRAMMER:      Ariadne (ariadne@xs4all.nl)
 * UPDATE HISTORY:
 *                  Created 01/11/98
 */

/* INCLUDES ****************************************************************/

#include <k32.h>

#define NDEBUG
#include "../include/debug.h"

/* FUNCTIONS ****************************************************************/

/*
 * @implemented
 */
BOOL
STDCALL
DeleteFileA (
    LPCSTR    lpFileName
    )
{
    PWCHAR FileNameW;

   if (!(FileNameW = FilenameA2W(lpFileName, FALSE)))
      return FALSE;

    return DeleteFileW (FileNameW);
}

/*
 * @implemented
 */
BOOL
STDCALL
DeleteFileW (
    LPCWSTR    lpFileName
    )
{
    FILE_DISPOSITION_INFORMATION FileDispInfo;
    OBJECT_ATTRIBUTES ObjectAttributes;
    IO_STATUS_BLOCK IoStatusBlock;
    UNICODE_STRING NtPathU;
    HANDLE FileHandle;
    NTSTATUS Status;

    DPRINT("DeleteFileW (lpFileName %S)\n",lpFileName);

    if (!RtlDosPathNameToNtPathName_U (lpFileName,
                                       &NtPathU,
                                       NULL,
                                       NULL))
   {
      SetLastError(ERROR_PATH_NOT_FOUND);
        return FALSE;
   }

    DPRINT("NtPathU \'%wZ\'\n", &NtPathU);

        InitializeObjectAttributes(&ObjectAttributes,
                                   &NtPathU,
                                   OBJ_CASE_INSENSITIVE,
                                   NULL,
                                   NULL);

    Status = NtCreateFile (&FileHandle,
                           DELETE,
                           &ObjectAttributes,
                           &IoStatusBlock,
                           NULL,
                           FILE_ATTRIBUTE_NORMAL,
                           FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                           FILE_OPEN,
                               FILE_NON_DIRECTORY_FILE,
                           NULL,
                           0);

    RtlFreeHeap(RtlGetProcessHeap(),
                    0,
                    NtPathU.Buffer);

    if (!NT_SUCCESS(Status))
    {
        CHECKPOINT;
        SetLastErrorByStatus (Status);
        return FALSE;
    }

    FileDispInfo.DeleteFile = TRUE;

    Status = NtSetInformationFile (FileHandle,
                                   &IoStatusBlock,
                                   &FileDispInfo,
                                   sizeof(FILE_DISPOSITION_INFORMATION),
                                   FileDispositionInformation);
    if (!NT_SUCCESS(Status))
    {
        CHECKPOINT;
        NtClose (FileHandle);
        SetLastErrorByStatus (Status);
        return FALSE;
    }

    Status = NtClose (FileHandle);
    if (!NT_SUCCESS (Status))
    {
        CHECKPOINT;
        SetLastErrorByStatus (Status);
        return FALSE;
    }

    return TRUE;
}

/* EOF */

Si vede chiaramente come il fulcro di tutto sia la chiamata a NtSetInformationFile con le impostazioni descritte in precedenza


 

 
 
Your Ad Here