Asynchronous NtQueryDirectoryFile? - winapi

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");
}
}

Related

Why timeout param doesn't work in GetAddrInfoExW()?

When I try to call:
timeval timeout{ 0, 999 };
::GetAddrInfoExW(L"my_name", L"", NS_DNS, nullptr, nullptr, &pResult, &timeout, nullptr, nullptr, nullptr);
I got 10022 "Invalid params".
However, if I replace "&timeout" with "nullptr", I got 0 (OK).
Why the timeout causes EINVAL error?
UNICODE macro is defined, my system is Windows 10.
if timeout not 0, the lpOverlapped must be also not 0. the code can be next
#include <ws2tcpip.h>
struct QUERY_CONTEXT : OVERLAPPED
{
PADDRINFOEX _pResult;
ULONG _dwThreadId = GetCurrentThreadId();
~QUERY_CONTEXT()
{
if (PADDRINFOEX pResult = _pResult)
{
FreeAddrInfoEx(_pResult);
}
}
static void CALLBACK QueryCompleteCallback(
_In_ ULONG dwError,
_In_ ULONG /*dwBytes*/,
_In_ OVERLAPPED* lpOverlapped
)
{
static_cast<QUERY_CONTEXT*>(lpOverlapped)->OnComplete(dwError);
}
void OnComplete(_In_ ULONG dwError)
{
DbgPrint("OnComplete(%u)\n");
if (PADDRINFOEX pResult = _pResult)
{
do
{
WCHAR buf[64];
ULONG len = _countof(buf);
if (!WSAAddressToStringW(pResult->ai_addr, (ULONG)pResult->ai_addrlen, 0, buf, &len))
{
DbgPrint("%S\n", buf);
}
} while (pResult = pResult->ai_next);
}
PostThreadMessageW(_dwThreadId, WM_QUIT, dwError, 0);
delete this;
}
ULONG Query(_In_ PCWSTR pName, _In_opt_ timeval *timeout)
{
ULONG dwError = GetAddrInfoExW(pName, 0, NS_DNS, 0, 0,
&_pResult, timeout, this, QueryCompleteCallback, 0);
//
// If GetAddrInfoExW() returns WSA_IO_PENDING, GetAddrInfoExW will invoke
// the completion routine. If GetAddrInfoExW returned anything else we must
// invoke the completion directly.
//
if (dwError != WSA_IO_PENDING)
{
QueryCompleteCallback(dwError, 0, this);
}
return dwError;
}
};
///////////////////////////////////////
WSADATA wd;
if (NOERROR == WSAStartup(WINSOCK_VERSION, &wd))
{
if (QUERY_CONTEXT* pqc = new QUERY_CONTEXT {})
{
timeval timeout{ 1 };
pqc->Query(L"stackoverflow.com", &timeout);
}
MessageBoxW(0, 0, 0, 0);
WSACleanup();
}
also for dns query more efficient direct use DnsQueryEx function (GetAddrInfoExW internally call DnsQueryEx, but before this - alot of another code executed)

Spoofing hard disk serial number via a driver

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).

Hide a process from Task Manager

I'm trying to hide a process from the taskmanager but it doesn't work .
I dont understand why ...
Thank you for your help in advance... !
This is my function who inject the hider_dll.dll :
int Inject(char* dll)
{
int pid = getpid();
HANDLE hProc=OpenProcess(PROCESS_ALL_ACCESS,false,pid);
if(hProc)
{
cout<<"OpenProcess success"<<endl;
}
else
{
cout<<"OpenProcess failed..."<<endl;
return 0;
}
LPVOID Vmem=VirtualAllocEx(hProc,0,strlen(dll)+1,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
DWORD wrt;
WriteProcessMemory(hProc,Vmem,dll,strlen(dll),(SIZE_T*)&wrt);
stringstream sstr;
sstr << wrt;
string str = sstr.str();
cout<<"Writed "+str+" bytes"<<endl;
FARPROC LoadLib=GetProcAddress(LoadLibrary(L"kernel32.dll"),"LoadLibraryA");
HANDLE h=CreateRemoteThread(hProc,0,0,(LPTHREAD_START_ROUTINE)LoadLib,Vmem,0,0);
if(h)
{
cout<<"CreateRemoteThread success"<<endl;
}
else
{
cout<<"CreateRemoteThread failed\r\nError:"<<GetLastError()<<endl;
return 0;
}
WaitForSingleObject(h,INFINITE);
DWORD exit;
GetExitCodeThread(h,&exit);
cout<<"Dll loaded to "<<exit<<endl;
return 1;
}
Here is a proper injector:
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
DWORD GetProcId(const char* procName)
{
DWORD procId = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 procEntry;
procEntry.dwSize = sizeof(procEntry);
if (Process32First(hSnap, &procEntry))
{
do
{
if (!_stricmp(procEntry.szExeFile, procName))
{
procId = procEntry.th32ProcessID;
break;
}
} while (Process32Next(hSnap, &procEntry));
}
}
CloseHandle(hSnap);
return procId;
}
int main()
{
const char* dllPath = "C:\\Users\\'%USERNAME%'\\Desktop\\dll.dll"; //
const char* procName = "processname.exe"; //
DWORD procId = 0;
while (!procId)
{
procId = GetProcId(procName);
Sleep(30);
}
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, 0, procId);
if (hProc && hProc != INVALID_HANDLE_VALUE)
{
void* loc = VirtualAllocEx(hProc, 0, MAX_PATH, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
WriteProcessMemory(hProc, loc, dllPath, strlen(dllPath) + 1, 0);
HANDLE hThread = CreateRemoteThread(hProc, 0, 0, (LPTHREAD_START_ROUTINE)LoadLibraryA, loc, 0, 0);
if (hThread)
{
CloseHandle(hThread);
}
}
if (hProc)
{
CloseHandle(hProc);
}
return 0;
}
To hide processes from Task Manager you need to hook NtQuerySystemInformation() and if the argument SYSTEM_PROCESS_INFORMATION is used, you need to remove your process from the linked list of processes.
This is what your hook would look like:
// Hooked function
NTSTATUS WINAPI HookedNtQuerySystemInformation(
__in SYSTEM_INFORMATION_CLASS SystemInformationClass,
__inout PVOID SystemInformation,
__in ULONG SystemInformationLength,
__out_opt PULONG ReturnLength
)
{
NTSTATUS status = OriginalNtQuerySystemInformation(SystemInformationClass,
SystemInformation,
SystemInformationLength,
ReturnLength);
if (SystemProcessInformation == SystemInformationClass && STATUS_SUCCESS == status)
{
// Loop through the list of processes
PMY_SYSTEM_PROCESS_INFORMATION pCurrent = NULL;
PMY_SYSTEM_PROCESS_INFORMATION pNext = (PMY_SYSTEM_PROCESS_INFORMATION)
SystemInformation;
do
{
pCurrent = pNext;
pNext = (PMY_SYSTEM_PROCESS_INFORMATION)((PUCHAR)pCurrent + pCurrent->
NextEntryOffset);
if (!wcsncmp(pNext->ImageName.Buffer, L"notepad.exe", pNext->ImageName.Length))
{
if (!pNext->NextEntryOffset)
{
pCurrent->NextEntryOffset = 0;
}
else
{
pCurrent->NextEntryOffset += pNext->NextEntryOffset;
}
pNext = pCurrent;
}
} while (pCurrent->NextEntryOffset != 0);
}
return status;
}

ChangeClipboardChain() fails when called from console CtrlHandler()

I know, this method is outdated, just curious.
When I call ChangeClipboardChain() from atexit handler, it succeeds. When precc Ctrl-C, it fails. I know it, because other clipboard viewers don't receive WM_CHANGECBCHAIN.
This sample program exits when something is copied to clipboard 4 times:
#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
#endif
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
static void pWin32Error(const char* fmt, ...);
static int counter=0;
static HWND nextWnd = NULL;
static
LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch (uMsg) {
case WM_CHANGECBCHAIN:
{
HWND wndRemove = (HWND)wParam;
HWND wndNextNext = (HWND)lParam;
printf("WM_CHANGECBCHAIN %p %p\n", (void*)wndRemove, (void*)wndNextNext);
if (nextWnd == wndRemove) {
printf("saving next window %p\n", (void*)wndNextNext);
nextWnd = wndNextNext;
} else if (nextWnd) {
printf("notifying next window %p\n", (void*)nextWnd);
return SendMessage(nextWnd,uMsg,wParam,lParam);
} else {
printf("not notifying next window %p\n", (void*)nextWnd);
}
}
break;
case WM_DRAWCLIPBOARD:
counter++;
if (counter > 4) exit(0);
printf("WM_DRAWCLIPBOARD\n");
if (nextWnd) {
printf("notifying next window %p\n", (void*)nextWnd);
return SendMessage(nextWnd,uMsg,wParam,lParam);
} else {
printf("not notifying next window %p\n", (void*)nextWnd);
}
break;
default:
return DefWindowProc( hwnd,uMsg,wParam,lParam);
}
return 0;
}
static volatile HWND global_hwnd = NULL;
WNDCLASS wndclass = {
0,/* UINT style;*/
WindowProc,/* WNDPROC lpfnWndProc;*/
0,/* int cbClsExtra;*/
0,/* int cbWndExtra;*/
NULL,/* HINSTANCE hInstance;*/
NULL,/* HICON hIcon;*/
NULL,/* HCURSOR hCursor;*/
NULL,/* HBRUSH hbrBackground;*/
NULL,/* LPCWSTR lpszMenuName;*/
_T("myclipmonitor")/* LPCWSTR lpszClassName;*/
};
static void unreg() {
HWND hwnd;
hwnd = (HWND)InterlockedExchangePointer(&global_hwnd, NULL); /* ignore the "cast to greater size" warning */
if (hwnd) {
printf("Removing self from chain: %p <- %p\n", (void*)hwnd, (void*)nextWnd);
if (!ChangeClipboardChain(hwnd, nextWnd) && GetLastError() != 0) {
pWin32Error("ChangeClipboardChain() failed");
}
}
}
static void exitproc() {
fprintf(stderr, "exitproc()\n");
unreg();
}
static
BOOL WINAPI CtrlHandler( DWORD fdwCtrlType )
{
fprintf(stderr, "CtrlHandler()\n");
unreg();
switch ( fdwCtrlType ) {
case CTRL_C_EVENT:
fprintf(stderr, "\n\n Stopping due to Ctrl-C.\n" );
break;
case CTRL_CLOSE_EVENT:
fprintf(stderr, "\n\n Stopping due to closing the window.\n" );
break;
case CTRL_BREAK_EVENT:
fprintf(stderr, "\n\n Stopping due to Ctrl-Break.\n" );
break;
// Pass other signals to the next handler - ret = FALSE
case CTRL_LOGOFF_EVENT:
fprintf(stderr, "\n\n Stopping due to logoff.\n" );
break;
case CTRL_SHUTDOWN_EVENT:
fprintf(stderr, "\n\n Stopping due to system shutdown.\n" );
break;
default:
fprintf(stderr, "\n\n Stopping due to unknown event.\n" );
}
return FALSE;
}
int _tmain(int argc, _TCHAR* argv[])
{
ATOM classatom;
HINSTANCE hinst = GetModuleHandle(NULL);
MSG msg;
wndclass.hInstance = hinst;
classatom = RegisterClass(&wndclass);
if (classatom == 0) {
pWin32Error("RegisterClass() failed");
return -1;
}
global_hwnd = CreateWindowEx(0, (LPCTSTR)classatom, NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL);
if (!global_hwnd) {
pWin32Error("CreateWindowEx() failed");
return -1;
}
printf("hwnd = %p\n", (void*)global_hwnd);
nextWnd = SetClipboardViewer(global_hwnd);
if (!nextWnd && GetLastError() != 0) {
pWin32Error("SetClipboardViewer() failed");
return -1;
}
printf("nextWnd = %p\n", (void*)nextWnd);
atexit(exitproc);
if (0 == SetConsoleCtrlHandler( CtrlHandler, TRUE )) {
pWin32Error("SetConsoleCtrlHandler() failed");
return -1;
}
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
static char *cleanstr(char *s)
{
while(*s) {
switch((int)*s){
case 13:
case 10:
*s=' ';
break;
}
s++;
}
return s;
}
static void __pWin32Error(int level, DWORD eNum, const char* fmt, va_list args)
{
char emsg[1024];
char *pend = emsg + sizeof(emsg);
size_t count = sizeof(emsg);
unsigned u;
do {
u = (unsigned)_vsnprintf(pend - count, count, fmt, args);
if (u >= count) break;
count -= u;
u = (unsigned)_snprintf(pend - count, count, ": ");
if (u >= count) break;
count -= u;
u = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, eNum,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
pend - count, (DWORD)count, NULL );
if (u == 0) {
u = (unsigned)_snprintf(pend - count, count, "0x%08x (%d)", eNum, eNum);
}
} while(0);
emsg[sizeof(emsg)-1] = '\0';
pend = cleanstr(emsg);
if (pend < emsg + sizeof(emsg)-1) {
pend++;
*pend = '\0';
}
pend[-1] = '\n';
puts(emsg);
}
static void pWin32Error(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
__pWin32Error(0, GetLastError(), fmt, args);
va_end(args);
}

Translating boost::thread->native_handle() to XP ThreadId

I've managed to get the Windows ThreadId out of the native_handle() from a boost::thread by using GetThreadId(HANDLE). Sadly that call is not available on Windows XP and after searching around I found the solution to offer als fallback support for XP by traversing all thread via Thread32First() and Thread32Next() functions of the WINAPI.
This does work somehow but my problem is I'm currently only able to identify the threads of my process... I don't now how to match the native_handle() / HANDLE from one side with the appropriate THREADENTRY32 from the loop traversal.
THREADENTRY32 te32;
//...
do {
if( te32.th32OwnerProcessID == GetCurrentProcessId() ) {
DWORD threadId = te32.th32ThreadID;
printf( "\n THREAD ID = 0x%08X", te32.th32ThreadID );
}
} while( Thread32Next(hThreadSnap, &te32 ) );
Can anyone help me with that? How do I convert a boost::thread->native_handle() to the ThreadId on WindowsXP?
Thank you very much!
Pass each thread ID in the loop to OpenThread() until you find a matching HANDLE. For example:
HANDLE hBoostThread = ...; // from boost::thread->native_handle()
DWORD dwBoostThreadID = 0;
THREADENTRY32 te32;
//...
do
{
if( te32.th32OwnerProcessID == GetCurrentProcessId() )
{
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID);
if (hThread != NULL)
{
if (hThread == hBoostThread)
{
CloseHandle(hThread);
dwBoostThreadID = te32.th32ThreadID;
break;
}
CloseHandle(hThread);
}
}
}
while( Thread32Next(hThreadSnap, &te32 ) );
For good measure, you can wrap this inside a function that you can call whenever GetThreadId() is not natively available so that your code does not need to know the difference, eg:
DWORD WINAPI MyGetThreadId(HANDLE Thread)
{
THREADENTRY32 te32;
HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hThreadSnap == INVALID_HANDLE_VALUE)
return 0;
if (Thread32First(hThreadSnap, &te32))
{
do
{
HANDLE hOpenThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID);
if (hOpenThread != NULL)
{
if (hOpenThread == Thread)
{
CloseHandle(hOpenThread);
CloseHandle(hThreadSnap);
return te32.th32ThreadID;
}
CloseHandle(hOpenThread);
}
}
while( Thread32Next(hThreadSnap, &te32 ) );
}
CloseHandle(hThreadSnap);
return 0;
}
typedef DWORD (WINAPI *LPFN_GTID)(HANDLE);
LPFN_GTID lpGetThreadId = (LPFN_GTID) GetProcAddress(GetModuleHandle("kernel32"), "GetThreadId");
if (!lpGetThreadId)
lpGetThreadId = &MyGetThreadId;
DWORD dwThreadID = lpGetThreadId((HANDLE) boost::thread->native_handle());
With that said, a better option is to directly query the target thread itself for its own ID, instead of trying to hunt for it manually:
typedef long (WINAPI *LPFN_NTQIT)(HANDLE thread, int infoclass, void *buf, long size, long *used);
typedef struct _THREAD_BASIC_INFORMATION
{
ULONG ExitStatus;
void* TebBaseAddress;
ULONG UniqueProcessId;
ULONG UniqueThreadId;
ULONG AffinityMask;
ULONG BasePriority;
ULONG DiffProcessPriority;
} THREAD_BASIC_INFORMATION;
DWORD WINAPI MyGetThreadId(HANDLE Thread)
{
DWORD dwThreadId = 0;
HMODULE hLib = LoadLibrary("ntdll.dll");
if (hLib != NULL)
{
LPFN_NTQIT lpNtQueryInformationThread = (LPFN_NTQIT) GetProcAddress(hLib, "NtQueryInformationThread");
if (lpNtQueryInformationThread != NULL)
{
THREAD_BASIC_INFORMATION tbi = {0};
ULONG used = 0;
if (lpNtQueryInformationThread(Thread, 0, &tbi, sizeof(tbi), &used) == 0)
dwThreadId = tbi.UniqueThreadId;
}
FreeLibrary(hLib);
}
return dwThreadId;
}

Resources