#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <tlhelp32.h>
#define STATUS_SUCCESS 0x00000000L


typedef LONG NTSTATUS;

typedef enum _FILE_INFORMATION_CLASS {
FileNameInformation=9,
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;

typedef struct _IO_STATUS_BLOCK {
    union {
        NTSTATUS Status;
        PVOID Pointer;
    };
    ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

typedef struct _FILE_NAME_INFORMATION {
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;

typedef struct _PARAM_FUNCT
{
	HANDLE handle;
	PFILE_NAME_INFORMATION* ptrpStructFileName;
}PARAMETRE_FUNC, *PPARAMETRE_FUNC;

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

typedef enum _POOL_TYPE {
    NonPagedPool,
    PagedPool,
    NonPagedPoolMustSucceed,
    DontUseThisType,
    NonPagedPoolCacheAligned,
    PagedPoolCacheAligned,
    NonPagedPoolCacheAlignedMustS,
    MaxPoolType,
    NonPagedPoolSession = 32,
    PagedPoolSession = NonPagedPoolSession + 1,
    NonPagedPoolMustSucceedSession = PagedPoolSession + 1,
    DontUseThisTypeSession = NonPagedPoolMustSucceedSession + 1,
    NonPagedPoolCacheAlignedSession = DontUseThisTypeSession + 1,
    PagedPoolCacheAlignedSession = NonPagedPoolCacheAlignedSession + 1,
    NonPagedPoolCacheAlignedMustSSession = PagedPoolCacheAlignedSession + 1,
} POOL_TYPE;

typedef struct _OBJECT_TYPE_INFORMATION {
UNICODE_STRING Name;
ULONG ObjectCount;
ULONG HandleCount;
ULONG Reserved1[4];
ULONG PeakObjectCount;
ULONG PeakHandleCount;
ULONG Reserved2[4];
ULONG InvalidAttributes;
GENERIC_MAPPING GenericMapping;
ULONG ValidAccess;
UCHAR Unknown;
BOOLEAN MaintainHandleDatabase;
POOL_TYPE PoolType;
ULONG PagedPoolUsage;
ULONG NonPagedPoolUsage;
} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;


typedef struct _OBJECT_NAME_INFORMATION {
UNICODE_STRING Name;
} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;

typedef enum _OBJECT_INFORMATION_CLASS
{
    ObjectBasicInformation,
    ObjectNameInformation,
    ObjectTypeInformation,
    ObjectAllTypesInformation,
    ObjectHandleInformation
} OBJECT_INFORMATION_CLASS;

typedef struct _SYSTEM_HANDLE_INFORMATION
{
    ULONG ProcessId;
    UCHAR ObjectTypeNumber;
    UCHAR Flags;
    USHORT Handle;
    PVOID Object;
    ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;

typedef enum _SYSTEM_INFORMATION_CLASS
{
	SystemHandleInformation = 16,
} SYSTEM_INFORMATION_CLASS;

long ThreadPourRecupererNom(PPARAMETRE_FUNC argument);
long NomProcessusToPid(char* process);
int CloseHandleInProcess(int pid ,HANDLE handleAClose );
long RetrouveHandleAClose(HANDLE handleProcSource,HANDLE handle,char* nameHandle,int pid);

typedef NTSTATUS (__stdcall *SYSTEMINFORMATION)( SYSTEM_INFORMATION_CLASS,PVOID,ULONG,PULONG );
typedef NTSTATUS (__stdcall *QUERYOBJECT)(HANDLE,OBJECT_INFORMATION_CLASS,PVOID,ULONG,PULONG);
typedef NTSTATUS (__stdcall *QUERYFILE)(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FILE_INFORMATION_CLASS);

int main(int argc,char* argv[])
{
    printf("Close a fucking file handle par 0vercl0k\n\n");
    long tailleStruct = sizeof(SYSTEM_HANDLE_INFORMATION) * 1000;
   	ULONG tailleTotal;
   	int i;
   	NTSTATUS retour;
   	PSYSTEM_HANDLE_INFORMATION ptrStructHandle = (PSYSTEM_HANDLE_INFORMATION)malloc(tailleStruct);
    SYSTEMINFORMATION ntQuerySystemInformation = (SYSTEMINFORMATION)GetProcAddress(GetModuleHandle("ntdll.dll") , "NtQuerySystemInformation");

    long pid = NomProcessusToPid(argv[1]);
    HANDLE handleProcess = OpenProcess( PROCESS_DUP_HANDLE , FALSE , pid );


    if( (pid == 0) || (ptrStructHandle == NULL) || (ntQuerySystemInformation == NULL) || (handleProcess == NULL))return 0;

    do
    {
        retour = ntQuerySystemInformation(SystemHandleInformation,ptrStructHandle,tailleStruct,&tailleTotal);
        tailleStruct *= 2;
        ptrStructHandle = (PSYSTEM_HANDLE_INFORMATION)realloc(ptrStructHandle,tailleStruct);
    }while(retour != STATUS_SUCCESS);

    long nbrHandle = (tailleTotal / sizeof(SYSTEM_HANDLE_INFORMATION));
    printf("[+] PID : %ld      Nombre Handles total : %ld\n\n",pid,nbrHandle);

    ptrStructHandle = (PSYSTEM_HANDLE_INFORMATION)((PUCHAR)ptrStructHandle + sizeof(ULONG)); //ntQuerySystemInformation renvoit au niveau du buffer un ULONG ( nombre de handle ) suivit de l'array de struct.
    for(i = 0 ; i < nbrHandle ; i++)
    {
        if( (ptrStructHandle->ProcessId) == pid)
        {
            if(RetrouveHandleAClose(handleProcess,(HANDLE)ptrStructHandle->Handle,"\\lolz.txt",pid) == 1)break;
        }
        ptrStructHandle++;
    }
    free(ptrStructHandle);
    CloseHandle(handleProcess);
    return 0;
}

int CloseHandleInProcess(int pid ,HANDLE handleAClose )
{
    HANDLE handleProcess = OpenProcess( PROCESS_ALL_ACCESS , FALSE , pid );

    if(handleProcess == NULL  ){printf("[!]OpenProcess\n");return 0;}

    DWORD identThread;
    LPTHREAD_START_ROUTINE addrCloseHandle = (LPTHREAD_START_ROUTINE)GetProcAddress(LoadLibrary("kernel32"),"CloseHandle");
    HANDLE retourFonctionRemoteThread = CreateRemoteThread( handleProcess , NULL , 0 , addrCloseHandle , handleAClose , 0 , &identThread );
    if(retourFonctionRemoteThread == NULL){printf("[!]CreateRemoteThread\n");return 0;}

    WaitForSingleObject(retourFonctionRemoteThread,INFINITE);

    CloseHandle(retourFonctionRemoteThread);
    CloseHandle(handleProcess);
    printf("\n\n\t[+]Handle closed.\n");
}

long NomProcessusToPid(char* process)
{
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
    PROCESSENTRY32 structprocsnapshot = {0};

    structprocsnapshot.dwSize = sizeof(PROCESSENTRY32);

    if(snapshot == INVALID_HANDLE_VALUE)return 0;
    if(Process32First(snapshot,&structprocsnapshot) == FALSE)return 0;

    while(Process32Next(snapshot,&structprocsnapshot) )
    {
       if(!strcmp(structprocsnapshot.szExeFile,process))
       {
            CloseHandle(snapshot);
            return structprocsnapshot.th32ProcessID;
       }
    }
    CloseHandle(snapshot);
    return 0;
}

long ThreadPourRecupererNom(PPARAMETRE_FUNC argument)
{
    QUERYFILE ntQueryInformationFile = (QUERYFILE)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtQueryInformationFile");
    IO_STATUS_BLOCK outFunct;

    if(ntQueryInformationFile == NULL)return 0;
   *(argument->ptrpStructFileName) = (PFILE_NAME_INFORMATION)malloc(MAX_PATH); //[..]the name is limited to MAX_PATH characters
    memset(*(argument->ptrpStructFileName),0,MAX_PATH);

    NTSTATUS retour = ntQueryInformationFile(argument->handle,&outFunct,*(argument->ptrpStructFileName),MAX_PATH,FileNameInformation);
    return retour;
}

long RetrouveHandleAClose(HANDLE handleProcSource,HANDLE handle,char* nameHandle,int pid)
{
    HANDLE targetHandle , handleThread;
    QUERYOBJECT ntQueryObject = (QUERYOBJECT)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtQueryObject");
    POBJECT_TYPE_INFORMATION ptrStructType = NULL;
    POBJECT_NAME_INFORMATION ptrStructName = NULL;
    PFILE_NAME_INFORMATION ptrStructFileName = NULL;

    ULONG taille;
    PARAMETRE_FUNC thParam ;

    int retour = DuplicateHandle(handleProcSource,(HANDLE)handle,GetCurrentProcess(),&targetHandle,0,false,DUPLICATE_SAME_ACCESS);

    NTSTATUS retour2 = ntQueryObject(targetHandle,ObjectTypeInformation,NULL,0,&taille); //type
    ptrStructType = (POBJECT_TYPE_INFORMATION)malloc(taille);

    retour2 = ntQueryObject(targetHandle,ObjectTypeInformation,ptrStructType,taille,&taille);
    if(retour2 != STATUS_SUCCESS)return 0;


    wprintf(L" - type : %s    ",ptrStructType->Name.Buffer);

    if(lstrcmpW(ptrStructType->Name.Buffer,L"File") == 0)
    {
        thParam.handle = targetHandle;
        thParam.ptrpStructFileName = &ptrStructFileName;

        DWORD tid;
        handleThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadPourRecupererNom,&thParam,0,&tid);
        if(WaitForSingleObject(handleThread,133) == WAIT_TIMEOUT)
        {
            TerminateThread(handleThread,0);//au revoir petit con :)
        }
        wprintf(L"%s",ptrStructFileName->FileName);
        char buff[MAX_PATH];
        WideCharToMultiByte(CP_ACP,0,ptrStructFileName->FileName,MAX_PATH,buff,MAX_PATH,NULL,NULL);
        CloseHandle(handleThread);
        free(ptrStructFileName);
        memset(ptrStructFileName,0,MAX_PATH);

        if(!strcmp(buff,nameHandle))
        {
            free(buff);
            CloseHandleInProcess(pid,handle);
            return 1;
        }
        free(buff);

    }
    else
    {
        NTSTATUS retour3 = ntQueryObject(targetHandle,ObjectNameInformation,NULL,0,&taille);//name
        ptrStructName = (POBJECT_NAME_INFORMATION)malloc(taille);

        retour3 = ntQueryObject(targetHandle,ObjectNameInformation,ptrStructName,taille,&taille);

        if(retour3 != STATUS_SUCCESS)return 0;
        if(ptrStructName->Name.Length)wprintf(L"Name : %s",ptrStructName->Name.Buffer);
    }

    printf("\n");

    CloseHandle(targetHandle);
    free(ptrStructName);
    free(ptrStructType);
}