Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 674
  • Last Modified:

File Creation

How do I monitor or detect a new creation of file?

I did test
http://www.osnews.com/story/7376/A-Directory-Monitor-Class-For-Delphi/page1/

Tthe problem is,  you have to specify each drive,  what if I have a..z drives.

So, is there a way to monitor file creation in all drives without specifying?

I did a proxy test with  ZwCreateFile,ZwWriteFile,ZwOpenFile, but it does not detect with this command;

procedure TfMainform.Button1Click(Sender: TObject);
begin
copyfile(application.exename, 'copytest.exe', false);
end;

Probably I need I callback, but I don't know how.
But,  if the problem is in the callback?


Thanks
I don't know which one is a callback.
Is it the TrueZwCreateFile? or the NewZwCreateFile?

function TrueZwCreateFile(
    OUT FileHandle:PHANDLE;
    const DesiredAccess:ACCESS_MASK;
    const ObjectAttributes:PObjectAttributes;
    OUT IoStatusBlock:PIO_STATUS_BLOCK;
    const AllocationSize : LARGE_INTEGER;
    const FileAttributes, ShareAccess, CreateDisposition,CreateOptions: ULONG;
    EaBuffer : PVOID;
    const EaLength :ULONG):NTStatus;
    stdcall;
var  Written: dword;
begin
  WriteProcessMemory(INVALID_HANDLE_VALUE, PtrZwq, @OldZwq, SizeOf(OldCode), Written);
  Result := ZwCreateFile(FileHandle,DesiredAccess,ObjectAttributes,IoStatusBlock,AllocationSize, FileAttributes, ShareAccess,CreateDisposition,CreateOptions, EaBuffer, EaLength);
  WriteProcessMemory(INVALID_HANDLE_VALUE, PtrZwq, @JmpZwq, SizeOf(far_jmp), Written);
end;
function NewZwCreateFile(
    OUT FileHandle:PHANDLE;
    const DesiredAccess:ACCESS_MASK;
    const ObjectAttributes:PObjectAttributes;
    OUT IoStatusBlock:PIO_STATUS_BLOCK;
    const AllocationSize : LARGE_INTEGER;
    const FileAttributes, ShareAccess, CreateDisposition,CreateOptions: ULONG;
    EaBuffer : PVOID;
    const EaLength :ULONG):NTStatus;
    stdcall;
var
fileName:string;
begin
fileName:= WideCharToString(ObjectAttributes^.ObjectName^.Buffer);

//access violation with this
if IoStatusBlock.Status = FILE_CREATED then
SendMessage(FindWindowEx(FindWindow('TForm1', nil), 0, 'TListBox', nil), LB_INSERTSTRING, 0, Integer(PChar('New Created')));


SendMessage(FindWindowEx(FindWindow('TForm1', nil), 0, 'TListBox', nil), LB_INSERTSTRING, 0, Integer(PChar(fileName)));
Result := TrueZwCreateFile(FileHandle,DesiredAccess,ObjectAttributes,IoStatusBlock,AllocationSize,FileAttributes, ShareAccess,CreateDisposition,CreateOptions,EaBuffer ,EaLength);
end;

Pep's the code is working, But it say's access violation when I click the Button1.

Any ideas?
Am I doing right?, with the callback?  huh, I don't even know what's the callback name I've write.

Open in new window

0
systan
Asked:
systan
  • 17
  • 7
1 Solution
 
epasquierCommented:
There are many Directory Notify/Monitor components, they all work pretty much the same, and no, none can monitor all drives at once as they are based on the same Windows API that works on a specific path.
But nothing can prevent you to create dynamically one such component for each drive.

Here is one free and simple : TDirNotify

http://www.carlosb.com/ctrl.php?fm=delphicomps
0
 
systanAuthor Commented:
epasquier;
thank you for that link, i'll deal with that later.

I know you are also flexible in programming different modules, with your overall experience in delphi I know you can help me with this,  even if you have a little? background of nt system programming.
So with that experience you are capable to help me with this.

First step;
Lets start with the callback, which one of them is the callback?
Is it the TrueZwCreateFile? or the NewZwCreateFile?
0
 
epasquierCommented:
I'm not too familiar with your code, but if I'm correct :

the function that is called by Windows is NewZwCreateFile , which calls TrueZwCreateFile, which in turn calls ZwCreateFile (after removing the hook to avoid infinite loop)
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
systanAuthor Commented:
So, TrueZwCreateFile is the callback ??
Here's the procedure that call's NewZwCreateFile
Procedure SetHook();
var
 Bytes: dword;
begin
  PtrZwq  := GetProcAddress(GetModuleHandle('ntdll.dll'),'ZwCreateFile');
  ReadProcessMemory(INVALID_HANDLE_VALUE, PtrZwq, @OldZwq, SizeOf(OldCode), Bytes);
  JmpZwq.PuhsOp  := $68;
  JmpZwq.PushArg := @NewZwCreateFile;
  JmpZwq.RetOp   := $C3;
  WriteProcessMemory(INVALID_HANDLE_VALUE, PtrZwq, @JmpZwq, SizeOf(far_jmp), Bytes);
end;

Open in new window

0
 
systanAuthor Commented:
Madshi's link, talking about file creation and deletion, but most talk about deletion.
http://forum.madshi.net/viewtopic.php?t=2639
0
 
epasquierCommented:
>> Here's the procedure that call's NewZwCreateFile

No, it does not call it. It replace IN ntdll the first instruction of ZwCreateFile with a call to your own. So next time somewhere this function is called, it will be in fact yours.
0
 
systanAuthor Commented:
Here's about ZwCreateFile
http://msdn.microsoft.com/en-us/library/ff566424%28v=VS.85%29.aspx

I'm not good in reading english programming sentences much more on understanding programming language writtings, so I really need help.
0
 
epasquierCommented:
one thing you need to understand is that when you are in NewZwCreateFile, you are WITHIN the API, not OUTSIDE it. Said otherwise, you have to reverse all the logic you might find in MSDN. When it says that a function will do this and that value can have this flag, that means that it is WHAT YOURS HAVE TO DO.
Or, in your case, since you are calling the real one, that you can only test the OUT parameters at the end of the function.

ALSO : Out reserved word in Delphi does not have the same meaning as in MSDN
"An out parameter, like a variable parameter, is passed by reference. With an out parameter, however, the initial value of the referenced variable is discarded by the routine it is passed to. The out parameter is for output only; that is, it tells the function or procedure where to store output, but doesn't provide any input."
Which means the value of the pointer is cleared and that is why you have an access violation.
function NewZwCreateFile(
    FileHandle:PHANDLE;
    const DesiredAccess:ACCESS_MASK;
    const ObjectAttributes:PObjectAttributes;
    IoStatusBlock:PIO_STATUS_BLOCK;
    const AllocationSize : LARGE_INTEGER;
    const FileAttributes, ShareAccess, CreateDisposition,CreateOptions: ULONG;
    EaBuffer : PVOID;
    const EaLength :ULONG):NTStatus;
    stdcall;
var
fileName:string;
begin
Result := TrueZwCreateFile(FileHandle,DesiredAccess,ObjectAttributes,IoStatusBlock,AllocationSize,FileAttributes, ShareAccess,CreateDisposition,CreateOptions,EaBuffer ,EaLength);

fileName:= WideCharToString(ObjectAttributes^.ObjectName^.Buffer);

//access violation with this
if Result And (IoStatusBlock.Status = FILE_CREATED) then
SendMessage(FindWindowEx(FindWindow('TForm1', nil), 0, 'TListBox', nil), LB_INSERTSTRING, 0, Integer(PChar('New Created')));


SendMessage(FindWindowEx(FindWindow('TForm1', nil), 0, 'TListBox', nil), LB_INSERTSTRING, 0, Integer(PChar(fileName)));

end;

Open in new window

0
 
systanAuthor Commented:
>>if Result And (IoStatusBlock.Status = FILE_CREATED) then
error on runtime;

if ( Result And IoStatusBlock.Status = FILE_CREATED) then
no error during runtime, but errors when I click the button with command copyfile

I guess its very hard, ok, ill test more code's....and .listening..



0
 
systanAuthor Commented:
epasquier;
I've analyze what you did, it's correct,  declaring the options/flags after the callback but include the (Result),
however, I have another idea;

Step 2;
Im getting the Allocationsize, but I can't, error during runtime;

if ( Result and AllocationSize<>0) then


What's the correct assignment for AllocationSize if not equal to zero?
0
 
systanAuthor Commented:
What's the correct assignment for AllocationSize if not equal to zero?  Please
0
 
epasquierCommented:
I don't understand your problem with AllocationSize. You simply pass it to the real ZwCreateFile, what else do you want to do with it ?

I think there is an error in your type definition for this parameter. First, it's a pointer. Second, here is the type from MSDN :
typedef union _LARGE_INTEGER {
  struct {
    DWORD LowPart;
    LONG  HighPart;
  } ;
  struct {
    DWORD LowPart;
    LONG  HighPart;
  } u;
  LONGLONG QuadPart;
} LARGE_INTEGER, *PLARGE_INTEGER;

but that is compatible with Int64, so your real definition should be PInt64

and when you want to use it, you must first see it it's assigned (<>nil)

if Assigned(AllocationSize) Then ShowMessageFmt('AllocationSize = %d', [ AllocationSize^ ] );
function NewZwCreateFile(
    FileHandle:pHandle;
    const DesiredAccess:ACCESS_MASK;
    const ObjectAttributes:PObjectAttributes;
    IoStatusBlock:PIO_STATUS_BLOCK;
    const AllocationSize : PInt64;
    const FileAttributes, ShareAccess, CreateDisposition,CreateOptions: Cardinal;
    EaBuffer : Pointer;
    const EaLength :Cardinal):NTStatus; stdcall;

Open in new window

0
 
systanAuthor Commented:
Thank you epasquier;
As you see I'm not really a delphi pro.
I test the AllocationSize, because, as I understand at CreateFile;
"
If AllocationSize is NULL, no allocation size is specified. If no file is created or overwritten, AllocationSize is ignored.
"
But it seems not working also, I don't know if I stop here, or just continue listening
Here's what I did in AllocationSize;
function NewZwCreateFile(
    FileHandle:pHandle;
    const DesiredAccess:ACCESS_MASK;
    const ObjectAttributes:PObjectAttributes;
    IoStatusBlock:PIO_STATUS_BLOCK;
    const AllocationSize : PInt64;
    const FileAttributes, ShareAccess, CreateDisposition,CreateOptions: Cardinal;
    EaBuffer : Pointer;
    const EaLength :Cardinal):NTStatus;
    stdcall;
var
fileName:string;
begin
fileName:= WideCharToString(ObjectAttributes^.ObjectName^.Buffer);
Result := TrueZwCreateFile(FileHandle,DesiredAccess,ObjectAttributes,IoStatusBlock,AllocationSize,FileAttributes, ShareAccess,CreateDisposition,CreateOptions,EaBuffer ,EaLength);

if ( Result and DesiredAccess <> 0) then
if Assigned(AllocationSize) then
begin
SendMessage(FindWindowEx(FindWindow('TForm1', nil), 0, 'TListBox', nil), LB_INSERTSTRING, 0, Integer(PChar(fileName+' created')));
end;
end;

Open in new window

0
 
systanAuthor Commented:
I also try this with NewZwOpenFile;
if ( Result and DesiredAccess = FILE_WRITE_ATTRIBUTES and SYNCHRONIZE and GENERIC_WRITE) then
if ( Result and OpenOptions = FILE_SYNCHRONOUS_IO_NONALERT and FILE_NON_DIRECTORY_FILE) then
SendMessage(FindWindowEx(FindWindow('TForm1', nil), 0, 'TListBox', nil), LB_INSERTSTRING, 0, Integer(PChar(fileName+' created')));
end;

But no luck to see file being created.
0
 
systanAuthor Commented:
All of a sudden, I think "ZwQueryVolumeInformationFile" is the answer here, but I can't fine a sample of the code snippet given to produce a NewZwQueryVolumeInformationFile.
0
 
epasquierCommented:
I don't think you have to test for the AllocationSize. A file could be created with that parameter not specified or 0, that just means that the system is not reserving any space for it, it just create an entry in the file table

besides, Result is not a boolean, and your former code was doing an AND binary operation between Result and DesiredAccess , which was only then compared to 0. No chance of that working.
You should always put brackets around single comparisons before using And/Or boolean operators. Delphi does not have the same operator priority than C/C++/Java etc...

Then, have you tested the sendmessage separately (with another app for example) ?
function NewZwCreateFile(
    FileHandle:pHandle;
    const DesiredAccess:ACCESS_MASK;
    const ObjectAttributes:PObjectAttributes;
    IoStatusBlock:PIO_STATUS_BLOCK;
    const AllocationSize : PInt64;
    const FileAttributes, ShareAccess, CreateDisposition,CreateOptions: Cardinal;
    EaBuffer : Pointer;
    const EaLength :Cardinal):NTStatus;
    stdcall;
var
 Msg:string;
 Hnd:THandle;
begin
 Result := TrueZwCreateFile(FileHandle,DesiredAccess,ObjectAttributes,
            IoStatusBlock,AllocationSize,FileAttributes,ShareAccess,
            CreateDisposition,CreateOptions,EaBuffer ,EaLength);
 if (Result=STATUS_SUCCESS) And (IoStatusBlock^.Information=FILE_CREATED)
  then 
   begin
    Msg:= WideCharToString(ObjectAttributes^.ObjectName^.Buffer)+' created';
    Hnd:=FindWindow('TForm1', nil); // you'll have to do better than that later
    if Hnd<>0 Then Hnd:=FindWindowEx(Hnd, 0, 'TListBox', nil);
    if Hnd<>0 Then SendMessage(Hnd,LB_INSERTSTRING, 0, Integer(PChar(Msg)));
   end;
end;

Open in new window

0
 
systanAuthor Commented:
I'm sorry epasquier but I've tested also that code snippet you've gave, its not detecting, I have to try another procedure.

But don't know if this can be done by a CBT hook, I hope may be it can.

While surfing the net I found this one, but only detects deleting files, but not files created or appended.
http://delphi.about.com/library/code/ncaa030403b.htm

But we'll stick on this Zwxxx or Ntxxx, its a superb functions.
0
 
systanAuthor Commented:
Step 3;
I know came up with ""ZwQueryVolumeInformationFile" but it seems I doubt, so I go to step 4
The "ZwWriteFile"
http://msdn.microsoft.com/en-us/library/ff567121%28v=VS.85%29.aspx
Buffer [in]
    Pointer to a caller-allocated buffer that contains the data to write to the file.

The result of the filename cant be read, it's ascii, how am I going to see it?
function NewZwWriteFile(
    const FileHandle: THANDLE;
    const Event:THANDLE;
    const ApcRoutine: Pointer;
    const ApcContext : Pointer;
    OUT   IoStatusBlock:PIO_STATUS_BLOCK;
    const Buffer : Pointer;
    const Length:cardinal;
    const ByteOffset: PInt64;
    const Key:PULONG): NTStatus;
    stdcall;
var
fileName:string;
begin
fileName:= WideCharToString(Buffer);
Result := TrueZwWriteFile(FileHandle,Event, ApcRoutine, ApcContext, IoStatusBlock, Buffer, Length, ByteOffset,Key);
SendMessage(FindWindowEx(FindWindow('TForm1', nil), 0, 'TListBox', nil), LB_INSERTSTRING, 0, Integer(PChar(fileName)));
end;

Open in new window

0
 
epasquierCommented:
The buffer is the data, not the file name. You have to use the FileHandle, and see if you can get the file name associated with it

http://msdn.microsoft.com/en-us/library/aa366789%28VS.85%29.aspx
0
 
systanAuthor Commented:
Actually I have that code;
But,
Buffer [in]
    Pointer to a caller-allocated buffer

So, I can get the application who has the buffer?
copyfile(application.exename, 'copytest.exe', false);

But I'll try to test your recommendations.
function GetFileNameFromHandle(hFile: THandle): string;
var
  dwFileSizeHi: Cardinal;
  dwFileSizeLo: Cardinal;
  hFileMap: Cardinal;
  pMem: Pointer;
begin
  Result := '';
  // Get the file size.
  dwFileSizeHi := 0;
  dwFileSizeLo := GetFileSize(hFile, @dwFileSizeHi);
  if (dwFileSizeLo = 0) and (dwFileSizeHi = 0) then
    exit;
  // Create a file mapping object.
  hFileMap := CreateFileMapping(hFile, nil, PAGE_READONLY, 0, 1, nil);
  if (hFileMap <> INVALID_HANDLE_VALUE) then
  try
    // Create a file mapping to get the file name.
    pMem := MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);
    if Assigned(pMem) then
    try
      SetLength(Result, MAX_PATH);
//    SetLength(Result, GetMappedFileName(GetCurrentProcess(), pMem, PChar(Result), MAX_PATH));
    finally
      UnmapViewOfFile(pMem);
    end;
  finally
    CloseHandle(hFileMap);
  end;
end;

Open in new window

0
 
systanAuthor Commented:
>>So, I can get the application who has the buffer?
Actually I want either of them, the source file or the destination file created.
I hope there is one possible function to do this kind of job.
0
 
systanAuthor Commented:
Oh, using ZwWriteFile if ZwCreateFile is called already, I have to research nore in this area.
0
 
systanAuthor Commented:
I doubt "ZwQueryVolumeInformationFile" is also be called.
0
 
systanAuthor Commented:
epasquier;
if you have the time to catch the problem, please do continue post here.

Thank you for the contribution, it helped me, specialy variables from plong to pint64 and others.
0

Featured Post

Vote for the Most Valuable Expert

It’s time to recognize experts that go above and beyond with helpful solutions and engagement on site. Choose from the top experts in the Hall of Fame or on the right rail of your favorite topic page. Look for the blue “Nominate” button on their profile to vote.

  • 17
  • 7
Tackle projects and never again get stuck behind a technical roadblock.
Join Now