I modified a windows driver that spoofs hard disk number by generating a random serial, I modified it to spoof a pre-known serial, now when it get loaded and query for the first time via wmi for the serial then it shows the pre-defined serial, but if I query again, it shows an empty string.
The driver implementation:
#include <ntifs.h>
#include <Ntdddisk.h>
#include <windef.h>
#include "main.h"
#include <sys/stat.h>
#include <tchar.h>
#include <stdio.h>
#include <winapifamily.h>
#include <iostream.h>
#include <sys/stat.h>
#include <Ntstrsafe.h>
PDRIVER_DISPATCH RealDiskDeviceControl = NULL;
char NumTable[] = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char SpoofedHWID[] = "XYXYXYYYYYXYXXYXYYYXXYYXXXXYYXYYYXYYX\0";
BOOL HWIDGenerated = 0;
char* newDiskId = "WD-WMATV3142957\0";
typedef struct _WIN32_FIND_DATA {
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD dwReserved0;
DWORD dwReserved1;
TCHAR cFileName[MAX_PATH];
TCHAR cAlternateFileName[14];
} WIN32_FIND_DATA, *PWIN32_FIND_DATA, *LPWIN32_FIND_DATA;
PDRIVER_OBJECT GetDriverObject(PUNICODE_STRING DriverName)
{
PDRIVER_OBJECT DrvObject;
if (NT_SUCCESS(ObReferenceObjectByName(DriverName, 0, NULL, 0, *IoDriverObjectType, KernelMode, NULL, &DrvObject)))
{
return DrvObject;
}
return NULL;
}
NTSTATUS SpoofSerialNumber(char* serialNumber)
{
//RtlSecureZeroMemory
if (!HWIDGenerated)
{
HWIDGenerated = 1;
size_t newDiskIdLen = 0;
RtlStringCchLengthA(newDiskId, NTSTRSAFE_MAX_CCH, &newDiskIdLen);
RtlCopyMemory((void*)serialNumber, (void*)newDiskId, ++newDiskIdLen);
}
return STATUS_SUCCESS;
}
NTSTATUS StorageQueryCompletionRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
{
PIO_COMPLETION_ROUTINE OldCompletionRoutine = NULL;
PVOID OldContext = NULL;
ULONG OutputBufferLength = 0;
PSTORAGE_DEVICE_DESCRIPTOR descriptor = NULL;
if (Context != NULL)
{
REQUEST_STRUCT* pRequest = (REQUEST_STRUCT*)Context;
OldCompletionRoutine = pRequest->OldRoutine;
OldContext = pRequest->OldContext;
OutputBufferLength = pRequest->OutputBufferLength;
descriptor = pRequest->StorageDescriptor;
ExFreePool(Context);
}
if (FIELD_OFFSET(STORAGE_DEVICE_DESCRIPTOR, SerialNumberOffset) < OutputBufferLength && descriptor->SerialNumberOffset > 0 && descriptor->SerialNumberOffset < OutputBufferLength)
{
char* SerialNumber = ((char*)descriptor) + descriptor->SerialNumberOffset;
size_t SerialNumberLen = 0;
RtlStringCchLengthA(SerialNumber, NTSTRSAFE_MAX_CCH, &SerialNumberLen);
RtlSecureZeroMemory(SerialNumber, SerialNumberLen);
SpoofSerialNumber(SerialNumber);
}
if ((Irp->StackCount >(ULONG)1) && (OldCompletionRoutine != NULL))
return OldCompletionRoutine(DeviceObject, Irp, OldContext);
return STATUS_SUCCESS;
}
NTSTATUS SmartCompletionRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
{
UNREFERENCED_PARAMETER(DeviceObject);
PIO_COMPLETION_ROUTINE OldCompletionRoutine = NULL;
PVOID OldContext = NULL;
if (Context != NULL)
{
REQUEST_STRUCT* pRequest = (REQUEST_STRUCT*)Context;
OldCompletionRoutine = pRequest->OldRoutine;
OldContext = pRequest->OldContext;
ExFreePool(Context);
}
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
return Irp->IoStatus.Status;
}
NTSTATUS DiskDriverDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
PIO_STACK_LOCATION Io = IoGetCurrentIrpStackLocation(Irp);
switch (Io->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_STORAGE_QUERY_PROPERTY:
{
PSTORAGE_PROPERTY_QUERY query = (PSTORAGE_PROPERTY_QUERY)Irp->AssociatedIrp.SystemBuffer;
if (query->PropertyId == StorageDeviceProperty)
{
Io->Control = 0;
Io->Control |= SL_INVOKE_ON_SUCCESS;
PVOID OldContext = Io->Context;
Io->Context = (PVOID)ExAllocatePool(NonPagedPool, sizeof(REQUEST_STRUCT));
REQUEST_STRUCT *pRequest = (REQUEST_STRUCT*)Io->Context;
pRequest->OldRoutine = Io->CompletionRoutine;
pRequest->OldContext = OldContext;
pRequest->OutputBufferLength = Io->Parameters.DeviceIoControl.OutputBufferLength;
pRequest->StorageDescriptor = (PSTORAGE_DEVICE_DESCRIPTOR)Irp->AssociatedIrp.SystemBuffer;
Io->CompletionRoutine = (PIO_COMPLETION_ROUTINE)StorageQueryCompletionRoutine;
}
break;
}
case SMART_RCV_DRIVE_DATA:
{
Io->Control = 0;
Io->Control |= SL_INVOKE_ON_SUCCESS;
PVOID OldContext = Io->Context;
Io->Context = (PVOID)ExAllocatePool(NonPagedPool, sizeof(REQUEST_STRUCT));
REQUEST_STRUCT *pRequest = (REQUEST_STRUCT*)Io->Context;
pRequest->OldRoutine = Io->CompletionRoutine;
pRequest->OldContext = OldContext;
Io->CompletionRoutine = (PIO_COMPLETION_ROUTINE)SmartCompletionRoutine;
break;
}
}
return RealDiskDeviceControl(DeviceObject, Irp);
}
NTSTATUS UnsupportedDispatch(
_In_ struct _DEVICE_OBJECT *DeviceObject,
_Inout_ struct _IRP *Irp
)
{
UNREFERENCED_PARAMETER(DeviceObject);
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Irp->IoStatus.Status;
}
NTSTATUS CreateDispatch(
_In_ struct _DEVICE_OBJECT *DeviceObject,
_Inout_ struct _IRP *Irp
)
{
UNREFERENCED_PARAMETER(DeviceObject);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Irp->IoStatus.Status;
}
NTSTATUS CloseDispatch(_In_ struct _DEVICE_OBJECT *DeviceObject, _Inout_ struct _IRP *Irp
)
{
UNREFERENCED_PARAMETER(DeviceObject);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Irp->IoStatus.Status;
}
NTSTATUS DriverEntry(_In_ struct _DRIVER_OBJECT *DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING diskDrvName;
RtlInitUnicodeString(&diskDrvName, L"\\Driver\\disk");
PDRIVER_OBJECT diskDrvObj = GetDriverObject(&diskDrvName);
RealDiskDeviceControl = diskDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL];
diskDrvObj->DriverInit = &DriverEntry;
diskDrvObj->DriverStart = (PVOID)DriverObject;
diskDrvObj->DriverSize = (ULONG)RegistryPath;
diskDrvObj->FastIoDispatch = NULL;
diskDrvObj->DriverStartIo = NULL;
diskDrvObj->DriverUnload = NULL;
/*for (ULONG t = 0; t <= IRP_MJ_MAXIMUM_FUNCTION; t++)
diskDrvObj->MajorFunction[t] = &UnsupportedDispatch;*/
diskDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = &DiskDriverDispatch;
/*diskDrvObj->MajorFunction[IRP_MJ_CREATE] = &CreateDispatch;
diskDrvObj->MajorFunction[IRP_MJ_CLOSE] = &CloseDispatch;*/
return status;
}
NTSTATUS SpoofSerialNumber(char* serialNumber)
{
//RtlSecureZeroMemory
if (!HWIDGenerated)
{
HWIDGenerated = 1;
There's your issue, I'm not sure if your using this for game-cheating purposes but if you are this is detected on all major anticheats (maybe not eac but def BE). The reason it only spoofs once is due to the very unusual code in this driver which makes it only spoof once (defeating the whole purpose of hooking disks dispatch routine), this is hwidfaker from github which is not a great example to see how spoofers work its quite simple and unorganized (its pasted).
i am trying to hook the CreateProcess under cmd.exe.
i manage to inject the dll the the cmd process but after the injection the dll process detach message receive and i fail to hook the createprocess function call.
i am using easyhook.
my code:
#include <windows.h>
#include <Shlwapi.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#include <easyhook.h>
BOOL WINAPI myCreateProcess(
_In_opt_ LPCTSTR lpApplicationName,
_Inout_opt_ LPTSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCTSTR lpCurrentDirectory,
_In_ LPSTARTUPINFO lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation
){
OutputDebugString(L"\n !!!!!! In CreateProcess HOOK\n !!!!!!!!");
return CreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCommandLine, lpStartupInfo, lpProcessInformation);
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
BOOL bErrorFlag = FALSE;
DWORD dwBytesToWrite = (DWORD)strlen(DataBuffer);
DWORD dwBytesWritten = 0;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
HOOK_TRACE_INFO hHook = { NULL }; // keep track of our hook
// Install the hook
NTSTATUS result = LhInstallHook(
GetProcAddress(GetModuleHandle(TEXT("kernel32")), "CreateProcessW"),
myCreateProcess,
NULL,
&hHook);
if (FAILED(result))
{
OutputDebugString(L"!!!!!!!!!!!FAIL!!!!!!!!");
return 1;
}
ULONG ACLEntries[1] = { 0 };
LhSetInclusiveACL(ACLEntries, 1, &hHook);
OutputDebugString(L"!!!!!!!!!!!!Injection Succeed!!!!!!!!!!!!");
break;
}
case DLL_THREAD_ATTACH:{
OutputDebugString(L"!!!!!!!!!!!!dll thread attach!!!!!!!!!!!!");
break;
}
case DLL_THREAD_DETACH:
{
OutputDebugString(L"!!!!!!!!!!!!dll thread Detach!!!!!!!!!!!!");
break;
}
case DLL_PROCESS_DETACH:
{
OutputDebugString(L"!!!!!!!!!!!!dll process Detach!!!!!!!!!!!!");
break;
}
}
}
i receive the "Injection Succeed" message and right after the "dll process Detach" message .
any ideas?
try changing :
LhSetInclusiveACL(ACLEntries, 1, &hHook);
to :
LhSetExclusiveACL(ACLEntries, 1, &hHook);
My file system minifilter driver for Windows 7x64 must denied access for some files. I`m get it, but associated application still work. I want to terminate process with this application. For example, when user try to open *.txt file, file and associated copy of notepad must be closed. I used example from WDK (Minispy) and functions ZwTerminateProcess and PsGetCurrentProcessId. Now, when user enter monitoring directory, my minifilter close explorer.exe. Example code:
minispy.c
...
NTSTATUS TermFunction( HANDLE ProcessID )
{
NTSTATUS ntStatus = STATUS_SUCCESS;
HANDLE hProcess;
OBJECT_ATTRIBUTES ObjectAttributes;
CLIENT_ID ClientId;
DbgPrint( "drvTerminateProcess( %u )", ProcessID );
InitializeObjectAttributes( &ObjectAttributes, NULL, OBJ_INHERIT, NULL, NULL );
ClientId.UniqueProcess = (HANDLE)ProcessID;
ClientId.UniqueThread = NULL;
__try
{
ntStatus = ZwOpenProcess( &hProcess, PROCESS_ALL_ACCESS, &ObjectAttributes, &ClientId );
if( NT_SUCCESS(ntStatus) )
{
ntStatus = ZwTerminateProcess( hProcess, 0 );
if( !NT_SUCCESS(ntStatus) )
DbgPrint( "ZwTerminateProcess failed with status : %08X\n", ntStatus );
ZwClose( hProcess );
}
else
DbgPrint( "ZwOpenProcess failed with status : %08X\n", ntStatus );
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
ntStatus = STATUS_UNSUCCESSFUL;
DbgPrint( "Exception caught in drvTerminateProcess()" );
}
return ntStatus;
}
...
FLT_PREOP_CALLBACK_STATUS
SpyPreOperationCallback (
_Inout_ PFLT_CALLBACK_DATA Data,
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_Flt_CompletionContext_Outptr_ PVOID *CompletionContext
)
{
UNICODE_STRING old_name;
PUNICODE_STRING new_old_name;
...
if (NT_SUCCESS( status )) {
nameToUse = &nameInfo->Name;
//
// Parse the name if requested
//
//Start of My func
RtlInitUnicodeString( &old_name, L"\\Device\\HarddiskVolume2\\secretfile.txt" );
new_old_name = &old_name;
if(RtlCompareUnicodeString(nameToUse, new_old_name, FALSE) == 0){
Data->IoStatus.Status = STATUS_ACCESS_DENIED;
TermFunction(PsGetCurrentProcessId);
return FLT_PREOP_COMPLETE;
}
...
}
....
}
Any idea?
(Excuse me if my English is bad)
I'm trying to write legacy filter-hook driver, firewall-like: look for dst port and block it.
But when packets are sent, dispatcher routine isn't called.
Register dispatch:
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DrvDispatch;
Start ipfilter driver:
C:\Users\unnamed>net start ipfilterdriver
After that, launch debug driver via Visual DDK. Driver load successfully, but breakpoint in dispatcher isn't reached. What am I doing wrong?
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
UNICODE_STRING DeviceName,Win32Device;
PDEVICE_OBJECT DeviceObject = NULL;
NTSTATUS status;
unsigned i;
RtlInitUnicodeString(&DeviceName,L"\\Device\\driver10");
RtlInitUnicodeString(&Win32Device,L"\\DosDevices\\driver10");
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
DriverObject->MajorFunction[i] = driver1DefaultHandler;
/*
DriverObject->MajorFunction[IRP_MJ_CREATE] = driver1CreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = driver1CreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DrvDispatch;
*/
status = IoCreateDevice(DriverObject, 0, &DeviceName,
FILE_DEVICE_DRVFLTIP, 0, FALSE,
&DeviceObject);
if (NT_SUCCESS(status)) {
status = IoCreateSymbolicLink(&Win32Device, &DeviceName);
if (!NT_SUCCESS(status))
dprintf("DrvFltIp.SYS: IoCreateSymbolicLink failed\n");
DriverObject->MajorFunction[IRP_MJ_CREATE] =
DriverObject->MajorFunction[IRP_MJ_CLOSE] =
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DrvDispatch;
DriverObject->DriverUnload = driver1Unload;
}
if (!NT_SUCCESS(status)) {
dprintf("Error in initialization. Unloading...");
driver1Unload(DriverObject);
}
if (!DeviceObject)
return STATUS_UNEXPECTED_IO_ERROR;
/*
DeviceObject->Flags |= DO_DIRECT_IO;
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
DeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
*/
DbgPrint("Driver started\n");
return status;
}
NTSTATUS DrvDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
dprintf("DrvDispatch called\n");
PIO_STACK_LOCATION irpStack;
PVOID ioBuffer;
ULONG inputBufferLength;
ULONG outputBufferLength;
ULONG ioControlCode;
NTSTATUS ntStatus;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
irpStack = IoGetCurrentIrpStackLocation(Irp);
switch (irpStack->MajorFunction) {
case IRP_MJ_CREATE:
dprintf("DrvFltIp.SYS: IRP_MJ_CREATE\n");
break;
case IRP_MJ_CLOSE:
dprintf("DrvFltIp.SYS: IRP_MJ_CLOSE\n");
break;
case IRP_MJ_DEVICE_CONTROL:
dprintf("DrvFltIp.SYS: IRP_MJ_DEVICE_CONTROL\n");
break;
}
ntStatus = Irp->IoStatus.Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return ntStatus;
}
Just forgot register filter-hook callback function in the DriverEntry:
Registering and Clearing a Filter Hook
Has anyone managed to figure out how asynchronous calls to NtQueryDirectoryFile work?
By an asynchronous call, I mean calling NtQueryDirectoryFile on directories not opened with FILE_SYNCHRONOUS_IO_ALERT or with FILE_SYNCHRONOUS_IO_NONALERT.
For me, it seems to return STATUS_PENDING just like a normal NtReadFile request does on a normal file, but when I tried using NtWaitForSingleObject on the directory, it didn't end properly, and I still don't get all the data... why does this happen?
As far as I know, none of the Windows filesystems support asynchronous query directory calls.
The Win32 APIs never call NtQueryDirectoryFile asnchronously, so support for it is hit-or-miss.
NTFS theoretically supports asynchronous NtQueryDirectoryFile but (as I mentioned) it is not extensively tested so it may not work.
You response indicated that you called WaitForSingleObject on the directory - that's not how the async pattern works in NT - you need to call WaitForSingleObject on the event handle provided as a parameter to NtQueryDirectoryFile.
This update is a result of asking the NTFS developer for more information, he tested this scenario on his machine and it worked for him (on Windows 7).
NtQueryDirectoryFile works well in asynchronous!
pass callback in ApcRoutine, and callback data in ApcContext
asynchronous procedure calls only call when the thread is in alertable state(for example: calling SleepEx(INFINITE, TRUE), WSAaccept)
this program shows how asynchronous NtQueryDirectoryFile work.
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <stdio.h>
#include <winternl.h>
#include <winnt.h>
#define LIST_DIR_SIZE 2000
#define STATUS_NO_MORE_FILES ((NTSTATUS)80000006)
typedef struct _FILE_NAMES_INFORMATION {
ULONG NextEntryOffset;
ULONG FileIndex;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_NAMES_INFORMATION, * PFILE_NAMES_INFORMATION;
typedef struct {
HANDLE hFile;
OVERLAPPED ol;
DECLSPEC_ALIGN(4) FILE_NAMES_INFORMATION buf[LIST_DIR_SIZE];
IO_STATUS_BLOCK iob;
bool finished;
} LIST_DIR_DATA, * PLIST_DIR_DATA; // my private data
__kernel_entry NTSYSCALLAPI
NTSTATUS
NTAPI
NtQueryDirectoryFile(
_In_ HANDLE FileHandle,
_In_opt_ HANDLE Event,
_In_opt_ PIO_APC_ROUTINE ApcRoutine,
_In_opt_ PVOID ApcContext,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_Out_writes_bytes_(Length) PVOID FileInformation,
_In_ ULONG Length,
_In_ FILE_INFORMATION_CLASS FileInformationClass,
_In_ BOOLEAN ReturnSingleEntry,
_In_opt_ PUNICODE_STRING FileName,
_In_ BOOLEAN RestartScan
);
#define NTDLL_extern(s) typedef decltype(&s) s##T;s##T s##F;
#define NTDLL_import(s) s##F = (s##T)GetProcAddress(ntdll, #s);
NTDLL_extern(NtOpenFile);
NTDLL_extern(NtQueryDirectoryFile);
NTDLL_extern(NtClose);
NTDLL_extern(RtlInitUnicodeString);
HMODULE ntdll;
VOID NTAPI callback(
IN PVOID ApcContext,
IN PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG Reserved) {
UNREFERENCED_PARAMETER(Reserved);
PFILE_NAMES_INFORMATION file_info = ((PLIST_DIR_DATA)ApcContext)->buf;
do {
fputws(file_info->FileName, stdout);
putwchar(L'\t');
file_info = (PFILE_NAMES_INFORMATION)((char*)file_info + file_info->NextEntryOffset);
} while (file_info->NextEntryOffset);
fputws(file_info->FileName, stdout);
putwchar(L'\t');
PLIST_DIR_DATA c = (PLIST_DIR_DATA)ApcContext;
if (IoStatusBlock->Information != 0) {
NTSTATUS status = NtQueryDirectoryFileF(
c->hFile,
NULL,
callback,
ApcContext,
&c->iob,
c->buf,
sizeof(c->buf),
FILE_INFORMATION_CLASS(12),
FALSE, NULL, FALSE);
switch (status) {
case STATUS_PENDING:
break;
default:
fputs("warning: status != STATUS_PENDING", stderr);
}
}
else {
c->finished = true;
}
}
BOOL init() {
ntdll = LoadLibraryW(L"NtDLL.dll");
if (ntdll == NULL) {
fputs("LoadLibraryW", stderr);
return FALSE;
}
NTDLL_import(NtQueryDirectoryFile);
NTDLL_import(NtOpenFile);
NTDLL_import(NtClose);
NTDLL_import(RtlInitUnicodeString);
if (NtCloseF != NULL && NtOpenFileF != NULL && NtCloseF != NULL) {
return TRUE;
}
else {
fputs("GetProcAddress", stderr);
return FALSE;
}
}
int main() {
if (init() == FALSE) {
fputs("error: init() failed!", stderr);
return -1;
}
NTSTATUS status;
PLIST_DIR_DATA data = new LIST_DIR_DATA{};
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING s;
RtlInitUnicodeStringF(&s, L"\\??\\c:\\Windows\\System32");
InitializeObjectAttributes(
&ObjectAttributes,
&s,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
status = NtOpenFileF(
&data->hFile,
FILE_READ_DATA | FILE_LIST_DIRECTORY, // | FILE_TRAVERSE | SYNCHRONIZE
&ObjectAttributes,
&data->iob,
FILE_SHARE_READ,
FILE_DIRECTORY_FILE); // | FILE_SYNCHRONOUS_IO_NONALERT
}
if (status < 0 || data->hFile == NULL) {
fputs("error: NtOpenFile failed", stderr);
return -2;
}
status = NtQueryDirectoryFileF(
data->hFile,
NULL,
callback,
data,
&data->iob,
data->buf,
sizeof(data->buf),
FILE_INFORMATION_CLASS(12),
FALSE, NULL, FALSE);
switch (status) {
case STATUS_PENDING:
break;
default:
fputs("warning: status != STATUS_PENDING", stderr);
}
for (;data->finished==false;) SleepEx(INFINITE, TRUE); // put main thread into alertable wait
NtCloseF(data->hFile);
FreeLibrary(ntdll);
return 0;
}
if you want UTF-8 output, try this (note: recommand use support UTF-8 terminal)
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <winternl.h>
#include <winnt.h>
#include <crtdbg.h>
#include <cstdio>
#define LIST_DIR_SIZE 200
#define STATUS_NO_MORE_FILES ((NTSTATUS)80000006)
typedef struct _FILE_NAMES_INFORMATION {
ULONG NextEntryOffset;
ULONG FileIndex;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_NAMES_INFORMATION, * PFILE_NAMES_INFORMATION;
typedef struct {
HANDLE hFile;
OVERLAPPED ol;
DECLSPEC_ALIGN(4) FILE_NAMES_INFORMATION buf[LIST_DIR_SIZE];
IO_STATUS_BLOCK iob;
bool finished;
} LIST_DIR_DATA, * PLIST_DIR_DATA; // my private data
__kernel_entry NTSYSCALLAPI
NTSTATUS
NTAPI
NtQueryDirectoryFile(
_In_ HANDLE FileHandle,
_In_opt_ HANDLE Event,
_In_opt_ PIO_APC_ROUTINE ApcRoutine,
_In_opt_ PVOID ApcContext,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_Out_writes_bytes_(Length) PVOID FileInformation,
_In_ ULONG Length,
_In_ FILE_INFORMATION_CLASS FileInformationClass,
_In_ BOOLEAN ReturnSingleEntry,
_In_opt_ PUNICODE_STRING FileName,
_In_ BOOLEAN RestartScan
);
#define NTDLL_extern(s) typedef decltype(&s) s##T;s##T s##F;
#define NTDLL_init(s) s##F = (s##T)GetProcAddress(ntdll, #s);
NTDLL_extern(NtOpenFile);
NTDLL_extern(NtQueryDirectoryFile);
NTDLL_extern(NtClose);
NTDLL_extern(RtlInitUnicodeString);
HMODULE ntdll;
HANDLE heap;
VOID NTAPI callback(
IN PVOID ApcContext,
IN PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG Reserved) {
UNREFERENCED_PARAMETER(Reserved);
PLIST_DIR_DATA c = (PLIST_DIR_DATA)ApcContext;
if (IoStatusBlock->Information){
PFILE_NAMES_INFORMATION file_info = c->buf;
ULONG_PTR length = 0;
ULONG last;
do {
last = file_info->NextEntryOffset;
file_info->FileNameLength /= 2; // wide char length always base of 2 in bytes
length += (
file_info->FileIndex=WideCharToMultiByte(
CP_UTF8, WC_ERR_INVALID_CHARS,
file_info->FileName, file_info->FileNameLength,
NULL, 0,
NULL, NULL)
)+1;
if (file_info->FileIndex == 0) { // FileIndex is how many byte is the UTF-8 string
_RPTF0(_CRT_WARN, "WideCharToMultiByte failed!");
}
file_info = (PFILE_NAMES_INFORMATION)((char*)file_info + file_info->NextEntryOffset);
} while (last);
LPSTR pData = (LPSTR)HeapAlloc(heap, HEAP_NO_SERIALIZE, length), ptr=pData;
if (ptr == NULL) {
_RPTF0(_CRT_ERROR, "HeapAlloc failed!");
return;
}
file_info = c->buf;
do {
last = file_info->NextEntryOffset;
if (WideCharToMultiByte(
CP_UTF8, WC_ERR_INVALID_CHARS,
file_info->FileName, file_info->FileNameLength,
pData, file_info->FileIndex,
NULL, NULL)==0) {
_RPTF0(_CRT_WARN, "WideCharToMultiByte failed!");
}
pData += file_info->FileIndex;
*pData++ = '\n';
file_info = (PFILE_NAMES_INFORMATION)((char*)file_info + file_info->NextEntryOffset);
} while (last);
// use data here
fwrite(ptr, length, 1, stdout);
// use data here
HeapFree(heap, HEAP_NO_SERIALIZE, ptr);
NTSTATUS status = NtQueryDirectoryFileF(
c->hFile,
NULL,
callback,
ApcContext,
&c->iob,
c->buf,
sizeof(c->buf),
FILE_INFORMATION_CLASS(12),
FALSE, NULL, FALSE);
switch (status) {
case STATUS_PENDING:
break;
default:
_RPTF0(_CRT_WARN, "status != STATUS_PENDING");
}
}else{
c->finished = true;
}
}
BOOL init() {
ntdll = LoadLibraryW(L"NtDLL.dll");
if (ntdll == NULL) {
_RPTF0(_CRT_ERROR, "fail to load NtDLL.dll");
return FALSE;
}
NTDLL_init(NtQueryDirectoryFile);
NTDLL_init(NtOpenFile);
NTDLL_init(NtClose);
NTDLL_init(RtlInitUnicodeString);
if (NtCloseF != NULL &&
NtOpenFileF != NULL &&
NtCloseF != NULL &&
(heap = HeapCreate(HEAP_NO_SERIALIZE, 4096,0))!=NULL
){
return TRUE;
}
else {
_RPTF0(_CRT_ERROR, "failed to load function and create heap");
return FALSE;
}
}
int main() {
if (init() == FALSE) {
_RPTF0(_CRT_ERROR, "init failed");
return -1;
}
SetConsoleCP(CP_UTF8);
NTSTATUS status;
PLIST_DIR_DATA data = new LIST_DIR_DATA{};
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING s;
RtlInitUnicodeStringF(&s, L"\\??\\c:\\Users");
InitializeObjectAttributes(
&ObjectAttributes,
&s,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
status = NtOpenFileF(
&data->hFile,
FILE_READ_DATA | FILE_LIST_DIRECTORY, // | FILE_TRAVERSE | SYNCHRONIZE
&ObjectAttributes,
&data->iob,
FILE_SHARE_READ,
FILE_DIRECTORY_FILE); // | FILE_SYNCHRONOUS_IO_NONALERT
}
if (status < 0 || data->hFile == NULL) {
_RPTF0(_CRT_ERROR, "NtOpenFile failed!");
return -2;
}
status = NtQueryDirectoryFileF(
data->hFile,
NULL,
callback,
data,
&data->iob,
data->buf,
sizeof(data->buf),
FILE_INFORMATION_CLASS(12),
FALSE, NULL, FALSE);
switch (status) {
case STATUS_PENDING:
break;
default:
_RPTF0(_CRT_WARN, "status != STATUS_PENDING");
}
for (;data->finished==false;) SleepEx(INFINITE, TRUE); // put main thread into alertable wait
if (NtCloseF(data->hFile)<0) {
_RPTF0(_CRT_ERROR, "NtClose failed!");
}
if (FreeLibrary(ntdll) == FALSE) {
_RPTF0(_CRT_WARN, "failed to Free libary");
}
if (HeapDestroy(heap) == FALSE) {
_RPTF0(_CRT_WARN, "fail to destroy heap");
}
}