5536 lines
180 KiB
C
5536 lines
180 KiB
C
/*
|
|
* Devctl.c
|
|
*
|
|
* IoCrash
|
|
*
|
|
* Copyright(c) 1997 Microsoft Corporation
|
|
*
|
|
* NeillC 23-Oct-97
|
|
*
|
|
* This program is designed to call as many of the user mode native NT API's as
|
|
* possible. The program is written to crash drivers as its primary function.
|
|
*
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#include "nt.h"
|
|
#include "ntrtl.h"
|
|
#include "nturtl.h"
|
|
#include <winsock2.h>
|
|
#include <mswsock.h>
|
|
#include "windows.h"
|
|
#include "wmistr.h"
|
|
#include "wmiumkm.h"
|
|
#include "time.h"
|
|
#include "tdi.h"
|
|
#include "vdm.h"
|
|
#include "sddl.h"
|
|
|
|
#define MAX_DEVICES 4096
|
|
#define PROT_REP 100000
|
|
#define MAX_RET 5000
|
|
#define DIAG_RET 50
|
|
#define CRASH_LINE_SIZE 1024
|
|
#define SLOP_SENTINAL 0xA5
|
|
|
|
#define SLOP 100
|
|
#define BIGBUF_SIZE 0x10000
|
|
#define RAND_REP 1000
|
|
#define MAX_IOCTL_TAILOR 100
|
|
#define INITIAL_IOCTL_TAILOR_SIZE 200
|
|
|
|
#define FLAGS_DO_IOCTL_NULL 0x00000001
|
|
#define FLAGS_DO_IOCTL_RANDOM 0x00000002
|
|
#define FLAGS_DO_FSCTL_NULL 0x00000004
|
|
#define FLAGS_DO_FSCTL_RANDOM 0x00000008
|
|
#define FLAGS_DO_USAGE 0x00000010
|
|
#define FLAGS_DO_LOGGING 0x00000020
|
|
#define FLAGS_DO_POOLCHECK 0x00000040
|
|
#define FLAGS_DO_SKIPDONE 0x00000080
|
|
#define FLAGS_DO_SKIPCRASH 0x00000100
|
|
#define FLAGS_DO_MISC 0x00000200
|
|
#define FLAGS_DO_QUERY 0x00000400
|
|
#define FLAGS_DO_SUBOPENS 0x00000800
|
|
#define FLAGS_DO_ALLDEVS 0x00001000
|
|
#define FLAGS_DO_ZEROEA 0x00002000
|
|
#define FLAGS_DO_GRAB 0x00004000
|
|
#define FLAGS_DO_ERRORS 0x00008000
|
|
#define FLAGS_DO_ALERT 0x00010000
|
|
#define FLAGS_DO_LPC 0x00020000
|
|
#define FLAGS_DO_MAPNULL 0x00040000
|
|
#define FLAGS_DO_STREAMS 0x00080000
|
|
#define FLAGS_DO_WINSOCK 0x00100000
|
|
#define FLAGS_DO_SYNC 0x00200000
|
|
#define FLAGS_DO_DISKS 0x00400000
|
|
#define FLAGS_DO_PROT 0x00800000
|
|
#define FLAGS_DO_SECURITY 0x01000000
|
|
#define FLAGS_DO_IMPERSONATION 0x02000000
|
|
#define FLAGS_DO_DIRECT_DEVICE 0x04000000
|
|
#define FLAGS_DO_FAILURE_INJECTION 0x08000000
|
|
#define FLAGS_DO_PRINT_DEVS 0x10000000
|
|
#define FLAGS_DO_RANDOM_DEVICE 0x20000000
|
|
#define FLAGS_DO_SYMBOLIC 0x40000000
|
|
#define FLAGS_DO_OPEN_CLOSE 0x80000000
|
|
|
|
#define FLAGS_DO_DRIVER 0x00000001
|
|
|
|
#define DIAG_NOEXCEPTIONS 0x1
|
|
|
|
#define OPEN_TYPE_TDI_CONNECTION 1
|
|
#define OPEN_TYPE_TDI_ADDR_IP 2
|
|
#define OPEN_TYPE_TDI_ADDR_NETBIOS 3
|
|
#define OPEN_TYPE_TDI_ADDR_IPX 4
|
|
#define OPEN_TYPE_TDI_ADDR_APPLE 5
|
|
#define OPEN_TYPE_NAMED_PIPE 6
|
|
#define OPEN_TYPE_MAIL_SLOT 7
|
|
#define OPEN_TYPE_TREE_CONNECT 8
|
|
|
|
typedef struct _DEVMAP {
|
|
OBJECT_NAME_INFORMATION *name;
|
|
FILE_NAME_INFORMATION *filename;
|
|
HANDLE handle;
|
|
DEVICE_TYPE devtype;
|
|
ACCESS_MASK access;
|
|
} DEVMAP, *PDEVMAP;
|
|
|
|
//
|
|
// Define a structure to keep a track of issued IOCTL's. We do this to try and make a
|
|
// guess at what IOCTL's/FSCTL's a driver is actualy processing.
|
|
//
|
|
typedef struct _IOCTLINFO {
|
|
NTSTATUS status;
|
|
ULONG ioctl;
|
|
ULONG count;
|
|
} IOCTLINFO, *PIOCTLINFO;
|
|
|
|
typedef struct _IOCTLREC {
|
|
ULONG total, count, start;
|
|
IOCTLINFO ioctl[];
|
|
} IOCTLREC, *PIOCTLREC;
|
|
|
|
typedef struct _CRASHNODE {
|
|
struct _CRASHNODE *next;
|
|
PWCHAR string;
|
|
} CRASHNODE, *PCRASHNODE;
|
|
|
|
DEVMAP devmap[MAX_DEVICES];
|
|
ULONG devscount;
|
|
ULONG skipped = 0;
|
|
ULONG random_device = 0;
|
|
UCHAR *bigbuf;
|
|
FILE *skipfile = NULL;
|
|
FILE *crashfile = NULL;
|
|
FILE *diag_file = NULL;
|
|
PCRASHNODE crashlist = NULL;
|
|
HANDLE changethread, randthread, alertthread, mainthread;
|
|
SOCKET ls, cs;
|
|
ULONG flags=0, flags2=0;
|
|
ULONG ioctl_min_function=0;
|
|
ULONG ioctl_max_function=400 /*0xFFF*/;
|
|
ULONG ioctl_min_devtype=0;
|
|
ULONG ioctl_max_devtype=200;
|
|
ULONG ioctl_inbuf_min=0x0;
|
|
ULONG ioctl_inbuf_max=0x200;
|
|
ULONG ioctl_outbuf_min=0;
|
|
ULONG ioctl_outbuf_max=0x200;
|
|
ULONG max_random_calls = 100000;
|
|
ULONG max_tailured_calls = 10000;
|
|
ULONG progress_counter=0;
|
|
ULONG alerted=0;
|
|
ULONG cid = 0;
|
|
HANDLE process_handle = NULL;
|
|
WCHAR lastcrashline[CRASH_LINE_SIZE];
|
|
HANDLE sync_event = NULL;
|
|
ULONG sessionid = 0;
|
|
PCHAR prefix_string = NULL;
|
|
HANDLE NonAdminToken=NULL;
|
|
UNICODE_STRING DriverName={0};
|
|
BOOLEAN Impersonating = FALSE;
|
|
|
|
HANDLE
|
|
Create_nonadmin_token ()
|
|
/*
|
|
Create a token with administrator filtered out.
|
|
*/
|
|
{
|
|
HANDLE ProcessToken, RestrictedToken;
|
|
SID_AND_ATTRIBUTES AdminSidAttrib;
|
|
PSID pSid;
|
|
SID_IDENTIFIER_AUTHORITY sia = {SECURITY_WORLD_SID_AUTHORITY};
|
|
|
|
|
|
//
|
|
// Open the process token
|
|
//
|
|
if (!OpenProcessToken (GetCurrentProcess (),
|
|
MAXIMUM_ALLOWED,
|
|
&ProcessToken)) {
|
|
printf ("OpenProcessToken failed %d\n", GetLastError ());
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
if (!AllocateAndInitializeSid (&sia, 1, 0, 0, 0, 0, 0, 0, 0, 0, &pSid)) {
|
|
printf ("AllocateAndInitializeSid failed %d\n", GetLastError ());
|
|
CloseHandle (ProcessToken);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
AdminSidAttrib.Sid = pSid;
|
|
AdminSidAttrib.Attributes = 0;
|
|
|
|
if (!CreateRestrictedToken (ProcessToken,
|
|
DISABLE_MAX_PRIVILEGE,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
1,
|
|
&AdminSidAttrib,
|
|
&RestrictedToken)) {
|
|
FreeSid (pSid);
|
|
CloseHandle (ProcessToken);
|
|
printf ("CreateRestrictedToken failed %d\n", GetLastError ());
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
FreeSid (pSid);
|
|
CloseHandle (ProcessToken);
|
|
|
|
if (!DuplicateToken (RestrictedToken,
|
|
SecurityDelegation,
|
|
&NonAdminToken)) {
|
|
CloseHandle (RestrictedToken);
|
|
printf ("DuplicateToken failed %d\n", GetLastError ());
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
CloseHandle (RestrictedToken);
|
|
|
|
return NonAdminToken;
|
|
}
|
|
|
|
VOID
|
|
Impersonate_nonadmin ()
|
|
{
|
|
Impersonating = TRUE;
|
|
if (NonAdminToken != NULL && !SetThreadToken (NULL, NonAdminToken)) {
|
|
printf ("SetThreadToken failed %d\n", GetLastError ());
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
Revert_from_admin ()
|
|
{
|
|
Impersonating = FALSE;
|
|
return RevertToSelf ();
|
|
}
|
|
|
|
|
|
void
|
|
tag_to_wide (PUCHAR t, PWCHAR wt)
|
|
{
|
|
ULONG i;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
*wt++ = *t++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Try and locate pool leaks by looking at pool tag info and lookaside list info.
|
|
Try and locate where handled exceptions might reveal problems in the code.
|
|
*/
|
|
BOOL
|
|
print_diags (ULONG diag_flags, ULONG ret)
|
|
{
|
|
static PSYSTEM_POOLTAG_INFORMATION opb=NULL;
|
|
PSYSTEM_POOLTAG_INFORMATION pb;
|
|
static PSYSTEM_LOOKASIDE_INFORMATION olpb=NULL;
|
|
static ULONG olpbl;
|
|
PSYSTEM_LOOKASIDE_INFORMATION lpb;
|
|
ULONG pbl, lpbl, i, j, retlen, retlen1;
|
|
BOOL found, diff, newtag;
|
|
NTSTATUS status;
|
|
static ULONG firsterror = 1;
|
|
static SYSTEM_EXCEPTION_INFORMATION sei, osei;
|
|
WCHAR wtag[4];
|
|
static ULONG lpbi = 1, pbi = 1;
|
|
|
|
if ((flags&FLAGS_DO_POOLCHECK) == 0) {
|
|
return FALSE;
|
|
}
|
|
if (!diag_file) {
|
|
diag_file = _wfopen (L"diags.log", L"ab");
|
|
if (!diag_file) {
|
|
printf ("Failed to open diags.log for diagnostics\n");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
diff = FALSE;
|
|
newtag = FALSE;
|
|
|
|
status = NtQuerySystemInformation (SystemExceptionInformation, &sei, sizeof (sei),
|
|
&retlen);
|
|
if (!NT_SUCCESS (status)) {
|
|
if (firsterror) {
|
|
printf ("NtQuerySystemInformation for SystemExceptionInformation failed %x\n",
|
|
status);
|
|
firsterror = 0;
|
|
}
|
|
flags &= ~FLAGS_DO_POOLCHECK;
|
|
return FALSE;
|
|
}
|
|
if (sei.ExceptionDispatchCount > osei.ExceptionDispatchCount &&
|
|
osei.ExceptionDispatchCount) {
|
|
if (!(diag_flags&DIAG_NOEXCEPTIONS)) {
|
|
printf ("Exception count changed from %d to %d\n", osei.ExceptionDispatchCount,
|
|
sei.ExceptionDispatchCount);
|
|
if (ret == DIAG_RET) {
|
|
fwprintf (diag_file, L"%s Exception count changed from %d to %d\r\n",
|
|
lastcrashline,
|
|
osei.ExceptionDispatchCount,
|
|
sei.ExceptionDispatchCount);
|
|
fflush (diag_file);
|
|
} else if (ret < DIAG_RET) {
|
|
diff = TRUE;
|
|
}
|
|
}
|
|
}
|
|
osei = sei;
|
|
|
|
while (1) {
|
|
/*
|
|
Get memory for tag info
|
|
*/
|
|
pbl = sizeof (*pb) + pbi * sizeof (pb->TagInfo[0]);
|
|
pb = malloc (pbl);
|
|
if (!pb) {
|
|
printf ("Failed to allocate memory for pool buffer\n");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
status = NtQuerySystemInformation (SystemPoolTagInformation, pb, pbl, &retlen1);
|
|
if (pbl <= retlen1) {
|
|
ULONG pbio = pbi;
|
|
pbi = 1 + (retlen1 - sizeof (*pb)) / sizeof (pb->TagInfo[0]);
|
|
// printf ("Increasing pooltag list table size to %d from %d\n", pbi, pbio);
|
|
free (pb);
|
|
continue;
|
|
}
|
|
if (!NT_SUCCESS (status)) {
|
|
if (firsterror) {
|
|
printf ("NtQuerySystemInformation failed %x\n", status);
|
|
firsterror = 0;
|
|
}
|
|
flags &= ~FLAGS_DO_POOLCHECK;
|
|
free (pb);
|
|
return FALSE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
while (1) {
|
|
/*
|
|
Get memory for lookaside info
|
|
*/
|
|
lpbl = sizeof (*lpb) * lpbi;
|
|
lpb = malloc (lpbl);
|
|
if (!pb) {
|
|
printf ("Failed to allocate memory for pool buffer\n");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
status = NtQuerySystemInformation (SystemLookasideInformation, lpb, lpbl, &retlen);
|
|
if (lpbl <= retlen) {
|
|
ULONG lpbio = lpbi;
|
|
lpbi = 1 + retlen / sizeof (*lpb);
|
|
// printf ("Increasing lookaside list table size to %d from %d\n", lpbi, lpbio);
|
|
free (lpb);
|
|
continue;
|
|
}
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtQuerySystemInformation failed %x\n", status);
|
|
flags &= ~FLAGS_DO_POOLCHECK;
|
|
free (lpb);
|
|
free (pb);
|
|
return FALSE;
|
|
}
|
|
break;
|
|
}
|
|
lpbl = retlen / sizeof (*lpb);
|
|
if (olpb) {
|
|
for (i = 0; i < lpbl; i++) {
|
|
/*
|
|
Quick check here. the tag is probably in the same place it was last time
|
|
*/
|
|
if (i < olpbl && lpb[i].Tag == olpb[i].Tag && lpb[i].Type == olpb[i].Type &&
|
|
lpb[i].Size == olpb[i].Size) {
|
|
found = TRUE;
|
|
j = i;
|
|
} else {
|
|
/*
|
|
It has moved so search them all.
|
|
*/
|
|
for (j = 0; j < olpbl; j++) {
|
|
if (lpb[i].Tag == olpb[j].Tag && lpb[i].Type == olpb[j].Type &&
|
|
lpb[i].Size == olpb[j].Size) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (found) {
|
|
if (olpb[i].CurrentDepth > lpb[i].CurrentDepth) {
|
|
printf ("Lookaside: %4.4s, size %d up %d\n",
|
|
&lpb[i].Tag, lpb[i].Size,
|
|
olpb[i].CurrentDepth - lpb[i].CurrentDepth);
|
|
diff = TRUE;
|
|
if (ret == DIAG_RET) {
|
|
tag_to_wide ((PUCHAR)&lpb[i].Tag, wtag);
|
|
fwprintf (diag_file, L"%s Lookaside: %4.4s, size %d up %d\r\n",
|
|
lastcrashline,
|
|
wtag, lpb[i].Size,
|
|
olpb[i].CurrentDepth - lpb[i].CurrentDepth);
|
|
fflush (diag_file);
|
|
}
|
|
}
|
|
} else {
|
|
/*
|
|
A new tag has appeared here
|
|
*/
|
|
printf ("New Lookaside %4.4s, size %d, depth %d\n",
|
|
&lpb[i].Tag, lpb[i].Size,
|
|
lpb[i].CurrentDepth);
|
|
diff = TRUE;
|
|
}
|
|
}
|
|
free (olpb);
|
|
}
|
|
|
|
/*
|
|
now do lookaside information
|
|
*/
|
|
// printf ("Total tags %d\n", pb->Count);
|
|
if (opb) {
|
|
for (i = 0; i < pb->Count; i++) {
|
|
found = FALSE;
|
|
if (i < opb->Count && pb->TagInfo[i].TagUlong == opb->TagInfo[i].TagUlong) {
|
|
j = i;
|
|
found = TRUE;
|
|
} else {
|
|
for (j = 0; j < pb->Count; j++) {
|
|
if (pb->TagInfo[i].TagUlong == opb->TagInfo[j].TagUlong) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (found) {
|
|
if (pb->TagInfo[i].PagedUsed > opb->TagInfo[j].PagedUsed ||
|
|
pb->TagInfo[i].NonPagedUsed > opb->TagInfo[j].NonPagedUsed) {
|
|
diff = TRUE;
|
|
printf ("Pool: %4.4s, Paged up %d, NonPaged up %d\n",
|
|
&pb->TagInfo[i].TagUlong,
|
|
pb->TagInfo[i].PagedUsed - opb->TagInfo[i].PagedUsed,
|
|
pb->TagInfo[i].NonPagedUsed - opb->TagInfo[i].NonPagedUsed);
|
|
if (ret == DIAG_RET) {
|
|
tag_to_wide ((PUCHAR)&pb->TagInfo[i].TagUlong, wtag);
|
|
fwprintf (diag_file, L"%s Pool: %4.4s, Paged up %d, NonPaged up %d\r\n",
|
|
lastcrashline,
|
|
wtag,
|
|
pb->TagInfo[i].PagedUsed - opb->TagInfo[i].PagedUsed,
|
|
pb->TagInfo[i].NonPagedUsed - opb->TagInfo[i].NonPagedUsed);
|
|
fflush (diag_file);
|
|
}
|
|
}
|
|
} else {
|
|
diff = TRUE;
|
|
newtag = TRUE;
|
|
printf ("New tag %4.4s\n", &pb->TagInfo[i].TagUlong);
|
|
}
|
|
}
|
|
free (opb);
|
|
}
|
|
opb = pb;
|
|
olpb = lpb;
|
|
olpbl = lpbl;
|
|
return diff;
|
|
}
|
|
/*
|
|
Turn on fault injection in the driver verifier
|
|
*/
|
|
void turn_on_fault_injection ()
|
|
{
|
|
ULONG svi;
|
|
NTSTATUS status;
|
|
|
|
svi = DRIVER_VERIFIER_SPECIAL_POOLING |
|
|
DRIVER_VERIFIER_FORCE_IRQL_CHECKING |
|
|
DRIVER_VERIFIER_INJECT_ALLOCATION_FAILURES;
|
|
status = NtSetSystemInformation (SystemVerifierInformation, &svi, sizeof (svi));
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtSetSystemInformation for SystemVerifierInformation failed %x\n",
|
|
status);
|
|
flags &= ~FLAGS_DO_FAILURE_INJECTION; // Turn off flag to prevent errors
|
|
}
|
|
}
|
|
|
|
/*
|
|
Turn off fault injection in the driver verifier
|
|
*/
|
|
void turn_off_fault_injection ()
|
|
{
|
|
ULONG svi;
|
|
NTSTATUS status;
|
|
|
|
svi = DRIVER_VERIFIER_SPECIAL_POOLING |
|
|
DRIVER_VERIFIER_FORCE_IRQL_CHECKING;
|
|
status = NtSetSystemInformation (SystemVerifierInformation, &svi, sizeof (svi));
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtSetSystemInformation for SystemVerifierInformation failed %x\n",
|
|
status);
|
|
}
|
|
}
|
|
|
|
/*
|
|
Read a line from the crash file and remove returns etc
|
|
*/
|
|
PWCHAR getline (PWCHAR templine, ULONG size, FILE *file)
|
|
{
|
|
PWCHAR ret;
|
|
PWCHAR cp;
|
|
|
|
ret = fgetws (templine, size, file);
|
|
if (ret) {
|
|
cp = wcsstr (templine, L"\r");
|
|
if (cp)
|
|
*cp = '\0';
|
|
cp = wcsstr (templine, L"\n");
|
|
if (cp)
|
|
*cp = '\0';
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
Add a line to the list of lines that crashed us before
|
|
*/
|
|
VOID add_crash_list (PWCHAR crashline)
|
|
{
|
|
PCRASHNODE node;
|
|
|
|
node = malloc (sizeof (CRASHNODE));
|
|
if (!node) {
|
|
printf ("Memory allocation failed for crash node!\n");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
node->next = crashlist;
|
|
crashlist = node;
|
|
node->string = malloc ((wcslen (crashline) + 1) * sizeof (WCHAR));
|
|
if (!node->string) {
|
|
printf ("Memory allocation failed for crash line!\n");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
wcscpy (node->string, crashline);
|
|
}
|
|
|
|
/*
|
|
See if this operation crashed us before
|
|
*/
|
|
BOOL crashes (PWCHAR path, PWCHAR thing1, PWCHAR thing2, PWCHAR thing3, PWCHAR thing4)
|
|
{
|
|
PWCHAR crashline = NULL;
|
|
PWCHAR templine = NULL;
|
|
BOOL result;
|
|
HANDLE crashfilehandle;
|
|
DWORD retlen;
|
|
BOOL opened;
|
|
PCRASHNODE node;
|
|
ULONG count;
|
|
BOOLEAN StoppedImpersonating;
|
|
|
|
progress_counter++;
|
|
_snwprintf (lastcrashline, sizeof (lastcrashline)/sizeof (WCHAR),
|
|
L"%s %s %s %s %s", path, thing1, thing2, thing3, thing4);
|
|
if ((flags&FLAGS_DO_LOGGING) == 0) {
|
|
wprintf (L"%s\n", lastcrashline);
|
|
SetConsoleTitleW (lastcrashline);
|
|
return FALSE;
|
|
}
|
|
crashline = malloc (CRASH_LINE_SIZE*sizeof (WCHAR));
|
|
if (!crashline) {
|
|
printf ("Failed to allocate crash line buffer\n");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
templine = malloc (CRASH_LINE_SIZE*sizeof (WCHAR));
|
|
if (!templine) {
|
|
printf ("Failed to allocate crash line buffer\n");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
StoppedImpersonating = FALSE;
|
|
if (Impersonating) {
|
|
Revert_from_admin ();
|
|
StoppedImpersonating = TRUE;
|
|
}
|
|
opened = FALSE;
|
|
if (!skipfile) {
|
|
/*
|
|
First time in openen up the files
|
|
*/
|
|
opened = TRUE;
|
|
skipfile = _wfopen (L"crash.log", L"ab");
|
|
if (skipfile) {
|
|
crashfile = _wfopen (L"crashn.log", L"rb");
|
|
if (crashfile) {
|
|
printf ("Opened crashn.log for reading\n");
|
|
crashline[0] = '\0';
|
|
while (getline (templine, CRASH_LINE_SIZE, crashfile)) {
|
|
if (wcslen (templine) > 0) {
|
|
if (flags&FLAGS_DO_SKIPDONE) {
|
|
add_crash_list (templine);
|
|
}
|
|
wcscpy (crashline, templine);
|
|
}
|
|
}
|
|
fclose (crashfile);
|
|
crashfile = NULL;
|
|
if (crashline[0] != '\0' && wcsncmp (crashline, L"DONE", 4) != 0) {
|
|
fputws (crashline, skipfile);
|
|
fputws (L"\r\n", skipfile);
|
|
}
|
|
}
|
|
fclose (skipfile);
|
|
}
|
|
skipfile = _wfopen (L"crash.log", L"rb");
|
|
}
|
|
if (skipfile && opened) {
|
|
while (getline (crashline, CRASH_LINE_SIZE, skipfile)) {
|
|
if (flags&FLAGS_DO_SKIPCRASH && wcscmp (crashline, L"DONE") != 0) {
|
|
add_crash_list (crashline);
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
Run through crashing lines looking for a match
|
|
*/
|
|
result = FALSE;
|
|
_snwprintf (templine, CRASH_LINE_SIZE, L"%s %s %s %s %s", path, thing1, thing2, thing3, thing4);
|
|
SetConsoleTitleW (templine);
|
|
for (node = crashlist; node; node = node->next) {
|
|
if (_wcsicmp (node->string, templine) == 0) {
|
|
result = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (!result) {
|
|
print_diags (0, 0);
|
|
count = 0;
|
|
do {
|
|
crashfilehandle = CreateFile("crashn.log", GENERIC_WRITE, 0, NULL,
|
|
OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH, 0 );
|
|
if (crashfilehandle == INVALID_HANDLE_VALUE) {
|
|
printf ("CreateFile failed for crash logging file %d\n", GetLastError ());
|
|
if (count++ > 20) {
|
|
break;
|
|
} else {
|
|
Sleep (5000);
|
|
}
|
|
}
|
|
} while (crashfilehandle == INVALID_HANDLE_VALUE);
|
|
|
|
if (crashfilehandle != INVALID_HANDLE_VALUE) {
|
|
SetFilePointer (crashfilehandle, 0, 0, FILE_END);
|
|
_snwprintf (templine, CRASH_LINE_SIZE,
|
|
L"%s %s %s %s %s\r\n", path, thing1, thing2, thing3, thing4);
|
|
wprintf (L"%s", templine);
|
|
/*
|
|
This is a bit excessive and costly but I really want to make sure this gets
|
|
logged as the next operation may crash the machine.
|
|
*/
|
|
if (!WriteFile (crashfilehandle, templine, wcslen(templine)*sizeof (WCHAR), &retlen, 0)) {
|
|
printf ("WriteFile failed fore crash line %d\n", GetLastError ());
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
if (!FlushFileBuffers (crashfilehandle)) {
|
|
printf ("FlushFileBuffers failed for crash file %d\n", GetLastError ());
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
if (!CloseHandle (crashfilehandle)) {
|
|
printf ("CloseHandle failed for crash file %d\n", GetLastError ());
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
}
|
|
if (StoppedImpersonating) {
|
|
Impersonate_nonadmin ();
|
|
}
|
|
|
|
free (crashline);
|
|
free (templine);
|
|
return result;
|
|
}
|
|
|
|
|
|
/*
|
|
Hack to get a 32 bit random value from a 15 bit source
|
|
*/
|
|
ULONG
|
|
rand32(
|
|
void
|
|
)
|
|
{
|
|
return(rand() << 17) + rand() + rand();
|
|
}
|
|
|
|
/*
|
|
RandInRange - produce a random number in some range
|
|
*/
|
|
ULONG
|
|
RandInRange( ULONG lowerb, ULONG upperb )
|
|
{
|
|
if( lowerb > upperb ) {
|
|
ULONG temp;
|
|
temp= upperb;
|
|
|
|
return lowerb + rand32()%(upperb-lowerb);
|
|
upperb= lowerb;
|
|
upperb= temp;
|
|
}
|
|
|
|
return lowerb + rand32()%(upperb-lowerb);
|
|
|
|
}
|
|
|
|
/*
|
|
Allocate a buffer with slop and fill the slop with a know value
|
|
*/
|
|
PVOID
|
|
reallocslop(
|
|
PVOID p,
|
|
ULONG len
|
|
)
|
|
{
|
|
progress_counter++;
|
|
p = realloc(p,
|
|
len + SLOP);
|
|
|
|
memset(p,
|
|
SLOP_SENTINAL,
|
|
len + SLOP);
|
|
|
|
return p;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Check to see if the driver wrote too far by checking the slop values
|
|
*/
|
|
VOID
|
|
testslop(
|
|
PVOID p,
|
|
ULONG len,
|
|
PWCHAR what,
|
|
PWCHAR subwhat
|
|
)
|
|
{
|
|
UCHAR string[100], *pc;
|
|
ULONG i;
|
|
|
|
pc = p;
|
|
|
|
pc += len;
|
|
|
|
for (i = 0; i < SLOP; i++, pc++) {
|
|
if (*pc != SLOP_SENTINAL) {
|
|
wprintf(L"Driver wrote beyond end during %s %s for length %d!\n",
|
|
what, subwhat, len);
|
|
|
|
scanf("%100s",
|
|
&string);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
Issue different sized EA's
|
|
*/
|
|
VOID
|
|
do_query_ea(
|
|
HANDLE handle,
|
|
PWCHAR path
|
|
)
|
|
{
|
|
ULONG l, i, old, ret;
|
|
IO_STATUS_BLOCK iosb;
|
|
ULONG tmp;
|
|
PVOID buf;
|
|
NTSTATUS status, last_status;
|
|
|
|
|
|
if (crashes (path, L"NtQueryEaFile", L"", L"", L""))
|
|
return;
|
|
|
|
ret = 0;
|
|
buf = NULL;
|
|
do {
|
|
last_status = 0;
|
|
|
|
l = 1024;
|
|
|
|
|
|
do {
|
|
buf = reallocslop(buf,
|
|
l);
|
|
|
|
status = NtQueryEaFile (handle, &iosb, buf, l, FALSE, NULL, 0, NULL, FALSE);
|
|
if (NT_SUCCESS (status))
|
|
status = iosb.Status;
|
|
testslop(buf,
|
|
l,
|
|
L"NtQueryEaFile",
|
|
L"");
|
|
|
|
if (status == STATUS_NOT_IMPLEMENTED ||
|
|
status == STATUS_INVALID_INFO_CLASS ||
|
|
status == STATUS_INVALID_DEVICE_REQUEST ||
|
|
status == STATUS_INVALID_PARAMETER ||
|
|
status == STATUS_ACCESS_DENIED) {
|
|
|
|
// break;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status) &&
|
|
status != last_status) {
|
|
|
|
last_status = status;
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf("NtQueryEaFile failed %x\n",
|
|
status);
|
|
}
|
|
} while (l-- != 0);
|
|
|
|
if (flags&FLAGS_DO_ZEROEA) {
|
|
status = NtQueryEaFile(handle,
|
|
&iosb,
|
|
(PVOID)-1024,
|
|
0,
|
|
FALSE, NULL, 0, NULL, FALSE);
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf("NtQueryEaFile failed %x\n",
|
|
status);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
|
|
status = NtCancelIoFile (handle, &iosb);
|
|
|
|
free(buf);
|
|
|
|
if (!(flags&FLAGS_DO_PROT) || crashes (path, L"NtQueryEaFile prot", L"", L"", L""))
|
|
return;
|
|
status = NtResumeThread (changethread, &tmp);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtResumeThread failed %x\n", status);
|
|
}
|
|
|
|
for (i = 1; i < PROT_REP; i++) {
|
|
if (!VirtualProtect (buf, 1, PAGE_READWRITE, &old)) {
|
|
printf ("VirtualProtect failed %d\n", GetLastError ());
|
|
}
|
|
status = NtQueryEaFile(handle,
|
|
&iosb,
|
|
bigbuf,
|
|
BIGBUF_SIZE,
|
|
FALSE, NULL, 0, NULL, FALSE);
|
|
}
|
|
status = NtSuspendThread (changethread, &tmp);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtResumeThread failed %x\n", status);
|
|
}
|
|
if (!VirtualProtect (buf, 1, PAGE_READWRITE, &old)) {
|
|
printf ("VirtualProtect failed %d\n", GetLastError ());
|
|
}
|
|
|
|
}
|
|
/*
|
|
Do volume queries of different lengths
|
|
*/
|
|
VOID
|
|
do_query_volume(
|
|
HANDLE handle,
|
|
FS_INFORMATION_CLASS InfoType,
|
|
ULONG bufl,
|
|
PWCHAR what,
|
|
PWCHAR path
|
|
)
|
|
{
|
|
ULONG l, ret;
|
|
IO_STATUS_BLOCK iosb;
|
|
PVOID buf;
|
|
NTSTATUS status, last_status;
|
|
|
|
if (crashes (path, L"NtQueryVolumeInformationFile", what, L"", L""))
|
|
return;
|
|
|
|
ret = 0;
|
|
buf = NULL;
|
|
do {
|
|
last_status = 0;
|
|
|
|
l = bufl + 1024;
|
|
|
|
|
|
do {
|
|
buf = reallocslop(buf,
|
|
l);
|
|
|
|
status = NtQueryVolumeInformationFile(handle,
|
|
&iosb,
|
|
buf,
|
|
l,
|
|
InfoType);
|
|
|
|
testslop(buf,
|
|
l,
|
|
L"NtQueryVolumeInformationFile",
|
|
what);
|
|
|
|
if (status == STATUS_NOT_IMPLEMENTED ||
|
|
status == STATUS_INVALID_INFO_CLASS ||
|
|
status == STATUS_INVALID_DEVICE_REQUEST ||
|
|
status == STATUS_INVALID_PARAMETER ||
|
|
status == STATUS_ACCESS_DENIED) {
|
|
|
|
// break;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status) &&
|
|
status != last_status) {
|
|
|
|
last_status = status;
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
wprintf(L"NtQueryVolumeInformationFile for %s failed %x\n",
|
|
what, status);
|
|
}
|
|
} while (l-- != 0);
|
|
|
|
status = NtQueryVolumeInformationFile(handle,
|
|
&iosb,
|
|
(PVOID)-1024,
|
|
0,
|
|
InfoType);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
wprintf(L"NtQueryVolumeInformationFile for %s failed %x\n",
|
|
what, status);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
|
|
status = NtCancelIoFile (handle, &iosb);
|
|
free(buf);
|
|
}
|
|
|
|
/*
|
|
Do volume sets of different lengths
|
|
*/
|
|
VOID
|
|
do_set_volume(
|
|
HANDLE handle,
|
|
FS_INFORMATION_CLASS InfoType,
|
|
ULONG bufl,
|
|
PWCHAR what,
|
|
PWCHAR path
|
|
)
|
|
{
|
|
ULONG l, i, ret;
|
|
IO_STATUS_BLOCK iosb;
|
|
PVOID buf;
|
|
NTSTATUS status, last_status;
|
|
|
|
if (crashes (path, L"NtSetVolumeInformationFile", what, L"", L""))
|
|
return;
|
|
|
|
ret = 0;
|
|
buf = NULL;
|
|
do {
|
|
last_status = 0;
|
|
|
|
l = bufl + 1024;
|
|
|
|
|
|
buf = malloc (l);
|
|
do {
|
|
for (i = 0; i < l; i++) {
|
|
((PCHAR)buf)[i] = (CHAR) rand ();
|
|
}
|
|
|
|
progress_counter++;
|
|
status = NtSetVolumeInformationFile(handle,
|
|
&iosb,
|
|
buf,
|
|
l,
|
|
InfoType);
|
|
|
|
if (status == STATUS_NOT_IMPLEMENTED ||
|
|
status == STATUS_INVALID_INFO_CLASS ||
|
|
status == STATUS_INVALID_DEVICE_REQUEST ||
|
|
status == STATUS_INVALID_PARAMETER ||
|
|
status == STATUS_ACCESS_DENIED) {
|
|
|
|
// break;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status) &&
|
|
status != last_status) {
|
|
|
|
last_status = status;
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
wprintf(L"NtSetVolumeInformationFile for %s failed %x\n",
|
|
what, status);
|
|
}
|
|
} while (l-- != 0);
|
|
|
|
progress_counter++;
|
|
status = NtSetVolumeInformationFile(handle,
|
|
&iosb,
|
|
(PVOID)-1024,
|
|
0,
|
|
InfoType);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
wprintf(L"NtSetVolumeInformationFile for %s failed %x\n",
|
|
what, status);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
|
|
status = NtCancelIoFile (handle, &iosb);
|
|
free(buf);
|
|
}
|
|
|
|
/*
|
|
Do file queries
|
|
*/
|
|
VOID
|
|
do_query_file(
|
|
HANDLE handle,
|
|
FILE_INFORMATION_CLASS InfoType,
|
|
ULONG bufl,
|
|
PWCHAR what,
|
|
PWCHAR path
|
|
)
|
|
{
|
|
ULONG l, i, ret;
|
|
IO_STATUS_BLOCK iosb;
|
|
PVOID buf;
|
|
NTSTATUS status, last_status;
|
|
ULONG tmp;
|
|
DWORD old;
|
|
|
|
if (crashes (path, L"NtQueryInformationFile", what, L"", L""))
|
|
return;
|
|
|
|
ret = 0;
|
|
buf = NULL;
|
|
do {
|
|
last_status = 0;
|
|
|
|
l = bufl + 1024;
|
|
|
|
|
|
do {
|
|
buf = reallocslop(buf,
|
|
l);
|
|
status = NtQueryInformationFile(handle,
|
|
&iosb,
|
|
buf,
|
|
l,
|
|
InfoType);
|
|
|
|
testslop(buf,
|
|
l,
|
|
L"NtQueryInformationFile",
|
|
what);
|
|
|
|
if (status == STATUS_NOT_IMPLEMENTED ||
|
|
status == STATUS_INVALID_INFO_CLASS ||
|
|
status == STATUS_INVALID_DEVICE_REQUEST ||
|
|
status == STATUS_INVALID_PARAMETER ||
|
|
status == STATUS_ACCESS_DENIED) {
|
|
|
|
// break;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status) &&
|
|
status != last_status) {
|
|
last_status = status;
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
wprintf(L"NtQueryInformationFile for %s failed %x\n",
|
|
what, status);
|
|
}
|
|
} while (l-- != 0);
|
|
|
|
status = NtQueryInformationFile(handle,
|
|
&iosb,
|
|
(PVOID)-1024,
|
|
0,
|
|
InfoType);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
wprintf(L"NtQueryInformationFile for %s failed %x\n",
|
|
what, status);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
status = NtCancelIoFile (handle, &iosb);
|
|
free(buf);
|
|
|
|
if (!(flags&FLAGS_DO_PROT) ||
|
|
crashes (path, L"NtQueryInformationFile prot", L"", L"", L""))
|
|
return;
|
|
status = NtResumeThread (changethread, &tmp);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtResumeThread failed %x\n", status);
|
|
}
|
|
|
|
for (i = 1; i < PROT_REP; i++) {
|
|
if (!VirtualProtect (buf, 1, PAGE_READWRITE, &old)) {
|
|
printf ("VirtualProtect failed %d\n", GetLastError ());
|
|
}
|
|
status = NtQueryInformationFile(handle,
|
|
&iosb,
|
|
bigbuf,
|
|
bufl,
|
|
InfoType);
|
|
}
|
|
status = NtSuspendThread (changethread, &tmp);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtResumeThread failed %x\n", status);
|
|
}
|
|
if (!VirtualProtect (buf, 1, PAGE_READWRITE, &old)) {
|
|
printf ("VirtualProtect failed %d\n", GetLastError ());
|
|
}
|
|
}
|
|
|
|
/*
|
|
Do file sets
|
|
*/
|
|
VOID
|
|
do_set_file(
|
|
HANDLE handle,
|
|
FILE_INFORMATION_CLASS InfoType,
|
|
ULONG bufl,
|
|
PWCHAR what,
|
|
PWCHAR path
|
|
)
|
|
{
|
|
ULONG l, i, ret;
|
|
IO_STATUS_BLOCK iosb;
|
|
PVOID buf;
|
|
NTSTATUS status, last_status;
|
|
ULONG tmp;
|
|
DWORD old;
|
|
|
|
if (crashes (path, L"NtSetInformationFile", what, L"", L""))
|
|
return;
|
|
|
|
ret = 0;
|
|
buf = NULL;
|
|
do {
|
|
last_status = 0;
|
|
|
|
l = bufl + 1024;
|
|
buf = malloc (l);
|
|
do {
|
|
for (i = 0; i < l; i++) {
|
|
((PCHAR)buf)[i] = (CHAR) rand ();
|
|
}
|
|
progress_counter++;
|
|
status = NtSetInformationFile(handle,
|
|
&iosb,
|
|
buf,
|
|
l,
|
|
InfoType);
|
|
|
|
if (status == STATUS_NOT_IMPLEMENTED ||
|
|
status == STATUS_INVALID_INFO_CLASS ||
|
|
status == STATUS_INVALID_DEVICE_REQUEST ||
|
|
status == STATUS_INVALID_PARAMETER ||
|
|
status == STATUS_ACCESS_DENIED) {
|
|
|
|
// break;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status) &&
|
|
status != last_status) {
|
|
last_status = status;
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
wprintf(L"NtSetInformationFile for %s failed %x\n",
|
|
what, status);
|
|
}
|
|
} while (l-- != 0);
|
|
|
|
status = NtSetInformationFile(handle,
|
|
&iosb,
|
|
(PVOID)-1024,
|
|
0,
|
|
InfoType);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
wprintf(L"NtSetInformationFile for %s failed %x\n",
|
|
what, status);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
status = NtCancelIoFile (handle, &iosb);
|
|
free(buf);
|
|
|
|
if (!(flags&FLAGS_DO_PROT) ||
|
|
crashes (path, L"NtSetInformationFile prot", L"", L"", L""))
|
|
return;
|
|
status = NtResumeThread (changethread, &tmp);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtResumeThread failed %x\n", status);
|
|
}
|
|
|
|
for (i = 1; i < PROT_REP; i++) {
|
|
if (!VirtualProtect (buf, 1, PAGE_READWRITE, &old)) {
|
|
printf ("VirtualProtect failed %d\n", GetLastError ());
|
|
}
|
|
status = NtSetInformationFile(handle,
|
|
&iosb,
|
|
bigbuf,
|
|
bufl,
|
|
InfoType);
|
|
}
|
|
status = NtSuspendThread (changethread, &tmp);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtResumeThread failed %x\n", status);
|
|
}
|
|
if (!VirtualProtect (buf, 1, PAGE_READWRITE, &old)) {
|
|
printf ("VirtualProtect failed %d\n", GetLastError ());
|
|
}
|
|
}
|
|
|
|
/*
|
|
Do object queries with variable length buffers
|
|
*/
|
|
VOID
|
|
do_query_object(
|
|
HANDLE handle,
|
|
OBJECT_INFORMATION_CLASS InfoType,
|
|
ULONG bufl,
|
|
PWCHAR what,
|
|
PWCHAR path
|
|
)
|
|
{
|
|
ULONG l, ret;
|
|
IO_STATUS_BLOCK iosb;
|
|
PVOID buf;
|
|
NTSTATUS status, last_status;
|
|
|
|
last_status = 0;
|
|
|
|
if (crashes (path, L"NtQueryObject", what, L"", L""))
|
|
return;
|
|
|
|
buf = NULL;
|
|
ret = 0;
|
|
do {
|
|
l = bufl + 1024;
|
|
|
|
|
|
do {
|
|
buf = reallocslop(buf,
|
|
l);
|
|
|
|
status = NtQueryObject(handle,
|
|
InfoType,
|
|
buf,
|
|
l,
|
|
NULL);
|
|
|
|
testslop(buf, l, L"NtQueryObject", what);
|
|
|
|
if (!NT_SUCCESS(status) &&
|
|
status != last_status) {
|
|
|
|
last_status = status;
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
wprintf(L"NtQueryObject for %s failed %x\n",
|
|
what, status);
|
|
}
|
|
} while (l-- != 0);
|
|
|
|
status = NtQueryObject(handle,
|
|
InfoType,
|
|
(PVOID)-1024,
|
|
0,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
wprintf(L"NtQueryObject for %s failed %x\n",
|
|
what, status);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
|
|
status = NtCancelIoFile (handle, &iosb);
|
|
free(buf);
|
|
}
|
|
|
|
/*
|
|
Do query security
|
|
*/
|
|
VOID
|
|
do_query_security(
|
|
HANDLE handle,
|
|
SECURITY_INFORMATION InfoType,
|
|
ULONG bufl,
|
|
PWCHAR what,
|
|
PWCHAR path
|
|
)
|
|
{
|
|
ULONG l, i, tmp, ret;
|
|
IO_STATUS_BLOCK iosb;
|
|
PVOID buf;
|
|
NTSTATUS status, last_status;
|
|
ULONG ln;
|
|
DWORD old;
|
|
|
|
if (crashes (path, L"NtQuerySecurityObject", what, L"", L""))
|
|
return;
|
|
|
|
buf = NULL;
|
|
ret = 0;
|
|
do {
|
|
last_status = 0;
|
|
|
|
l = bufl + 1024;
|
|
|
|
|
|
do {
|
|
buf = reallocslop(buf,
|
|
l);
|
|
|
|
status = NtQuerySecurityObject(handle,
|
|
InfoType,
|
|
buf,
|
|
l,
|
|
&ln);
|
|
|
|
testslop(buf, l, L"NtQuerySecurityObject", what);
|
|
|
|
if (!NT_SUCCESS(status) &&
|
|
status != last_status && status) {
|
|
|
|
last_status = status;
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
wprintf(L"NtQuerySecurityObject for %s failed %x\n",
|
|
what, status);
|
|
}
|
|
} while (l-- != 0);
|
|
|
|
status = NtQuerySecurityObject(handle,
|
|
InfoType,
|
|
(PVOID)-1024,
|
|
0,
|
|
&ln);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
wprintf(L"NtQuerySecurityObject for %s failed %x\n",
|
|
what, status);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
|
|
status = NtCancelIoFile (handle, &iosb);
|
|
free(buf);
|
|
|
|
if (!(flags&FLAGS_DO_PROT) ||
|
|
crashes (path, L"NtQuerySecurityFile prot", L"", L"", L""))
|
|
return;
|
|
status = NtResumeThread (changethread, &tmp);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtResumeThread failed %x\n", status);
|
|
}
|
|
|
|
for (i = 1; i < PROT_REP; i++) {
|
|
if (!VirtualProtect (buf, 1, PAGE_READWRITE, &old)) {
|
|
printf ("VirtualProtect failed %d\n", GetLastError ());
|
|
}
|
|
status = NtQuerySecurityObject(handle,
|
|
InfoType,
|
|
bigbuf,
|
|
bufl,
|
|
&ln);
|
|
}
|
|
status = NtSuspendThread (changethread, &tmp);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtResumeThread failed %x\n", status);
|
|
}
|
|
if (!VirtualProtect (buf, 1, PAGE_READWRITE, &old)) {
|
|
printf ("VirtualProtect failed %d\n", GetLastError ());
|
|
}
|
|
}
|
|
|
|
/*
|
|
Do set security
|
|
*/
|
|
VOID
|
|
do_set_security(
|
|
HANDLE handle,
|
|
SECURITY_INFORMATION InfoType,
|
|
ULONG bufl,
|
|
PWCHAR what,
|
|
PWCHAR path
|
|
)
|
|
{
|
|
ULONG l, i, tmp, ret;
|
|
IO_STATUS_BLOCK iosb;
|
|
PVOID buf;
|
|
NTSTATUS status, last_status;
|
|
ULONG ln;
|
|
DWORD old;
|
|
PSECURITY_DESCRIPTOR psd;
|
|
LPTSTR tsd;
|
|
|
|
if (crashes (path, L"NtSetSecurityObject", what, L"", L""))
|
|
return;
|
|
|
|
psd = malloc (l = 4096);
|
|
if (!psd) {
|
|
printf ("Failed to allocate security descriptor space\n");
|
|
return;
|
|
}
|
|
status = NtQuerySecurityObject(handle,
|
|
InfoType,
|
|
psd,
|
|
l,
|
|
&ln);
|
|
if (!NT_SUCCESS(status)) {
|
|
free (psd);
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
wprintf(L"NtQuerySecurityObject for %s failed %x\n",
|
|
what, status);
|
|
return;
|
|
}
|
|
if (InfoType) {
|
|
if (ConvertSecurityDescriptorToStringSecurityDescriptor (psd,
|
|
SDDL_REVISION_1,
|
|
InfoType,
|
|
&tsd,
|
|
NULL)) {
|
|
printf ("%ws: %s\n", what, tsd);
|
|
LocalFree (tsd);
|
|
} else {
|
|
printf ("ConvertSecurityDescriptorToStringSecurityDescriptor failed %d\n", GetLastError ());
|
|
}
|
|
}
|
|
buf = NULL;
|
|
ret = 0;
|
|
do {
|
|
last_status = 0;
|
|
|
|
status = NtSetSecurityObject(handle,
|
|
InfoType,
|
|
psd);
|
|
|
|
if (!NT_SUCCESS(status) &&
|
|
status != last_status && status) {
|
|
|
|
last_status = status;
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
wprintf(L"NtSetSecurityObject for %s failed %x\n",
|
|
what, status);
|
|
}
|
|
status = NtCancelIoFile (handle, &iosb);
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
|
|
free(psd);
|
|
}
|
|
|
|
/*
|
|
Do all the query functions
|
|
*/
|
|
NTSTATUS
|
|
query_object(
|
|
HANDLE handle,
|
|
PDEVMAP devmap,
|
|
PWCHAR path
|
|
)
|
|
{
|
|
OBJECT_NAME_INFORMATION *on = NULL;
|
|
FILE_NAME_INFORMATION *fn = NULL;
|
|
ULONG sfn, son;
|
|
FILE_FS_DEVICE_INFORMATION devinfo;
|
|
NTSTATUS status;
|
|
static IO_STATUS_BLOCK iosb;
|
|
|
|
sfn = sizeof (*fn) + 1024;
|
|
son = sizeof (*on) + 1024;
|
|
fn = reallocslop(NULL,
|
|
sfn);
|
|
on = reallocslop(NULL,
|
|
son);
|
|
if (devmap) {
|
|
devmap->filename = fn;
|
|
devmap->name = on;
|
|
}
|
|
|
|
if (fn == NULL || on == NULL) {
|
|
printf("Memory allocation failure in query_object!\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
status = NtQueryObject(handle,
|
|
ObjectNameInformation,
|
|
on,
|
|
son,
|
|
NULL);
|
|
|
|
testslop(on,
|
|
son, L"NtQueryObject", L"ObjectNameInformation");
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
if (flags&FLAGS_DO_ERRORS) {
|
|
wprintf(L"NtQueryObject for ObjectNameInformation failed %x\n",
|
|
status);
|
|
}
|
|
|
|
on->Name.Length = 0;
|
|
} else {
|
|
wprintf (L"Object name is %s\n", on->Name.Buffer);
|
|
}
|
|
|
|
status = NtQueryInformationFile(handle,
|
|
&iosb,
|
|
fn,
|
|
sfn,
|
|
FileNameInformation);
|
|
|
|
testslop(fn,
|
|
sfn,
|
|
L"NtQueryInformationFile",
|
|
L"FileNameInformation");
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
status = iosb.Status;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
wprintf(L"NtQueryInformationFile for FileNameInformation failed %x\n",
|
|
status);
|
|
fn->FileNameLength = 0;
|
|
}
|
|
|
|
if (!devmap) {
|
|
free (fn);
|
|
free (on);
|
|
}
|
|
|
|
status = NtQueryVolumeInformationFile(handle,
|
|
&iosb,
|
|
&devinfo,
|
|
sizeof (devinfo),
|
|
FileFsDeviceInformation);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
status = iosb.Status;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
wprintf(L"NtQueryVolumeInformationFile for FileFsDeviceInformation failed %x\n",
|
|
status);
|
|
|
|
if (devmap)
|
|
devmap->devtype = 0;
|
|
} else {
|
|
if (devmap)
|
|
devmap->devtype = devinfo.DeviceType;
|
|
// printf("Got the device number for a device!\n");
|
|
}
|
|
|
|
if (flags&FLAGS_DO_QUERY) {
|
|
//
|
|
// Do loads of different queries with different buffer lengths.
|
|
//
|
|
do_query_object(handle,
|
|
ObjectNameInformation,
|
|
sizeof (OBJECT_NAME_INFORMATION),
|
|
L"ObjectNameInformation",
|
|
path);
|
|
|
|
do_query_file(handle,
|
|
FileBasicInformation,
|
|
sizeof (FILE_BASIC_INFORMATION),
|
|
L"FileBasicInformation",
|
|
path);
|
|
|
|
do_query_file(handle,
|
|
FileStandardInformation,
|
|
sizeof (FILE_STANDARD_INFORMATION),
|
|
L"FileStandardInformation",
|
|
path);
|
|
|
|
do_query_file(handle,
|
|
FileInternalInformation,
|
|
sizeof (FILE_INTERNAL_INFORMATION),
|
|
L"FileInternalInformation",
|
|
path);
|
|
|
|
do_query_file(handle,
|
|
FileEaInformation,
|
|
sizeof (FILE_EA_INFORMATION),
|
|
L"FileEaInformation",
|
|
path);
|
|
|
|
do_query_file(handle,
|
|
FileAccessInformation,
|
|
sizeof (FILE_ACCESS_INFORMATION),
|
|
L"FileAccessInformation",
|
|
path);
|
|
|
|
do_query_file(handle,
|
|
FileNameInformation,
|
|
sizeof (FILE_NAME_INFORMATION) + 1024,
|
|
L"FileNameInformation",
|
|
path);
|
|
|
|
//
|
|
// We end up turning off alertable handle with this.
|
|
//
|
|
// do_query_file(handle,
|
|
// FileModeInformation,
|
|
// sizeof (FILE_MODE_INFORMATION),
|
|
// L"FileModeInformation",
|
|
// path);
|
|
|
|
do_query_file(handle,
|
|
FileAlignmentInformation,
|
|
sizeof (FILE_ALIGNMENT_INFORMATION),
|
|
L"FileAlignmentInformation",
|
|
path);
|
|
|
|
do_query_file(handle,
|
|
FileAllInformation,
|
|
sizeof (FILE_ALL_INFORMATION),
|
|
L"FileAllInformation",
|
|
path);
|
|
|
|
do_query_file(handle,
|
|
FileStreamInformation,
|
|
sizeof (FILE_STREAM_INFORMATION),
|
|
L"FileStreamInformation",
|
|
path);
|
|
|
|
do_query_file(handle,
|
|
FilePipeInformation,
|
|
sizeof (FILE_PIPE_INFORMATION),
|
|
L"FilePipeInformation",
|
|
path);
|
|
|
|
do_query_file(handle,
|
|
FilePipeLocalInformation,
|
|
sizeof (FILE_PIPE_LOCAL_INFORMATION),
|
|
L"FilePipeLocalInformation",
|
|
path);
|
|
|
|
do_query_file(handle,
|
|
FilePipeRemoteInformation,
|
|
sizeof (FILE_PIPE_REMOTE_INFORMATION),
|
|
L"FilePipeRemoteInformation",
|
|
path);
|
|
|
|
do_query_file(handle,
|
|
FileCompressionInformation,
|
|
sizeof (FILE_COMPRESSION_INFORMATION),
|
|
L"FileCompressionInformation",
|
|
path);
|
|
|
|
do_query_file(handle,
|
|
FileObjectIdInformation,
|
|
sizeof (FILE_OBJECTID_INFORMATION),
|
|
L"FileObjectIdInformation",
|
|
path);
|
|
|
|
do_query_file(handle,
|
|
FileMailslotQueryInformation,
|
|
sizeof (FILE_MAILSLOT_QUERY_INFORMATION),
|
|
L"FileMailslotQueryInformation",
|
|
path);
|
|
|
|
do_query_file(handle,
|
|
FileQuotaInformation,
|
|
sizeof (FILE_QUOTA_INFORMATION),
|
|
L"FileQuotaInformation",
|
|
path);
|
|
|
|
do_query_file(handle,
|
|
FileReparsePointInformation,
|
|
sizeof (FILE_REPARSE_POINT_INFORMATION),
|
|
L"FileReparsePointInformation",
|
|
path);
|
|
|
|
do_query_file(handle,
|
|
FileNetworkOpenInformation,
|
|
sizeof (FILE_NETWORK_OPEN_INFORMATION),
|
|
L"FileNetworkOpenInformation",
|
|
path);
|
|
|
|
do_query_file(handle,
|
|
FileAttributeTagInformation,
|
|
sizeof (FILE_ATTRIBUTE_TAG_INFORMATION),
|
|
L"FileAttributeTagInformation",
|
|
path);
|
|
|
|
do_set_file(handle,
|
|
FileBasicInformation,
|
|
sizeof (FILE_BASIC_INFORMATION),
|
|
L"FileBasicInformation",
|
|
path);
|
|
|
|
do_set_file(handle,
|
|
FileRenameInformation,
|
|
sizeof (FILE_RENAME_INFORMATION),
|
|
L"FileRenameInformation",
|
|
path);
|
|
|
|
do_set_file(handle,
|
|
FileLinkInformation,
|
|
sizeof (FILE_LINK_INFORMATION),
|
|
L"FileLinkInformation",
|
|
path);
|
|
|
|
do_set_file(handle,
|
|
FileDispositionInformation,
|
|
sizeof (FILE_DISPOSITION_INFORMATION),
|
|
L"FileDispositionInformation",
|
|
path);
|
|
|
|
do_set_file(handle,
|
|
FilePositionInformation,
|
|
sizeof (FILE_POSITION_INFORMATION),
|
|
L"FilePositionInformation",
|
|
path);
|
|
|
|
do_set_file(handle,
|
|
FileAllocationInformation,
|
|
sizeof (FILE_ALLOCATION_INFORMATION),
|
|
L"FileAllocationInformation",
|
|
path);
|
|
|
|
do_set_file(handle,
|
|
FileEndOfFileInformation,
|
|
sizeof (FILE_END_OF_FILE_INFORMATION),
|
|
L"FileEndOfFileInformation",
|
|
path);
|
|
|
|
do_set_file(handle,
|
|
FilePipeInformation,
|
|
sizeof (FILE_PIPE_INFORMATION),
|
|
L"FilePipeInformation",
|
|
path);
|
|
|
|
do_set_file(handle,
|
|
FilePipeRemoteInformation,
|
|
sizeof (FILE_PIPE_REMOTE_INFORMATION),
|
|
L"FilePipeRemoteInformation",
|
|
path);
|
|
|
|
do_set_file(handle,
|
|
FileMailslotSetInformation,
|
|
sizeof (FILE_MAILSLOT_SET_INFORMATION),
|
|
L"FileMailslotSetInformation",
|
|
path);
|
|
|
|
do_set_file(handle,
|
|
FileObjectIdInformation,
|
|
sizeof (FILE_OBJECTID_INFORMATION),
|
|
L"FileObjectIdInformation",
|
|
path);
|
|
|
|
do_set_file(handle,
|
|
FileMoveClusterInformation,
|
|
sizeof (FILE_MOVE_CLUSTER_INFORMATION),
|
|
L"FileMoveClusterInformation",
|
|
path);
|
|
|
|
do_set_file(handle,
|
|
FileQuotaInformation,
|
|
sizeof (FILE_QUOTA_INFORMATION),
|
|
L"FileQuotaInformation",
|
|
path);
|
|
|
|
do_set_file(handle,
|
|
FileTrackingInformation,
|
|
sizeof (FILE_TRACKING_INFORMATION),
|
|
L"FileTrackingInformation",
|
|
path);
|
|
|
|
do_set_file(handle,
|
|
FileValidDataLengthInformation,
|
|
sizeof (FILE_VALID_DATA_LENGTH_INFORMATION),
|
|
L"FileValidDataLengthInformation",
|
|
path);
|
|
|
|
do_set_file(handle,
|
|
FileShortNameInformation,
|
|
sizeof (FILE_NAME_INFORMATION) + 1024,
|
|
L"FileShortNameInformation",
|
|
path);
|
|
|
|
do_query_volume(handle,
|
|
FileFsVolumeInformation,
|
|
sizeof( FILE_FS_VOLUME_INFORMATION ) + 1024,
|
|
L"FileFsVolumeInformation",
|
|
path);
|
|
|
|
do_query_volume(handle,
|
|
FileFsSizeInformation,
|
|
sizeof( FILE_FS_SIZE_INFORMATION ),
|
|
L"FileFsSizeInformation",
|
|
path);
|
|
|
|
do_query_volume(handle,
|
|
FileFsDeviceInformation,
|
|
sizeof( FILE_FS_DEVICE_INFORMATION ) + 1024,
|
|
L"FileFsDeviceInformation",
|
|
path);
|
|
|
|
do_query_volume(handle,
|
|
FileFsAttributeInformation,
|
|
sizeof( FILE_FS_ATTRIBUTE_INFORMATION ),
|
|
L"FileFsAttributeInformation",
|
|
path);
|
|
|
|
do_query_volume(handle,
|
|
FileFsControlInformation,
|
|
sizeof( FILE_FS_CONTROL_INFORMATION ),
|
|
L"FileFsControlInformation",
|
|
path);
|
|
|
|
do_query_volume(handle,
|
|
FileFsFullSizeInformation,
|
|
sizeof( FILE_FS_SIZE_INFORMATION ),
|
|
L"FileFsFullSizeInformation",
|
|
path);
|
|
|
|
do_query_volume(handle,
|
|
FileFsObjectIdInformation,
|
|
sizeof( FILE_FS_OBJECTID_INFORMATION ) + 1024,
|
|
L"FileFsObjectIdInformation",
|
|
path);
|
|
|
|
do_query_volume(handle,
|
|
FileFsDriverPathInformation,
|
|
sizeof( FILE_FS_DRIVER_PATH_INFORMATION ) + 1024,
|
|
L"FileFsDriverPathInformation",
|
|
path);
|
|
|
|
do_set_volume(handle,
|
|
FileFsObjectIdInformation,
|
|
sizeof( FILE_FS_OBJECTID_INFORMATION ) + 1024,
|
|
L"FileFsObjectIdInformation",
|
|
path);
|
|
|
|
do_set_volume(handle,
|
|
FileFsControlInformation,
|
|
sizeof( FILE_FS_CONTROL_INFORMATION ) + 1024,
|
|
L"FileFsControlInformation",
|
|
path);
|
|
|
|
do_set_volume(handle,
|
|
FileFsLabelInformation,
|
|
sizeof( FILE_FS_LABEL_INFORMATION ) + 1024,
|
|
L"FileFsLabelInformation",
|
|
path);
|
|
}
|
|
|
|
if (flags&FLAGS_DO_SECURITY) {
|
|
do_query_security(handle,
|
|
0,
|
|
1024,
|
|
L"NONE",
|
|
path);
|
|
|
|
do_query_security(handle,
|
|
OWNER_SECURITY_INFORMATION,
|
|
1024,
|
|
L"OWNER_SECURITY_INFORMATION",
|
|
path);
|
|
|
|
do_query_security(handle,
|
|
GROUP_SECURITY_INFORMATION,
|
|
1024,
|
|
L"GROUP_SECURITY_INFORMATION",
|
|
path);
|
|
|
|
do_query_security(handle,
|
|
DACL_SECURITY_INFORMATION,
|
|
1024,
|
|
L"DACL_SECURITY_INFORMATION",
|
|
path);
|
|
|
|
do_query_security(handle,
|
|
SACL_SECURITY_INFORMATION,
|
|
1024,
|
|
L"SACL_SECURITY_INFORMATION",
|
|
path);
|
|
|
|
do_set_security(handle,
|
|
0,
|
|
1024,
|
|
L"NONE",
|
|
path);
|
|
|
|
do_set_security(handle,
|
|
OWNER_SECURITY_INFORMATION,
|
|
1024,
|
|
L"OWNER_SECURITY_INFORMATION",
|
|
path);
|
|
|
|
do_set_security(handle,
|
|
GROUP_SECURITY_INFORMATION,
|
|
1024,
|
|
L"GROUP_SECURITY_INFORMATION",
|
|
path);
|
|
|
|
do_set_security(handle,
|
|
DACL_SECURITY_INFORMATION,
|
|
1024,
|
|
L"DACL_SECURITY_INFORMATION",
|
|
path);
|
|
|
|
do_set_security(handle,
|
|
SACL_SECURITY_INFORMATION,
|
|
1024,
|
|
L"SACL_SECURITY_INFORMATION",
|
|
path);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
Do the fast queries on the open path
|
|
*/
|
|
NTSTATUS
|
|
try_fast_query_delete_etc(
|
|
POBJECT_ATTRIBUTES poa,
|
|
PWCHAR path,
|
|
PWCHAR type)
|
|
{
|
|
PVOID fi = NULL;
|
|
NTSTATUS status;
|
|
ULONG ret;
|
|
|
|
if (!(flags&FLAGS_DO_MISC))
|
|
return 0;
|
|
|
|
status = STATUS_SUCCESS;
|
|
if (!crashes (path, L"NtQueryAttributesFile", type, L"", L"")) {
|
|
ret = 0;
|
|
do {
|
|
fi = reallocslop(fi,
|
|
sizeof (FILE_BASIC_INFORMATION));
|
|
status = NtQueryAttributesFile (poa, fi);
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtQueryAttributesFile failed %x\n", status);
|
|
}
|
|
testslop(fi,
|
|
sizeof (FILE_BASIC_INFORMATION), L"NtQueryAttributesFile", L"");
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
}
|
|
|
|
if (!crashes (path, L"NtQueryFullAttributesFile", type, L"", L"")) {
|
|
ret = 0;
|
|
do {
|
|
fi = reallocslop(fi,
|
|
sizeof (FILE_NETWORK_OPEN_INFORMATION));
|
|
status = NtQueryFullAttributesFile (poa, fi);
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtQueryFullAttributesFile failed %x\n", status);
|
|
}
|
|
testslop(fi,
|
|
sizeof (FILE_NETWORK_OPEN_INFORMATION), L"NtQueryFULLAttributesFile", L"");
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
}
|
|
|
|
|
|
if (!crashes (path, L"NtDeleteFile", type, L"", L"")) {
|
|
ret = 0;
|
|
do {
|
|
status = NtDeleteFile(poa);
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtDeleteFile failed %x\n", status);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
}
|
|
free (fi);
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
Do a whole bunch of random things
|
|
*/
|
|
NTSTATUS misc_functions(
|
|
HANDLE handle,
|
|
PWCHAR path,
|
|
ULONG sync
|
|
)
|
|
{
|
|
IO_STATUS_BLOCK iosb;
|
|
NTSTATUS status;
|
|
PVOID buf;
|
|
ULONG bufl;
|
|
LONG i;
|
|
HANDLE sectionhandle;
|
|
LARGE_INTEGER bo, bl;
|
|
ULONG ret, managed_read, managed_write;
|
|
|
|
if (!(flags&FLAGS_DO_MISC))
|
|
return STATUS_SUCCESS;
|
|
|
|
buf = malloc (bufl = 1024);
|
|
if (buf == 0) {
|
|
printf ("Failed to allocate buffer!\n");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
managed_read = 0;
|
|
if (!sync) {
|
|
if (!crashes (path, L"NtReadFile", L"", L"", L"")) {
|
|
for (i = bufl; i >= 0; i--) {
|
|
ret = 0;
|
|
do {
|
|
progress_counter++;
|
|
bo.QuadPart = 0;
|
|
status = NtReadFile (handle, NULL, NULL, NULL, &iosb, buf, i,
|
|
&bo, NULL);
|
|
if (NT_SUCCESS (status)) {
|
|
status = iosb.Status;
|
|
managed_read = 1;
|
|
}
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtReadFile failed %x\n", status);
|
|
}
|
|
progress_counter++;
|
|
bo.QuadPart = 0x7FFFFFFFFFFFFFFF - i + 1;
|
|
status = NtReadFile (handle, NULL, NULL, NULL, &iosb, buf, i,
|
|
&bo, NULL);
|
|
if (NT_SUCCESS (status))
|
|
status = iosb.Status;
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtReadFile failed %x\n", status);
|
|
}
|
|
NtCancelIoFile (handle, &iosb);
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
}
|
|
}
|
|
|
|
if (managed_read) {
|
|
printf ("Managed to read from the device\n");
|
|
if (diag_file) {
|
|
fwprintf (diag_file, L"Managed to read from device %s\r\n", path);
|
|
}
|
|
}
|
|
|
|
managed_write = 0;
|
|
if (!crashes (path, L"NtWriteFile", L"", L"", L"")) {
|
|
for (i = bufl; i >= 0; i--) {
|
|
ret = 0;
|
|
do {
|
|
progress_counter++;
|
|
bo.QuadPart = 0;
|
|
status = NtWriteFile (handle, NULL, NULL, NULL, &iosb, buf, i,
|
|
&bo, NULL);
|
|
if (NT_SUCCESS (status)) {
|
|
status = iosb.Status;
|
|
managed_write = 0;
|
|
}
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtWriteFile failed %x\n", status);
|
|
}
|
|
/*
|
|
Wrap to negative call
|
|
*/
|
|
progress_counter++;
|
|
bo.QuadPart = 0x7FFFFFFFFFFFFFFF - i + 1;
|
|
status = NtWriteFile (handle, NULL, NULL, NULL, &iosb, buf, i,
|
|
&bo, NULL);
|
|
if (NT_SUCCESS (status))
|
|
status = iosb.Status;
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtWriteFile failed %x\n", status);
|
|
}
|
|
/*
|
|
Do an append call.
|
|
*/
|
|
progress_counter++;
|
|
bo.QuadPart = -1;
|
|
status = NtWriteFile (handle, NULL, NULL, NULL, &iosb, buf, i,
|
|
&bo, NULL);
|
|
if (NT_SUCCESS (status))
|
|
status = iosb.Status;
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtWriteFile failed %x\n", status);
|
|
}
|
|
NtCancelIoFile (handle, &iosb);
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
}
|
|
}
|
|
if (managed_write) {
|
|
printf ("Managed to write to the device\n");
|
|
if (diag_file) {
|
|
fwprintf (diag_file, L"Managed to write to the device %s\r\n", path);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!crashes (path, L"NtCancelIoFile", L"", L"", L"")) {
|
|
ret = 0;
|
|
do {
|
|
status = NtCancelIoFile (handle, &iosb);
|
|
if (NT_SUCCESS (status))
|
|
status = iosb.Status;
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtCancelIoFile failed %x\n", status);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
}
|
|
|
|
if (!crashes (path, L"NtFlushBuffersFile", L"", L"", L"")) {
|
|
ret = 0;
|
|
do {
|
|
progress_counter++;
|
|
status = NtFlushBuffersFile (handle, &iosb);
|
|
if (NT_SUCCESS (status))
|
|
status = iosb.Status;
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtFlushBuffersFile failed %x\n", status);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
}
|
|
if (!crashes (path, L"NtQueryDirectoryFile", L"FileNamesInformation", L"", L"")) {
|
|
ULONG first = 1, j, datalen, l;
|
|
WCHAR bufn[1024];
|
|
PFILE_NAMES_INFORMATION tfni;
|
|
|
|
for (i = bufl; i >= 0; i--) {
|
|
ret = 0;
|
|
do {
|
|
progress_counter++;
|
|
status = NtQueryDirectoryFile (handle, NULL, NULL, NULL, &iosb, buf, i,
|
|
FileNamesInformation, FALSE, NULL, TRUE);
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtQueryDirectoryFile failed for type FileNamesInformation %x\n",
|
|
status);
|
|
} else if (first && status != STATUS_PENDING) {
|
|
first = 0;
|
|
datalen = (ULONG) iosb.Information;
|
|
for (j = 0; j < datalen; j += tfni->NextEntryOffset) {
|
|
tfni = (PFILE_NAMES_INFORMATION)((PCHAR)buf + j);
|
|
memset (bufn, 0, sizeof (bufn));
|
|
l = tfni->FileNameLength / sizeof (WCHAR);
|
|
if (l >= sizeof (bufn) / sizeof (bufn[0]))
|
|
l = sizeof (bufn) / sizeof (bufn[0]) - 1;
|
|
wcsncpy (bufn, tfni->FileName, l);
|
|
wprintf (L"-> %s\n", bufn);
|
|
if (tfni->NextEntryOffset == 0)
|
|
break;
|
|
}
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
}
|
|
}
|
|
if (!crashes (path, L"NtQueryDirectoryFile", L"FileDirectoryInformation", L"", L"")) {
|
|
for (i = bufl; i >= 0; i--) {
|
|
ret = 0;
|
|
do {
|
|
progress_counter++;
|
|
status = NtQueryDirectoryFile (handle, NULL, NULL, NULL, &iosb, buf, i,
|
|
FileDirectoryInformation, FALSE, NULL, TRUE);
|
|
if (NT_SUCCESS (status))
|
|
status = iosb.Status;
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtQueryDirectoryFile failed for type FileDirectoryInformation %x\n", status);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
}
|
|
}
|
|
if (!crashes (path, L"NtQueryDirectoryFile", L"FileFullDirectoryInformation", L"", L"")) {
|
|
for (i = bufl; i >= 0; i--) {
|
|
ret = 0;
|
|
do {
|
|
progress_counter++;
|
|
status = NtQueryDirectoryFile (handle, NULL, NULL, NULL, &iosb, buf, i,
|
|
FileFullDirectoryInformation, FALSE, NULL, TRUE);
|
|
if (NT_SUCCESS (status))
|
|
status = iosb.Status;
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtQueryDirectoryFile failed for type FileFullDirectoryInformation %x\n", status);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
}
|
|
}
|
|
|
|
if (!crashes (path, L"NtQueryDirectoryFile", L"FileBothDirectoryInformation", L"", L"")) {
|
|
for (i = bufl; i >= 0; i--) {
|
|
ret = 0;
|
|
do {
|
|
progress_counter++;
|
|
status = NtQueryDirectoryFile (handle, NULL, NULL, NULL, &iosb, buf, i,
|
|
FileBothDirectoryInformation, FALSE, NULL, TRUE);
|
|
if (NT_SUCCESS (status))
|
|
status = iosb.Status;
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtQueryDirectoryFile failed for type FileBothDirectoryInformation %x\n", status);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
}
|
|
}
|
|
|
|
if (!crashes (path, L"NtQueryDirectoryFile", L"FileObjectIdInformation", L"", L"")) {
|
|
for (i = bufl; i >= 0; i--) {
|
|
ret = 0;
|
|
do {
|
|
progress_counter++;
|
|
status = NtQueryDirectoryFile (handle, NULL, NULL, NULL, &iosb, buf, i,
|
|
FileObjectIdInformation, FALSE, NULL, TRUE);
|
|
if (NT_SUCCESS (status))
|
|
status = iosb.Status;
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtQueryDirectoryFile failed for type FileObjectIdInformation %x\n", status);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
}
|
|
}
|
|
|
|
if (!crashes (path, L"NtQueryDirectoryFile", L"FileQuotaInformation", L"", L"")) {
|
|
for (i = bufl; i >= 0; i--) {
|
|
ret = 0;
|
|
do {
|
|
progress_counter++;
|
|
status = NtQueryDirectoryFile (handle, NULL, NULL, NULL, &iosb, buf, i,
|
|
FileQuotaInformation, FALSE, NULL, TRUE);
|
|
if (NT_SUCCESS (status))
|
|
status = iosb.Status;
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtQueryDirectoryFile failed for type FileQuotaInformation %x\n", status);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
}
|
|
}
|
|
|
|
if (!crashes (path, L"NtQueryDirectoryFile", L"FileReparsePointInformation", L"", L"")) {
|
|
for (i = bufl; i >= 0; i--) {
|
|
ret = 0;
|
|
do {
|
|
progress_counter++;
|
|
status = NtQueryDirectoryFile (handle, NULL, NULL, NULL, &iosb, buf, i,
|
|
FileReparsePointInformation, FALSE, NULL, TRUE);
|
|
if (NT_SUCCESS (status))
|
|
status = iosb.Status;
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtQueryDirectoryFile failed for type FileReparsePointInformation %x\n", status);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
}
|
|
}
|
|
|
|
if (!crashes (path, L"NtVdmContol", L"VdmQueryDir", L"", L"")) {
|
|
VDMQUERYDIRINFO vqdi;
|
|
UNICODE_STRING name;
|
|
|
|
memset (&vqdi, 0, sizeof (vqdi));
|
|
RtlInitUnicodeString (&name, L"*");
|
|
for (i = bufl; i >= 0; i--) {
|
|
ret = 0;
|
|
do {
|
|
progress_counter++;
|
|
vqdi.FileHandle = handle;
|
|
vqdi.FileInformation = buf;
|
|
vqdi.Length = bufl;
|
|
vqdi.FileName = &name;
|
|
|
|
status = NtVdmControl(VdmQueryDir, &vqdi);
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtVdmControl failed for type VdmQueryDir %x\n", status);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
}
|
|
}
|
|
|
|
if (!sync) {
|
|
if (!crashes (path, L"NtNotifyChangeDirectoryFile", L"", L"", L"")) {
|
|
for (i = bufl; i >= 0; i--) {
|
|
ret = 0;
|
|
do {
|
|
progress_counter++;
|
|
status = NtNotifyChangeDirectoryFile (handle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&iosb,
|
|
buf,
|
|
i,
|
|
FILE_NOTIFY_CHANGE_FILE_NAME,
|
|
FALSE);
|
|
if (NT_SUCCESS (status))
|
|
status = iosb.Status;
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtNotifyChangeDirectoryFile failed %x\n", status);
|
|
}
|
|
NtCancelIoFile (handle, &iosb);
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
Query the EA info
|
|
*/
|
|
do_query_ea (handle, path);
|
|
|
|
if (!crashes (path, L"NtCreateSection", L"", L"", L"")) {
|
|
ret = 0;
|
|
do {
|
|
status = NtCreateSection (§ionhandle, GENERIC_READ,
|
|
NULL, NULL, PAGE_READONLY, SEC_COMMIT, handle);
|
|
if (NT_SUCCESS (status)) {
|
|
printf ("Created a section!\n");
|
|
status = NtClose (sectionhandle);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtClose on section handle failed %x\n", status);
|
|
}
|
|
} else if (flags&FLAGS_DO_ERRORS){
|
|
printf ("NtCreateSection failed %x\n", status);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
ret = 0;
|
|
do {
|
|
status = NtCreateSection (§ionhandle, GENERIC_READ,
|
|
NULL, NULL, PAGE_READONLY, SEC_IMAGE, handle);
|
|
if (NT_SUCCESS (status)) {
|
|
printf ("Created a section!\n");
|
|
status = NtClose (sectionhandle);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtClose on section handle failed %x\n", status);
|
|
}
|
|
} else if (flags&FLAGS_DO_ERRORS){
|
|
printf ("NtCreateSection failed for image %x\n", status);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
}
|
|
|
|
if (!crashes (path, L"NtLockFile", L"", L"", L"")) {
|
|
ret = 0;
|
|
do {
|
|
progress_counter++;
|
|
bl.QuadPart = 1;
|
|
bo.QuadPart = 1;
|
|
status = NtLockFile (handle, NULL, NULL, NULL, &iosb, &bo, &bl, 0, TRUE, FALSE);
|
|
if (NT_SUCCESS (status) && status != STATUS_PENDING) {
|
|
NtUnlockFile (handle, &iosb, &bo, &bl, 0);
|
|
}
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtLockFile failed %x\n", status);
|
|
}
|
|
NtCancelIoFile (handle, &iosb);
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
}
|
|
if (!crashes (path, L"NtUnlockFile", L"", L"", L"")) {
|
|
ret = 0;
|
|
do {
|
|
progress_counter++;
|
|
status = NtUnlockFile (handle, &iosb, &bo, &bl, 0);
|
|
if (NT_SUCCESS (status))
|
|
status = iosb.Status;
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtUnlockFile failed %x\n", status);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
}
|
|
if (!crashes (path, L"NtQueryQuotaInformationFile", L"", L"", L"")) {
|
|
for (i = bufl; i >= 0; i--) {
|
|
ret = 0;
|
|
do {
|
|
progress_counter++;
|
|
status = NtQueryQuotaInformationFile(handle, &iosb, buf, i, FALSE, NULL, 0,
|
|
NULL, TRUE);
|
|
if (NT_SUCCESS (status))
|
|
status = iosb.Status;
|
|
if (!NT_SUCCESS (status)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("NtQueryQuotaInformationFile failed %x\n", status);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
}
|
|
}
|
|
if (flags&FLAGS_DO_WINSOCK) {
|
|
if (!crashes (path, L"TransmitFile", L"", L"", L"")) {
|
|
progress_counter++;
|
|
if (!TransmitFile (cs, handle, 10, 0, NULL, NULL, TF_WRITE_BEHIND)) {
|
|
if (flags&FLAGS_DO_ERRORS)
|
|
printf ("TransmitFile failed %d\n", WSAGetLastError ());
|
|
}
|
|
}
|
|
}
|
|
NtCancelIoFile (devmap->handle, &iosb);
|
|
free (buf);
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
Get the access mask for this handle
|
|
*/
|
|
NTSTATUS
|
|
get_handle_access (HANDLE handle, PACCESS_MASK access)
|
|
{
|
|
NTSTATUS status;
|
|
OBJECT_BASIC_INFORMATION obi;
|
|
//
|
|
// Find out our handle access so we can know what IOCTLs and FSCTLs we can do.
|
|
//
|
|
status = NtQueryObject (handle,
|
|
ObjectBasicInformation,
|
|
&obi,
|
|
sizeof (obi),
|
|
NULL);
|
|
if (NT_SUCCESS (status)) {
|
|
*access = obi.GrantedAccess;
|
|
} else {
|
|
printf ("NtQueryObject for handle access failed %x\n", status);
|
|
*access = 0;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS check_tdi_handle (HANDLE handle)
|
|
{
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK iosb;
|
|
TDI_REQUEST_QUERY_INFORMATION trqi;
|
|
TDI_PROVIDER_INFO tpi;
|
|
|
|
trqi.QueryType = TDI_QUERY_PROVIDER_INFORMATION;
|
|
status = NtDeviceIoControlFile (handle, sync_event, NULL, NULL,
|
|
&iosb,
|
|
IOCTL_TDI_QUERY_INFORMATION,
|
|
&trqi,
|
|
sizeof (trqi),
|
|
&tpi,
|
|
sizeof (tpi));
|
|
if (status == STATUS_PENDING) {
|
|
status = NtWaitForSingleObject (sync_event, FALSE, NULL);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtWaitForSingleObject failed %x\n", status);
|
|
} else {
|
|
status = iosb.Status;
|
|
}
|
|
}
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtDeviceIoControlFile failed for IOCTL_TDI_QUERY_INFORMATION %x\n", status);
|
|
return status;
|
|
}
|
|
printf ("Detected a TDI driver\n");
|
|
return status;
|
|
}
|
|
//
|
|
// Do a load of opens etc relative from the current handle
|
|
//
|
|
NTSTATUS
|
|
do_sub_open_etc(
|
|
HANDLE handle,
|
|
PWCHAR s,
|
|
PWCHAR path
|
|
)
|
|
{
|
|
OBJECT_ATTRIBUTES oa;
|
|
UNICODE_STRING name;
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK iosb;
|
|
ACCESS_MASK access;
|
|
LARGE_INTEGER tmo;
|
|
PWCHAR as;
|
|
|
|
if (wcslen (s) > 30) {
|
|
as = L"Big...";
|
|
} else {
|
|
as = s;
|
|
}
|
|
|
|
if (crashes (path, L"Sub open", as, L"", L""))
|
|
return STATUS_SUCCESS;
|
|
|
|
wprintf (L"Doing sub open for %s\n", as);
|
|
RtlInitUnicodeString (&name, s);
|
|
InitializeObjectAttributes(&oa,
|
|
&name,
|
|
OBJ_CASE_INSENSITIVE,
|
|
handle,
|
|
NULL);
|
|
status = NtCreateFile(&handle,
|
|
MAXIMUM_ALLOWED,
|
|
&oa,
|
|
&iosb,
|
|
NULL,
|
|
0,
|
|
0,
|
|
FILE_OPEN,
|
|
0,
|
|
NULL,
|
|
0);
|
|
if (NT_SUCCESS (status))
|
|
status = iosb.Status;
|
|
if (NT_SUCCESS (status)) {
|
|
status = get_handle_access (handle, &access);
|
|
wprintf (L"Sub open for %s worked with access %x\n", as, access);
|
|
if (DELETE&access) {
|
|
printf ("Got delete access to device\n");
|
|
if (diag_file) {
|
|
fwprintf (diag_file, L"Got DELETE access to %s\r\n", path);
|
|
}
|
|
}
|
|
if (WRITE_DAC&access) {
|
|
printf ("Got write_dac access to device\n");
|
|
if (diag_file) {
|
|
fwprintf (diag_file, L"Got WRITE_DAC access to %s\r\n", path);
|
|
}
|
|
}
|
|
if (WRITE_OWNER&access) {
|
|
printf ("Got write_owner access to device\n");
|
|
if (diag_file) {
|
|
fwprintf (diag_file, L"Got WRITE_OWNER access to %s\r\n", path);
|
|
}
|
|
}
|
|
if (FILE_WRITE_ACCESS&access) {
|
|
printf ("Got write access to device\n");
|
|
if (diag_file) {
|
|
fwprintf (diag_file, L"Got FILE_WRITE_ACCESS access to %s\r\n", path);
|
|
}
|
|
}
|
|
if (FILE_READ_ACCESS&access) {
|
|
printf ("Got read access to device\n");
|
|
if (diag_file) {
|
|
fwprintf (diag_file, L"Got FILE_READ_ACCESS access to %s\r\n", path);
|
|
}
|
|
}
|
|
query_object(handle, NULL, path);
|
|
misc_functions (handle, path, 0);
|
|
status = NtClose (handle);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtClose failed %x\n", status);
|
|
}
|
|
} else {
|
|
printf ("NtCreateFile failed %x\n", status);
|
|
}
|
|
if (crashes (path, L"Sub create pipe", as, L"", L""))
|
|
return STATUS_SUCCESS;
|
|
|
|
tmo.QuadPart = 1000;
|
|
status = NtCreateNamedPipeFile (&handle,
|
|
MAXIMUM_ALLOWED,
|
|
&oa,
|
|
&iosb,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
FILE_CREATE,
|
|
0,
|
|
FILE_PIPE_MESSAGE_TYPE,
|
|
FILE_PIPE_MESSAGE_MODE,
|
|
FILE_PIPE_COMPLETE_OPERATION,
|
|
10,
|
|
1000, 1000,
|
|
&tmo);
|
|
if (NT_SUCCESS (status))
|
|
status = iosb.Status;
|
|
if (NT_SUCCESS (status)) {
|
|
status = get_handle_access (handle, &access);
|
|
wprintf (L"Sub create pipe for %s worked with access %x\n", as, access);
|
|
if (DELETE&access) {
|
|
printf ("Got delete access to device\n");
|
|
}
|
|
if (WRITE_DAC&access) {
|
|
printf ("Got write_dac access to device\n");
|
|
}
|
|
if (WRITE_OWNER&access) {
|
|
printf ("Got write_owner access to device\n");
|
|
}
|
|
query_object(handle, NULL, path);
|
|
misc_functions (handle, path, 0);
|
|
status = NtClose (handle);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtClose failed %x\n", status);
|
|
}
|
|
} else {
|
|
printf ("NtCreateNamedPipeFile failed %x\n", status);
|
|
}
|
|
if (crashes (path, L"Sub create mailslot", as, L"", L""))
|
|
return STATUS_SUCCESS;
|
|
|
|
tmo.QuadPart = 1000;
|
|
status = NtCreateMailslotFile (&handle,
|
|
MAXIMUM_ALLOWED,
|
|
&oa,
|
|
&iosb,
|
|
0,
|
|
1024,
|
|
256,
|
|
&tmo);
|
|
if (NT_SUCCESS (status)) {
|
|
status = get_handle_access (handle, &access);
|
|
wprintf (L"Sub create mailslot for %s worked with access %x\n", as, access);
|
|
if (DELETE&access) {
|
|
printf ("Got delete access to device\n");
|
|
}
|
|
if (WRITE_DAC&access) {
|
|
printf ("Got write_dac access to device\n");
|
|
}
|
|
if (WRITE_OWNER&access) {
|
|
printf ("Got write_owner access to device\n");
|
|
}
|
|
query_object(handle, NULL, path);
|
|
misc_functions (handle, path, 0);
|
|
status = NtClose (handle);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtClose failed %x\n", status);
|
|
}
|
|
} else {
|
|
printf ("NtCreateMailslotFile failed %x\n", status);
|
|
}
|
|
|
|
try_fast_query_delete_etc (&oa, path, L"Sub open");
|
|
return status;
|
|
}
|
|
//
|
|
// Try a few opens relative to the device its self.
|
|
//
|
|
NTSTATUS
|
|
try_funny_opens(
|
|
HANDLE handle,
|
|
PWCHAR path
|
|
)
|
|
{
|
|
ULONG ret, i;
|
|
static PWCHAR big=NULL;
|
|
static ULONG bigl;
|
|
|
|
if (!(flags&FLAGS_DO_SUBOPENS))
|
|
return 0;
|
|
|
|
if (big == NULL) {
|
|
big = malloc (bigl = 0x10000);
|
|
if (big == NULL) {
|
|
printf ("Memory allocation failure in try_funny_opens!\n");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
bigl /= sizeof (big[0]);
|
|
for (i = 0; i < bigl; i++)
|
|
big[i] = 'A';
|
|
big[bigl - 3] = '\0';
|
|
}
|
|
ret = 0;
|
|
do {
|
|
do_sub_open_etc (handle, L"", path);
|
|
do_sub_open_etc (handle, L" ", path);
|
|
do_sub_open_etc (handle, L"\\", path);
|
|
do_sub_open_etc (handle, L"\\\\\\\\\\\\", path);
|
|
do_sub_open_etc (handle, big, path);
|
|
if (flags&FLAGS_DO_STREAMS) {
|
|
do_sub_open_etc (handle, L":", path);
|
|
do_sub_open_etc (handle, L" :", path);
|
|
do_sub_open_etc (handle, L": ", path);
|
|
do_sub_open_etc (handle, L": ", path);
|
|
do_sub_open_etc (handle, L"::", path);
|
|
do_sub_open_etc (handle, L": :", path);
|
|
do_sub_open_etc (handle, L"::$UNUSED", path);
|
|
do_sub_open_etc (handle, L"::$STANDARD_INFORMATION", path);
|
|
do_sub_open_etc (handle, L"::$ATTRIBUTE_LIST", path);
|
|
do_sub_open_etc (handle, L"::$FILE_NAME", path);
|
|
do_sub_open_etc (handle, L"::$OBJECT_ID", path);
|
|
do_sub_open_etc (handle, L"::$SECURITY_DESCRIPTOR", path);
|
|
do_sub_open_etc (handle, L"::$VOLUME_NAME", path);
|
|
do_sub_open_etc (handle, L"::$VOLUME_INFORMATION", path);
|
|
do_sub_open_etc (handle, L"::$DATA", path);
|
|
do_sub_open_etc (handle, L"::$INDEX_ROOT", path);
|
|
do_sub_open_etc (handle, L"::$INDEX_ALLOCATION", path);
|
|
do_sub_open_etc (handle, L"::$BITMAP", path);
|
|
do_sub_open_etc (handle, L"::$REPARSE_POINT", path);
|
|
do_sub_open_etc (handle, L"::$EA_INFORMATION", path);
|
|
do_sub_open_etc (handle, L"::$PROPERTY_SET", path);
|
|
do_sub_open_etc (handle, L"::$FIRST_USER_DEFINED_ATTRIBUTE", path);
|
|
do_sub_open_etc (handle, L"::$END", path);
|
|
}
|
|
} while (print_diags (0, ret++) && ret < MAX_RET);
|
|
return 0;
|
|
}
|
|
|
|
VOID
|
|
randomize_buf(
|
|
PVOID buf,
|
|
ULONG bufl
|
|
)
|
|
{
|
|
ULONG i;
|
|
PUCHAR pc = buf;
|
|
|
|
for (i = 0; i < bufl; i++) {
|
|
pc[i] = rand() & 0xff;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Thread used to randomize buffers
|
|
*/
|
|
DWORD WINAPI
|
|
randomize(
|
|
PVOID buf
|
|
)
|
|
{
|
|
ULONG i;
|
|
PUCHAR pc = buf;
|
|
|
|
while (1) {
|
|
try {
|
|
for (i = 0; i < BIGBUF_SIZE; i++) {
|
|
pc[i] = rand() & 0xff;
|
|
}
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
}
|
|
Sleep (0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// changeprot and alerter won't return and we do not need to be
|
|
// told this by the compiler
|
|
#pragma warning(disable:4715)
|
|
|
|
DWORD WINAPI
|
|
changeprot(
|
|
PVOID buf
|
|
)
|
|
{
|
|
DWORD old;
|
|
|
|
while (1) {
|
|
if (!VirtualProtect (buf, 1, PAGE_READONLY, &old)) {
|
|
printf ("VirtualProtect failed %d\n", GetLastError ());
|
|
}
|
|
Sleep (1);
|
|
if (!VirtualProtect (buf, 1, PAGE_NOACCESS, &old)) {
|
|
printf ("VirtualProtect failed %d\n", GetLastError ());
|
|
}
|
|
Sleep (1);
|
|
if (!VirtualProtect (buf, 1, PAGE_GUARD|PAGE_READONLY, &old)) {
|
|
printf ("VirtualProtect failed %d\n", GetLastError ());
|
|
}
|
|
Sleep (1);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
Thread used to alert the main
|
|
*/
|
|
DWORD WINAPI
|
|
alerter(
|
|
PVOID handle
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
ULONG last = progress_counter, count;
|
|
|
|
//
|
|
// Do a nasty hack to keep the main thread moving if it gets stuck in a sync IOCTL
|
|
//
|
|
while (1) {
|
|
if (flags&FLAGS_DO_ALERT) {
|
|
Sleep (0);
|
|
} else {
|
|
last = progress_counter;
|
|
Sleep (60000);
|
|
if (progress_counter == 0 || progress_counter != last) {
|
|
continue;
|
|
}
|
|
printf ("Alerting thread\n");
|
|
}
|
|
// status = NtAlertResumeThread ((HANDLE) handle, &count);
|
|
// if (!NT_SUCCESS (status)) {
|
|
// printf ("NtAlertResumeThread failed %x\n", status);
|
|
// }
|
|
status = NtAlertThread ((HANDLE) handle);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtAlertThread failed %x\n", status);
|
|
}
|
|
alerted++;
|
|
if (alerted > 10) {
|
|
if (diag_file) {
|
|
fwprintf (diag_file, L"Main thread appears hung. Teminating process\r\n");
|
|
fflush (diag_file);
|
|
NtTerminateProcess (NtCurrentProcess (), 0);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#pragma warning(3:4715)
|
|
|
|
void record_ioctl (PIOCTLREC *piorec, ULONG ioctl, NTSTATUS status)
|
|
{
|
|
PIOCTLREC iorec = *piorec;
|
|
IOCTLINFO tmp;
|
|
ULONG i, j, new;
|
|
|
|
if (!iorec) {
|
|
iorec = malloc (sizeof (*iorec) +
|
|
INITIAL_IOCTL_TAILOR_SIZE * sizeof (iorec->ioctl[0]));
|
|
if (!iorec) {
|
|
return;
|
|
}
|
|
*piorec = iorec;
|
|
iorec->total = INITIAL_IOCTL_TAILOR_SIZE;
|
|
iorec->count = 0;
|
|
iorec->start = 0;
|
|
}
|
|
new = 1;
|
|
for (i = 0; i < iorec->count; i++) {
|
|
if (iorec->ioctl[i].ioctl == ioctl && iorec->ioctl[i].status == status) {
|
|
return;
|
|
}
|
|
if (iorec->ioctl[i].status == status) {
|
|
new = 0;
|
|
if (iorec->ioctl[i].count > MAX_IOCTL_TAILOR) {
|
|
return; // too many seen of this one
|
|
}
|
|
if (++iorec->ioctl[i].count > MAX_IOCTL_TAILOR) {
|
|
printf ("Removing IOCTLs with status %X\n", status);
|
|
for (j = i + 1; j < iorec->count; j++) {
|
|
if (iorec->ioctl[j].status == status) {
|
|
/*
|
|
printf ("Removing IOCTL %X with status %X\n",
|
|
iorec->ioctl[j].ioctl, iorec->ioctl[j].status);
|
|
*/
|
|
iorec->ioctl[j] = iorec->ioctl[--iorec->count];
|
|
j--;
|
|
}
|
|
}
|
|
tmp = iorec->ioctl[iorec->start];
|
|
iorec->ioctl[iorec->start++] = iorec->ioctl[i];
|
|
iorec->ioctl[i] = tmp;
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (new) {
|
|
printf ("New status for IOCTL %X status %X\n", ioctl, status);
|
|
}
|
|
if (iorec->total == iorec->count) {
|
|
iorec = realloc (iorec, sizeof (*iorec) +
|
|
iorec->total * 2 * sizeof (iorec->ioctl[0]));
|
|
if (!iorec) {
|
|
return;
|
|
}
|
|
*piorec = iorec;
|
|
iorec->total *= 2;
|
|
}
|
|
i = iorec->count;
|
|
iorec->ioctl[i].status = status;
|
|
iorec->ioctl[i].ioctl = ioctl;
|
|
iorec->ioctl[i].count = 0;
|
|
iorec->count = i + 1;
|
|
}
|
|
|
|
void do_tailored_ioctl (PDEVMAP devmap,
|
|
PWCHAR path,
|
|
PIOCTLREC iorec,
|
|
ULONG fsctl)
|
|
{
|
|
ULONG method, ioctl_val;
|
|
PVOID inbuf, outbuf;
|
|
ULONG inlen, outlen;
|
|
static IO_STATUS_BLOCK static_iosb;
|
|
ULONG ret;
|
|
ULONG i, j, k;
|
|
WCHAR num[20];
|
|
NTSTATUS status;
|
|
ULONG tmp;
|
|
DWORD old;
|
|
ULONG done_something;
|
|
|
|
if (!iorec) {
|
|
return;
|
|
}
|
|
|
|
do {
|
|
done_something = 0;
|
|
for (i = 1; i < iorec->count; i++) {
|
|
IOCTLINFO ii;
|
|
if (iorec->ioctl[i-1].ioctl < iorec->ioctl[i].ioctl) {
|
|
continue;
|
|
} else if (iorec->ioctl[i-1].ioctl == iorec->ioctl[i].ioctl &&
|
|
iorec->ioctl[i-1].count <= iorec->ioctl[i].count) {
|
|
continue;
|
|
}
|
|
ii = iorec->ioctl[i-1];
|
|
iorec->ioctl[i-1] = iorec->ioctl[i];
|
|
iorec->ioctl[i] = ii;
|
|
done_something = 1;
|
|
}
|
|
} while (done_something);
|
|
|
|
for (i = 0; i < iorec->count; i++) {
|
|
if (iorec->ioctl[i].count >= MAX_IOCTL_TAILOR) {
|
|
continue;
|
|
}
|
|
if (i > 0 && iorec->ioctl[i].ioctl == iorec->ioctl[i-1].ioctl) {
|
|
continue;
|
|
}
|
|
ioctl_val = iorec->ioctl[i].ioctl;
|
|
method = ioctl_val&0x3;
|
|
_snwprintf (num, sizeof (num) / sizeof (WCHAR), L"%%X%X", ioctl_val);
|
|
if (crashes (path, L"IOCTL value", num, L"", L""))
|
|
continue;
|
|
|
|
alerted = 0;
|
|
for (j = 0; j < max_tailured_calls; j += RAND_REP) {
|
|
ret = 0;
|
|
do {
|
|
if (ret != 0) {
|
|
printf ("Re-doing random with ioctl %%X%x\n", ioctl_val);
|
|
}
|
|
|
|
for (k = 0; k < RAND_REP; k++) {
|
|
switch(method) {
|
|
case METHOD_BUFFERED :
|
|
|
|
inlen = RandInRange( ioctl_inbuf_min, ioctl_inbuf_max );
|
|
outlen = RandInRange( ioctl_outbuf_min, ioctl_outbuf_max );
|
|
|
|
inbuf = bigbuf;
|
|
if (outlen == 0)
|
|
outbuf = (PVOID) -1024;
|
|
else
|
|
outbuf = bigbuf;
|
|
|
|
randomize_buf (inbuf, inlen);
|
|
break;
|
|
|
|
case METHOD_IN_DIRECT :
|
|
case METHOD_OUT_DIRECT :
|
|
|
|
inlen = RandInRange( ioctl_inbuf_min, ioctl_inbuf_max );
|
|
outlen = RandInRange( ioctl_outbuf_min, ioctl_outbuf_max );
|
|
|
|
inbuf = bigbuf;
|
|
outbuf = &bigbuf[BIGBUF_SIZE - outlen];
|
|
randomize_buf (inbuf, inlen);
|
|
randomize_buf (outbuf, outlen);
|
|
|
|
break;
|
|
|
|
case METHOD_NEITHER :
|
|
|
|
switch (rand ()&3) {
|
|
//
|
|
// Completely random pointers. We may corrupt ourselves here
|
|
// case 0 :
|
|
// inlen = rand32();
|
|
// outlen = rand32();
|
|
//
|
|
// inbuf = (PVOID)rand32();
|
|
// outbuf = (PVOID)rand32();
|
|
// break;
|
|
|
|
//
|
|
// Kernel crashing pointers with smallish lengths
|
|
case 1 :
|
|
inbuf = (PVOID) -1024;
|
|
outbuf = (PVOID) -1024;
|
|
inlen = RandInRange( ioctl_inbuf_min, ioctl_inbuf_max );
|
|
outlen = RandInRange( ioctl_outbuf_min, ioctl_outbuf_max );
|
|
break;
|
|
//
|
|
// Good pointers
|
|
case 0 :
|
|
case 2 :
|
|
inlen = RandInRange( ioctl_inbuf_min, ioctl_inbuf_max );
|
|
outlen = RandInRange( ioctl_outbuf_min, ioctl_outbuf_max );
|
|
|
|
inbuf = &bigbuf[BIGBUF_SIZE - outlen];
|
|
outbuf = &bigbuf[BIGBUF_SIZE - outlen];
|
|
break;
|
|
//
|
|
// Bad user mode pointers
|
|
case 3 :
|
|
inlen = rand() & 0xFFFF;
|
|
outlen = rand() & 0xFFFF;
|
|
inbuf = UintToPtr( rand() & 0xFFFF );
|
|
outbuf = UintToPtr( rand() & 0xFFFF );
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
progress_counter++;
|
|
if (!fsctl) {
|
|
status = NtDeviceIoControlFile(devmap->handle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&static_iosb,
|
|
ioctl_val,
|
|
inbuf,
|
|
inlen,
|
|
outbuf,
|
|
outlen);
|
|
} else {
|
|
status = NtFsControlFile(devmap->handle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&static_iosb,
|
|
ioctl_val,
|
|
inbuf,
|
|
inlen,
|
|
outbuf,
|
|
outlen);
|
|
}
|
|
}
|
|
NtCancelIoFile (devmap->handle, &static_iosb);
|
|
if (alerted > 5) {
|
|
break;
|
|
}
|
|
} while (print_diags ((method == METHOD_BUFFERED)?0:DIAG_NOEXCEPTIONS, ret++) && ret < MAX_RET);
|
|
if (alerted > 5) {
|
|
break;
|
|
}
|
|
|
|
}
|
|
if (!(flags&FLAGS_DO_PROT) ||
|
|
crashes (path, L"IOCTL prot value", num, L"", L"")) {
|
|
continue;
|
|
}
|
|
|
|
status = NtResumeThread (changethread, &tmp);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtResumeThread failed %x\n", status);
|
|
}
|
|
|
|
for (i = 1; i < PROT_REP; i += RAND_REP) {
|
|
ret = 0;
|
|
do {
|
|
if (ret != 0) {
|
|
printf ("Re-doing random with ioctl %%X%x\n", ioctl_val);
|
|
}
|
|
for (k = 0; k < RAND_REP; k++) {
|
|
if (!VirtualProtect (bigbuf, 1, PAGE_READWRITE, &old)) {
|
|
printf ("VirtualProtect failed %d\n", GetLastError ());
|
|
}
|
|
inlen = RandInRange( ioctl_inbuf_min, ioctl_inbuf_max );
|
|
outlen = RandInRange( ioctl_outbuf_min, ioctl_outbuf_max );
|
|
|
|
inbuf = bigbuf;
|
|
outbuf = bigbuf;
|
|
|
|
progress_counter++;
|
|
if (!fsctl) {
|
|
status = NtDeviceIoControlFile(devmap->handle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&static_iosb,
|
|
ioctl_val,
|
|
inbuf,
|
|
inlen,
|
|
outbuf,
|
|
outlen);
|
|
} else {
|
|
status = NtFsControlFile(devmap->handle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&static_iosb,
|
|
ioctl_val,
|
|
inbuf,
|
|
inlen,
|
|
outbuf,
|
|
outlen);
|
|
}
|
|
}
|
|
NtCancelIoFile (devmap->handle, &static_iosb);
|
|
if (alerted > 5) {
|
|
break;
|
|
}
|
|
} while (print_diags (DIAG_NOEXCEPTIONS, ret++) && ret < MAX_RET);
|
|
|
|
if (alerted > 5) {
|
|
break;
|
|
}
|
|
}
|
|
status = NtSuspendThread (changethread, &tmp);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtResumeThread failed %x\n", status);
|
|
}
|
|
if (!VirtualProtect (bigbuf, 1, PAGE_READWRITE, &old)) {
|
|
printf ("VirtualProtect failed %d\n", GetLastError ());
|
|
}
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
do_ioctl(
|
|
PDEVMAP devmap,
|
|
PWCHAR path
|
|
)
|
|
{
|
|
ULONG function, method, access, i, j, ioctl_val;
|
|
static IO_STATUS_BLOCK static_iosb;
|
|
PVOID inbuf, outbuf;
|
|
ULONG inlen, outlen;
|
|
ULONG tmp;
|
|
NTSTATUS status;
|
|
ULONG devtype;
|
|
ULONG ret;
|
|
BOOL hit_leak;
|
|
WCHAR num[20];
|
|
PIOCTLREC iorec = NULL, fsrec = NULL;
|
|
ULONG set_rand;
|
|
|
|
if ((flags&(FLAGS_DO_IOCTL_NULL|FLAGS_DO_FSCTL_NULL)) &&
|
|
ioctl_inbuf_min == 0 && ioctl_outbuf_min == 0) {
|
|
//
|
|
// do I/O calls with no buffer
|
|
//
|
|
for (function = ioctl_min_function; function <= ioctl_max_function; function++) {
|
|
_snwprintf (num, sizeof (num) / sizeof (WCHAR), L"%d", function);
|
|
if (crashes (path, L"IOCTL function ", num, L"", L""))
|
|
continue;
|
|
for (devtype = ioctl_min_devtype; devtype <= ioctl_max_devtype; devtype++) {
|
|
ret = 0;
|
|
do {
|
|
if (ret != 0)
|
|
printf ("Re-doing devtype = %d, function = %d\n", devtype, function);
|
|
hit_leak = FALSE;
|
|
for (access = FILE_ANY_ACCESS;
|
|
access <= (devmap->access&(FILE_READ_ACCESS|FILE_WRITE_ACCESS));
|
|
access++) {
|
|
for (method = 0; method < 4; method++) {
|
|
ioctl_val = CTL_CODE(devtype, function, method, access);
|
|
|
|
progress_counter++;
|
|
if ((flags&FLAGS_DO_IOCTL_NULL)) {
|
|
status = NtDeviceIoControlFile(devmap->handle,
|
|
NULL, NULL, NULL,
|
|
&static_iosb,
|
|
ioctl_val,
|
|
(PVOID) -1024,
|
|
0,
|
|
(PVOID) -1024,
|
|
0);
|
|
record_ioctl (&iorec, ioctl_val, status);
|
|
}
|
|
if ((flags&FLAGS_DO_FSCTL_NULL)) {
|
|
status = NtFsControlFile(devmap->handle, NULL, NULL, NULL,
|
|
&static_iosb,
|
|
ioctl_val,
|
|
(PVOID) -1024,
|
|
0,
|
|
(PVOID) -1024,
|
|
0);
|
|
record_ioctl (&fsrec, ioctl_val, status);
|
|
}
|
|
Sleep (0);
|
|
}
|
|
}
|
|
if (ret > (MAX_RET * 95 ) / 100) {
|
|
NtCancelIoFile (devmap->handle, &static_iosb);
|
|
//
|
|
// Report exceptions for method buffered.
|
|
// This may be ok but its worth knowing.
|
|
//
|
|
if (print_diags ((method == METHOD_BUFFERED)?0:DIAG_NOEXCEPTIONS, ret++)) {
|
|
printf ("IOCTL/FSCTL %x devtype %x (%d) function %x (%d) access %x method %x\n",
|
|
ioctl_val, devtype, devtype, function, function,
|
|
access, method);
|
|
hit_leak = TRUE;
|
|
}
|
|
}
|
|
NtCancelIoFile (devmap->handle, &static_iosb);
|
|
} while ((hit_leak || print_diags ((method == METHOD_BUFFERED)?0:DIAG_NOEXCEPTIONS, ret++)) && ret < MAX_RET);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (flags&(FLAGS_DO_IOCTL_RANDOM|FLAGS_DO_FSCTL_RANDOM) &&
|
|
!crashes (path, L"IOCTL", L"random", L"", L"")) {
|
|
// if (!(flags&FLAGS_DO_RANDOM_DEVICE)) {
|
|
// status = NtResumeThread (randthread, &tmp);
|
|
// if (!NT_SUCCESS (status)) {
|
|
// printf ("NtResumeThread failed %x\n", status);
|
|
// }
|
|
// }
|
|
for (i = 0; i < max_random_calls; i += RAND_REP) {
|
|
if (ioctl_min_function >= ioctl_max_function)
|
|
function = ioctl_min_function;
|
|
else
|
|
function = RandInRange( ioctl_min_function, ioctl_max_function );
|
|
ret = 0;
|
|
do {
|
|
if (ret != 0) {
|
|
printf ("Re-doing random with function %x\n", function);
|
|
}
|
|
for (j = 0; j < RAND_REP; j++) {
|
|
if (ioctl_min_devtype >= ioctl_max_devtype)
|
|
devtype = ioctl_min_devtype;
|
|
else
|
|
devtype = RandInRange( ioctl_min_devtype, ioctl_max_devtype );
|
|
|
|
switch (rand ()&3) {
|
|
case 0 :
|
|
if (fsrec && fsrec->count - fsrec->start) {
|
|
devtype = fsrec->ioctl[fsrec->start +
|
|
(rand()%(fsrec->count - fsrec->start))].ioctl>>16;
|
|
}
|
|
break;
|
|
case 1 :
|
|
if (iorec && iorec->count - iorec->start) {
|
|
devtype = iorec->ioctl[iorec->start +
|
|
(rand()%(iorec->count - iorec->start))].ioctl>>16;
|
|
}
|
|
break;
|
|
case 2 :
|
|
case 3 :
|
|
break;
|
|
}
|
|
method = rand() & 0x3;
|
|
|
|
access = rand() & devmap->access&(FILE_READ_ACCESS|FILE_WRITE_ACCESS);
|
|
|
|
ioctl_val = CTL_CODE(devtype,
|
|
function,
|
|
method,
|
|
access);
|
|
|
|
set_rand = 0;
|
|
switch(method) {
|
|
case METHOD_BUFFERED :
|
|
|
|
inlen = RandInRange( ioctl_inbuf_min, ioctl_inbuf_max );
|
|
outlen = RandInRange( ioctl_outbuf_min, ioctl_outbuf_max );
|
|
|
|
inbuf = bigbuf;
|
|
if (outlen == 0)
|
|
outbuf = (PVOID) -1024;
|
|
else
|
|
outbuf = bigbuf;
|
|
|
|
set_rand = 1;
|
|
break;
|
|
|
|
case METHOD_IN_DIRECT :
|
|
case METHOD_OUT_DIRECT :
|
|
|
|
inlen = RandInRange( ioctl_inbuf_min, ioctl_inbuf_max );
|
|
outlen = RandInRange( ioctl_outbuf_min, ioctl_outbuf_max );
|
|
|
|
inbuf = bigbuf;
|
|
outbuf = &bigbuf[BIGBUF_SIZE - outlen];
|
|
// printf ("%p %d %p %d\n", inbuf, inlen, outbuf, outlen);
|
|
|
|
set_rand = 1;
|
|
break;
|
|
|
|
case METHOD_NEITHER :
|
|
|
|
switch (rand ()&3) {
|
|
//
|
|
// Completely random pointers. We may corrupt ourselves here
|
|
// case 0 :
|
|
// inlen = rand32();
|
|
// outlen = rand32();
|
|
//
|
|
// inbuf = (PVOID)rand32();
|
|
// outbuf = (PVOID)rand32();
|
|
// break;
|
|
|
|
//
|
|
// Kernel crashing pointers with smallish lengths
|
|
case 1 :
|
|
inbuf = (PVOID) -1024;
|
|
outbuf = (PVOID) -1024;
|
|
inlen = RandInRange( ioctl_inbuf_min, ioctl_inbuf_max );
|
|
outlen = RandInRange( ioctl_outbuf_min, ioctl_outbuf_max );
|
|
break;
|
|
//
|
|
// Good pointers
|
|
case 0 :
|
|
case 2 :
|
|
inlen = RandInRange( ioctl_inbuf_min, ioctl_inbuf_max );
|
|
outlen = RandInRange( ioctl_outbuf_min, ioctl_outbuf_max );
|
|
|
|
inbuf = &bigbuf[BIGBUF_SIZE - outlen];
|
|
outbuf = &bigbuf[BIGBUF_SIZE - outlen];
|
|
set_rand = 1;
|
|
break;
|
|
//
|
|
// Bad user mode pointers
|
|
case 3 :
|
|
inlen = rand() & 0xFFFF;
|
|
outlen = rand() & 0xFFFF;
|
|
inbuf = UintToPtr( rand() & 0xFFFF);
|
|
outbuf = UintToPtr( rand() & 0xFFFF);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (set_rand) {
|
|
randomize_buf (inbuf, inlen);
|
|
}
|
|
progress_counter++;
|
|
if (flags&FLAGS_DO_IOCTL_RANDOM) {
|
|
status = NtDeviceIoControlFile(devmap->handle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&static_iosb,
|
|
ioctl_val,
|
|
inbuf,
|
|
inlen,
|
|
outbuf,
|
|
outlen);
|
|
record_ioctl (&iorec, ioctl_val, status);
|
|
}
|
|
|
|
if (flags&FLAGS_DO_FSCTL_RANDOM) {
|
|
status = NtFsControlFile(devmap->handle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&static_iosb,
|
|
ioctl_val,
|
|
inbuf,
|
|
inlen,
|
|
outbuf,
|
|
outlen);
|
|
record_ioctl (&fsrec, ioctl_val, status);
|
|
}
|
|
}
|
|
|
|
NtCancelIoFile (devmap->handle, &static_iosb);
|
|
} while (print_diags ((method == METHOD_BUFFERED)?0:DIAG_NOEXCEPTIONS, ret++) && ret < MAX_RET);
|
|
}
|
|
|
|
// if (!(flags&FLAGS_DO_RANDOM_DEVICE)) {
|
|
// status = NtSuspendThread (randthread, &tmp);
|
|
// if (!NT_SUCCESS (status)) {
|
|
// printf ("NtSuspendThread failed %x\n", status);
|
|
// }
|
|
// }
|
|
}
|
|
if (flags&FLAGS_DO_IOCTL_RANDOM) {
|
|
do_tailored_ioctl (devmap, path, iorec, 0);
|
|
}
|
|
if (flags&FLAGS_DO_FSCTL_RANDOM) {
|
|
do_tailored_ioctl (devmap, path, fsrec, 1);
|
|
}
|
|
|
|
if (iorec) {
|
|
free (iorec);
|
|
}
|
|
if (fsrec) {
|
|
free (fsrec);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
PFILE_FULL_EA_INFORMATION build_adr_ea (PCHAR name, USHORT adrtype,
|
|
USHORT adrl, PVOID padr,
|
|
PULONG peal)
|
|
{
|
|
PFILE_FULL_EA_INFORMATION ea = NULL;
|
|
TRANSPORT_ADDRESS UNALIGNED *pta;
|
|
TA_ADDRESS *ptaa;
|
|
ULONG eal;
|
|
ULONG nl;
|
|
|
|
nl = strlen (name);
|
|
eal = sizeof (FILE_FULL_EA_INFORMATION) + nl +
|
|
sizeof (TRANSPORT_ADDRESS) - 1 + adrl;
|
|
ea = malloc (eal);
|
|
if (!ea) {
|
|
printf ("Failed to allocate %d bytes\n", eal);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
memset (ea, 0, eal);
|
|
ea->EaNameLength = (UCHAR) nl;
|
|
strcpy (ea->EaName, name);
|
|
ea->EaValueLength = (USHORT)(eal - sizeof (*ea) - nl);
|
|
pta = (TRANSPORT_ADDRESS UNALIGNED *)(ea->EaName + nl + 1);
|
|
pta->TAAddressCount = 1;
|
|
ptaa = (TA_ADDRESS *) pta->Address;
|
|
ptaa->AddressLength = adrl;
|
|
ptaa->AddressType = adrtype;
|
|
memcpy (ptaa->Address, padr, adrl);
|
|
*peal = eal;
|
|
return ea;
|
|
}
|
|
|
|
PFILE_FULL_EA_INFORMATION build_con_ea (PCHAR name, CONNECTION_CONTEXT ctx,
|
|
PULONG peal)
|
|
{
|
|
PFILE_FULL_EA_INFORMATION ea = NULL;
|
|
CONNECTION_CONTEXT UNALIGNED *pctx;
|
|
ULONG eal;
|
|
ULONG nl;
|
|
|
|
nl = strlen (name);
|
|
eal = sizeof (FILE_FULL_EA_INFORMATION) + nl +
|
|
sizeof (ctx);
|
|
ea = malloc (eal);
|
|
if (!ea) {
|
|
printf ("Failed to allocate %d bytes\n", eal);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
memset (ea, 0, eal);
|
|
ea->EaNameLength = (UCHAR) nl;
|
|
strcpy (ea->EaName, name);
|
|
ea->EaValueLength = (USHORT)(eal - sizeof (*ea) - nl);
|
|
pctx = (CONNECTION_CONTEXT UNALIGNED*) (ea->EaName + nl + 1);
|
|
*pctx = ctx;
|
|
*peal = eal;
|
|
return ea;
|
|
}
|
|
|
|
#define DRIVER_PREFIX1 L"\\Driver\\"
|
|
#define DRIVER_PREFIX2 L"\\FileSystem\\"
|
|
|
|
NTSTATUS
|
|
check_driver (HANDLE handle,
|
|
PUNICODE_STRING DriverName)
|
|
/*
|
|
Check to see if the specified device object is associated with the driver object
|
|
*/
|
|
{
|
|
PFILE_FS_DRIVER_PATH_INFORMATION fsDpInfo;
|
|
ULONG fsDpSize;
|
|
ULONG DriverBufferLength;
|
|
UNICODE_STRING us;
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK iosb;
|
|
|
|
DriverBufferLength = sizeof (DRIVER_PREFIX1);
|
|
if (sizeof (DRIVER_PREFIX2) > DriverBufferLength) {
|
|
DriverBufferLength = sizeof (DRIVER_PREFIX2);
|
|
}
|
|
DriverBufferLength += DriverName->Length;
|
|
|
|
fsDpSize = sizeof(FILE_FS_DRIVER_PATH_INFORMATION) + DriverBufferLength;
|
|
|
|
fsDpInfo = malloc (fsDpSize);
|
|
if (fsDpInfo == 0) {
|
|
printf ("Failed to allocate buffer for driver query\n");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
ZeroMemory(fsDpInfo, fsDpSize);
|
|
|
|
us.MaximumLength = (USHORT)DriverBufferLength;
|
|
us.Length = 0;
|
|
us.Buffer = fsDpInfo->DriverName;
|
|
RtlAppendUnicodeToString (&us, DRIVER_PREFIX1);
|
|
RtlAppendUnicodeStringToString (&us, DriverName);
|
|
fsDpInfo->DriverNameLength = us.Length;
|
|
|
|
|
|
status = NtQueryVolumeInformationFile(handle,
|
|
&iosb,
|
|
fsDpInfo,
|
|
fsDpSize,
|
|
FileFsDriverPathInformation);
|
|
|
|
if (NT_SUCCESS (status)) {
|
|
if (fsDpInfo->DriverInPath) {
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = -1;
|
|
}
|
|
free (fsDpInfo);
|
|
return status;
|
|
}
|
|
|
|
us.MaximumLength = (USHORT)DriverBufferLength;
|
|
us.Length = 0;
|
|
us.Buffer = fsDpInfo->DriverName;
|
|
RtlAppendUnicodeToString (&us, DRIVER_PREFIX2);
|
|
RtlAppendUnicodeStringToString (&us, DriverName);
|
|
fsDpInfo->DriverNameLength = us.Length;
|
|
status = NtQueryVolumeInformationFile(handle,
|
|
&iosb,
|
|
fsDpInfo,
|
|
fsDpSize,
|
|
FileFsDriverPathInformation);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtQueryVolumeInformationFile for FileFsDriverPathInformation failed %x\n", status);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
if (fsDpInfo->DriverInPath) {
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = -1;
|
|
}
|
|
free (fsDpInfo);
|
|
return status;
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
do_open_close_thread (
|
|
LPVOID arg)
|
|
{
|
|
ULONG i;
|
|
POBJECT_ATTRIBUTES oa = arg;
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK iosb;
|
|
HANDLE handle;
|
|
|
|
for (i = 0; i < 10000; i++) {
|
|
status = NtCreateFile (&handle,
|
|
MAXIMUM_ALLOWED,
|
|
oa,
|
|
&iosb,
|
|
NULL,
|
|
0,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
|
|
FILE_OPEN,
|
|
0,
|
|
NULL,
|
|
0);
|
|
if (NT_SUCCESS (status)) {
|
|
status = NtClose (handle);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtClose failed %x\n", status);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
VOID
|
|
do_open_close (POBJECT_ATTRIBUTES oa,
|
|
PUNICODE_STRING name,
|
|
PWCHAR path)
|
|
/*
|
|
Open and close the device rapidly to catch open close races
|
|
*/
|
|
{
|
|
#define MAX_OPEN_THREAD 4
|
|
HANDLE Thread[MAX_OPEN_THREAD];
|
|
ULONG i;
|
|
DWORD id;
|
|
|
|
if (crashes (path, L"OPENCLOSE", L"", L"", L"")) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < MAX_OPEN_THREAD; i++) {
|
|
Thread[i] = CreateThread (NULL, 0, do_open_close_thread, oa, 0, &id);
|
|
if (Thread[i] == NULL) {
|
|
printf ("CreateThread failed %d\n", GetLastError ());
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
for (i = 0; i < MAX_OPEN_THREAD; i++) {
|
|
WaitForSingleObject (Thread[i], INFINITE);
|
|
CloseHandle (Thread[i]);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Open device with various options
|
|
*/
|
|
NTSTATUS
|
|
open_device(
|
|
HANDLE parent,
|
|
PUNICODE_STRING name,
|
|
PDEVMAP devmap,
|
|
BOOL synch, // Do a synchronous open
|
|
BOOL addbackslash, // Add trailing backslash to name
|
|
BOOL direct, // Do a direct open
|
|
ULONG opentype, // Connection, address etc.
|
|
PWCHAR path
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK iosb;
|
|
ULONG i, l, lw, first;
|
|
WCHAR dn[1024];
|
|
UNICODE_STRING dnu;
|
|
ULONG options;
|
|
OBJECT_ATTRIBUTES oa;
|
|
ACCESS_MASK am;
|
|
ULONG share;
|
|
PFILE_FULL_EA_INFORMATION pea = NULL;
|
|
ULONG eal = 0;
|
|
TDI_ADDRESS_IP ipaddr;
|
|
TDI_ADDRESS_NETBIOS netbiosaddr;
|
|
TDI_ADDRESS_IPX ipxaddr;
|
|
TDI_ADDRESS_APPLETALK appleaddr;
|
|
LARGE_INTEGER tmo;
|
|
PCHAR api;
|
|
|
|
if (direct && !(FLAGS_DO_DIRECT_DEVICE&flags)) {
|
|
return STATUS_ACCESS_DENIED;
|
|
}
|
|
l = name->Length;
|
|
if (l >= sizeof (dn))
|
|
l = sizeof (dn) - 1;
|
|
lw = l / sizeof (dn[0]);
|
|
wcsncpy (dn, name->Buffer, lw);
|
|
dn[lw] = '\0';
|
|
RtlInitUnicodeString (&dnu, dn);
|
|
if (addbackslash && dnu.Length < sizeof (dn)) {
|
|
dn[min (dnu.Length, sizeof (dn) - sizeof (dn[0]))/sizeof(dn[0])] = '\\';
|
|
dnu.Length += 2;
|
|
}
|
|
dn[min(dnu.Length, sizeof (dn) - sizeof (dn[0]))/sizeof(dn[0])] = 0;
|
|
|
|
InitializeObjectAttributes(&oa,
|
|
&dnu,
|
|
OBJ_CASE_INSENSITIVE,
|
|
parent,
|
|
NULL);
|
|
|
|
if ((flags2&FLAGS_DO_DRIVER) != 0) {
|
|
HANDLE handle;
|
|
status = NtCreateFile (&handle,
|
|
MAXIMUM_ALLOWED,
|
|
&oa,
|
|
&iosb,
|
|
NULL,
|
|
0,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
|
|
FILE_OPEN,
|
|
0,
|
|
NULL,
|
|
0);
|
|
if (NT_SUCCESS (status)) {
|
|
status = check_driver (handle, &DriverName);
|
|
NtClose (handle);
|
|
if (!NT_SUCCESS (status)) {
|
|
return status;
|
|
}
|
|
} else {
|
|
wprintf(L"Failed to open device %s for driver checking %x\n",
|
|
dn, status);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if ((flags&FLAGS_DO_OPEN_CLOSE) && !synch && !direct && opentype == 0) {
|
|
do_open_close (&oa,
|
|
name,
|
|
path);
|
|
}
|
|
|
|
devmap->handle = NULL;
|
|
|
|
if (direct) {
|
|
options = 0;
|
|
am = SYNCHRONIZE|FILE_READ_ATTRIBUTES|READ_CONTROL|WRITE_OWNER|WRITE_DAC;
|
|
} else if (synch) {
|
|
options = FILE_SYNCHRONOUS_IO_ALERT;
|
|
am = MAXIMUM_ALLOWED|SYNCHRONIZE;
|
|
} else {
|
|
options = 0;
|
|
am = MAXIMUM_ALLOWED;
|
|
}
|
|
if (opentype == OPEN_TYPE_NAMED_PIPE) {
|
|
share = FILE_SHARE_READ|FILE_SHARE_WRITE;
|
|
} else if (opentype == OPEN_TYPE_TREE_CONNECT) {
|
|
share = FILE_SHARE_READ|FILE_SHARE_WRITE;
|
|
options |= FILE_CREATE_TREE_CONNECTION;
|
|
} else {
|
|
share = 0;
|
|
}
|
|
if (opentype == OPEN_TYPE_TDI_CONNECTION) {
|
|
pea = build_con_ea (TdiConnectionContext, (CONNECTION_CONTEXT) 12345, &eal);
|
|
} else if (opentype == OPEN_TYPE_TDI_ADDR_IP) {
|
|
memset (&ipaddr, 0, sizeof (ipaddr));
|
|
pea = build_adr_ea (TdiTransportAddress,
|
|
TDI_ADDRESS_TYPE_IP,
|
|
sizeof (ipaddr), &ipaddr,
|
|
&eal);
|
|
} else if (opentype == OPEN_TYPE_TDI_ADDR_NETBIOS) {
|
|
memset (&netbiosaddr, 0, sizeof (netbiosaddr));
|
|
pea = build_adr_ea (TdiTransportAddress,
|
|
TDI_ADDRESS_TYPE_NETBIOS,
|
|
sizeof (netbiosaddr), &netbiosaddr,
|
|
&eal);
|
|
} else if (opentype == OPEN_TYPE_TDI_ADDR_IPX) {
|
|
memset (&ipxaddr, 0, sizeof (ipxaddr));
|
|
pea = build_adr_ea (TdiTransportAddress,
|
|
TDI_ADDRESS_TYPE_IPX,
|
|
sizeof (ipxaddr), &ipxaddr,
|
|
&eal);
|
|
} else if (opentype == OPEN_TYPE_TDI_ADDR_APPLE) {
|
|
memset (&appleaddr, 0, sizeof (appleaddr));
|
|
pea = build_adr_ea (TdiTransportAddress,
|
|
TDI_ADDRESS_TYPE_APPLETALK,
|
|
sizeof (appleaddr), &appleaddr,
|
|
&eal);
|
|
}
|
|
|
|
wprintf(L"Trying to open device %s %s %s %s\n",
|
|
dn, direct?L"direct ":L"", synch?L"synchronous":L"",
|
|
pea?L"TDI open":(opentype == OPEN_TYPE_NAMED_PIPE)?
|
|
L"NamedPipe":(opentype == OPEN_TYPE_MAIL_SLOT)?
|
|
L"Mailslot":L"");
|
|
|
|
if (crashes (path, L"Open", direct?L"direct":L"", synch?L"synchronous":L"",
|
|
addbackslash?L"Add backslash":L""))
|
|
status = STATUS_ACCESS_DENIED;
|
|
else {
|
|
do {
|
|
if (opentype == OPEN_TYPE_NAMED_PIPE) {
|
|
tmo.QuadPart = -1000;
|
|
api = "NtCreateNamedPipeFile";
|
|
status = NtCreateNamedPipeFile (&devmap->handle,
|
|
am,
|
|
&oa,
|
|
&iosb,
|
|
share,
|
|
FILE_CREATE,
|
|
options,
|
|
FILE_PIPE_MESSAGE_TYPE,
|
|
FILE_PIPE_MESSAGE_MODE,
|
|
FILE_PIPE_COMPLETE_OPERATION,
|
|
10,
|
|
1000, 1000,
|
|
&tmo);
|
|
} else if (opentype == OPEN_TYPE_MAIL_SLOT) {
|
|
tmo.QuadPart = -1000;
|
|
api = "NtCreateMailslotFile";
|
|
status = NtCreateMailslotFile (&devmap->handle,
|
|
am,
|
|
&oa,
|
|
&iosb,
|
|
options,
|
|
1024,
|
|
256,
|
|
&tmo);
|
|
|
|
} else {
|
|
api = "NtCreateFile";
|
|
status = NtCreateFile(&devmap->handle,
|
|
am,
|
|
&oa,
|
|
&iosb,
|
|
NULL,
|
|
0,
|
|
share,
|
|
FILE_OPEN,
|
|
options,
|
|
pea,
|
|
eal);
|
|
}
|
|
|
|
if (status == STATUS_SHARING_VIOLATION) {
|
|
printf ("Hit file share violation for %X\n", share);
|
|
if (share&FILE_SHARE_READ) {
|
|
share &= ~FILE_SHARE_READ;
|
|
if (share&FILE_SHARE_WRITE) {
|
|
share &= ~FILE_SHARE_WRITE;
|
|
if (share&FILE_SHARE_DELETE) {
|
|
break;
|
|
} else {
|
|
share |= FILE_SHARE_DELETE;
|
|
}
|
|
} else {
|
|
share |= FILE_SHARE_WRITE;
|
|
}
|
|
} else {
|
|
share |= FILE_SHARE_READ;
|
|
}
|
|
} else if (status == STATUS_ACCESS_DENIED) {
|
|
printf ("Hit file protection violation for %X\n", am);
|
|
if (am&MAXIMUM_ALLOWED) {
|
|
am &= ~MAXIMUM_ALLOWED;
|
|
am |= FILE_READ_DATA|FILE_WRITE_DATA|SYNCHRONIZE|FILE_READ_ATTRIBUTES|
|
|
READ_CONTROL|FILE_APPEND_DATA;
|
|
} else if (am&FILE_WRITE_DATA) {
|
|
am &= ~FILE_WRITE_DATA;
|
|
} else if (am&FILE_APPEND_DATA) {
|
|
am &= ~FILE_APPEND_DATA;
|
|
} else if (am&FILE_READ_DATA) {
|
|
am &= ~FILE_READ_DATA;
|
|
} else if (am&WRITE_OWNER) {
|
|
am &= ~WRITE_OWNER;
|
|
} else if (am&WRITE_DAC) {
|
|
am &= ~WRITE_DAC;
|
|
} else if (am&WRITE_DAC) {
|
|
am &= ~WRITE_DAC;
|
|
} else if (am&READ_CONTROL) {
|
|
am &= ~READ_CONTROL;
|
|
} else if (am&FILE_READ_ATTRIBUTES) {
|
|
am &= ~FILE_READ_ATTRIBUTES;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
} while (status == STATUS_SHARING_VIOLATION || status == STATUS_ACCESS_DENIED);
|
|
}
|
|
if (pea)
|
|
free (pea);
|
|
if (NT_SUCCESS(status)) {
|
|
status = get_handle_access (devmap->handle, &devmap->access);
|
|
}
|
|
if (NT_SUCCESS(status)) {
|
|
wprintf(L"Opened file %s with access %x\n",
|
|
dn,
|
|
devmap->access);
|
|
|
|
if (DELETE&devmap->access) {
|
|
printf ("Got delete access to device\n");
|
|
}
|
|
if (WRITE_DAC&devmap->access) {
|
|
printf ("Got write_dac access to device\n");
|
|
}
|
|
if (WRITE_OWNER&devmap->access) {
|
|
printf ("Got write_owner access to device\n");
|
|
}
|
|
query_object(devmap->handle, devmap, path);
|
|
misc_functions (devmap->handle, path, synch);
|
|
} else {
|
|
if (status != STATUS_INVALID_DEVICE_REQUEST &&
|
|
status != STATUS_ACCESS_DENIED) {
|
|
printf("%s failed %x\n", api,
|
|
status);
|
|
}
|
|
}
|
|
if ((direct && synch) || (addbackslash & !synch && !direct)) // Only do this twice
|
|
try_fast_query_delete_etc (&oa, path, L"Top open");
|
|
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
Compare routine for sorting the object directory
|
|
*/
|
|
int __cdecl compare_unicode (const void *arg1, const void *arg2)
|
|
{
|
|
POBJECT_DIRECTORY_INFORMATION s1, s2;
|
|
ULONG i, j;
|
|
|
|
s1 = (POBJECT_DIRECTORY_INFORMATION) arg1;
|
|
s2 = (POBJECT_DIRECTORY_INFORMATION) arg2;
|
|
for (i = 0, j = 0;
|
|
(i < s1->Name.Length / sizeof (WCHAR)) &&
|
|
(j < s2->Name.Length / sizeof (WCHAR)); i++, j++) {
|
|
if (s1->Name.Buffer[i] < s2->Name.Buffer[j])
|
|
return -1;
|
|
else if (s1->Name.Buffer[i] > s2->Name.Buffer[j])
|
|
return +1;
|
|
}
|
|
if (i > j)
|
|
return -1;
|
|
else if (i < j)
|
|
return +1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
Do all the various different opens looking for handles
|
|
*/
|
|
NTSTATUS do_device_opens (HANDLE handle,
|
|
PUNICODE_STRING name,
|
|
PDEVMAP devmap,
|
|
PULONG devscount,
|
|
PWCHAR path,
|
|
PWCHAR devbuf)
|
|
{
|
|
NTSTATUS status;
|
|
ULONG do_tdi_opens=0;
|
|
ULONG OrigDevCount;
|
|
|
|
|
|
OrigDevCount = *devscount;
|
|
|
|
if (flags&FLAGS_DO_SYNC) {
|
|
status = open_device(handle,
|
|
name,
|
|
&devmap[*devscount],
|
|
TRUE, /* Synchronous */
|
|
FALSE, /* No added backslash */
|
|
FALSE, /* No direct device open */
|
|
0,
|
|
path);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
if (NT_SUCCESS (check_tdi_handle (devmap[*devscount].handle))) {
|
|
do_tdi_opens = 1;
|
|
}
|
|
try_funny_opens(devmap[*devscount].handle, path);
|
|
|
|
do_ioctl(&devmap[*devscount], path);
|
|
|
|
*devscount = *devscount + 1;
|
|
|
|
} else {
|
|
if (status == -1) {
|
|
return status;
|
|
} else {
|
|
wprintf(L"Failed to open device %s status is %x\n",
|
|
devbuf,
|
|
status);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
status = open_device(handle,
|
|
name,
|
|
&devmap[*devscount],
|
|
FALSE, /* Synchronous */
|
|
FALSE, /* No added backslash */
|
|
FALSE, /* No direct device access */
|
|
0,
|
|
path);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
if (!do_tdi_opens && NT_SUCCESS (check_tdi_handle (devmap[*devscount].handle))) {
|
|
do_tdi_opens = 1;
|
|
}
|
|
try_funny_opens(devmap[*devscount].handle, path);
|
|
do_ioctl(&devmap[*devscount], path);
|
|
|
|
*devscount = *devscount + 1;
|
|
} else {
|
|
if (status == -1) {
|
|
return status;
|
|
} else {
|
|
wprintf(L"Failed to open device %s status is %x\n",
|
|
devbuf,
|
|
status);
|
|
}
|
|
}
|
|
|
|
status = open_device(handle,
|
|
name,
|
|
&devmap[*devscount],
|
|
FALSE, /* Synchronous */
|
|
TRUE, /* No added backslash */
|
|
FALSE, /* No direct device access */
|
|
0,
|
|
path);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
try_funny_opens(devmap[*devscount].handle, path);
|
|
do_ioctl(&devmap[*devscount], path);
|
|
|
|
*devscount = *devscount + 1;
|
|
} else {
|
|
if (status == -1) {
|
|
return status;
|
|
} else {
|
|
wprintf(L"Failed to open device %s status is %x\n",
|
|
devbuf,
|
|
status);
|
|
}
|
|
}
|
|
|
|
if (flags&FLAGS_DO_SYNC) {
|
|
status = open_device(handle,
|
|
name,
|
|
&devmap[*devscount],
|
|
TRUE, /* Synchronous */
|
|
FALSE, /* No added backslash */
|
|
TRUE, /* Direct device access */
|
|
0,
|
|
path);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
try_funny_opens(devmap[*devscount].handle, path);
|
|
do_ioctl(&devmap[*devscount], path);
|
|
|
|
*devscount = *devscount + 1;
|
|
} else {
|
|
if (status == -1) {
|
|
return status;
|
|
} else {
|
|
wprintf(L"Failed to open device %s status is %x\n",
|
|
devbuf,
|
|
status);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (flags&FLAGS_DO_SYNC) {
|
|
status = open_device(handle,
|
|
name,
|
|
&devmap[*devscount],
|
|
TRUE, /* Synchronous */
|
|
FALSE, /* No added backslash */
|
|
FALSE, /* Direct device access */
|
|
OPEN_TYPE_NAMED_PIPE,
|
|
path);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
try_funny_opens(devmap[*devscount].handle, path);
|
|
do_ioctl(&devmap[*devscount], path);
|
|
|
|
*devscount = *devscount + 1;
|
|
} else {
|
|
if (status == -1) {
|
|
return status;
|
|
} else {
|
|
wprintf(L"Failed to open device %s status is %x\n",
|
|
devbuf,
|
|
status);
|
|
}
|
|
}
|
|
status = open_device(handle,
|
|
name,
|
|
&devmap[*devscount],
|
|
TRUE, /* Synchronous */
|
|
FALSE, /* No added backslash */
|
|
FALSE, /* Direct device access */
|
|
OPEN_TYPE_MAIL_SLOT,
|
|
path);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
try_funny_opens(devmap[*devscount].handle, path);
|
|
do_ioctl(&devmap[*devscount], path);
|
|
|
|
*devscount = *devscount + 1;
|
|
} else {
|
|
if (status == -1) {
|
|
return status;
|
|
} else {
|
|
wprintf(L"Failed to open device %s status is %x\n",
|
|
devbuf,
|
|
status);
|
|
}
|
|
}
|
|
}
|
|
status = open_device(handle,
|
|
name,
|
|
&devmap[*devscount],
|
|
FALSE, /* Synchronous */
|
|
FALSE, /* No added backslash */
|
|
FALSE, /* Direct device access */
|
|
OPEN_TYPE_NAMED_PIPE,
|
|
path);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
try_funny_opens(devmap[*devscount].handle, path);
|
|
do_ioctl(&devmap[*devscount], path);
|
|
|
|
*devscount = *devscount + 1;
|
|
} else {
|
|
if (status == -1) {
|
|
return status;
|
|
} else {
|
|
wprintf(L"Failed to open device %s status is %x\n",
|
|
devbuf,
|
|
status);
|
|
}
|
|
}
|
|
status = open_device(handle,
|
|
name,
|
|
&devmap[*devscount],
|
|
FALSE, /* Synchronous */
|
|
FALSE, /* No added backslash */
|
|
FALSE, /* Direct device access */
|
|
OPEN_TYPE_MAIL_SLOT,
|
|
path);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
try_funny_opens(devmap[*devscount].handle, path);
|
|
do_ioctl(&devmap[*devscount], path);
|
|
|
|
*devscount = *devscount + 1;
|
|
} else {
|
|
if (status == -1) {
|
|
return status;
|
|
} else {
|
|
wprintf(L"Failed to open device %s status is %x\n",
|
|
devbuf,
|
|
status);
|
|
}
|
|
}
|
|
|
|
status = open_device(handle,
|
|
name,
|
|
&devmap[*devscount],
|
|
FALSE, /* Synchronous */
|
|
FALSE, /* No added backslash */
|
|
FALSE, /* Direct device access */
|
|
OPEN_TYPE_TREE_CONNECT,
|
|
path);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
try_funny_opens(devmap[*devscount].handle, path);
|
|
do_ioctl(&devmap[*devscount], path);
|
|
|
|
*devscount = *devscount + 1;
|
|
} else {
|
|
if (status == -1) {
|
|
return status;
|
|
} else {
|
|
wprintf(L"Failed to open device %s status is %x\n",
|
|
devbuf,
|
|
status);
|
|
}
|
|
}
|
|
|
|
if (do_tdi_opens) {
|
|
status = open_device(handle,
|
|
name,
|
|
&devmap[*devscount],
|
|
FALSE, /* Synchronous */
|
|
FALSE, /* No added backslash */
|
|
FALSE, /* Direct device access */
|
|
OPEN_TYPE_TDI_CONNECTION,
|
|
path);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
try_funny_opens(devmap[*devscount].handle, path);
|
|
do_ioctl(&devmap[*devscount], path);
|
|
|
|
*devscount = *devscount + 1;
|
|
} else {
|
|
if (status == -1) {
|
|
return status;
|
|
} else {
|
|
wprintf(L"Failed to open device %s status is %x\n",
|
|
devbuf,
|
|
status);
|
|
}
|
|
}
|
|
|
|
status = open_device(handle,
|
|
name,
|
|
&devmap[*devscount],
|
|
FALSE, /* Synchronous */
|
|
FALSE, /* No added backslash */
|
|
FALSE, /* Direct device access */
|
|
OPEN_TYPE_TDI_ADDR_IP,
|
|
path);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
try_funny_opens(devmap[*devscount].handle, path);
|
|
do_ioctl(&devmap[*devscount], path);
|
|
|
|
*devscount = *devscount + 1;
|
|
} else {
|
|
if (status == -1) {
|
|
return status;
|
|
} else {
|
|
wprintf(L"Failed to open device %s status is %x\n",
|
|
devbuf,
|
|
status);
|
|
}
|
|
}
|
|
status = open_device(handle,
|
|
name,
|
|
&devmap[*devscount],
|
|
FALSE, /* Synchronous */
|
|
FALSE, /* No added backslash */
|
|
FALSE, /* Direct device access */
|
|
OPEN_TYPE_TDI_ADDR_IPX,
|
|
path);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
try_funny_opens(devmap[*devscount].handle, path);
|
|
do_ioctl(&devmap[*devscount], path);
|
|
|
|
*devscount = *devscount + 1;
|
|
} else {
|
|
if (status == -1) {
|
|
return status;
|
|
} else {
|
|
wprintf(L"Failed to open device %s status is %x\n",
|
|
devbuf,
|
|
status);
|
|
}
|
|
}
|
|
status = open_device(handle,
|
|
name,
|
|
&devmap[*devscount],
|
|
FALSE, /* Synchronous */
|
|
FALSE, /* No added backslash */
|
|
FALSE, /* Direct device access */
|
|
OPEN_TYPE_TDI_ADDR_NETBIOS,
|
|
path);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
try_funny_opens(devmap[*devscount].handle, path);
|
|
do_ioctl(&devmap[*devscount], path);
|
|
|
|
*devscount = *devscount + 1;
|
|
} else {
|
|
if (status == -1) {
|
|
return status;
|
|
} else {
|
|
wprintf(L"Failed to open device %s status is %x\n",
|
|
devbuf,
|
|
status);
|
|
}
|
|
}
|
|
status = open_device(handle,
|
|
name,
|
|
&devmap[*devscount],
|
|
FALSE, /* Synchronous */
|
|
FALSE, /* No added backslash */
|
|
FALSE, /* Direct device access */
|
|
OPEN_TYPE_TDI_ADDR_APPLE,
|
|
path);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
try_funny_opens(devmap[*devscount].handle, path);
|
|
do_ioctl(&devmap[*devscount], path);
|
|
|
|
*devscount = *devscount + 1;
|
|
} else {
|
|
if (status == -1) {
|
|
return status;
|
|
} else {
|
|
wprintf(L"Failed to open device %s status is %x\n",
|
|
devbuf,
|
|
status);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OrigDevCount == *devscount) {
|
|
crashes (path, L"FAILED all open attempts", L"", L"", L"");
|
|
}
|
|
|
|
crashes (path, L"DONE", L"", L"", L"");
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
do_lpc_connect (HANDLE handle,
|
|
PUNICODE_STRING name,
|
|
PDEVMAP devmap,
|
|
PULONG devscount,
|
|
PWCHAR path,
|
|
PWCHAR devbuf)
|
|
{
|
|
HANDLE nhandle;
|
|
NTSTATUS status;
|
|
SECURITY_QUALITY_OF_SERVICE qos;
|
|
ULONG maxmsg, i, opened;
|
|
UNICODE_STRING fullname;
|
|
|
|
RtlInitUnicodeString (&fullname, path);
|
|
qos.ImpersonationLevel = SecurityImpersonation;
|
|
qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
|
|
qos.EffectiveOnly = TRUE;
|
|
opened = 0;
|
|
for (i = 0; i < 1000; i++) {
|
|
status = NtConnectPort (&nhandle, &fullname, &qos, NULL, NULL, &maxmsg, NULL, NULL);
|
|
if (!NT_SUCCESS (status)) {
|
|
wprintf (L"NtConnectPort failed to %s %x\n", path, status);
|
|
return status;
|
|
}
|
|
opened++;
|
|
status = NtClose (nhandle);
|
|
if (!NT_SUCCESS (status)) {
|
|
wprintf (L"NtClose of port handle failed %x\n", status);
|
|
}
|
|
}
|
|
if (opened) {
|
|
wprintf (L"Opened port %ws %d times\n", path, opened);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
Traverse the object tree looking for devices
|
|
*/
|
|
NTSTATUS
|
|
recurse(
|
|
HANDLE handle,
|
|
PUNICODE_STRING name,
|
|
PDEVMAP devmap,
|
|
PULONG devscount,
|
|
PWCHAR path,
|
|
ULONG depth
|
|
)
|
|
{
|
|
HANDLE nhandle, shandle;
|
|
NTSTATUS status;
|
|
OBJECT_ATTRIBUTES oa;
|
|
OBJECT_DIRECTORY_INFORMATION *od;
|
|
PVOID buffer;
|
|
ULONG bufferlen;
|
|
ULONG context;
|
|
ULONG retlen;
|
|
ULONG ul;
|
|
UNICODE_STRING equiv;
|
|
WCHAR buf[100], devbuf[200], objtype[80];
|
|
PWCHAR npath = NULL;
|
|
static WCHAR ans[100]={0};
|
|
ULONG c;
|
|
|
|
if (depth > 10) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
InitializeObjectAttributes(&oa,
|
|
name,
|
|
OBJ_CASE_INSENSITIVE,
|
|
handle,
|
|
NULL);
|
|
|
|
wcsncpy(devbuf,
|
|
name->Buffer,
|
|
sizeof (devbuf) / sizeof (devbuf[0]));
|
|
|
|
devbuf[sizeof (devbuf) - 1] = L'\0';
|
|
|
|
status = NtOpenDirectoryObject(&nhandle,
|
|
MAXIMUM_ALLOWED/*DIRECTORY_QUERY | DIRECTORY_TRAVERSE*/,
|
|
&oa);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
context = 0;
|
|
|
|
bufferlen = 0x10000;
|
|
|
|
buffer = malloc(bufferlen);
|
|
|
|
status = NtQueryDirectoryObject(nhandle,
|
|
buffer,
|
|
bufferlen,
|
|
FALSE,
|
|
TRUE,
|
|
&context,
|
|
&retlen);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
for (od = (POBJECT_DIRECTORY_INFORMATION) buffer, c = 0;
|
|
od->Name.Length != 0 || od->TypeName.Length != 0; od++, c++)
|
|
;
|
|
|
|
qsort (buffer, c, sizeof (*od), compare_unicode);
|
|
|
|
for (od = (POBJECT_DIRECTORY_INFORMATION) buffer;
|
|
*devscount < MAX_DEVICES; od++) {
|
|
|
|
if (od->Name.Length == 0 &&
|
|
od->TypeName.Length == 0) {
|
|
|
|
break;
|
|
}
|
|
|
|
wcsncpy(devbuf,
|
|
od->Name.Buffer,
|
|
sizeof (devbuf) / sizeof (devbuf[0]));
|
|
devbuf[sizeof (devbuf) / sizeof (devbuf[0]) - 1] = L'\0';
|
|
|
|
wcsncpy(objtype,
|
|
od->TypeName.Buffer,
|
|
sizeof (objtype) / sizeof (objtype[0]));
|
|
objtype[sizeof (objtype) / sizeof (objtype[0]) - 1] = L'\0';
|
|
|
|
npath = realloc (npath,
|
|
(wcslen (path) + 1 + wcslen (devbuf) + 1) *
|
|
sizeof (WCHAR));
|
|
if (!npath) {
|
|
printf ("Memory allocation failed for path buffer!");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
wcscpy (npath, path);
|
|
if (path[wcslen (path)-1] != '\\' &&
|
|
devbuf[wcslen (devbuf)-1] != '\\')
|
|
wcscat (npath, L"\\");
|
|
wcscat (npath, devbuf);
|
|
if (wcsncmp(objtype,
|
|
L"Directory",
|
|
od->TypeName.Length / sizeof (WCHAR)) == 0) {
|
|
|
|
recurse(nhandle,
|
|
&od->Name,
|
|
devmap,
|
|
devscount,
|
|
npath,
|
|
depth+1);
|
|
|
|
} else if (!(flags&FLAGS_DO_LPC) && (
|
|
wcsncmp(objtype,
|
|
L"Device",
|
|
od->TypeName.Length / sizeof (WCHAR)) == 0 ||
|
|
(wcsncmp(objtype,
|
|
L"SymbolicLink",
|
|
od->TypeName.Length / sizeof (WCHAR)) == 0 && (flags&FLAGS_DO_SYMBOLIC)))) {
|
|
if (!(flags&FLAGS_DO_ALLDEVS)) {
|
|
if (skipped == 0) {
|
|
ans[0] = 0;
|
|
skipped = 1;
|
|
}
|
|
if (ans[0] == '/') {
|
|
// wprintf (L"Matching \"%s\" against \"%s\"\n", &ans[1], devbuf);
|
|
if (_wcsnicmp (&ans[1], devbuf, wcslen (&ans[1])) != 0)
|
|
continue;
|
|
} else if (ans[0] == '?' || (flags&FLAGS_DO_PRINT_DEVS)) {
|
|
if (prefix_string) {
|
|
printf ("%s %ws\\%ws\n", prefix_string, path, devbuf);
|
|
} else {
|
|
printf ("%ws %ws\\%ws\n", objtype, path, devbuf);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
progress_counter = 0;
|
|
if (flags & FLAGS_DO_RANDOM_DEVICE) {
|
|
if (random_device > 0) {
|
|
// wprintf (L"%s %s\\%s\n", objtype, path, devbuf);
|
|
random_device--;
|
|
continue;
|
|
}
|
|
} else if (ans[0] != 'a' && ans[0] != 'A') {
|
|
wprintf (L"Open device %s %s\\%s? ", objtype, path, devbuf);
|
|
wscanf (L"%100s", ans);
|
|
if (ans[0] == 'q' || ans[0] == 'Q') {
|
|
exit (EXIT_SUCCESS);
|
|
} else if (ans[0] != 'y' && ans[0] != 'Y' &&
|
|
ans[0] != 'a' && ans[0] != 'A') {
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if (!(flags&FLAGS_DO_DISKS)) {
|
|
if (wcsstr (path, L"Harddisk") ||
|
|
wcsstr (path, L"Ide") ||
|
|
wcsstr (path, L"Scsi")) {
|
|
printf ("Skipping this device as it looks like a disk\n");
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (flags&FLAGS_DO_FAILURE_INJECTION) {
|
|
turn_on_fault_injection ();
|
|
}
|
|
if (flags&FLAGS_DO_IMPERSONATION) {
|
|
Impersonate_nonadmin ();
|
|
}
|
|
|
|
status = do_device_opens (nhandle,
|
|
&od->Name,
|
|
devmap,
|
|
devscount,
|
|
npath,
|
|
devbuf);
|
|
|
|
|
|
if (flags&FLAGS_DO_IMPERSONATION) {
|
|
if (!Revert_from_admin ()) {
|
|
printf ("Revert_from_admin failed %d\n", GetLastError ());
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
if (flags&FLAGS_DO_FAILURE_INJECTION) {
|
|
turn_off_fault_injection ();
|
|
}
|
|
print_diags (0, 0);
|
|
if (flags & FLAGS_DO_RANDOM_DEVICE) {
|
|
break;
|
|
}
|
|
} else if ((flags&FLAGS_DO_LPC) &&
|
|
wcsncmp(od->TypeName.Buffer,
|
|
L"Port",
|
|
od->TypeName.Length / sizeof (WCHAR)) == 0) {
|
|
|
|
if (!(flags&FLAGS_DO_ALLDEVS)) {
|
|
if (skipped == 0) {
|
|
ans[0] = 0;
|
|
skipped = 1;
|
|
}
|
|
if (ans[0] == '/') {
|
|
wprintf (L"Matching \"%s\" against \"%s\"\n", &ans[1], devbuf);
|
|
if (_wcsnicmp (&ans[1], devbuf, wcslen (&ans[1])) != 0)
|
|
continue;
|
|
} else if (ans[0] == '?') {
|
|
wprintf (L"%s\\%s\n", path, devbuf);
|
|
continue;
|
|
} else if (ans[0] == 'q' || ans[0] == 'Q') {
|
|
exit (EXIT_SUCCESS);
|
|
}
|
|
if (ans[0] != 'a' && ans[0] != 'A') {
|
|
wprintf (L"Open LPC port %s\\%s? ", path, devbuf);
|
|
wscanf (L"%100s", ans);
|
|
if (ans[0] != 'y' && ans[0] != 'Y' &&
|
|
ans[0] != 'a' && ans[0] != 'A')
|
|
continue;
|
|
}
|
|
if (flags&FLAGS_DO_IMPERSONATION) {
|
|
Impersonate_nonadmin ();
|
|
}
|
|
|
|
|
|
status = do_lpc_connect (nhandle,
|
|
&od->Name,
|
|
devmap,
|
|
devscount,
|
|
npath,
|
|
devbuf);
|
|
if (flags&FLAGS_DO_IMPERSONATION) {
|
|
if (!Revert_from_admin ()) {
|
|
printf ("Revert_from_admin failed %d\n", GetLastError ());
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (status != STATUS_NO_MORE_ENTRIES) {
|
|
wprintf(L"NtQueryDirectoryObject failed %x for directory %s\n",
|
|
status,
|
|
devbuf);
|
|
}
|
|
}
|
|
|
|
free(buffer);
|
|
|
|
NtClose(nhandle);
|
|
} else {
|
|
wprintf(L"NtOpenDirectoryObject failed %x for directory %s\n",
|
|
status,
|
|
devbuf);
|
|
}
|
|
|
|
free (npath);
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
Look who registers for WMI
|
|
*/
|
|
void do_wmi ()
|
|
{
|
|
UNICODE_STRING name;
|
|
OBJECT_ATTRIBUTES oa;
|
|
NTSTATUS status;
|
|
PKMREGINFO reginfo = NULL;
|
|
HANDLE handle;
|
|
IO_STATUS_BLOCK iosb;
|
|
ULONG reginfol, i;
|
|
|
|
RtlInitUnicodeString (&name, L"\\Device\\WMIServiceDevice\\");
|
|
InitializeObjectAttributes (&oa, &name, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
|
status = NtOpenFile (&handle,
|
|
MAXIMUM_ALLOWED|SYNCHRONIZE,
|
|
&oa,
|
|
&iosb,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_NONALERT);
|
|
if (NT_SUCCESS (status)) {
|
|
status = iosb.Status;
|
|
}
|
|
if (!NT_SUCCESS (status)) {
|
|
// printf ("Failed to open WMI device %x\n", status);
|
|
return;
|
|
}
|
|
|
|
reginfo = malloc (reginfol = 4096);
|
|
if (!reginfo) {
|
|
printf ("Memory allocation failure for WMI buffer\n");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
status = NtDeviceIoControlFile (handle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&iosb,
|
|
IOCTL_WMI_GET_ALL_REGISTRANT,
|
|
NULL,
|
|
0,
|
|
reginfo,
|
|
reginfol);
|
|
|
|
|
|
if (NT_SUCCESS (status)) {
|
|
status = iosb.Status;
|
|
}
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtDeviceIoControlFile failed %X\n", status);
|
|
} else {
|
|
for (i = 0; i < iosb.Information / sizeof (*reginfo); i++) {
|
|
printf ("Device %x registered with WMI\n", reginfo[i].ProviderId);
|
|
}
|
|
}
|
|
|
|
if (reginfo)
|
|
free (reginfo);
|
|
status = NtClose (handle);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtClose failed %x\n", status);
|
|
}
|
|
}
|
|
|
|
/*
|
|
Thread to read from a socket so we can test out transmit file
|
|
*/
|
|
DWORD WINAPI do_listen (LPVOID arg)
|
|
{
|
|
SOCKET s;
|
|
struct sockaddr_in sockaddr;
|
|
int l;
|
|
int status;
|
|
DWORD retlen;
|
|
CHAR buf[100];
|
|
|
|
l = sizeof (sockaddr);
|
|
s = accept (ls, (struct sockaddr *) &sockaddr, &l);
|
|
if (s == INVALID_SOCKET) {
|
|
printf ("Socket failed %d\n", WSAGetLastError ());
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
while (1) {
|
|
l = recv (s, buf, sizeof (buf), 0);
|
|
if (l == 0) {
|
|
break;
|
|
}
|
|
if (l == SOCKET_ERROR) {
|
|
printf ("recv failed %d\n", WSAGetLastError ());
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void do_handle_grab (PDEVMAP devmap,
|
|
PULONG devscount)
|
|
{
|
|
NTSTATUS status;
|
|
CLIENT_ID clid;
|
|
OBJECT_ATTRIBUTES oa;
|
|
HANDLE handle;
|
|
|
|
InitializeObjectAttributes (&oa, NULL, 0, NULL, NULL);
|
|
clid.UniqueThread = 0;
|
|
clid.UniqueProcess = UlongToHandle( cid );
|
|
status = NtOpenProcess (&handle, PROCESS_DUP_HANDLE, &oa, &clid);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtOpenProcess for process %d failed %x\n", cid, status);
|
|
return;
|
|
}
|
|
status = NtDuplicateObject (handle, process_handle, NtCurrentProcess (),
|
|
&devmap->handle, 0, 0, DUPLICATE_SAME_ACCESS);
|
|
if (NT_SUCCESS (status)) {
|
|
*devscount += 1;
|
|
status = get_handle_access (devmap->handle, &devmap->access);
|
|
if (NT_SUCCESS(status)) {
|
|
wprintf(L"Grabbed handle with access %x\n",
|
|
devmap->access);
|
|
if (DELETE&devmap->access) {
|
|
printf ("Got delete access to device\n");
|
|
}
|
|
if (WRITE_DAC&devmap->access) {
|
|
printf ("Got write_dac access to device\n");
|
|
}
|
|
if (WRITE_OWNER&devmap->access) {
|
|
printf ("Got write_owner access to device\n");
|
|
}
|
|
}
|
|
query_object(devmap->handle, devmap, L"HANDLE");
|
|
misc_functions (devmap->handle, L"HANDLE", 0);
|
|
InitializeObjectAttributes (&oa, NULL, 0, devmap->handle, NULL);
|
|
try_fast_query_delete_etc (&oa, L"HANDLE", L"Top open");
|
|
try_funny_opens(devmap->handle, L"HANDLE");
|
|
do_ioctl(devmap, L"HANDLE");
|
|
} else {
|
|
printf ("NtDuplicateObject failed %x\n", status);
|
|
}
|
|
|
|
status = NtClose (handle);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtClose for process handle failed %x\n", status);
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Parse command line
|
|
//
|
|
void process_parameters(int argc, char *argv[], PUNICODE_STRING name, long *flags, long *flags2)
|
|
{
|
|
char c, nc, *p, st;
|
|
int i;
|
|
NTSTATUS status;
|
|
|
|
*flags = FLAGS_DO_IOCTL_NULL|FLAGS_DO_IOCTL_RANDOM|
|
|
FLAGS_DO_FSCTL_NULL|FLAGS_DO_FSCTL_RANDOM|
|
|
FLAGS_DO_LOGGING|FLAGS_DO_SKIPCRASH|FLAGS_DO_POOLCHECK|
|
|
FLAGS_DO_MISC|FLAGS_DO_QUERY|FLAGS_DO_SUBOPENS|FLAGS_DO_ZEROEA|
|
|
FLAGS_DO_DISKS|FLAGS_DO_SECURITY|FLAGS_DO_OPEN_CLOSE|
|
|
FLAGS_DO_DIRECT_DEVICE|FLAGS_DO_SYMBOLIC|FLAGS_DO_IMPERSONATION;
|
|
*flags2 = 0;
|
|
|
|
name->Length = name->MaximumLength = 0;
|
|
name->Buffer = NULL;
|
|
while (--argc) {
|
|
p = *++argv;
|
|
st = *p;
|
|
if (st == '/' || st == '-' || st == '+') {
|
|
c = *++p;
|
|
nc = *++p;
|
|
nc = (char) toupper (nc);
|
|
switch (toupper (c)) {
|
|
case 'I' :
|
|
if (nc == 'R') {
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_IOCTL_RANDOM;
|
|
else
|
|
*flags |= FLAGS_DO_IOCTL_RANDOM;
|
|
} else if (nc == 'N') {
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_IOCTL_NULL;
|
|
else
|
|
*flags |= FLAGS_DO_IOCTL_NULL;
|
|
} else if (nc == 'F') {
|
|
if (st == '-')
|
|
*flags &= ~(FLAGS_DO_IOCTL_NULL|FLAGS_DO_FSCTL_NULL|
|
|
FLAGS_DO_IOCTL_RANDOM|FLAGS_DO_FSCTL_RANDOM);
|
|
else
|
|
*flags |= FLAGS_DO_IOCTL_NULL|FLAGS_DO_FSCTL_NULL|
|
|
FLAGS_DO_IOCTL_RANDOM|FLAGS_DO_FSCTL_RANDOM;
|
|
} else if (nc == 'M') {
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_IMPERSONATION;
|
|
else
|
|
*flags |= FLAGS_DO_IMPERSONATION;
|
|
} else if (nc == 'L') {
|
|
if (argc > 1) {
|
|
ioctl_inbuf_min = atoi (*++argv);
|
|
ioctl_inbuf_min = min (ioctl_inbuf_min, BIGBUF_SIZE);
|
|
argc--;
|
|
printf ("IOCTL/FSCTL lower input buffer limit %d\n", ioctl_inbuf_min);
|
|
} else {
|
|
printf ("IOCTL/FSCTL lower input limit missing\n");
|
|
}
|
|
} else if (nc == 'U') {
|
|
if (argc > 1) {
|
|
ioctl_inbuf_max = atoi (*++argv);
|
|
ioctl_inbuf_max = min (ioctl_inbuf_max, BIGBUF_SIZE);
|
|
argc--;
|
|
printf ("IOCTL/FSCTL upper input buffer limit %d\n", ioctl_inbuf_max);
|
|
} else {
|
|
printf ("IOCTL/FSCTL upper input limit missing\n");
|
|
}
|
|
} else if (!nc) {
|
|
if (st == '-')
|
|
*flags &= ~(FLAGS_DO_IOCTL_NULL|FLAGS_DO_IOCTL_RANDOM);
|
|
else
|
|
*flags |= FLAGS_DO_IOCTL_NULL|FLAGS_DO_IOCTL_RANDOM;
|
|
}
|
|
break;
|
|
case 'F' :
|
|
if (nc == 'L') {
|
|
if (argc > 1) {
|
|
ioctl_min_function = atoi (*++argv);
|
|
ioctl_min_function = min (ioctl_min_function, 0xFFF);
|
|
argc--;
|
|
printf ("IOCTL/FSCTL lower function limit %d\n", ioctl_min_function);
|
|
} else {
|
|
printf ("IOCTL/FSCTL lower function limit missing\n");
|
|
}
|
|
} else if (nc == 'U') {
|
|
if (argc > 1) {
|
|
ioctl_max_function = atoi (*++argv);
|
|
ioctl_max_function = min (ioctl_max_function, 0xFFF);
|
|
argc--;
|
|
printf ("IOCTL/FSCTL upper function limit %d\n", ioctl_max_function);
|
|
} else {
|
|
printf ("IOCTL/FSCTL upper function limit missing\n");
|
|
}
|
|
} else if (nc == 'R') {
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_FSCTL_RANDOM;
|
|
else
|
|
*flags |= FLAGS_DO_FSCTL_RANDOM;
|
|
} else if (nc == 'N') {
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_FSCTL_NULL;
|
|
else
|
|
*flags |= FLAGS_DO_FSCTL_NULL;
|
|
} else if (nc == 'I') {
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_FAILURE_INJECTION;
|
|
else
|
|
*flags |= FLAGS_DO_FAILURE_INJECTION;
|
|
} else if (!nc) {
|
|
if (st == '-')
|
|
*flags &= ~(FLAGS_DO_FSCTL_NULL|FLAGS_DO_FSCTL_RANDOM);
|
|
else
|
|
*flags |= FLAGS_DO_FSCTL_NULL|FLAGS_DO_FSCTL_RANDOM;
|
|
}
|
|
break;
|
|
case 'C' :
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_SKIPCRASH;
|
|
else
|
|
*flags |= FLAGS_DO_SKIPCRASH;
|
|
break;
|
|
case 'L' :
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_LOGGING;
|
|
else
|
|
*flags |= FLAGS_DO_LOGGING;
|
|
break;
|
|
case 'P' :
|
|
if (!nc) {
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_POOLCHECK;
|
|
else
|
|
*flags |= FLAGS_DO_POOLCHECK;
|
|
} else if (nc == 'R') {
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_PROT;
|
|
else
|
|
*flags |= FLAGS_DO_PROT;
|
|
} else if (nc == 'D') {
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_PRINT_DEVS;
|
|
else
|
|
*flags |= FLAGS_DO_PRINT_DEVS;
|
|
} else if (nc == 'S') {
|
|
if (argc > 1) {
|
|
prefix_string = *++argv;
|
|
argc--;
|
|
} else {
|
|
printf ("Prefix string missing\n");
|
|
}
|
|
}
|
|
break;
|
|
case 'R' :
|
|
if (!nc) {
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_SKIPDONE;
|
|
else
|
|
*flags |= FLAGS_DO_SKIPDONE;
|
|
} else if (nc == 'D') {
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_RANDOM_DEVICE;
|
|
else
|
|
*flags |= FLAGS_DO_RANDOM_DEVICE;
|
|
}
|
|
break;
|
|
case 'M' :
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_MISC;
|
|
else
|
|
*flags |= FLAGS_DO_MISC;
|
|
break;
|
|
case 'N' :
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_MAPNULL;
|
|
else
|
|
*flags |= FLAGS_DO_MAPNULL;
|
|
break;
|
|
case 'O' :
|
|
if (nc == 'L') {
|
|
if (argc > 1) {
|
|
ioctl_outbuf_min = atoi (*++argv);
|
|
ioctl_outbuf_min = min (ioctl_outbuf_min, BIGBUF_SIZE);
|
|
argc--;
|
|
printf ("IOCTL/FSCTL lower output buffer limit %d\n", ioctl_outbuf_min);
|
|
} else {
|
|
printf ("IOCTL/FSCTL lower output limit missing\n");
|
|
}
|
|
} else if (nc == 'U') {
|
|
if (argc > 1) {
|
|
ioctl_outbuf_max = atoi (*++argv);
|
|
ioctl_outbuf_max = min (ioctl_outbuf_max, BIGBUF_SIZE);
|
|
argc--;
|
|
printf ("IOCTL/FSCTL upper output buffer limit %d\n", ioctl_outbuf_max);
|
|
} else {
|
|
printf ("IOCTL/FSCTL upper output limit missing\n");
|
|
}
|
|
} else if (nc == 'C') {
|
|
if (st == '-') {
|
|
*flags &= ~FLAGS_DO_OPEN_CLOSE;
|
|
} else {
|
|
*flags |= FLAGS_DO_OPEN_CLOSE;
|
|
}
|
|
}
|
|
break;
|
|
case 'S' :
|
|
if (nc == 'D') {
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_SECURITY;
|
|
else
|
|
*flags |= FLAGS_DO_SECURITY;
|
|
} else if (nc == 'L'){
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_SYMBOLIC;
|
|
else
|
|
*flags |= FLAGS_DO_SYMBOLIC;
|
|
} else {
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_SUBOPENS;
|
|
else
|
|
*flags |= FLAGS_DO_SUBOPENS;
|
|
}
|
|
break;
|
|
case 'Q' :
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_QUERY;
|
|
else
|
|
*flags |= FLAGS_DO_QUERY;
|
|
break;
|
|
case 'A' :
|
|
if (nc == 'L') {
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_ALERT;
|
|
else
|
|
*flags |= FLAGS_DO_ALERT;
|
|
} else {
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_ALLDEVS;
|
|
else
|
|
*flags |= FLAGS_DO_ALLDEVS;
|
|
}
|
|
break;
|
|
case 'E' :
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_ZEROEA;
|
|
else
|
|
*flags |= FLAGS_DO_ZEROEA;
|
|
break;
|
|
case 'Z' :
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_LPC;
|
|
else
|
|
*flags |= FLAGS_DO_LPC;
|
|
break;
|
|
case 'V' :
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_ERRORS;
|
|
else
|
|
*flags |= FLAGS_DO_ERRORS;
|
|
break;
|
|
case 'J' :
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_STREAMS;
|
|
else
|
|
*flags |= FLAGS_DO_STREAMS;
|
|
break;
|
|
case 'W' :
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_WINSOCK;
|
|
else
|
|
*flags |= FLAGS_DO_WINSOCK;
|
|
break;
|
|
case 'K' :
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_SYNC;
|
|
else
|
|
*flags |= FLAGS_DO_SYNC;
|
|
break;
|
|
case 'T' :
|
|
if (nc == 'T') {
|
|
if (argc > 1) {
|
|
max_tailured_calls = atoi (*++argv);
|
|
argc--;
|
|
max_tailured_calls = ((max_tailured_calls + RAND_REP - 1) / RAND_REP) *
|
|
RAND_REP;
|
|
printf ("IOCTL/FSCTL tailured calls %d\n", max_tailured_calls);
|
|
} else {
|
|
printf ("IOCTL/FSCTL tailured calls value is missing\n");
|
|
}
|
|
} else {
|
|
if (argc > 1) {
|
|
max_random_calls = atoi (*++argv);
|
|
argc--;
|
|
max_random_calls = ((max_random_calls + RAND_REP - 1) / RAND_REP) *
|
|
RAND_REP;
|
|
printf ("IOCTL/FSCTL random calls %d\n", max_random_calls);
|
|
} else {
|
|
printf ("IOCTL/FSCTL random calls value is missing\n");
|
|
}
|
|
}
|
|
break;
|
|
case 'D' :
|
|
if (nc == 'L') {
|
|
if (argc > 1) {
|
|
ioctl_min_devtype = atoi (*++argv);
|
|
argc--;
|
|
ioctl_min_devtype = min (ioctl_min_devtype, 0xFFFF);
|
|
printf ("IOCTL/FSCTL lower device type limit %d\n",
|
|
ioctl_min_devtype);
|
|
} else {
|
|
printf ("IOCTL/FSCTL lower device type limit missing\n");
|
|
}
|
|
} else if (nc == 'U') {
|
|
if (argc > 1) {
|
|
ioctl_max_devtype = atoi (*++argv);
|
|
ioctl_max_devtype = min (ioctl_max_devtype, 0xFFFF);
|
|
argc--;
|
|
printf ("IOCTL/FSCTL upper device type limit %d\n",
|
|
ioctl_max_devtype);
|
|
} else {
|
|
printf ("IOCTL/FSCTL upper device type limit missing\n");
|
|
}
|
|
} else if (nc == 'D') {
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_DIRECT_DEVICE;
|
|
else
|
|
*flags |= FLAGS_DO_DIRECT_DEVICE;
|
|
break;
|
|
} else if (nc == 'R') {
|
|
if (st == '-') {
|
|
*flags2 &= ~FLAGS_DO_DRIVER;
|
|
} else {
|
|
*flags2 |= FLAGS_DO_DRIVER;
|
|
*flags |= FLAGS_DO_ALLDEVS;
|
|
if (argc > 1) {
|
|
status = RtlCreateUnicodeStringFromAsciiz (&DriverName, *++argv);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("RtlCreateUnicodeStringFromAsciiz failed %x\n", status);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
argc--;
|
|
} else {
|
|
printf ("Input driver name missing on command line\n");
|
|
}
|
|
}
|
|
break;
|
|
} else if (!nc) {
|
|
if (argc > 1) {
|
|
status = RtlCreateUnicodeStringFromAsciiz (name, *++argv);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("RtlCreateUnicodeStringFromAsciiz failed %x\n", status);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
argc--;
|
|
} else {
|
|
printf ("Input device missing on command line\n");
|
|
}
|
|
}
|
|
break;
|
|
case 'G':
|
|
if (argc > 2) {
|
|
*flags |= FLAGS_DO_GRAB;
|
|
cid = atoi (*++argv);
|
|
process_handle = UlongToHandle( atoi (*++argv) );
|
|
argc -= 2;
|
|
} else {
|
|
printf ("Client ID and handle missing\n");
|
|
}
|
|
break;
|
|
case 'Y' :
|
|
if (st == '-')
|
|
*flags &= ~FLAGS_DO_DISKS;
|
|
else
|
|
*flags |= FLAGS_DO_DISKS;
|
|
break;
|
|
case '?':
|
|
case 'H':
|
|
default :
|
|
*flags |= FLAGS_DO_USAGE;
|
|
break;
|
|
}
|
|
} else {
|
|
status = RtlCreateUnicodeStringFromAsciiz (name, *argv);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("RtlCreateUnicodeStringFromAsciiz failed %x\n", status);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
}
|
|
ioctl_inbuf_max = max (ioctl_inbuf_min, ioctl_inbuf_max);
|
|
ioctl_outbuf_max = max (ioctl_outbuf_min, ioctl_outbuf_max);
|
|
if (prefix_string && (*flags&FLAGS_DO_PRINT_DEVS) == 0) {
|
|
prefix_string = NULL;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
Print out usage message
|
|
*/
|
|
void
|
|
do_usage (void)
|
|
{
|
|
printf ("devctl [/i] [/l] [/il nn] [/iu mm] [devnam]\n\n");
|
|
printf ("/ and + enable options, - disables options\n\n");
|
|
printf ("/a\tDo all devices in system. Don't prompt for yes/no etc\n");
|
|
printf ("/al\tAlert the main thread periodically\n");
|
|
printf ("/c\tEnable or disable skipping operations that aborted or crashed\n");
|
|
printf ("/dd\tEnable or disable the direct device open paths\n");
|
|
printf ("/dl nn\tSets max for device type portion of IOCTL/FSCTL code, default 0\n");
|
|
printf ("/dr drv\tOnly runs on device objects with driver <drv> in their stack\n");
|
|
printf ("/du nn\tSets min limit for device type portion of IOCTL/FSCTL code, default 200\n");
|
|
printf ("/e\tEnable or disable zero length EA's, needed on checked builds\n");
|
|
printf ("/f\tEnable or disable all FSCTL paths\n");
|
|
printf ("/fi\tEnable or disable turning on failure injection in the driver verifier\n");
|
|
printf ("/fn\tEnable or disable FSCTL paths with null buffers\n");
|
|
printf ("/fr\tEnable or disable FSCTL paths with random buffers\n");
|
|
printf ("/fl nn\tSets max for function portion of IOCTL and FSCTL code, default 0\n");
|
|
printf ("/fu nn\tSets min for function portion of IOCTL and FSCTL code, default 400\n");
|
|
printf ("/g c h\tGrabs a handle from another process\n");
|
|
printf ("/h /?\tPrints this message\n");
|
|
printf ("/i\tEnable or disable all IOCTL paths\n");
|
|
printf ("/if\tEnable or disable all FSCTL and IOCTL paths\n");
|
|
printf ("/in\tEnable or disable IOCTL paths with null buffers\n");
|
|
printf ("/il nnn\tSet lower input buffer size\n");
|
|
printf ("/im\tEnable or disable the impersonation of a non-admin during the test\n");
|
|
printf ("/iu nnn\tSet upper input buffer size\n");
|
|
printf ("/ir\tEnable or disable IOCTL paths with random buffers\n");
|
|
printf ("/j\tEnable or disable relative stream opens for filesystems\n");
|
|
printf ("/k\tEnable or disable synchronous handles\n");
|
|
printf ("/l\tEnable or disable logging and skipping failing functions\n");
|
|
printf ("/m\tEnable or disable the misc functions\n");
|
|
printf ("/n\tMap zero page so that NULL pointer de-references don't raise\n");
|
|
printf ("/oc\tEnable or disable the multithreaded open and close stage\n");
|
|
printf ("/ol nnn\tSet lower output buffer size\n");
|
|
printf ("/ou nnn\tSet upper output buffer size\n");
|
|
printf ("/p\tEnable or disable the checks on pool usage via tags and lookaside lists\n");
|
|
printf ("/pd\tPrint out device objects and symbolic links and exit\n");
|
|
printf ("/pr\tEnable or disable protection change tests\n");
|
|
printf ("/ps sss\tSet prefix string for use with /pd\n");
|
|
printf ("/q\tEnable or disable the normal handle query functions\n");
|
|
printf ("/r\tEnable or disable skipping operations already logged as done\n");
|
|
printf ("/rd\tSelect a random device object or symbolic link for testing\n");
|
|
printf ("/s\tEnable or disable the sub or relative opens to obtain handles\n");
|
|
printf ("/sd\tEnable or disable the query and set security functions\n");
|
|
printf ("/sl\tEnable or disable the opening of symbolic links\n");
|
|
printf ("/se nnn\tSet session id to nnn\n");
|
|
printf ("/t nn\tSet max IOCTL/FSCTL calls made with random buffers, default 100000\n");
|
|
printf ("/tt nn\tSet max tailured calls made for discovered IOCTLs/FSCTLs, default 10000\n");
|
|
printf ("/v\tEnable or disable the printing of error status values for calls\n");
|
|
printf ("/w\tEnable or disable the winsock TransmitFile test\n");
|
|
printf ("/y\tEnable or disable touching disk devices\n");
|
|
printf ("\n");
|
|
printf ("Defaults: devctl -a -al +c +dd +dl 0 -dr +du 200 +e +fn +fr +fl 0 fu 400 +im\n");
|
|
printf (" +il 0 +in +iu 512 +ir -j -k +l +m -n +oc +ol 0 +ou 512 +p -pr\n");
|
|
printf (" +q +s +sd +sl +t 100000 +tt 10000 -v -w +y\n");
|
|
}
|
|
|
|
void change_session (ULONG sessionid)
|
|
{
|
|
HANDLE token;
|
|
|
|
if (!OpenProcessToken (NtCurrentProcess (), MAXIMUM_ALLOWED, &token)) {
|
|
printf ("OpenProcessToken failed %d\n", GetLastError ());
|
|
return;
|
|
}
|
|
if (SetTokenInformation (token, TokenSessionId, &sessionid, sizeof (sessionid))) {
|
|
printf ("Token session ID changed to %d\n", sessionid);
|
|
} else {
|
|
printf ("SetTokenInformation failed %d\n", GetLastError ());
|
|
}
|
|
if (!CloseHandle (token)) {
|
|
printf ("CloseHandle failed %d\n", GetLastError ());
|
|
return;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
EnableDebugPrivilege (
|
|
)
|
|
{
|
|
struct
|
|
{
|
|
DWORD Count;
|
|
LUID_AND_ATTRIBUTES Privilege [1];
|
|
|
|
} Info;
|
|
|
|
HANDLE Token;
|
|
BOOL Result;
|
|
|
|
//
|
|
// open the process token
|
|
//
|
|
|
|
Result = OpenProcessToken (
|
|
GetCurrentProcess (),
|
|
TOKEN_ADJUST_PRIVILEGES,
|
|
& Token);
|
|
|
|
if( Result != TRUE )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// prepare the info structure
|
|
//
|
|
|
|
Info.Count = 1;
|
|
Info.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
|
Result = LookupPrivilegeValue (
|
|
NULL,
|
|
SE_DEBUG_NAME,
|
|
&(Info.Privilege[0].Luid));
|
|
|
|
if( Result != TRUE )
|
|
{
|
|
CloseHandle( Token );
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// adjust the privileges
|
|
//
|
|
|
|
Result = AdjustTokenPrivileges (
|
|
Token,
|
|
FALSE,
|
|
(PTOKEN_PRIVILEGES) &Info,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
if( Result != TRUE || GetLastError() != ERROR_SUCCESS )
|
|
{
|
|
CloseHandle( Token );
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
CloseHandle( Token );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
__cdecl
|
|
main(
|
|
int argc, char **argv
|
|
)
|
|
{
|
|
ULONG seed, i;
|
|
UNICODE_STRING us;
|
|
ULONG id, tmp;
|
|
DWORD old;
|
|
NTSTATUS status;
|
|
UNICODE_STRING name;
|
|
WSADATA wsadata;
|
|
WORD version;
|
|
int istatus;
|
|
SOCKET s;
|
|
struct sockaddr_in sockaddr;
|
|
char nameb[255];
|
|
HOSTENT *host;
|
|
struct in_addr localaddr;
|
|
DWORD retlen;
|
|
int t;
|
|
HANDLE listenthread;
|
|
struct sockaddr_in laddr;
|
|
SIZE_T size;
|
|
PVOID base;
|
|
|
|
//
|
|
// Turn off popups for a missing floppy etc
|
|
//
|
|
SetErrorMode(SEM_FAILCRITICALERRORS);
|
|
|
|
Create_nonadmin_token ();
|
|
|
|
//
|
|
// Create and event for any requests we really need to work on a async handle
|
|
//
|
|
status = NtCreateEvent (&sync_event, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtCreateEvent failed %x\n", status);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
process_parameters (argc, argv, &name, &flags, &flags2);
|
|
if (flags&FLAGS_DO_USAGE) {
|
|
do_usage ();
|
|
exit (EXIT_SUCCESS);
|
|
}
|
|
EnableDebugPrivilege ();
|
|
|
|
/*
|
|
Seed RNG
|
|
*/
|
|
|
|
|
|
// printf("Seed? ");
|
|
// scanf("%d", &seed);
|
|
// srand(seed);
|
|
srand ((unsigned) time (NULL));
|
|
|
|
//
|
|
// Build a socket etc to handle the TransmitFile API
|
|
//
|
|
do {
|
|
if (!(flags&FLAGS_DO_WINSOCK))
|
|
break;
|
|
if (flags&FLAGS_DO_PRINT_DEVS)
|
|
break;
|
|
|
|
version = MAKEWORD (2, 0);
|
|
istatus = WSAStartup (version, &wsadata);
|
|
if (istatus != 0) {
|
|
printf ("Failed to start winsock %x!\n", istatus);
|
|
flags &= ~FLAGS_DO_WINSOCK;
|
|
break;
|
|
}
|
|
|
|
istatus = gethostname (nameb, sizeof (nameb));
|
|
if (istatus != 0) {
|
|
printf ("Gethostname failed %d\n", WSAGetLastError ());
|
|
flags &= ~FLAGS_DO_WINSOCK;
|
|
break;
|
|
}
|
|
|
|
host = gethostbyname (nameb);
|
|
if (!host) {
|
|
printf ("Gethostbyname failed %d\n", WSAGetLastError ());
|
|
flags &= ~FLAGS_DO_WINSOCK;
|
|
break;
|
|
}
|
|
localaddr = *(struct in_addr *) host->h_addr_list[0];
|
|
|
|
ls = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
if (ls == INVALID_SOCKET) {
|
|
printf ("Socket failed %d\n", WSAGetLastError ());
|
|
flags &= ~FLAGS_DO_WINSOCK;
|
|
break;
|
|
}
|
|
memset (&sockaddr, 0, sizeof (sockaddr));
|
|
sockaddr.sin_family = AF_INET;
|
|
sockaddr.sin_port = htons (0);
|
|
sockaddr.sin_addr = localaddr;
|
|
istatus = bind (ls, (struct sockaddr *) &sockaddr, sizeof (sockaddr));
|
|
if (istatus != 0) {
|
|
printf ("Bind failed %d\n", WSAGetLastError ());
|
|
flags &= ~FLAGS_DO_WINSOCK;
|
|
break;
|
|
}
|
|
|
|
istatus = listen (ls, 2);
|
|
if (istatus != 0) {
|
|
printf ("Listen failed %d\n", WSAGetLastError ());
|
|
flags &= ~FLAGS_DO_WINSOCK;
|
|
break;
|
|
}
|
|
|
|
t = sizeof (laddr);
|
|
istatus = getsockname (ls, (struct sockaddr *) &laddr, &t);
|
|
if (istatus != 0) {
|
|
printf ("Getsockname failed %d\n", WSAGetLastError ());
|
|
flags &= ~FLAGS_DO_WINSOCK;
|
|
break;
|
|
}
|
|
printf ("Listen socket on port %d address %s\n",
|
|
ntohs (laddr.sin_port), inet_ntoa (laddr.sin_addr));
|
|
|
|
listenthread = CreateThread (NULL, 0, do_listen, NULL, 0, &id);
|
|
if (!listenthread) {
|
|
printf ("CreateThread failed %d\n", GetLastError ());
|
|
flags &= ~FLAGS_DO_WINSOCK;
|
|
break;
|
|
}
|
|
|
|
cs = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
if (cs == INVALID_SOCKET) {
|
|
printf ("Socket failed %d\n", WSAGetLastError ());
|
|
flags &= ~FLAGS_DO_WINSOCK;
|
|
break;
|
|
}
|
|
istatus = connect (cs, (struct sockaddr *) &laddr, sizeof (laddr));
|
|
if (istatus != 0) {
|
|
printf ("connect failed %d\n", WSAGetLastError ());
|
|
flags &= ~FLAGS_DO_WINSOCK;
|
|
break;
|
|
}
|
|
} while (FALSE);
|
|
|
|
//
|
|
// Build a big buffer to pass to requests
|
|
//
|
|
bigbuf = VirtualAlloc(NULL, BIGBUF_SIZE + SLOP, MEM_COMMIT, PAGE_READWRITE);
|
|
if (!bigbuf) {
|
|
printf ("Failed to allocate I/O buffers %x\n", GetLastError ());
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
//
|
|
// Map the zero page and fill it with junk
|
|
//
|
|
if (flags&FLAGS_DO_MAPNULL) {
|
|
base = (PVOID) 1;
|
|
size = 1;
|
|
status = NtAllocateVirtualMemory (NtCurrentProcess (), &base, 1, &size,
|
|
MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtAllocateVirtualMemory for zero page failed %x\n", status);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
for (i = 0; i < size; i++) {
|
|
*((PUCHAR) base + i) = (UCHAR) rand ();
|
|
}
|
|
}
|
|
// randthread = CreateThread (NULL, 0, randomize, bigbuf, CREATE_SUSPENDED, &id);
|
|
// if (!randthread) {
|
|
// printf ("Failed to create radomizing thread %x\n", GetLastError ());
|
|
// exit (EXIT_FAILURE);
|
|
// }
|
|
//
|
|
// Create a thread to change the page protection of our buffer if need be
|
|
//
|
|
if (flags&FLAGS_DO_PROT) {
|
|
changethread = CreateThread (NULL, 0, changeprot, bigbuf, CREATE_SUSPENDED, &id);
|
|
if (!changethread) {
|
|
printf ("Failed to create protection change thread %x\n", GetLastError ());
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
//
|
|
// Get a real handle to our thread to pass to other threads
|
|
//
|
|
status = NtDuplicateObject (NtCurrentProcess (), NtCurrentThread (),
|
|
NtCurrentProcess (), &mainthread,
|
|
0, 0, DUPLICATE_SAME_ACCESS);
|
|
if (!NT_SUCCESS (status)) {
|
|
printf ("NtDuplcateObject failed %x\n", status);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
//
|
|
// Create a thread to alert this one periodicaly or when it thinks we are stuck
|
|
//
|
|
alertthread = CreateThread (NULL, 0, alerter, mainthread, 0, &id);
|
|
if (!alertthread) {
|
|
printf ("Failed to create alerting thread %x\n", GetLastError ());
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
// status = NtSuspendThread (changethread, &tmp);
|
|
// if (!NT_SUCCESS (status)) {
|
|
// printf ("NtSuspendThread failed %x\n", status);
|
|
// }
|
|
// status = NtSuspendThread (randthread, &tmp);
|
|
// if (!NT_SUCCESS (status)) {
|
|
// printf ("NtSuspendThread failed %x\n", status);
|
|
// }
|
|
if (!VirtualProtect (bigbuf, 1, PAGE_READWRITE, &old)) {
|
|
printf ("VirtualProtect failed %d\n", GetLastError ());
|
|
}
|
|
|
|
devscount = 0;
|
|
print_diags (0, 0);
|
|
if (flags&FLAGS_DO_GRAB) {
|
|
do_handle_grab (devmap,
|
|
&devscount);
|
|
}
|
|
|
|
/*
|
|
* Crash the system.
|
|
*/
|
|
if (name.Length > 0) {
|
|
if (flags&FLAGS_DO_IMPERSONATION) {
|
|
Impersonate_nonadmin ();
|
|
}
|
|
|
|
status = do_device_opens (NULL,
|
|
&name,
|
|
devmap,
|
|
&devscount,
|
|
name.Buffer,
|
|
name.Buffer);
|
|
|
|
if (flags&FLAGS_DO_IMPERSONATION) {
|
|
if (!Revert_from_admin ()) {
|
|
printf ("Revert_from_admin failed %d\n", GetLastError ());
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
} else {
|
|
do_wmi ();
|
|
|
|
random_device = (rand () % 1345) + 1;
|
|
|
|
while (1) {
|
|
|
|
RtlInitUnicodeString(&us,
|
|
L"\\");
|
|
|
|
skipped = 0;
|
|
recurse(0,
|
|
&us,
|
|
devmap,
|
|
&devscount,
|
|
L"",
|
|
1);
|
|
|
|
for (i = 0; i < devscount; i++) {
|
|
free (devmap[i].name);
|
|
devmap[i].name = NULL;
|
|
free (devmap[i].filename);
|
|
devmap[i].filename = NULL;
|
|
NtClose(devmap[i].handle);
|
|
}
|
|
devscount = 0;
|
|
if (flags&(FLAGS_DO_ALLDEVS|FLAGS_DO_PRINT_DEVS)) {
|
|
break;
|
|
}
|
|
if ((flags&FLAGS_DO_RANDOM_DEVICE) && (random_device == 0)) {
|
|
Sleep (30*1000);
|
|
random_device = (rand () % 1345) + 1;
|
|
}
|
|
}
|
|
}
|
|
if ((flags&FLAGS_DO_PRINT_DEVS) == 0) {
|
|
crashes (L"DONE", L"", L"", L"", L"");
|
|
}
|
|
|
|
exit(EXIT_SUCCESS);
|
|
}
|