├── src ├── makefile.def ├── inc │ ├── winerr.h │ ├── log.h │ ├── driver.h │ └── getopt.h ├── build.bat ├── makefile.txt ├── log.c ├── drivercode.c ├── driverfuzz.c ├── driverenum.c ├── crashmeat.c └── getopt.c └── README.md /src/makefile.def: -------------------------------------------------------------------------------- 1 | !INCLUDE $(NTMAKEENV)\makefile.def 2 | -------------------------------------------------------------------------------- /src/inc/winerr.h: -------------------------------------------------------------------------------- 1 | /*********************************************************** 2 | * Project : CrashMeat 3 | * Author : Nixawk 4 | * Description : A Fuzz Framework for Analysis 5 | * License : GPL3 6 | ***********************************************************/ 7 | 8 | #pragma once 9 | 10 | #ifndef _WINERR_ 11 | #define _WINERR_ 12 | 13 | // Handle Windows Error 14 | 15 | #pragma warning(disable:4996) 16 | #pragma warning(disable:4127) 17 | 18 | #endif -------------------------------------------------------------------------------- /src/inc/log.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 rxi 3 | * 4 | * This library is free software; you can redistribute it and/or modify it 5 | * under the terms of the MIT license. See `log.c` for details. 6 | */ 7 | 8 | #ifndef LOG_H 9 | #define LOG_H 10 | 11 | #include 12 | #include 13 | 14 | #define LOG_VERSION "0.1.0" 15 | 16 | typedef void (*log_LockFn)(void *udata, int lock); 17 | 18 | enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL }; 19 | 20 | #define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) 21 | #define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) 22 | #define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) 23 | #define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__) 24 | #define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) 25 | #define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) 26 | 27 | void log_set_udata(void *udata); 28 | void log_set_lock(log_LockFn fn); 29 | void log_set_fp(FILE *fp); 30 | void log_set_level(int level); 31 | void log_set_quiet(int enable); 32 | 33 | void log_log(int level, const char *file, int line, const char *fmt, ...); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM bldusr.bat ---------------------------------------------------------------- 3 | 4 | REM Set up build environment--------------------------------------------------- 5 | 6 | set THIS_FILE=build.bat 7 | 8 | ECHO [%THIS_FILE%]: Establish build environment 9 | set SAVED_PATH=%PATH% 10 | set PATH=%PATH%;C:\WinDDK\7600.16385.1\bin\x86;C:\WinDDK\7600.16385.1\bin\x86\x86 11 | 12 | REM Perform Build-------------------------------------------------------------- 13 | 14 | ECHO [%THIS_FILE%]: Invoking nmake.exe 15 | 16 | IF "%~1" == "" GOTO usage 17 | IF %1 == debug (echo [%THIS_FILE%]: Debug)&(nmake.exe /NOLOGO /S /F makefile.txt BLDTYPE=DEBUG %1)&(GOTO ELevel) 18 | IF %1 == release (echo [%THIS_FILE%]: Release)&(nmake.exe /NOLOGO /S /F makefile.txt %1)&(GOTO ELevel) 19 | IF %1 == clean (echo [%THIS_FILE%]: Clean)&(nmake.exe /NOLOGO /S /F makefile.txt %1)&(GOTO ELevel) 20 | 21 | :usage 22 | ECHO [%THIS_FILE%]: ********ERROR - BAD ARGUMENTS********************* 23 | ECHO [%THIS_FILE%]: USAGE: %THIS_FILE% ^( debug ^| release ^| clean ^) 24 | GOTO end 25 | 26 | :ELevel 27 | IF %ERRORLEVEL% == 0 GOTO good 28 | IF %ERRORLEVEL% == 1 GOTO incomplete 29 | IF %ERRORLEVEL% == 2 GOTO apperror 30 | IF %ERRORLEVEL% == 4 GOTO syserror 31 | IF %ERRORLEVEL% == 255 GOTO uptodate 32 | GOTO unexpected 33 | 34 | :good 35 | ECHO [%THIS_FILE%]: Success 36 | GOTO END 37 | :incomplete 38 | ECHO [%THIS_FILE%]: Incomplete build (issued only when /K is used) 39 | GOTO END 40 | :apperror 41 | ECHO [%THIS_FILE%]: Program error (makefile syntax error, command error, or user interruption) 42 | GOTO END 43 | :syserror 44 | ECHO [%THIS_FILE%]: System error (out of memory) 45 | GOTO END 46 | :uptodate 47 | ECHO [%THIS_FILE%]: Target is not up to date (issued only when /Q is used) 48 | GOTO END 49 | :unexpected 50 | ECHO [%THIS_FILE%]: Unexpected return code 51 | GOTO END 52 | :end 53 | ECHO [%THIS_FILE%]: ERRORLEVEL= %ERRORLEVEL% 54 | 55 | REM Restore Old Environment---------------------------------------------------- 56 | 57 | ECHO [%THIS_FILE%]: Restoring old environment 58 | set PATH="" 59 | set PATH=%SAVED_PATH% -------------------------------------------------------------------------------- /src/makefile.txt: -------------------------------------------------------------------------------- 1 | # +---------------------------------------------------------------------------+ 2 | # | | 3 | # | makefile.txt | 4 | # | | 5 | # +---------------------------------------------------------------------------+ 6 | 7 | # [File Names]----------------------------------------------------------------- 8 | 9 | SRC_FILES = crashmeat.c getopt.c driverenum.c drivercode.c driverfuzz.c 10 | OBJ_FILES = crashmeat.obj getopt.obj driverenum.obj drivercode.obj driverfuzz.obj 11 | 12 | DEBUG_NAME = crashmeat 13 | RELEASE_NAME = crashmeat 14 | 15 | # [Directories]---------------------------------------------------------------- 16 | 17 | API_DIR1 = "C:\Program Files\Microsoft Visual Studio 10.0\VC" 18 | API_DIR2 = "C:\Program Files\Microsoft SDKs\Windows\v7.0A" 19 | OUT_DIR = ..\bin 20 | 21 | # [Include Files]-------------------------------------------------------------- 22 | 23 | API_INC = /I $(API_DIR1)\include 24 | API_INC2 = /I $(API_DIR2)\Include 25 | APP_USR_INC = /I "inc" 26 | APP_USR_INC2 = /I "." 27 | INCLUDES = $(API_INC) $(API_INC2) $(APP_USR_INC) $(APP_USR_INC2) 28 | 29 | # [Library Paths]-------------------------------------------------------------- 30 | 31 | LIBS1 = /LIBPATH:$(API_DIR1)\lib 32 | LIBS2 = /LIBPATH:$(API_DIR2)\Lib 33 | LIBS = $(LIBS1) $(LIBS2) 34 | 35 | # [Tools]---------------------------------------------------------------------- 36 | 37 | CC = cl.exe 38 | LINK = link.exe 39 | 40 | # [Tool arguments]------------------------------------------------------------- 41 | 42 | CFLAGS = /c /nologo /FAcs $(INCLUDES) /W4 43 | CC_DEBUG_FLAGS = /Od /Fd$(DEBUG_NAME) /ZI 44 | CC_RELEASE_FLAGS = /O1 /DLOG_OFF 45 | 46 | LNK_FLAGS = /NOLOGO $(LIBS) /SUBSYSTEM:CONSOLE /VERSION:1.0 /WX 47 | LNK_DEBUG_FLAGS = /DEBUG /OUT:$(OUT_DIR)\$(DEBUG_NAME).EXE 48 | LNK_RELEASE_FLAGS = /OUT:$(OUT_DIR)\$(RELEASE_NAME).EXE 49 | 50 | # [Inference Rules]------------------------------------------------------------ 51 | 52 | # If the BLDTYPE macro is defined, we want to include debug info 53 | 54 | !IFDEF BLDTYPE 55 | .c.obj:: 56 | $(CC) $(CFLAGS) $(CC_DEBUG_FLAGS) $< 57 | !ELSE 58 | .c.obj:: 59 | $(CC) $(CFLAGS) $(CC_RELEASE_FLAGS) $< 60 | !ENDIF 61 | 62 | # [Description Blocks]--------------------------------------------------------- 63 | 64 | # .cod listing file (assembly, machine code) 65 | # .obj object code 66 | # .exe final product 67 | # .pdb debug symbols (debug build only) 68 | # .idb VC++ Minimum Rebuild Dependency File (debug build only) 69 | # .ilk incremental link file (debug build only) 70 | 71 | clean: 72 | del *.cod 73 | del *.obj 74 | del *.pdb 75 | del *.idb 76 | del $(OUT_DIR)\*.pdb 77 | del $(OUT_DIR)\*.ilk 78 | del $(OUT_DIR)\*.exe 79 | 80 | debug: $(OBJ_FILES) 81 | $(LINK) $(LNK_FLAGS) $(LNK_DEBUG_FLAGS) $(OBJ_FILES) 82 | 83 | release: $(OBJ_FILES) 84 | $(LINK) $(LNK_FLAGS) $(LNK_RELEASE_FLAGS) $(OBJ_FILES) -------------------------------------------------------------------------------- /src/log.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 rxi 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "log.h" 30 | 31 | static struct { 32 | void *udata; 33 | log_LockFn lock; 34 | FILE *fp; 35 | int level; 36 | int quiet; 37 | } L; 38 | 39 | 40 | static const char *level_names[] = { 41 | "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" 42 | }; 43 | 44 | #ifdef LOG_USE_COLOR 45 | static const char *level_colors[] = { 46 | "\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m" 47 | }; 48 | #endif 49 | 50 | 51 | static void lock(void) { 52 | if (L.lock) { 53 | L.lock(L.udata, 1); 54 | } 55 | } 56 | 57 | 58 | static void unlock(void) { 59 | if (L.lock) { 60 | L.lock(L.udata, 0); 61 | } 62 | } 63 | 64 | 65 | void log_set_udata(void *udata) { 66 | L.udata = udata; 67 | } 68 | 69 | 70 | void log_set_lock(log_LockFn fn) { 71 | L.lock = fn; 72 | } 73 | 74 | 75 | void log_set_fp(FILE *fp) { 76 | L.fp = fp; 77 | } 78 | 79 | 80 | void log_set_level(int level) { 81 | L.level = level; 82 | } 83 | 84 | 85 | void log_set_quiet(int enable) { 86 | L.quiet = enable ? 1 : 0; 87 | } 88 | 89 | 90 | void log_log(int level, const char *file, int line, const char *fmt, ...) { 91 | time_t t; 92 | struct tm *lt; 93 | 94 | if (level < L.level) { 95 | return; 96 | } 97 | 98 | /* Acquire lock */ 99 | lock(); 100 | 101 | /* Get current time */ 102 | // time_t t = time(NULL); 103 | // struct tm *lt = localtime(&t); 104 | 105 | t = time(NULL); 106 | lt = localtime(&t); 107 | 108 | /* Log to stderr */ 109 | if (!L.quiet) { 110 | va_list args; 111 | char buf[16]; 112 | buf[strftime(buf, sizeof(buf), "%H:%M:%S", lt)] = '\0'; 113 | #ifdef LOG_USE_COLOR 114 | fprintf( 115 | stderr, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", 116 | buf, level_colors[level], level_names[level], file, line); 117 | #else 118 | fprintf(stderr, "%s %-5s %s:%d: ", buf, level_names[level], file, line); 119 | // fprintf(stderr, "%s %-5s : ", buf, level_names[level]); 120 | #endif 121 | va_start(args, fmt); 122 | vfprintf(stderr, fmt, args); 123 | va_end(args); 124 | fprintf(stderr, "\n"); 125 | } 126 | 127 | /* Log to file */ 128 | if (L.fp) { 129 | va_list args; 130 | char buf[32]; 131 | buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", lt)] = '\0'; 132 | fprintf(L.fp, "%s %-5s %s:%d: ", buf, level_names[level], file, line); 133 | // fprintf(L.fp, "%s %-5s : ", buf, level_names[level]); 134 | va_start(args, fmt); 135 | vfprintf(L.fp, fmt, args); 136 | va_end(args); 137 | fprintf(L.fp, "\n"); 138 | } 139 | 140 | /* Release lock */ 141 | unlock(); 142 | } 143 | -------------------------------------------------------------------------------- /src/drivercode.c: -------------------------------------------------------------------------------- 1 | /*********************************************************** 2 | * Project : CrashMeat 3 | * Author : Nixawk 4 | * Description : A Fuzz Framework for Analysis 5 | * License : GPL3 6 | ***********************************************************/ 7 | 8 | #include "winerr.h" 9 | #include "driver.h" 10 | // #include "log.h" 11 | 12 | BOOL Crack_IoControlCode(LPCSTR SymbolicLinkName) // Wait 13 | { 14 | // An I/O control code is a 32-bit value that consists of several fields. 15 | // The following figure illustrates the layout of I/O control codes. 16 | 17 | 18 | // #define IOCTL_Device_Function CTL_CODE(DeviceType, Function, Method, Access) 19 | 20 | // DeviceType 21 | // https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/specifying-device-types 22 | 23 | // FunctionCode 24 | // - Values of less than 0x8000 are reserved for Microsoft. 25 | // - Values of 0x8000 and higher can be used by vendors. 26 | 27 | // TransferType 28 | // - METHOD_BUFFERED 29 | // - METHOD_IN_DIRECT 30 | // - METHOD_OUT_DIRECT 31 | // - METHOD_NEITHER 32 | 33 | // RequiredAccess 34 | // - FILE_ANY_ACCESS 35 | // - FILE_READ_DATA 36 | // - FILE_WRITE_DATA 37 | 38 | // Example: 39 | // #define CTL_HEL CTL_CODE(FILE_DEVICE_UNKNOWN,0x801, METHOD_BUFFERED, FILE_ANY_ACCESS) 40 | 41 | return FALSE; 42 | 43 | } 44 | 45 | void Push_IoControlCode(PIO_CONTROL_CODE_ENTRY *pIoControlCodeEntry, DWORD Start, DWORD End) 46 | { 47 | PIO_CONTROL_CODE_ENTRY pIoControlCodeEntryNew = NULL; 48 | 49 | pIoControlCodeEntryNew = (PIO_CONTROL_CODE_ENTRY)malloc(sizeof(IO_CONTROL_CODE_ENTRY)); 50 | if (NULL == pIoControlCodeEntryNew) 51 | { 52 | printf("[-] Push_IoControlCode Error: malloc failed\n"); 53 | exit(-1); 54 | } 55 | 56 | pIoControlCodeEntryNew->Start = Start; 57 | pIoControlCodeEntryNew->End = End; 58 | pIoControlCodeEntryNew->Next = *pIoControlCodeEntry; 59 | 60 | *pIoControlCodeEntry = pIoControlCodeEntryNew; 61 | } 62 | 63 | 64 | PIO_CONTROL_CODE_ENTRY ParseIoControlCodeFromOptArg(char *IoControlCodeLst) 65 | { 66 | PIO_CONTROL_CODE_ENTRY pIoControlCodeEntry = NULL; 67 | 68 | char *IoControlCodeLstToken = NULL; 69 | char *IoControlCodeLstTokenParse = NULL; 70 | 71 | DWORD IoControlCodeIndex = 0; 72 | 73 | if (NULL == IoControlCodeLst) 74 | { 75 | printf("[-] ParseIoControlCodeFromOptArg Error: no IoControlCode string\n"); 76 | goto CLEANUP_AND_EXIT; 77 | } 78 | 79 | IoControlCodeLstToken = strtok(IoControlCodeLst, ","); 80 | while (NULL != IoControlCodeLstToken) 81 | { 82 | if (NULL != strchr(IoControlCodeLstToken, '-')) 83 | { 84 | // printf("Index: %ld, IoControlCode Range : %s\n", IoControlCodeIndex, IoControlCodeLstToken); 85 | 86 | // Attention: strtok will change the pointer status. 87 | IoControlCodeLstTokenParse = strchr(IoControlCodeLstToken, '-'); 88 | *IoControlCodeLstTokenParse = '\0'; 89 | 90 | Push_IoControlCode( 91 | &pIoControlCodeEntry, 92 | (DWORD)atoi(IoControlCodeLstToken), 93 | (DWORD)atoi(IoControlCodeLstTokenParse + 1) 94 | ); 95 | 96 | } else { 97 | // printf("Index: %ld, IoControlCode Single : %s\n", IoControlCodeIndex, IoControlCodeLstToken); 98 | 99 | Push_IoControlCode( 100 | &pIoControlCodeEntry, 101 | (DWORD)atoi(IoControlCodeLstToken), 102 | (DWORD)atoi(IoControlCodeLstToken) 103 | ); 104 | 105 | } 106 | 107 | IoControlCodeIndex += 2; 108 | 109 | IoControlCodeLstToken = strtok(NULL, ","); 110 | } 111 | 112 | // printf( 113 | // "{" 114 | // "'func': 'ParseIoControlCodeFromOptArg', " 115 | // "'text': 'IoControlCode Count: %ld'," 116 | // "}\n", 117 | // IoControlCodeIndex / 2 118 | // ); 119 | 120 | // printf("[*] IoControlCode Count, [%ld]\n", IoControlCodeIndex / 2); 121 | 122 | // while (NULL != pIoControlCodeEntry) 123 | // { 124 | // printf( 125 | // "Start: %ld, End: %ld\n", 126 | // pIoControlCodeEntry->Start, 127 | // pIoControlCodeEntry->End 128 | // ); 129 | 130 | // pIoControlCodeEntry = pIoControlCodeEntry->Next; 131 | // } 132 | 133 | 134 | CLEANUP_AND_EXIT: 135 | return pIoControlCodeEntry; 136 | 137 | } 138 | 139 | 140 | // https://www.thegeekstuff.com/2012/08/c-linked-list-example/ 141 | // http://www.learn-c.org/en/Linked_lists 142 | // https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/defining-i-o-control-codes 143 | -------------------------------------------------------------------------------- /src/inc/driver.h: -------------------------------------------------------------------------------- 1 | /*********************************************************** 2 | * Project : CrashMeat 3 | * Author : Nixawk 4 | * Description : A Fuzz Framework for Analysis 5 | * License : GPL3 6 | ***********************************************************/ 7 | 8 | #pragma once 9 | 10 | #ifndef _DRIVER_ 11 | #define _DRIVER_ 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | // https://doxygen.reactos.org/db/ded/reactos_2wine_2winternl_8h_source.html#l00001 18 | // typedef ULONG NTSTATUS; 19 | typedef LONG NTSTATUS; 20 | 21 | // https://doxygen.reactos.org/dd/df3/env__spec__w32_8h_source.html#l00368 22 | typedef struct _UNICODE_STRING { 23 | USHORT Length; 24 | USHORT MaximumLength; 25 | PWSTR Buffer; 26 | } UNICODE_STRING; 27 | typedef UNICODE_STRING *PUNICODE_STRING; 28 | 29 | // https://doxygen.reactos.org/da/dc1/umtypes_8h_source.html#l00169 30 | typedef struct _OBJECT_ATTRIBUTES 31 | { 32 | ULONG Length; 33 | HANDLE RootDirectory; 34 | PUNICODE_STRING ObjectName; 35 | ULONG Attributes; 36 | PVOID SecurityDescriptor; 37 | PVOID SecurityQualityOfService; 38 | } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; 39 | 40 | // https://doxygen.reactos.org/db/ded/reactos_2wine_2winternl_8h_source.html#l02148 41 | typedef struct _DIRECTORY_BASIC_INFORMATION { 42 | UNICODE_STRING ObjectName; 43 | UNICODE_STRING ObjectTypeName; 44 | } DIRECTORY_BASIC_INFORMATION, *PDIRECTORY_BASIC_INFORMATION; 45 | 46 | // https://doxygen.reactos.org/d2/dea/psdk_2winternl_8h_source.html#l00228 47 | #define OBJ_INHERIT 0x00000002L 48 | #define OBJ_PERMANENT 0x00000010L 49 | #define OBJ_EXCLUSIVE 0x00000020L 50 | #define OBJ_CASE_INSENSITIVE 0x00000040L 51 | #define OBJ_OPENIF 0x00000080L 52 | #define OBJ_OPENLINK 0x00000100L 53 | #define OBJ_KERNEL_HANDLE 0x00000200L 54 | #define OBJ_FORCE_ACCESS_CHECK 0x00000400L 55 | #define OBJ_VALID_ATTRIBUTES 0x000007F2L 56 | 57 | // https://doxygen.reactos.org/dd/da0/om_8c_source.html#l00211 58 | #define DIRECTORY_QUERY (0x0001) 59 | #define SYMBOLIC_LINK_QUERY 0x0001 60 | 61 | // https://doxygen.reactos.org/df/db3/udferr__usr_8h_source.html#l00124 62 | #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) 63 | #define STATUS_MORE_ENTRIES ((NTSTATUS)0x00000105L) 64 | #define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L) 65 | 66 | // https://doxygen.reactos.org/de/d63/modules_2rostests_2winetests_2ntdll_2reg_8c_source.html#l00106 67 | #define InitializeObjectAttributes(p,n,a,r,s) \ 68 | do { \ 69 | (p)->Length = sizeof(OBJECT_ATTRIBUTES); \ 70 | (p)->RootDirectory = r; \ 71 | (p)->Attributes = a; \ 72 | (p)->ObjectName = n; \ 73 | (p)->SecurityDescriptor = s; \ 74 | (p)->SecurityQualityOfService = NULL; \ 75 | } while (0) 76 | 77 | // https://doxygen.reactos.org/de/d46/tunneltest_8c_source.html#l00014 78 | #define RTL_CONSTANT_STRING(s) { sizeof(s)-sizeof((s)[0]), sizeof(s), s } 79 | 80 | // https://doxygen.reactos.org/db/dc9/nt__native_8h.html#a5e6d7af51cb6d106401f3967b6b44b12 81 | // https://www.sysnative.com/forums/programming/8592-ntcreatefile-example.html 82 | typedef VOID(CALLBACK* RTLINITUNICODESTRING)( 83 | PUNICODE_STRING DestinationString, 84 | PCWSTR SourceString 85 | ); 86 | 87 | // https://doxygen.reactos.org/de/df6/ndk_2obfuncs_8h.html#a409c7b692423f91807fbf39cb2c79555 88 | typedef NTSTATUS(WINAPI *ZWOPENDIRECTORYOBJECT)( 89 | OUT PHANDLE DirectoryHandle, 90 | IN ACCESS_MASK DesiredAccess, 91 | IN POBJECT_ATTRIBUTES ObjectAttributes 92 | ); 93 | 94 | // https://msdn.microsoft.com/en-us/library/bb470238(v=vs.85).aspx 95 | typedef NTSTATUS(WINAPI *ZWQUERYDIRECTORYOBJECT)( 96 | IN HANDLE DirectoryHandle, 97 | OUT PVOID Buffer, 98 | IN ULONG BufferLength, 99 | IN BOOLEAN ReturnSingleEntry, 100 | IN BOOLEAN RestartScan, 101 | IN OUT PULONG Context, 102 | OUT PULONG ReturnLength OPTIONAL 103 | ); 104 | 105 | // https://doxygen.reactos.org/de/df6/ndk_2obfuncs_8h.html#a5e0a128a3b03af9e6deef339000e30e0 106 | typedef NTSTATUS(WINAPI *ZWCLOSE)( 107 | IN HANDLE Handle 108 | ); 109 | 110 | 111 | typedef struct _IO_CONTROL_CODE_ENTRY { 112 | DWORD Start; 113 | DWORD End; 114 | struct _IO_CONTROL_CODE_ENTRY * Next; 115 | } IO_CONTROL_CODE_ENTRY, *PIO_CONTROL_CODE_ENTRY; 116 | 117 | 118 | // https://stackoverflow.com/questions/5351919/how-many-chars-can-be-in-a-char-array 119 | // https://github.com/torvalds/linux/blob/master/include/uapi/linux/limits.h 120 | 121 | // ---- Functions Here ---- 122 | 123 | // [[ ---- driverenum.c 124 | // Get All Available Device Drivers from OS System 125 | extern HANDLE OpenDriverBySymbolicLinkName(LPCSTR SymbolicLinkName); 126 | extern BOOL AccessDriverBySymbolicLinkName(LPCSTR SymbolicLinkName); 127 | extern PDIRECTORY_BASIC_INFORMATION GetAllDriversSymbolicLink(); 128 | extern void PrintAllDriverSymbolicLink(); 129 | // driverenum.c ---- ]] 130 | 131 | // [[ ---- drivercode.c 132 | extern PIO_CONTROL_CODE_ENTRY ParseIoControlCodeFromOptArg(char *IoControlCodeLst); 133 | // drivercode.c ---- ]] 134 | 135 | 136 | // [[ ---- driverfuzz.c 137 | #ifndef MAX_STACKOVERFLOW_SIZE 138 | #define MAX_STACKOVERFLOW_SIZE 0x10000 // 0xFFFF == 65535 139 | #endif 140 | 141 | #ifndef MAX_HEAPADDRESS_COUNT // Heap Address Count to malloc 142 | #define MAX_HEAPADDRESS_COUNT 30 143 | #endif 144 | 145 | extern BOOL Crack_IoControlCode(LPCSTR SymbolicLinkName); 146 | extern BOOL Fuzz_NULL_Pointer(LPCSTR SymbolicLinkName, DWORD dwIoControlCode); 147 | extern BOOL Fuzz_Stack_Overflow(LPCSTR SymbolicLinkName, DWORD dwIoControlCode, char paddingChar); 148 | extern BOOL Fuzz_Invalid_Address(LPCSTR SymbolicLinkName, DWORD dwIoControlCode); 149 | 150 | extern void Fuzz_NULL_Pointer_PDBI(PDIRECTORY_BASIC_INFORMATION pSymbolicLinkDirectory, DWORD dwIoControlCode); 151 | extern void Fuzz_Stack_Overflow_PDBI(PDIRECTORY_BASIC_INFORMATION pSymbolicLinkDirectory, DWORD dwIoControlCode, char paddingChar); 152 | extern void Fuzz_Invalid_Address_PDBI(PDIRECTORY_BASIC_INFORMATION pSymbolicLinkDirectory, DWORD dwIoControlCode); 153 | 154 | // driverfuzz.c ---- ]] 155 | 156 | #endif -------------------------------------------------------------------------------- /src/inc/getopt.h: -------------------------------------------------------------------------------- 1 | /* getopt.h */ 2 | /* Declarations for getopt. 3 | Copyright (C) 1989-1994, 1996-1999, 2001 Free Software 4 | Foundation, Inc. This file is part of the GNU C Library. 5 | 6 | The GNU C Library is free software; you can redistribute 7 | it and/or modify it under the terms of the GNU Lesser 8 | General Public License as published by the Free Software 9 | Foundation; either version 2.1 of the License, or 10 | (at your option) any later version. 11 | 12 | The GNU C Library is distributed in the hope that it will 13 | be useful, but WITHOUT ANY WARRANTY; without even the 14 | implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | PARTICULAR PURPOSE. See the GNU Lesser General Public 16 | License for more details. 17 | 18 | You should have received a copy of the GNU Lesser General 19 | Public License along with the GNU C Library; if not, write 20 | to the Free Software Foundation, Inc., 59 Temple Place, 21 | Suite 330, Boston, MA 02111-1307 USA. */ 22 | 23 | 24 | #pragma once 25 | 26 | 27 | #ifndef _GETOPT_H 28 | 29 | #ifndef __need_getopt 30 | # define _GETOPT_H 1 31 | #endif 32 | 33 | /* If __GNU_LIBRARY__ is not already defined, either we are being used 34 | standalone, or this is the first header included in the source file. 35 | If we are being used with glibc, we need to include , but 36 | that does not exist if we are standalone. So: if __GNU_LIBRARY__ is 37 | not defined, include , which will pull in for us 38 | if it's from glibc. (Why ctype.h? It's guaranteed to exist and it 39 | doesn't flood the namespace with stuff the way some other headers do.) */ 40 | #if !defined __GNU_LIBRARY__ 41 | # include 42 | #endif 43 | 44 | #ifdef __cplusplus 45 | extern "C" { 46 | #endif 47 | 48 | /* For communication from `getopt' to the caller. 49 | When `getopt' finds an option that takes an argument, 50 | the argument value is returned here. 51 | Also, when `ordering' is RETURN_IN_ORDER, 52 | each non-option ARGV-element is returned here. */ 53 | 54 | extern char *optarg; 55 | 56 | /* Index in ARGV of the next element to be scanned. 57 | This is used for communication to and from the caller 58 | and for communication between successive calls to `getopt'. 59 | 60 | On entry to `getopt', zero means this is the first call; initialize. 61 | 62 | When `getopt' returns -1, this is the index of the first of the 63 | non-option elements that the caller should itself scan. 64 | 65 | Otherwise, `optind' communicates from one call to the next 66 | how much of ARGV has been scanned so far. */ 67 | 68 | extern int optind; 69 | 70 | /* Callers store zero here to inhibit the error message `getopt' prints 71 | for unrecognized options. */ 72 | 73 | extern int opterr; 74 | 75 | /* Set to an option character which was unrecognized. */ 76 | 77 | extern int optopt; 78 | 79 | #ifndef __need_getopt 80 | /* Describe the long-named options requested by the application. 81 | The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector 82 | of `struct option' terminated by an element containing a name which is 83 | zero. 84 | 85 | The field `has_arg' is: 86 | no_argument (or 0) if the option does not take an argument, 87 | required_argument (or 1) if the option requires an argument, 88 | optional_argument (or 2) if the option takes an optional argument. 89 | 90 | If the field `flag' is not NULL, it points to a variable that is set 91 | to the value given in the field `val' when the option is found, but 92 | left unchanged if the option is not found. 93 | 94 | To have a long-named option do something other than set an `int' to 95 | a compiled-in constant, such as set a value from `optarg', set the 96 | option's `flag' field to zero and its `val' field to a nonzero 97 | value (the equivalent single-letter option character, if there is 98 | one). For long options that have a zero `flag' field, `getopt' 99 | returns the contents of the `val' field. */ 100 | 101 | struct option 102 | { 103 | # if (defined __STDC__ && __STDC__) || defined __cplusplus 104 | const char *name; 105 | # else 106 | char *name; 107 | # endif 108 | /* has_arg can't be an enum because some compilers complain about 109 | type mismatches in all the code that assumes it is an int. */ 110 | int has_arg; 111 | int *flag; 112 | int val; 113 | }; 114 | 115 | /* Names for the values of the `has_arg' field of `struct option'. */ 116 | 117 | # define no_argument 0 118 | # define required_argument 1 119 | # define optional_argument 2 120 | #endif /* need getopt */ 121 | 122 | 123 | /* Get definitions and prototypes for functions to process the 124 | arguments in ARGV (ARGC of them, minus the program name) for 125 | options given in OPTS. 126 | 127 | Return the option character from OPTS just read. Return -1 when 128 | there are no more options. For unrecognized options, or options 129 | missing arguments, `optopt' is set to the option letter, and '?' is 130 | returned. 131 | 132 | The OPTS string is a list of characters which are recognized option 133 | letters, optionally followed by colons, specifying that that letter 134 | takes an argument, to be placed in `optarg'. 135 | 136 | If a letter in OPTS is followed by two colons, its argument is 137 | optional. This behavior is specific to the GNU `getopt'. 138 | 139 | The argument `--' causes premature termination of argument 140 | scanning, explicitly telling `getopt' that there are no more 141 | options. 142 | 143 | If OPTS begins with `--', then non-option arguments are treated as 144 | arguments to the option '\0'. This behavior is specific to the GNU 145 | `getopt'. */ 146 | 147 | #if (defined __STDC__ && __STDC__) || defined __cplusplus 148 | # ifdef __GNU_LIBRARY__ 149 | /* Many other libraries have conflicting prototypes for getopt, with 150 | differences in the consts, in stdlib.h. To avoid compilation 151 | errors, only prototype getopt for the GNU C library. */ 152 | extern int getopt(int ___argc, char *const *___argv, const char *__shortopts); 153 | # else /* not __GNU_LIBRARY__ */ 154 | extern int getopt(); 155 | # endif /* __GNU_LIBRARY__ */ 156 | 157 | # ifndef __need_getopt 158 | extern int getopt_long(int ___argc, char *const *___argv, 159 | const char *__shortopts, 160 | const struct option *__longopts, int *__longind); 161 | extern int getopt_long_only(int ___argc, char *const *___argv, 162 | const char *__shortopts, 163 | const struct option *__longopts, int *__longind); 164 | 165 | /* Internal only. Users should not call this directly. */ 166 | extern int _getopt_internal(int ___argc, char *const *___argv, 167 | const char *__shortopts, 168 | const struct option *__longopts, int *__longind, 169 | int __long_only); 170 | # endif 171 | #else /* not __STDC__ */ 172 | extern int getopt(); 173 | # ifndef __need_getopt 174 | extern int getopt_long(); 175 | extern int getopt_long_only(); 176 | 177 | extern int _getopt_internal(); 178 | # endif 179 | #endif /* __STDC__ */ 180 | 181 | #ifdef __cplusplus 182 | } 183 | #endif 184 | 185 | /* Make sure we later can get all the definitions and declarations. */ 186 | #undef __need_getopt 187 | 188 | #endif /* getopt.h */ 189 | -------------------------------------------------------------------------------- /src/driverfuzz.c: -------------------------------------------------------------------------------- 1 | /*********************************************************** 2 | * Project : CrashMeat 3 | * Author : Nixawk 4 | * Description : A Fuzz Framework for Analysis 5 | * License : GPL3 6 | ***********************************************************/ 7 | 8 | #include 9 | 10 | #include "winerr.h" 11 | #include "driver.h" 12 | // #include "log.h" 13 | 14 | 15 | BOOL Fuzz_Stack_Overflow(LPCSTR SymbolicLinkName, DWORD dwIoControlCode, char paddingChar) 16 | { 17 | BOOL bStatus = FALSE; 18 | DWORD BytesReturned = 0; 19 | HANDLE hDevice = NULL; 20 | char InBuffer[MAX_STACKOVERFLOW_SIZE] = {0}; 21 | 22 | hDevice = OpenDriverBySymbolicLinkName(SymbolicLinkName); 23 | if (NULL == hDevice) 24 | { 25 | exit(GetLastError()); 26 | } 27 | 28 | printf( 29 | "{" 30 | "'func': 'Fuzz_Stack_Overflow', " 31 | "'text': 'IoControlCode: %08X'," 32 | "'code': %ld," 33 | "'symlink': '%s'," 34 | "'bufsize': %ld," 35 | "}\n", 36 | dwIoControlCode, GetLastError(), SymbolicLinkName, MAX_STACKOVERFLOW_SIZE 37 | ); 38 | 39 | memset(InBuffer, paddingChar, MAX_STACKOVERFLOW_SIZE); 40 | 41 | bStatus = DeviceIoControl( 42 | hDevice, 43 | dwIoControlCode, 44 | (LPVOID)InBuffer, 45 | MAX_STACKOVERFLOW_SIZE, 46 | NULL, 47 | 0, 48 | &BytesReturned, 49 | NULL 50 | ); 51 | 52 | // ERROR_INVALID_FUNCTION - 1 53 | // ERROR_GEN_FAILURE - 31 (0x1F) 54 | 55 | CloseHandle(hDevice); 56 | 57 | return bStatus; 58 | } 59 | 60 | BOOL Fuzz_NULL_Pointer(LPCSTR SymbolicLinkName, DWORD dwIoControlCode) 61 | { 62 | BOOL bStatus = FALSE; 63 | DWORD BytesReturned = 0; 64 | HANDLE hDevice = NULL; 65 | 66 | hDevice = OpenDriverBySymbolicLinkName(SymbolicLinkName); 67 | if (NULL == hDevice) 68 | { 69 | exit(GetLastError()); 70 | } 71 | 72 | printf( 73 | "{" 74 | "'func': 'Fuzz_NULL_Pointer', " 75 | "'text': 'IoControlCode: %08X'," 76 | "'code': %ld," 77 | "'symlink': '%s'" 78 | "}\n", 79 | dwIoControlCode, GetLastError(), SymbolicLinkName 80 | ); 81 | 82 | bStatus = DeviceIoControl( 83 | hDevice, 84 | dwIoControlCode, 85 | NULL, 86 | 0, 87 | NULL, 88 | 0, 89 | &BytesReturned, 90 | NULL 91 | ); 92 | 93 | // ERROR_INVALID_FUNCTION - 1 94 | // ERROR_GEN_FAILURE - 31 (0x1F) 95 | 96 | CloseHandle(hDevice); 97 | 98 | return bStatus; 99 | } 100 | 101 | 102 | BOOL Fuzz_Invalid_Address(LPCSTR SymbolicLinkName, DWORD dwIoControlCode) 103 | { 104 | BOOL bStatus = FALSE; 105 | DWORD BytesReturned = 0; 106 | HANDLE hDevice = NULL; 107 | 108 | LPVOID InvalidHeapAddress = NULL; 109 | 110 | int i; 111 | 112 | #ifdef _WIN64 113 | DWORD InvalidAddress[] = { 114 | 0x0000000000000000, 115 | 0x00000000FFFFFFFF, 116 | 0xFFFFFFFF00000000, 117 | 0x8000000000000000, 118 | 0xCCCCCCCCCCCCCCCC, 119 | 0xFFFFFFFFFFFFFFFF, 120 | }; 121 | #else 122 | DWORD InvalidAddress[] = { 123 | 0x00000000, 124 | 0x0000FFFF, 125 | 0x80000000, 126 | 0xCCCCCCCC, 127 | 0xFFFF0000, 128 | 0xFFFFFFFF, 129 | }; 130 | #endif 131 | 132 | hDevice = OpenDriverBySymbolicLinkName(SymbolicLinkName); 133 | if (NULL == hDevice) 134 | { 135 | exit(GetLastError()); 136 | } 137 | 138 | for (i = 0; i < (sizeof(InvalidAddress) / sizeof(InvalidAddress[0])); i++) 139 | { 140 | 141 | printf( 142 | "{" 143 | "'func': 'Fuzz_Invalid_Address', " 144 | "'text': 'IoControlCode: %08X, InvalidAddress: %08X'," 145 | "'symlink': '%s'," 146 | "'bufsize': %ld" 147 | "}\n", 148 | dwIoControlCode, InvalidAddress[i], SymbolicLinkName, MAX_STACKOVERFLOW_SIZE 149 | ); 150 | 151 | bStatus = DeviceIoControl( 152 | hDevice, 153 | dwIoControlCode, 154 | (LPVOID)InvalidAddress[i], 155 | MAX_STACKOVERFLOW_SIZE, // Length ? 156 | (LPVOID)InvalidAddress[i], 157 | MAX_STACKOVERFLOW_SIZE, 158 | &BytesReturned, 159 | NULL 160 | ); 161 | 162 | } 163 | 164 | InvalidHeapAddress = malloc(MAX_STACKOVERFLOW_SIZE); 165 | if (NULL == InvalidHeapAddress) 166 | { 167 | printf( 168 | "{" 169 | "'func': 'Fuzz_Invalid_Address', " 170 | "'error': 'Failed to malloc heap memory.'," 171 | "'code': %ld" // 1111 - error code 172 | "}\n", GetLastError()); 173 | } 174 | free(InvalidHeapAddress); // Release and Use By DeviceIoControl 175 | 176 | 177 | for (i = MAX_HEAPADDRESS_COUNT; i > 0; i--) 178 | { 179 | printf( 180 | "{" 181 | "'func': 'Fuzz_Invalid_Address', " 182 | "'text': 'IoControlCode: %08X, InvalidHeapAddress: %08X'," 183 | "'symlink': '%s'," 184 | "'bufsize': %ld" 185 | "}\n", 186 | dwIoControlCode, (DWORD)InvalidHeapAddress + i, SymbolicLinkName, MAX_STACKOVERFLOW_SIZE 187 | ); 188 | 189 | bStatus = DeviceIoControl( 190 | hDevice, 191 | dwIoControlCode, 192 | (LPVOID)((DWORD)InvalidHeapAddress + i), 193 | MAX_STACKOVERFLOW_SIZE, // Length ? 194 | (LPVOID)((DWORD)InvalidHeapAddress + i), 195 | MAX_STACKOVERFLOW_SIZE, 196 | &BytesReturned, 197 | NULL 198 | ); 199 | 200 | } 201 | 202 | // ERROR_INVALID_FUNCTION - 1 203 | // ERROR_GEN_FAILURE - 31 (0x1F) 204 | 205 | CloseHandle(hDevice); 206 | 207 | return bStatus; 208 | } 209 | 210 | // ---- Batch Mode 211 | 212 | void Fuzz_Stack_Overflow_PDBI(PDIRECTORY_BASIC_INFORMATION pSymbolicLinkDirectory, DWORD dwIoControlCode, char paddingChar) 213 | { 214 | char SymbolicLinkName[MAX_PATH] = {0}; 215 | BOOL bStatus = FALSE; 216 | 217 | while ((pSymbolicLinkDirectory->ObjectName.Length != 0) && (pSymbolicLinkDirectory->ObjectTypeName.Length != 0)) 218 | { 219 | WideCharToMultiByte( 220 | CP_ACP, 221 | 0, 222 | pSymbolicLinkDirectory->ObjectName.Buffer, 223 | -1, 224 | SymbolicLinkName, 225 | sizeof(SymbolicLinkName), 226 | NULL, 227 | NULL 228 | ); 229 | 230 | bStatus = Fuzz_Stack_Overflow(SymbolicLinkName, dwIoControlCode, paddingChar); 231 | 232 | pSymbolicLinkDirectory++; 233 | } 234 | 235 | } 236 | 237 | void Fuzz_NULL_Pointer_PDBI(PDIRECTORY_BASIC_INFORMATION pSymbolicLinkDirectory, DWORD dwIoControlCode) 238 | { 239 | char SymbolicLinkName[MAX_PATH] = {0}; 240 | BOOL bStatus = FALSE; 241 | 242 | while ((pSymbolicLinkDirectory->ObjectName.Length != 0) && (pSymbolicLinkDirectory->ObjectTypeName.Length != 0)) 243 | { 244 | // wctomb(SymbolicLinkPath, pBufferBackup->ObjectName.Buffer); // PWSTR -> LPCSTR 245 | WideCharToMultiByte( 246 | CP_ACP, 247 | 0, 248 | pSymbolicLinkDirectory->ObjectName.Buffer, 249 | -1, 250 | SymbolicLinkName, 251 | sizeof(SymbolicLinkName), 252 | NULL, 253 | NULL 254 | ); 255 | 256 | bStatus = Fuzz_NULL_Pointer(SymbolicLinkName, dwIoControlCode); 257 | 258 | pSymbolicLinkDirectory++; 259 | } 260 | 261 | } 262 | 263 | void Fuzz_Invalid_Address_PDBI(PDIRECTORY_BASIC_INFORMATION pSymbolicLinkDirectory, DWORD dwIoControlCode) 264 | { 265 | char SymbolicLinkName[MAX_PATH] = {0}; 266 | BOOL bStatus = FALSE; 267 | 268 | while ((pSymbolicLinkDirectory->ObjectName.Length != 0) && (pSymbolicLinkDirectory->ObjectTypeName.Length != 0)) 269 | { 270 | // wctomb(SymbolicLinkPath, pBufferBackup->ObjectName.Buffer); // PWSTR -> LPCSTR 271 | WideCharToMultiByte( 272 | CP_ACP, 273 | 0, 274 | pSymbolicLinkDirectory->ObjectName.Buffer, 275 | -1, 276 | SymbolicLinkName, 277 | sizeof(SymbolicLinkName), 278 | NULL, 279 | NULL 280 | ); 281 | 282 | bStatus = Fuzz_Invalid_Address(SymbolicLinkName, dwIoControlCode); 283 | 284 | pSymbolicLinkDirectory++; 285 | } 286 | 287 | } 288 | 289 | // https://osandamalith.com/2017/06/22/windows-kernel-exploitation-null-pointer-dereference/ 290 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx 291 | // https://msdn.microsoft.com/en-us/library/b0084kay.aspx 292 | // https://stackoverflow.com/questions/1202687/how-do-i-get-a-specific-range-of-numbers-from-rand 293 | // https://www.geeksforgeeks.org/generating-random-number-range-c/ 294 | -------------------------------------------------------------------------------- /src/driverenum.c: -------------------------------------------------------------------------------- 1 | /*********************************************************** 2 | * Project : CrashMeat 3 | * Author : Nixawk 4 | * Description : A Fuzz Framework for Analysis 5 | * License : GPL3 6 | ***********************************************************/ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "winerr.h" 13 | #include "driver.h" 14 | // #include "log.h" 15 | 16 | /*********************************************************** 17 | * OpenDriverBySymbolicLinkName 18 | * 19 | * Purpose: Open a driver based on symbolic link name, and 20 | * return a handle. 21 | * 22 | * Parameters: 23 | * LPCSTR SymbolicLinkName 24 | * 25 | * 26 | * Return Values: 27 | * A WINDOWS HANDLE 28 | * 29 | ***********************************************************/ 30 | HANDLE OpenDriverBySymbolicLinkName(LPCSTR SymbolicLinkName) 31 | { 32 | HANDLE hDevice = NULL; 33 | char SymbolicLinkPath[MAX_PATH] = {0}; 34 | 35 | if (!SymbolicLinkName) 36 | { 37 | // printf( 38 | // "{" 39 | // "'func': 'OpenDriverBySymbolicLinkName', " 40 | // "'error': 'The symbolic link is invalid.'," 41 | // "'code': 1111" // 1111 - error code 42 | // "}\n"); 43 | goto CLEANUP_AND_EXIT; 44 | } 45 | 46 | sprintf(SymbolicLinkPath, "\\\\.\\%s", SymbolicLinkName); 47 | // printf("SymbolicLinkPath: %s\n", SymbolicLinkPath); 48 | 49 | hDevice = CreateFile( 50 | SymbolicLinkPath, 51 | GENERIC_WRITE | GENERIC_READ, 52 | 0, 53 | NULL, 54 | OPEN_EXISTING, 55 | 0, 56 | NULL 57 | ); 58 | 59 | if (INVALID_HANDLE_VALUE == hDevice) 60 | { 61 | // printf( 62 | // "{" 63 | // "'func': 'OpenDriverBySymbolicLinkName', " 64 | // "'error': 'The handle is invalid.'," 65 | // "'code': %ld, " 66 | // "'symlink': '%s'" 67 | // "}\n", GetLastError(), SymbolicLinkName); 68 | // printf("[-] OpenDriverBySymbolicLinkName Error: [%s, %ld]\n", SymbolicLinkPath, GetLastError()); 69 | goto CLEANUP_AND_EXIT; 70 | } 71 | 72 | 73 | CLEANUP_AND_EXIT: 74 | return hDevice; 75 | } 76 | 77 | BOOL AccessDriverBySymbolicLinkName(LPCSTR SymbolicLinkName) 78 | { 79 | HANDLE hDevice = OpenDriverBySymbolicLinkName(SymbolicLinkName); 80 | if (INVALID_HANDLE_VALUE == hDevice) 81 | { 82 | return FALSE; 83 | } 84 | 85 | CloseHandle(hDevice); 86 | return TRUE; 87 | } 88 | 89 | 90 | PDIRECTORY_BASIC_INFORMATION GetAllDriversSymbolicLink() 91 | { 92 | 93 | // ---- variable part ---- 94 | 95 | HMODULE hModule = NULL; 96 | 97 | // RTLINITUNICODESTRING RtlInitUnicodeString; 98 | ZWOPENDIRECTORYOBJECT ZwOpenDirectoryObject = NULL; 99 | ZWQUERYDIRECTORYOBJECT ZwQueryDirectoryObject = NULL; 100 | ZWCLOSE ZwClose = NULL; 101 | 102 | UNICODE_STRING ObjectName = RTL_CONSTANT_STRING(L"\\Global??"); 103 | OBJECT_ATTRIBUTES InitializedAttributes; 104 | ULONG Attributes = OBJ_CASE_INSENSITIVE; 105 | HANDLE RootDirectory = NULL; 106 | PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; 107 | 108 | HANDLE DirectoryHandle = NULL; 109 | NTSTATUS NTStatus; 110 | 111 | PDIRECTORY_BASIC_INFORMATION pSymbolicLinkDirectory = NULL; 112 | 113 | ULONG uContext; 114 | ULONG uReturnLength; 115 | 116 | size_t MallocSize = 0x200; 117 | 118 | // ---- function part ---- 119 | 120 | hModule = LoadLibrary("ntdll.dll"); 121 | if (NULL == hModule) 122 | { 123 | printf("[-] LoadLibrary Error : %ld\n", GetLastError()); 124 | goto CLEANUP_AND_EXIT; 125 | } 126 | // printf("[*] LoadLibrary Success: ntdll.dll\n"); 127 | 128 | // RtlInitUnicodeString = (RTLINITUNICODESTRING)GetProcAddress(hModule, "RtlInitUnicodeString"); 129 | ZwOpenDirectoryObject = (ZWOPENDIRECTORYOBJECT)GetProcAddress(hModule, "ZwOpenDirectoryObject"); 130 | ZwQueryDirectoryObject = (ZWQUERYDIRECTORYOBJECT)GetProcAddress(hModule, "ZwQueryDirectoryObject"); 131 | ZwClose = (ZWCLOSE)GetProcAddress(hModule, "ZwClose"); 132 | 133 | // printf("[*] GetProcAddress Success: RtlInitUnicodeString\n"); 134 | // printf("[*] GetProcAddress Success: ZwOpenDirectoryObject\n"); 135 | // printf("[*] GetProcAddress Success: ZwQueryDirectoryObject\n"); 136 | // printf("[*] GetProcAddress Success: ZwClose\n"); 137 | 138 | if (!ZwOpenDirectoryObject || !ZwQueryDirectoryObject || !ZwClose) 139 | { 140 | printf("[-] GetProcAddress Error : %ld\n", GetLastError()); 141 | goto CLEANUP_AND_EXIT; 142 | } 143 | 144 | InitializeObjectAttributes( 145 | &InitializedAttributes, 146 | &ObjectName, 147 | Attributes, 148 | RootDirectory, 149 | SecurityDescriptor 150 | ); 151 | // printf("[*] InitializeObjectAttributes Success\n"); 152 | 153 | NTStatus = ZwOpenDirectoryObject( 154 | &DirectoryHandle, 155 | DIRECTORY_QUERY, 156 | &InitializedAttributes 157 | ); 158 | if (STATUS_SUCCESS != NTStatus) 159 | { 160 | printf("[-] ZwOpenDirectoryObject Error : %ld\n", GetLastError()); 161 | goto CLEANUP_AND_EXIT; 162 | } 163 | // printf("[*] ZwOpenDirectoryObject Success\n"); 164 | 165 | do 166 | { 167 | if (NULL != pSymbolicLinkDirectory) 168 | { 169 | free(pSymbolicLinkDirectory); 170 | } 171 | 172 | MallocSize *= 2; 173 | pSymbolicLinkDirectory = (PDIRECTORY_BASIC_INFORMATION)malloc(MallocSize); 174 | if (NULL == pSymbolicLinkDirectory) 175 | { 176 | printf("[-] malloc Error: %ld\n", GetLastError()); 177 | goto CLEANUP_AND_EXIT; 178 | } 179 | 180 | NTStatus = ZwQueryDirectoryObject( 181 | DirectoryHandle, 182 | pSymbolicLinkDirectory, 183 | MallocSize, 184 | FALSE, 185 | TRUE, 186 | &uContext, 187 | &uReturnLength 188 | ); 189 | 190 | // printf("[!] ZwQueryDirectoryObject out return is %ld.\n", uReturnLength); 191 | } while (STATUS_MORE_ENTRIES == NTStatus || STATUS_BUFFER_TOO_SMALL == NTStatus); 192 | 193 | 194 | CLEANUP_AND_EXIT: 195 | 196 | if (NULL != DirectoryHandle) 197 | { 198 | ZwClose(DirectoryHandle); 199 | } 200 | 201 | if (NULL != hModule) 202 | { 203 | FreeLibrary(hModule); 204 | } 205 | 206 | return pSymbolicLinkDirectory; 207 | } 208 | 209 | void PrintAllDriverSymbolicLink() 210 | { 211 | char SymbolicLinkPath[MAX_PATH] = {0}; 212 | int AvailableSymbolicLinkNameCount = 0; 213 | int UnAvailableSymbolicLinkNameCount = 0; 214 | PDIRECTORY_BASIC_INFORMATION pSymbolicLinkDirectory = NULL; 215 | BOOL AccessStatus = FALSE; 216 | 217 | pSymbolicLinkDirectory = GetAllDriversSymbolicLink(); 218 | if (NULL == pSymbolicLinkDirectory) 219 | { 220 | printf("[-] PrintAllDriverSymbolicLink Error: No available SymbolicLinkName\n"); 221 | exit(-1); 222 | } 223 | 224 | while ((pSymbolicLinkDirectory->ObjectName.Length != 0) && (pSymbolicLinkDirectory->ObjectTypeName.Length != 0)) 225 | { 226 | // wctomb(SymbolicLinkPath, pBufferBackup->ObjectName.Buffer); // PWSTR -> LPCSTR 227 | WideCharToMultiByte( 228 | CP_ACP, 229 | 0, 230 | pSymbolicLinkDirectory->ObjectName.Buffer, 231 | -1, 232 | SymbolicLinkPath, 233 | sizeof(SymbolicLinkPath), 234 | NULL, 235 | NULL 236 | ); 237 | 238 | AccessStatus = AccessDriverBySymbolicLinkName(SymbolicLinkPath); 239 | 240 | printf( 241 | "{'ObjectName': '%S', " 242 | "'ObjectTypeName': '%S', " 243 | "'AccessStatus': '%s', " 244 | "'GetLastError': %ld}\n", 245 | pSymbolicLinkDirectory->ObjectName.Buffer, 246 | pSymbolicLinkDirectory->ObjectTypeName.Buffer, 247 | AccessStatus ? "Yes" : "No", 248 | GetLastError() 249 | ); 250 | 251 | if (AccessStatus) 252 | AvailableSymbolicLinkNameCount++; 253 | else 254 | UnAvailableSymbolicLinkNameCount++; 255 | 256 | pSymbolicLinkDirectory++; 257 | } 258 | 259 | printf( 260 | "\n[*] All SymbolicLink - Available : %d, SymbolicLinkName: %d\n", 261 | AvailableSymbolicLinkNameCount, 262 | UnAvailableSymbolicLinkNameCount 263 | ); 264 | } 265 | 266 | // References 267 | // https://msdn.microsoft.com/en-us/library/6ewkz86d.aspx 268 | // http://www.moserware.com/2008/01/constants-on-left-are-better-but-this.html 269 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx 270 | -------------------------------------------------------------------------------- /src/crashmeat.c: -------------------------------------------------------------------------------- 1 | /*********************************************************** 2 | * Project : CrashMeat 3 | * Author : Nixawk 4 | * Description : A Fuzz Framework for Analysis 5 | * License : GPL3 6 | ***********************************************************/ 7 | 8 | /* OUTPUT 9 | 10 | {'func': '', 'text': '', ...} 11 | {'func': '', 'error': '', 'code': ''} 12 | 13 | */ 14 | 15 | #include "winerr.h" 16 | #include "getopt.h" 17 | #include "driver.h" 18 | // #include "log.h" 19 | 20 | 21 | void banner() 22 | { 23 | printf("\n" 24 | " _____ _ __ __ _ \n" 25 | " / ____| | | | \\/ | | | \n" 26 | " | | _ __ __ _ ___| |__ | \\ / | ___ __ _| |_ \n" 27 | " | | | '__/ _` / __| '_ \\ | |\\/| |/ _ \\/ _` | __| \n" 28 | " | |____| | | (_| \\__ \\ | | | | | | | __/ (_| | |_ \n" 29 | " \\_____|_| \\__,_|___/_| |_| |_| |_|\\___|\\__,_|\\__|\n" 30 | "\n" 31 | " [Nixawk]\n" 32 | "\n" 33 | ); 34 | } 35 | 36 | void usage(char *programname) 37 | { 38 | banner(); 39 | printf( 40 | " Usage\n" 41 | " -----\n" 42 | "\n" 43 | " :: Help\n" 44 | " -h/-? Show help information\n" 45 | "\n" 46 | " :: Enum Drivers\n" 47 | " -l List all drivers name and status in system.\n" 48 | "\n" 49 | " :: Load Drivers\n" 50 | " -a Load all drivers in system automatically\n" 51 | " -d Load a driver with symlink name\n" 52 | "\n" 53 | " :: Load Io Control Code\n" 54 | " -c Input available io control code, split with dot (ex: 1,3-5)\n" 55 | " -b Bruteforce io control code\n" 56 | "\n" 57 | " :: Fuzz Mode\n" 58 | " -n Null Pointer Fuzz\n" 59 | " -s Stack Overflow Fuzz\n" 60 | " -i Invalid Address Fuzz\n" 61 | "\n" 62 | " :: Verbose Mode\n" 63 | " -v Make the operation more talkative\n" 64 | "\n", 65 | programname 66 | ); 67 | 68 | // exit(-1); 69 | } 70 | 71 | 72 | int 73 | main(int argc, char *argv[]) 74 | { 75 | int getoptval; 76 | 77 | BOOL Switch_Enum_Drivers = FALSE; 78 | BOOL Switch_Load_Drivers_a = FALSE; 79 | BOOL Switch_Load_IoControlCode_c = FALSE; // Input IoControlCoe 80 | BOOL Switch_Load_IoControlCode_b = FALSE; // IoControlCode bruteforce or not 81 | BOOL Switch_Fuzz_Mode_n = FALSE; // fuzz mode - null pointer 82 | BOOL Switch_Fuzz_Mode_s = FALSE; // fuzz mode - stack overflow 83 | BOOL Switch_Fuzz_Mode_i = FALSE; // fuzz mode - invalid address 84 | 85 | char *SymbolicLinkName = NULL; 86 | 87 | char *IoControlCodeOptArg = NULL; 88 | 89 | PIO_CONTROL_CODE_ENTRY pIoControlCodeEntry = NULL; // List Entry 90 | PDIRECTORY_BASIC_INFORMATION pSymbolicLinkDirectory = NULL; // List Entry 91 | 92 | DWORD FuzzIndex; // Index 93 | 94 | char stack_overflow_padding_char = 'A'; 95 | 96 | while ((getoptval = getopt(argc, argv, "d:c:r:labnsih?v")) != -1) 97 | { 98 | switch(getoptval) 99 | { 100 | case 'l': // List all drivers 101 | Switch_Enum_Drivers = TRUE; 102 | break; 103 | 104 | case 'a': // analysis automatically 105 | Switch_Load_Drivers_a = TRUE; 106 | break; 107 | 108 | case 'd': // input a driver symbolic name 109 | SymbolicLinkName = optarg; 110 | break; 111 | 112 | case 'c': // input 113 | Switch_Load_IoControlCode_c = TRUE; 114 | IoControlCodeOptArg = optarg; 115 | break; 116 | 117 | case 'b': 118 | Switch_Load_IoControlCode_b = TRUE; 119 | break; 120 | 121 | case 'n': 122 | Switch_Fuzz_Mode_n = TRUE; 123 | break; 124 | 125 | case 's': 126 | Switch_Fuzz_Mode_s = TRUE; 127 | break; 128 | 129 | case 'i': 130 | Switch_Fuzz_Mode_i = TRUE; 131 | break; 132 | 133 | case 'v': 134 | break; 135 | 136 | case 'h': 137 | case '?': 138 | break; 139 | } 140 | } 141 | 142 | // list all available symbolic links or not 143 | if (Switch_Enum_Drivers) 144 | { 145 | PrintAllDriverSymbolicLink(); 146 | exit(0); 147 | } 148 | 149 | // 1. Get a valid symbolic link name 150 | if (NULL == SymbolicLinkName && !Switch_Load_Drivers_a) 151 | { 152 | usage(argv[0]); 153 | printf( 154 | "{" 155 | "'func': 'main', " 156 | "'error': 'Please set a Load Drivers option'," 157 | "'code': 1111" 158 | "}\n"); 159 | exit(-1); 160 | } 161 | 162 | // 2. Get a valid io control code 163 | if (NULL == IoControlCodeOptArg && !Switch_Load_IoControlCode_b) 164 | { 165 | usage(argv[0]); 166 | printf( 167 | "{" 168 | "'func': 'main', " 169 | "'error': 'Please set a Load Io Control Code option'," 170 | "'code': 1111" 171 | "}\n"); 172 | exit(-1); 173 | } 174 | 175 | if (Switch_Load_IoControlCode_c) 176 | pIoControlCodeEntry = ParseIoControlCodeFromOptArg(IoControlCodeOptArg); 177 | 178 | if (NULL == pIoControlCodeEntry) 179 | { 180 | printf( 181 | "{" 182 | "'func': 'main', " 183 | "'error': 'Fail to get a Io Control Code'," 184 | "'code': 1111" 185 | "}\n"); 186 | exit(-1); 187 | } 188 | 189 | if (Switch_Load_IoControlCode_b) 190 | printf("[*] Bruteforce IoControlCode will be in the future\n"); 191 | 192 | // 3. Fuzz 193 | 194 | if (!Switch_Fuzz_Mode_n && !Switch_Fuzz_Mode_s && !Switch_Fuzz_Mode_i) 195 | { 196 | printf( 197 | "{" 198 | "'func': 'main', " 199 | "'error': 'Please set a Fuzz Mode option'," 200 | "'code': 1111" 201 | "}\n"); 202 | exit(-1); 203 | } 204 | 205 | if (Switch_Load_Drivers_a) // auto analysis all drivers 206 | pSymbolicLinkDirectory = GetAllDriversSymbolicLink(); 207 | 208 | while (NULL != pIoControlCodeEntry) 209 | { 210 | 211 | // printf( 212 | // "{" 213 | // "'func': 'main', " 214 | // "'text': 'IoControlCode range, [%08x, %08X]'," 215 | // "}\n", 216 | // pIoControlCodeEntry->Start, pIoControlCodeEntry->End 217 | // ); 218 | 219 | // printf( 220 | // "[*] IoControlCode Range, [Start: %08x, End: %08X]\n", 221 | // pIoControlCodeEntry->Start, pIoControlCodeEntry->End 222 | // ); 223 | 224 | if (pIoControlCodeEntry->Start >= pIoControlCodeEntry->End) 225 | { 226 | pIoControlCodeEntry->Start ^= pIoControlCodeEntry->End; 227 | pIoControlCodeEntry->End ^= pIoControlCodeEntry->Start; 228 | pIoControlCodeEntry->Start ^= pIoControlCodeEntry->End; 229 | } 230 | 231 | // Fuzz a single driver 232 | if (NULL != SymbolicLinkName && AccessDriverBySymbolicLinkName(SymbolicLinkName)) 233 | { 234 | for (FuzzIndex = pIoControlCodeEntry->Start; FuzzIndex <= pIoControlCodeEntry->End; FuzzIndex++) 235 | { 236 | if (Switch_Fuzz_Mode_n) 237 | Fuzz_NULL_Pointer(SymbolicLinkName, FuzzIndex); 238 | 239 | if (Switch_Fuzz_Mode_s) 240 | Fuzz_Stack_Overflow(SymbolicLinkName, FuzzIndex, stack_overflow_padding_char); 241 | 242 | if (Switch_Fuzz_Mode_i) 243 | Fuzz_Invalid_Address(SymbolicLinkName, FuzzIndex); 244 | } 245 | } 246 | 247 | 248 | // Fuzz multi fuzz 249 | if (NULL != pSymbolicLinkDirectory) 250 | { 251 | for (FuzzIndex = pIoControlCodeEntry->Start; FuzzIndex <= pIoControlCodeEntry->End; FuzzIndex++) 252 | { 253 | 254 | // All Driver - Fuzz 255 | 256 | if (Switch_Fuzz_Mode_n) 257 | Fuzz_NULL_Pointer_PDBI(pSymbolicLinkDirectory, FuzzIndex); 258 | 259 | if (Switch_Fuzz_Mode_s) 260 | Fuzz_Stack_Overflow_PDBI(pSymbolicLinkDirectory, FuzzIndex, stack_overflow_padding_char); 261 | 262 | if (Switch_Fuzz_Mode_i) 263 | Fuzz_Invalid_Address_PDBI(pSymbolicLinkDirectory, FuzzIndex); 264 | 265 | } 266 | } 267 | 268 | pIoControlCodeEntry = pIoControlCodeEntry->Next; 269 | } 270 | 271 | return 0; 272 | } 273 | 274 | 275 | // https://stackoverflow.com/questions/2519851/how-to-deal-with-warning-c4100-in-visual-studio-2008 276 | // https://stackoverflow.com/questions/133698/why-does-fatal-error-lnk1104-cannot-open-file-c-program-obj-occur-when-i-c 277 | // https://stackoverflow.com/questions/3889992/how-does-strtok-split-the-string-into-tokens-in-c 278 | // https://github.com/rxi/log.c/ 279 | // https://stackoverflow.com/questions/10017272/programming-with-verbose-option-in-c 280 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # CrashMeat 3 | 4 | A simple fuzz demo for windows driver based on io control code. (Some features will be in the future). 5 | A fuzz framework should have: 6 | 7 | - 1. Raw data input 8 | - 2. Rand raw data 9 | - 3. Crash targets 10 | - 4. Recv crash log 11 | - 5. Analysis log 12 | 13 | ## :: Help 14 | 15 | ``` 16 | C:\Users\debug\Desktop\CrashMeat\src>..\bin\crashmeat.EXE 17 | 18 | _____ _ __ __ _ 19 | / ____| | | | \/ | | | 20 | | | _ __ __ _ ___| |__ | \ / | ___ __ _| |_ 21 | | | | '__/ _` / __| '_ \ | |\/| |/ _ \/ _` | __| 22 | | |____| | | (_| \__ \ | | | | | | | __/ (_| | |_ 23 | \_____|_| \__,_|___/_| |_| |_| |_|\___|\__,_|\__| 24 | 25 | [Nixawk] 26 | 27 | Usage 28 | ----- 29 | 30 | :: Help 31 | -h/-? Show help information 32 | 33 | :: Enum Drivers 34 | -l List all drivers name and status in system. 35 | 36 | :: Load Drivers 37 | -a Load all drivers in system automatically 38 | -d Load a driver with symlink name 39 | 40 | :: Load Io Control Code 41 | -c Input available io control code, split with dot (ex: 1,3-5) 42 | -b Bruteforce io control code 43 | 44 | :: Fuzz Mode 45 | -n Null Pointer Fuzz 46 | -s Stack Overflow Fuzz 47 | -i Invalid Address Fuzz 48 | 49 | :: Verbose Mode 50 | -v Make the operation more talkative 51 | 52 | ``` 53 | 54 | ## :: Enum Mode 55 | 56 | ``` 57 | C:\Users\debug\Desktop\CrashMeat\src>..\bin\crashmeat.EXE -l | more 58 | {'ObjectName': 'USB#VID_0E0F&PID_0002#6&201153c1&0&7#{f18a0e88-c30c-11d0-8815-00a0c906bed8}', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'Yes', 'GetLastError': 0} 59 | {'ObjectName': 'D:', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'Yes', 'GetLastError': 0} 60 | {'ObjectName': 'ACPI#PNP0501#1#{4d36e978-e325-11ce-bfc1-08002be10318}', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'Yes', 'GetLastError': 0} 61 | {'ObjectName': 'ACPI#PNP0501#3#{4d36e978-e325-11ce-bfc1-08002be10318}', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'Yes', 'GetLastError': 0} 62 | {'ObjectName': 'VmGenerationCounter', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'No', 'GetLastError': 5} 63 | {'ObjectName': 'PhysicalDrive0', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'No', 'GetLastError': 5} 64 | {'ObjectName': 'VDRVROOT', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'Yes', 'GetLastError': 0} 65 | {'ObjectName': 'DISPLAY1', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'No', 'GetLastError': 5} 66 | {'ObjectName': 'ROOT#SYSTEM#0000#{97ebaacb-95bd-11d0-a3ea-00a0c9223196}', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'Yes', 'GetLastError': 0} 67 | {'ObjectName': 'gpuenergydrv', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'Yes', 'GetLastError': 0} 68 | {'ObjectName': 'SWD#IP_TUNNEL_VBUS#ISATAP_0#{ad498944-762f-11d0-8dcb-00c04fc3358c}', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'Yes', 'GetLastError': 0} 69 | {'ObjectName': 'WUDFLpcDevice', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'No', 'GetLastError': 5} 70 | {'ObjectName': '{28B8F286-E5AB-473E-869E-ADE5F342366F}', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'Yes', 'GetLastError': 0} 71 | {'ObjectName': 'ACPI#PNP0501#1#{86e0d1e0-8089-11d0-9ce4-08003e301f73}', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'Yes', 'GetLastError': 0} 72 | {'ObjectName': 'Volume{a1814082-f32d-4f98-ada4-e073e440b01d}', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'No', 'GetLastError': 5} 73 | {'ObjectName': 'ROOT#spaceport#0000#{ef66a56f-88d1-4cd8-98c4-49faf57ad8af}', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'Yes', 'GetLastError': 0} 74 | {'ObjectName': 'SWD#MMDEVAPI#{0.0.0.00000000}.{cbd0ca6f-1229-4c9f-8dd8-74962834ad71}#{e6327cad-dcec-4949-ae8a-991e976a79d2}', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'No', 'GetLastError': 1} 75 | {'ObjectName': 'PCI#VEN_15AD&DEV_0774&SUBSYS_197615AD&REV_00#4&b70f118&0&0088#{3abf6f2d-71c4-462a-8a92-1e6861e6af27}', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'Yes', 'GetLastError': 0} 76 | {'ObjectName': 'Psched', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'No', 'GetLastError': 5} 77 | {'ObjectName': 'SWD#RADIO#Bluetooth_c4e3ac32bcac#{a8804298-2d5f-42e3-9531-9c8c39eb29ce}', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'No', 'GetLastError': 1} 78 | {'ObjectName': 'PCI#VEN_15AD&DEV_0405&SUBSYS_040515AD&REV_00#3&18d45aa6&0&78#{1ca05180-a699-450a-9a0c-de4fbe3ddd89}', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'No', 'GetLastError': 5} 79 | {'ObjectName': 'ROOT#SYSTEM#0000#{cf1dda2c-9743-11d0-a3ee-00a0c9223196}', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'Yes', 'GetLastError': 0} 80 | {'ObjectName': 'STORAGE#Volume#{a72219b9-54a9-11e8-9bc2-806e6f6e6963}#0000000022600000#{7f108a28-9833-4b3b-b780-2c6b5fa5c062}', 'ObjectTypeName': 'SymbolicLink', 'AccessStatus': 'Yes', 'GetLastError': 0} 81 | -- More -- 82 | ``` 83 | 84 | ## :: Fuzz Mode 85 | 86 | ``` 87 | C:\Users\debug\Desktop\CrashMeat\src>..\bin\crashmeat.EXE -d AUX -c 1 -i -s -n 88 | {'func': 'Fuzz_NULL_Pointer', 'text': 'IoControlCode: 00000001','code': 0,'symlink': 'AUX'} 89 | {'func': 'Fuzz_Stack_Overflow', 'text': 'IoControlCode: 00000001','code': 0,'symlink': 'AUX','bufsize': 65536,} 90 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidAddress: 00000000','symlink': 'AUX','bufsize': 65536} 91 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidAddress: FFFFFFFF','symlink': 'AUX','bufsize': 65536} 92 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidAddress: 00000000','symlink': 'AUX','bufsize': 65536} 93 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidAddress: 00000000','symlink': 'AUX','bufsize': 65536} 94 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidAddress: CCCCCCCC','symlink': 'AUX','bufsize': 65536} 95 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidAddress: FFFFFFFF','symlink': 'AUX','bufsize': 65536} 96 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17BE','symlink': 'AUX','bufsize': 65536} 97 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17BD','symlink': 'AUX','bufsize': 65536} 98 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17BC','symlink': 'AUX','bufsize': 65536} 99 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17BB','symlink': 'AUX','bufsize': 65536} 100 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17BA','symlink': 'AUX','bufsize': 65536} 101 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17B9','symlink': 'AUX','bufsize': 65536} 102 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17B8','symlink': 'AUX','bufsize': 65536} 103 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17B7','symlink': 'AUX','bufsize': 65536} 104 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17B6','symlink': 'AUX','bufsize': 65536} 105 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17B5','symlink': 'AUX','bufsize': 65536} 106 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17B4','symlink': 'AUX','bufsize': 65536} 107 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17B3','symlink': 'AUX','bufsize': 65536} 108 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17B2','symlink': 'AUX','bufsize': 65536} 109 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17B1','symlink': 'AUX','bufsize': 65536} 110 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17B0','symlink': 'AUX','bufsize': 65536} 111 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17AF','symlink': 'AUX','bufsize': 65536} 112 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17AE','symlink': 'AUX','bufsize': 65536} 113 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17AD','symlink': 'AUX','bufsize': 65536} 114 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17AC','symlink': 'AUX','bufsize': 65536} 115 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17AB','symlink': 'AUX','bufsize': 65536} 116 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17AA','symlink': 'AUX','bufsize': 65536} 117 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17A9','symlink': 'AUX','bufsize': 65536} 118 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17A8','symlink': 'AUX','bufsize': 65536} 119 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17A7','symlink': 'AUX','bufsize': 65536} 120 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17A6','symlink': 'AUX','bufsize': 65536} 121 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17A5','symlink': 'AUX','bufsize': 65536} 122 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17A4','symlink': 'AUX','bufsize': 65536} 123 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17A3','symlink': 'AUX','bufsize': 65536} 124 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17A2','symlink': 'AUX','bufsize': 65536} 125 | {'func': 'Fuzz_Invalid_Address', 'text': 'IoControlCode: 00000001, InvalidHeapAddress: 79FC17A1','symlink': 'AUX','bufsize': 65536} 126 | ``` 127 | 128 | ## References 129 | 130 | - https://github.com/koutto/ioctlbf/ 131 | - https://github.com/k0keoyo/kDriver-Fuzzer 132 | - https://github.com/hacksysteam/HackSysExtremeVulnerableDriver 133 | -------------------------------------------------------------------------------- /src/getopt.c: -------------------------------------------------------------------------------- 1 | /* Getopt for GNU. 2 | NOTE: getopt is now part of the C library, so if you don't know what 3 | "Keep this file name-space clean" means, talk to drepper@gnu.org 4 | before changing it! 5 | Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001 6 | Free Software Foundation, Inc. 7 | This file is part of the GNU C Library. 8 | 9 | The GNU C Library is free software; you can redistribute it and/or 10 | modify it under the terms of the GNU Lesser General Public 11 | License as published by the Free Software Foundation; either 12 | version 2.1 of the License, or (at your option) any later version. 13 | 14 | The GNU C Library is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | Lesser General Public License for more details. 18 | 19 | You should have received a copy of the GNU Lesser General Public 20 | License along with the GNU C Library; if not, write to the Free 21 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 22 | 02111-1307 USA. */ 23 | 24 | /* This tells Alpha OSF/1 not to define a getopt prototype in . 25 | Ditto for AIX 3.2 and . */ 26 | #ifndef _NO_PROTO 27 | # define _NO_PROTO 28 | #endif 29 | 30 | #ifdef HAVE_CONFIG_H 31 | # include 32 | #endif 33 | 34 | #if !defined __STDC__ || !__STDC__ 35 | /* This is a separate conditional since some stdc systems 36 | reject `defined (const)'. */ 37 | # ifndef const 38 | # define const 39 | # endif 40 | #endif 41 | 42 | #include 43 | 44 | /* Comment out all this code if we are using the GNU C Library, and are not 45 | actually compiling the library itself. This code is part of the GNU C 46 | Library, but also included in many other GNU distributions. Compiling 47 | and linking in this code is a waste when using the GNU C library 48 | (especially if it is a shared library). Rather than having every GNU 49 | program understand `configure --with-gnu-libc' and omit the object files, 50 | it is simpler to just do this in the source for each such file. */ 51 | 52 | #define GETOPT_INTERFACE_VERSION 2 53 | #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 54 | # include 55 | # if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION 56 | # define ELIDE_CODE 57 | # endif 58 | #endif 59 | 60 | #ifndef ELIDE_CODE 61 | 62 | 63 | /* This needs to come after some library #include 64 | to get __GNU_LIBRARY__ defined. */ 65 | #ifdef __GNU_LIBRARY__ 66 | /* Don't include stdlib.h for non-GNU C libraries because some of them 67 | contain conflicting prototypes for getopt. */ 68 | # include 69 | # include 70 | #endif /* GNU C library. */ 71 | 72 | #ifdef VMS 73 | # include 74 | # if HAVE_STRING_H - 0 75 | # include 76 | # endif 77 | #endif 78 | 79 | #ifndef _ 80 | /* This is for other GNU distributions with internationalized messages. */ 81 | # if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC 82 | # include 83 | # ifndef _ 84 | # define _(msgid) gettext (msgid) 85 | # endif 86 | # else 87 | # define _(msgid) (msgid) 88 | # endif 89 | # if defined _LIBC && defined USE_IN_LIBIO 90 | # include 91 | # endif 92 | #endif 93 | 94 | /* This version of `getopt' appears to the caller like standard Unix `getopt' 95 | but it behaves differently for the user, since it allows the user 96 | to intersperse the options with the other arguments. 97 | 98 | As `getopt' works, it permutes the elements of ARGV so that, 99 | when it is done, all the options precede everything else. Thus 100 | all application programs are extended to handle flexible argument order. 101 | 102 | Setting the environment variable POSIXLY_CORRECT disables permutation. 103 | Then the behavior is completely standard. 104 | 105 | GNU application programs can use a third alternative mode in which 106 | they can distinguish the relative order of options and other arguments. */ 107 | 108 | #include "getopt.h" 109 | 110 | /* For communication from `getopt' to the caller. 111 | When `getopt' finds an option that takes an argument, 112 | the argument value is returned here. 113 | Also, when `ordering' is RETURN_IN_ORDER, 114 | each non-option ARGV-element is returned here. */ 115 | 116 | char *optarg; 117 | 118 | /* Index in ARGV of the next element to be scanned. 119 | This is used for communication to and from the caller 120 | and for communication between successive calls to `getopt'. 121 | 122 | On entry to `getopt', zero means this is the first call; initialize. 123 | 124 | When `getopt' returns -1, this is the index of the first of the 125 | non-option elements that the caller should itself scan. 126 | 127 | Otherwise, `optind' communicates from one call to the next 128 | how much of ARGV has been scanned so far. */ 129 | 130 | /* 1003.2 says this must be 1 before any call. */ 131 | int optind = 1; 132 | 133 | /* Formerly, initialization of getopt depended on optind==0, which 134 | causes problems with re-calling getopt as programs generally don't 135 | know that. */ 136 | 137 | int __getopt_initialized; 138 | 139 | /* The next char to be scanned in the option-element 140 | in which the last option character we returned was found. 141 | This allows us to pick up the scan where we left off. 142 | 143 | If this is zero, or a null string, it means resume the scan 144 | by advancing to the next ARGV-element. */ 145 | 146 | static char *nextchar; 147 | 148 | /* Callers store zero here to inhibit the error message 149 | for unrecognized options. */ 150 | 151 | int opterr = 1; 152 | 153 | /* Set to an option character which was unrecognized. 154 | This must be initialized on some systems to avoid linking in the 155 | system's own getopt implementation. */ 156 | 157 | int optopt = '?'; 158 | 159 | /* Describe how to deal with options that follow non-option ARGV-elements. 160 | 161 | If the caller did not specify anything, 162 | the default is REQUIRE_ORDER if the environment variable 163 | POSIXLY_CORRECT is defined, PERMUTE otherwise. 164 | 165 | REQUIRE_ORDER means don't recognize them as options; 166 | stop option processing when the first non-option is seen. 167 | This is what Unix does. 168 | This mode of operation is selected by either setting the environment 169 | variable POSIXLY_CORRECT, or using `+' as the first character 170 | of the list of option characters. 171 | 172 | PERMUTE is the default. We permute the contents of ARGV as we scan, 173 | so that eventually all the non-options are at the end. This allows options 174 | to be given in any order, even with programs that were not written to 175 | expect this. 176 | 177 | RETURN_IN_ORDER is an option available to programs that were written 178 | to expect options and other ARGV-elements in any order and that care about 179 | the ordering of the two. We describe each non-option ARGV-element 180 | as if it were the argument of an option with character code 1. 181 | Using `-' as the first character of the list of option characters 182 | selects this mode of operation. 183 | 184 | The special argument `--' forces an end of option-scanning regardless 185 | of the value of `ordering'. In the case of RETURN_IN_ORDER, only 186 | `--' can cause `getopt' to return -1 with `optind' != ARGC. */ 187 | 188 | static enum 189 | { 190 | REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER 191 | } ordering; 192 | 193 | /* Value of POSIXLY_CORRECT environment variable. */ 194 | static char *posixly_correct; 195 | 196 | #ifdef __GNU_LIBRARY__ 197 | /* We want to avoid inclusion of string.h with non-GNU libraries 198 | because there are many ways it can cause trouble. 199 | On some systems, it contains special magic macros that don't work 200 | in GCC. */ 201 | # include 202 | # define my_index strchr 203 | #else 204 | 205 | 206 | 207 | /* Avoid depending on library functions or files 208 | whose names are inconsistent. */ 209 | 210 | #ifndef getenv 211 | extern char *getenv(); 212 | #endif 213 | 214 | static char * 215 | my_index(str, chr) 216 | const char *str; 217 | int chr; 218 | { 219 | while (*str) 220 | { 221 | if (*str == chr) 222 | return (char *)str; 223 | str++; 224 | } 225 | return 0; 226 | } 227 | 228 | /* If using GCC, we can safely declare strlen this way. 229 | If not using GCC, it is ok not to declare it. */ 230 | #ifdef __GNUC__ 231 | /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. 232 | That was relevant to code that was here before. */ 233 | # if (!defined __STDC__ || !__STDC__) && !defined strlen 234 | /* gcc with -traditional declares the built-in strlen to return int, 235 | and has done so at least since version 2.4.5. -- rms. */ 236 | extern int strlen(const char *); 237 | # endif /* not __STDC__ */ 238 | #endif /* __GNUC__ */ 239 | 240 | #endif /* not __GNU_LIBRARY__ */ 241 | 242 | /* Handle permutation of arguments. */ 243 | 244 | /* Describe the part of ARGV that contains non-options that have 245 | been skipped. `first_nonopt' is the index in ARGV of the first of them; 246 | `last_nonopt' is the index after the last of them. */ 247 | 248 | static int first_nonopt; 249 | static int last_nonopt; 250 | 251 | #ifdef _LIBC 252 | /* Stored original parameters. 253 | XXX This is no good solution. We should rather copy the args so 254 | that we can compare them later. But we must not use malloc(3). */ 255 | extern int __libc_argc; 256 | extern char **__libc_argv; 257 | 258 | /* Bash 2.0 gives us an environment variable containing flags 259 | indicating ARGV elements that should not be considered arguments. */ 260 | 261 | # ifdef USE_NONOPTION_FLAGS 262 | /* Defined in getopt_init.c */ 263 | extern char *__getopt_nonoption_flags; 264 | 265 | static int nonoption_flags_max_len; 266 | static int nonoption_flags_len; 267 | # endif 268 | 269 | # ifdef USE_NONOPTION_FLAGS 270 | # define SWAP_FLAGS(ch1, ch2) \ 271 | if (nonoption_flags_len > 0) \ 272 | { \ 273 | char __tmp = __getopt_nonoption_flags[ch1]; \ 274 | __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ 275 | __getopt_nonoption_flags[ch2] = __tmp; \ 276 | } 277 | # else 278 | # define SWAP_FLAGS(ch1, ch2) 279 | # endif 280 | #else /* !_LIBC */ 281 | # define SWAP_FLAGS(ch1, ch2) 282 | #endif /* _LIBC */ 283 | 284 | /* Exchange two adjacent subsequences of ARGV. 285 | One subsequence is elements [first_nonopt,last_nonopt) 286 | which contains all the non-options that have been skipped so far. 287 | The other is elements [last_nonopt,optind), which contains all 288 | the options processed since those non-options were skipped. 289 | 290 | `first_nonopt' and `last_nonopt' are relocated so that they describe 291 | the new indices of the non-options in ARGV after they are moved. */ 292 | 293 | #if defined __STDC__ && __STDC__ 294 | static void exchange(char **); 295 | #endif 296 | 297 | static void 298 | exchange(argv) 299 | char **argv; 300 | { 301 | int bottom = first_nonopt; 302 | int middle = last_nonopt; 303 | int top = optind; 304 | char *tem; 305 | 306 | /* Exchange the shorter segment with the far end of the longer segment. 307 | That puts the shorter segment into the right place. 308 | It leaves the longer segment in the right place overall, 309 | but it consists of two parts that need to be swapped next. */ 310 | 311 | #if defined _LIBC && defined USE_NONOPTION_FLAGS 312 | /* First make sure the handling of the `__getopt_nonoption_flags' 313 | string can work normally. Our top argument must be in the range 314 | of the string. */ 315 | if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) 316 | { 317 | /* We must extend the array. The user plays games with us and 318 | presents new arguments. */ 319 | char *new_str = malloc(top + 1); 320 | if (new_str == NULL) 321 | nonoption_flags_len = nonoption_flags_max_len = 0; 322 | else 323 | { 324 | memset(__mempcpy(new_str, __getopt_nonoption_flags, 325 | nonoption_flags_max_len), 326 | '\0', top + 1 - nonoption_flags_max_len); 327 | nonoption_flags_max_len = top + 1; 328 | __getopt_nonoption_flags = new_str; 329 | } 330 | } 331 | #endif 332 | 333 | while (top > middle && middle > bottom) 334 | { 335 | if (top - middle > middle - bottom) 336 | { 337 | /* Bottom segment is the short one. */ 338 | int len = middle - bottom; 339 | register int i; 340 | 341 | /* Swap it with the top part of the top segment. */ 342 | for (i = 0; i < len; i++) 343 | { 344 | tem = argv[bottom + i]; 345 | argv[bottom + i] = argv[top - (middle - bottom) + i]; 346 | argv[top - (middle - bottom) + i] = tem; 347 | SWAP_FLAGS(bottom + i, top - (middle - bottom) + i); 348 | } 349 | /* Exclude the moved bottom segment from further swapping. */ 350 | top -= len; 351 | } 352 | else 353 | { 354 | /* Top segment is the short one. */ 355 | int len = top - middle; 356 | register int i; 357 | 358 | /* Swap it with the bottom part of the bottom segment. */ 359 | for (i = 0; i < len; i++) 360 | { 361 | tem = argv[bottom + i]; 362 | argv[bottom + i] = argv[middle + i]; 363 | argv[middle + i] = tem; 364 | SWAP_FLAGS(bottom + i, middle + i); 365 | } 366 | /* Exclude the moved top segment from further swapping. */ 367 | bottom += len; 368 | } 369 | } 370 | 371 | /* Update records for the slots the non-options now occupy. */ 372 | 373 | first_nonopt += (optind - last_nonopt); 374 | last_nonopt = optind; 375 | } 376 | 377 | /* Initialize the internal data when the first call is made. */ 378 | 379 | #if defined __STDC__ && __STDC__ 380 | static const char *_getopt_initialize(int, char *const *, const char *); 381 | #endif 382 | static const char * 383 | _getopt_initialize(argc, argv, optstring) 384 | int argc; 385 | char *const *argv; 386 | const char *optstring; 387 | { 388 | /* Start processing options with ARGV-element 1 (since ARGV-element 0 389 | is the program name); the sequence of previously skipped 390 | non-option ARGV-elements is empty. */ 391 | 392 | first_nonopt = last_nonopt = optind; 393 | 394 | nextchar = NULL; 395 | 396 | posixly_correct = getenv("POSIXLY_CORRECT"); 397 | 398 | /* Determine how to handle the ordering of options and nonoptions. */ 399 | 400 | if (optstring[0] == '-') 401 | { 402 | ordering = RETURN_IN_ORDER; 403 | ++optstring; 404 | } 405 | else if (optstring[0] == '+') 406 | { 407 | ordering = REQUIRE_ORDER; 408 | ++optstring; 409 | } 410 | else if (posixly_correct != NULL) 411 | ordering = REQUIRE_ORDER; 412 | else 413 | ordering = PERMUTE; 414 | 415 | #if defined _LIBC && defined USE_NONOPTION_FLAGS 416 | if (posixly_correct == NULL 417 | && argc == __libc_argc && argv == __libc_argv) 418 | { 419 | if (nonoption_flags_max_len == 0) 420 | { 421 | if (__getopt_nonoption_flags == NULL 422 | || __getopt_nonoption_flags[0] == '\0') 423 | nonoption_flags_max_len = -1; 424 | else 425 | { 426 | const char *orig_str = __getopt_nonoption_flags; 427 | int len = nonoption_flags_max_len = strlen(orig_str); 428 | if (nonoption_flags_max_len < argc) 429 | nonoption_flags_max_len = argc; 430 | __getopt_nonoption_flags = 431 | (char *)malloc(nonoption_flags_max_len); 432 | if (__getopt_nonoption_flags == NULL) 433 | nonoption_flags_max_len = -1; 434 | else 435 | memset(__mempcpy(__getopt_nonoption_flags, orig_str, len), 436 | '\0', nonoption_flags_max_len - len); 437 | } 438 | } 439 | nonoption_flags_len = nonoption_flags_max_len; 440 | } 441 | else 442 | nonoption_flags_len = 0; 443 | #endif 444 | 445 | return optstring; 446 | } 447 | 448 | /* Scan elements of ARGV (whose length is ARGC) for option characters 449 | given in OPTSTRING. 450 | 451 | If an element of ARGV starts with '-', and is not exactly "-" or "--", 452 | then it is an option element. The characters of this element 453 | (aside from the initial '-') are option characters. If `getopt' 454 | is called repeatedly, it returns successively each of the option characters 455 | from each of the option elements. 456 | 457 | If `getopt' finds another option character, it returns that character, 458 | updating `optind' and `nextchar' so that the next call to `getopt' can 459 | resume the scan with the following option character or ARGV-element. 460 | 461 | If there are no more option characters, `getopt' returns -1. 462 | Then `optind' is the index in ARGV of the first ARGV-element 463 | that is not an option. (The ARGV-elements have been permuted 464 | so that those that are not options now come last.) 465 | 466 | OPTSTRING is a string containing the legitimate option characters. 467 | If an option character is seen that is not listed in OPTSTRING, 468 | return '?' after printing an error message. If you set `opterr' to 469 | zero, the error message is suppressed but we still return '?'. 470 | 471 | If a char in OPTSTRING is followed by a colon, that means it wants an arg, 472 | so the following text in the same ARGV-element, or the text of the following 473 | ARGV-element, is returned in `optarg'. Two colons mean an option that 474 | wants an optional arg; if there is text in the current ARGV-element, 475 | it is returned in `optarg', otherwise `optarg' is set to zero. 476 | 477 | If OPTSTRING starts with `-' or `+', it requests different methods of 478 | handling the non-option ARGV-elements. 479 | See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. 480 | 481 | Long-named options begin with `--' instead of `-'. 482 | Their names may be abbreviated as long as the abbreviation is unique 483 | or is an exact match for some defined option. If they have an 484 | argument, it follows the option name in the same ARGV-element, separated 485 | from the option name by a `=', or else the in next ARGV-element. 486 | When `getopt' finds a long-named option, it returns 0 if that option's 487 | `flag' field is nonzero, the value of the option's `val' field 488 | if the `flag' field is zero. 489 | 490 | The elements of ARGV aren't really const, because we permute them. 491 | But we pretend they're const in the prototype to be compatible 492 | with other systems. 493 | 494 | LONGOPTS is a vector of `struct option' terminated by an 495 | element containing a name which is zero. 496 | 497 | LONGIND returns the index in LONGOPT of the long-named option found. 498 | It is only valid when a long-named option has been found by the most 499 | recent call. 500 | 501 | If LONG_ONLY is nonzero, '-' as well as '--' can introduce 502 | long-named options. */ 503 | 504 | int 505 | _getopt_internal(argc, argv, optstring, longopts, longind, long_only) 506 | int argc; 507 | char *const *argv; 508 | const char *optstring; 509 | const struct option *longopts; 510 | int *longind; 511 | int long_only; 512 | { 513 | int print_errors = opterr; 514 | if (optstring[0] == ':') 515 | print_errors = 0; 516 | 517 | if (argc < 1) 518 | return -1; 519 | 520 | optarg = NULL; 521 | 522 | if (optind == 0 || !__getopt_initialized) 523 | { 524 | if (optind == 0) 525 | optind = 1; /* Don't scan ARGV[0], the program name. */ 526 | optstring = _getopt_initialize(argc, argv, optstring); 527 | __getopt_initialized = 1; 528 | } 529 | 530 | /* Test whether ARGV[optind] points to a non-option argument. 531 | Either it does not have option syntax, or there is an environment flag 532 | from the shell indicating it is not an option. The later information 533 | is only used when the used in the GNU libc. */ 534 | #if defined _LIBC && defined USE_NONOPTION_FLAGS 535 | # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ 536 | || (optind < nonoption_flags_len \ 537 | && __getopt_nonoption_flags[optind] == '1')) 538 | #else 539 | # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') 540 | #endif 541 | 542 | if (nextchar == NULL || *nextchar == '\0') 543 | { 544 | /* Advance to the next ARGV-element. */ 545 | 546 | /* Give FIRST_NONOPT and LAST_NONOPT rational values if OPTIND has been 547 | moved back by the user (who may also have changed the arguments). */ 548 | if (last_nonopt > optind) 549 | last_nonopt = optind; 550 | if (first_nonopt > optind) 551 | first_nonopt = optind; 552 | 553 | if (ordering == PERMUTE) 554 | { 555 | /* If we have just processed some options following some non-options, 556 | exchange them so that the options come first. */ 557 | 558 | if (first_nonopt != last_nonopt && last_nonopt != optind) 559 | exchange((char **)argv); 560 | else if (last_nonopt != optind) 561 | first_nonopt = optind; 562 | 563 | /* Skip any additional non-options 564 | and extend the range of non-options previously skipped. */ 565 | 566 | while (optind < argc && NONOPTION_P) 567 | optind++; 568 | last_nonopt = optind; 569 | } 570 | 571 | /* The special ARGV-element `--' means premature end of options. 572 | Skip it like a null option, 573 | then exchange with previous non-options as if it were an option, 574 | then skip everything else like a non-option. */ 575 | 576 | if (optind != argc && !strcmp(argv[optind], "--")) 577 | { 578 | optind++; 579 | 580 | if (first_nonopt != last_nonopt && last_nonopt != optind) 581 | exchange((char **)argv); 582 | else if (first_nonopt == last_nonopt) 583 | first_nonopt = optind; 584 | last_nonopt = argc; 585 | 586 | optind = argc; 587 | } 588 | 589 | /* If we have done all the ARGV-elements, stop the scan 590 | and back over any non-options that we skipped and permuted. */ 591 | 592 | if (optind == argc) 593 | { 594 | /* Set the next-arg-index to point at the non-options 595 | that we previously skipped, so the caller will digest them. */ 596 | if (first_nonopt != last_nonopt) 597 | optind = first_nonopt; 598 | return -1; 599 | } 600 | 601 | /* If we have come to a non-option and did not permute it, 602 | either stop the scan or describe it to the caller and pass it by. */ 603 | 604 | if (NONOPTION_P) 605 | { 606 | if (ordering == REQUIRE_ORDER) 607 | return -1; 608 | optarg = argv[optind++]; 609 | return 1; 610 | } 611 | 612 | /* We have found another option-ARGV-element. 613 | Skip the initial punctuation. */ 614 | 615 | nextchar = (argv[optind] + 1 616 | + (longopts != NULL && argv[optind][1] == '-')); 617 | } 618 | 619 | /* Decode the current option-ARGV-element. */ 620 | 621 | /* Check whether the ARGV-element is a long option. 622 | 623 | If long_only and the ARGV-element has the form "-f", where f is 624 | a valid short option, don't consider it an abbreviated form of 625 | a long option that starts with f. Otherwise there would be no 626 | way to give the -f short option. 627 | 628 | On the other hand, if there's a long option "fubar" and 629 | the ARGV-element is "-fu", do consider that an abbreviation of 630 | the long option, just like "--fu", and not "-f" with arg "u". 631 | 632 | This distinction seems to be the most useful approach. */ 633 | 634 | if (longopts != NULL 635 | && (argv[optind][1] == '-' 636 | || (long_only && (argv[optind][2] || !my_index(optstring, argv[optind][1]))))) 637 | { 638 | char *nameend; 639 | const struct option *p; 640 | const struct option *pfound = NULL; 641 | int exact = 0; 642 | int ambig = 0; 643 | int indfound = -1; 644 | int option_index; 645 | 646 | for (nameend = nextchar; *nameend && *nameend != '='; nameend++) 647 | /* Do nothing. */; 648 | 649 | /* Test all long options for either exact match 650 | or abbreviated matches. */ 651 | for (p = longopts, option_index = 0; p->name; p++, option_index++) 652 | if (!strncmp(p->name, nextchar, nameend - nextchar)) 653 | { 654 | if ((unsigned int)(nameend - nextchar) 655 | == (unsigned int)strlen(p->name)) 656 | { 657 | /* Exact match found. */ 658 | pfound = p; 659 | indfound = option_index; 660 | exact = 1; 661 | break; 662 | } 663 | else if (pfound == NULL) 664 | { 665 | /* First nonexact match found. */ 666 | pfound = p; 667 | indfound = option_index; 668 | } 669 | else if (long_only 670 | || pfound->has_arg != p->has_arg 671 | || pfound->flag != p->flag 672 | || pfound->val != p->val) 673 | /* Second or later nonexact match found. */ 674 | ambig = 1; 675 | } 676 | 677 | if (ambig && !exact) 678 | { 679 | if (print_errors) 680 | { 681 | #if defined _LIBC && defined USE_IN_LIBIO 682 | char *buf; 683 | 684 | __asprintf(&buf, _("%s: option `%s' is ambiguous\n"), 685 | argv[0], argv[optind]); 686 | 687 | if (_IO_fwide(stderr, 0) > 0) 688 | __fwprintf(stderr, L"%s", buf); 689 | else 690 | fputs(buf, stderr); 691 | 692 | free(buf); 693 | #else 694 | fprintf(stderr, _("%s: option `%s' is ambiguous\n"), 695 | argv[0], argv[optind]); 696 | #endif 697 | } 698 | nextchar += strlen(nextchar); 699 | optind++; 700 | optopt = 0; 701 | return '?'; 702 | } 703 | 704 | if (pfound != NULL) 705 | { 706 | option_index = indfound; 707 | optind++; 708 | if (*nameend) 709 | { 710 | /* Don't test has_arg with >, because some C compilers don't 711 | allow it to be used on enums. */ 712 | if (pfound->has_arg) 713 | optarg = nameend + 1; 714 | else 715 | { 716 | if (print_errors) 717 | { 718 | #if defined _LIBC && defined USE_IN_LIBIO 719 | char *buf; 720 | #endif 721 | 722 | if (argv[optind - 1][1] == '-') 723 | { 724 | /* --option */ 725 | #if defined _LIBC && defined USE_IN_LIBIO 726 | __asprintf(&buf, _("\ 727 | %s: option `--%s' doesn't allow an argument\n"), 728 | argv[0], pfound->name); 729 | #else 730 | fprintf(stderr, _("\ 731 | %s: option `--%s' doesn't allow an argument\n"), 732 | argv[0], pfound->name); 733 | #endif 734 | } 735 | else 736 | { 737 | /* +option or -option */ 738 | #if defined _LIBC && defined USE_IN_LIBIO 739 | __asprintf(&buf, _("\ 740 | %s: option `%c%s' doesn't allow an argument\n"), 741 | argv[0], argv[optind - 1][0], 742 | pfound->name); 743 | #else 744 | fprintf(stderr, _("\ 745 | %s: option `%c%s' doesn't allow an argument\n"), 746 | argv[0], argv[optind - 1][0], pfound->name); 747 | #endif 748 | } 749 | 750 | #if defined _LIBC && defined USE_IN_LIBIO 751 | if (_IO_fwide(stderr, 0) > 0) 752 | __fwprintf(stderr, L"%s", buf); 753 | else 754 | fputs(buf, stderr); 755 | 756 | free(buf); 757 | #endif 758 | } 759 | 760 | nextchar += strlen(nextchar); 761 | 762 | optopt = pfound->val; 763 | return '?'; 764 | } 765 | } 766 | else if (pfound->has_arg == 1) 767 | { 768 | if (optind < argc) 769 | optarg = argv[optind++]; 770 | else 771 | { 772 | if (print_errors) 773 | { 774 | #if defined _LIBC && defined USE_IN_LIBIO 775 | char *buf; 776 | 777 | __asprintf(&buf, 778 | _("%s: option `%s' requires an argument\n"), 779 | argv[0], argv[optind - 1]); 780 | 781 | if (_IO_fwide(stderr, 0) > 0) 782 | __fwprintf(stderr, L"%s", buf); 783 | else 784 | fputs(buf, stderr); 785 | 786 | free(buf); 787 | #else 788 | fprintf(stderr, 789 | _("%s: option `%s' requires an argument\n"), 790 | argv[0], argv[optind - 1]); 791 | #endif 792 | } 793 | nextchar += strlen(nextchar); 794 | optopt = pfound->val; 795 | return optstring[0] == ':' ? ':' : '?'; 796 | } 797 | } 798 | nextchar += strlen(nextchar); 799 | if (longind != NULL) 800 | *longind = option_index; 801 | if (pfound->flag) 802 | { 803 | *(pfound->flag) = pfound->val; 804 | return 0; 805 | } 806 | return pfound->val; 807 | } 808 | 809 | /* Can't find it as a long option. If this is not getopt_long_only, 810 | or the option starts with '--' or is not a valid short 811 | option, then it's an error. 812 | Otherwise interpret it as a short option. */ 813 | if (!long_only || argv[optind][1] == '-' 814 | || my_index(optstring, *nextchar) == NULL) 815 | { 816 | if (print_errors) 817 | { 818 | #if defined _LIBC && defined USE_IN_LIBIO 819 | char *buf; 820 | #endif 821 | 822 | if (argv[optind][1] == '-') 823 | { 824 | /* --option */ 825 | #if defined _LIBC && defined USE_IN_LIBIO 826 | __asprintf(&buf, _("%s: unrecognized option `--%s'\n"), 827 | argv[0], nextchar); 828 | #else 829 | fprintf(stderr, _("%s: unrecognized option `--%s'\n"), 830 | argv[0], nextchar); 831 | #endif 832 | } 833 | else 834 | { 835 | /* +option or -option */ 836 | #if defined _LIBC && defined USE_IN_LIBIO 837 | __asprintf(&buf, _("%s: unrecognized option `%c%s'\n"), 838 | argv[0], argv[optind][0], nextchar); 839 | #else 840 | fprintf(stderr, _("%s: unrecognized option `%c%s'\n"), 841 | argv[0], argv[optind][0], nextchar); 842 | #endif 843 | } 844 | 845 | #if defined _LIBC && defined USE_IN_LIBIO 846 | if (_IO_fwide(stderr, 0) > 0) 847 | __fwprintf(stderr, L"%s", buf); 848 | else 849 | fputs(buf, stderr); 850 | 851 | free(buf); 852 | #endif 853 | } 854 | nextchar = (char *) ""; 855 | optind++; 856 | optopt = 0; 857 | return '?'; 858 | } 859 | } 860 | 861 | /* Look at and handle the next short option-character. */ 862 | 863 | { 864 | char c = *nextchar++; 865 | char *temp = my_index(optstring, c); 866 | 867 | /* Increment `optind' when we start to process its last character. */ 868 | if (*nextchar == '\0') 869 | ++optind; 870 | 871 | if (temp == NULL || c == ':') 872 | { 873 | if (print_errors) 874 | { 875 | #if defined _LIBC && defined USE_IN_LIBIO 876 | char *buf; 877 | #endif 878 | 879 | if (posixly_correct) 880 | { 881 | /* 1003.2 specifies the format of this message. */ 882 | #if defined _LIBC && defined USE_IN_LIBIO 883 | __asprintf(&buf, _("%s: illegal option -- %c\n"), 884 | argv[0], c); 885 | #else 886 | fprintf(stderr, _("%s: illegal option -- %c\n"), argv[0], c); 887 | #endif 888 | } 889 | else 890 | { 891 | #if defined _LIBC && defined USE_IN_LIBIO 892 | __asprintf(&buf, _("%s: invalid option -- %c\n"), 893 | argv[0], c); 894 | #else 895 | fprintf(stderr, _("%s: invalid option -- %c\n"), argv[0], c); 896 | #endif 897 | } 898 | 899 | #if defined _LIBC && defined USE_IN_LIBIO 900 | if (_IO_fwide(stderr, 0) > 0) 901 | __fwprintf(stderr, L"%s", buf); 902 | else 903 | fputs(buf, stderr); 904 | 905 | free(buf); 906 | #endif 907 | } 908 | optopt = c; 909 | return '?'; 910 | } 911 | /* Convenience. Treat POSIX -W foo same as long option --foo */ 912 | if (temp[0] == 'W' && temp[1] == ';') 913 | { 914 | char *nameend; 915 | const struct option *p; 916 | const struct option *pfound = NULL; 917 | int exact = 0; 918 | int ambig = 0; 919 | int indfound = 0; 920 | int option_index; 921 | 922 | /* This is an option that requires an argument. */ 923 | if (*nextchar != '\0') 924 | { 925 | optarg = nextchar; 926 | /* If we end this ARGV-element by taking the rest as an arg, 927 | we must advance to the next element now. */ 928 | optind++; 929 | } 930 | else if (optind == argc) 931 | { 932 | if (print_errors) 933 | { 934 | /* 1003.2 specifies the format of this message. */ 935 | #if defined _LIBC && defined USE_IN_LIBIO 936 | char *buf; 937 | 938 | __asprintf(&buf, _("%s: option requires an argument -- %c\n"), 939 | argv[0], c); 940 | 941 | if (_IO_fwide(stderr, 0) > 0) 942 | __fwprintf(stderr, L"%s", buf); 943 | else 944 | fputs(buf, stderr); 945 | 946 | free(buf); 947 | #else 948 | fprintf(stderr, _("%s: option requires an argument -- %c\n"), 949 | argv[0], c); 950 | #endif 951 | } 952 | optopt = c; 953 | if (optstring[0] == ':') 954 | c = ':'; 955 | else 956 | c = '?'; 957 | return c; 958 | } 959 | else 960 | /* We already incremented `optind' once; 961 | increment it again when taking next ARGV-elt as argument. */ 962 | optarg = argv[optind++]; 963 | 964 | /* optarg is now the argument, see if it's in the 965 | table of longopts. */ 966 | 967 | for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) 968 | /* Do nothing. */; 969 | 970 | /* Test all long options for either exact match 971 | or abbreviated matches. */ 972 | for (p = longopts, option_index = 0; p->name; p++, option_index++) 973 | if (!strncmp(p->name, nextchar, nameend - nextchar)) 974 | { 975 | if ((unsigned int)(nameend - nextchar) == strlen(p->name)) 976 | { 977 | /* Exact match found. */ 978 | pfound = p; 979 | indfound = option_index; 980 | exact = 1; 981 | break; 982 | } 983 | else if (pfound == NULL) 984 | { 985 | /* First nonexact match found. */ 986 | pfound = p; 987 | indfound = option_index; 988 | } 989 | else 990 | /* Second or later nonexact match found. */ 991 | ambig = 1; 992 | } 993 | if (ambig && !exact) 994 | { 995 | if (print_errors) 996 | { 997 | #if defined _LIBC && defined USE_IN_LIBIO 998 | char *buf; 999 | 1000 | __asprintf(&buf, _("%s: option `-W %s' is ambiguous\n"), 1001 | argv[0], argv[optind]); 1002 | 1003 | if (_IO_fwide(stderr, 0) > 0) 1004 | __fwprintf(stderr, L"%s", buf); 1005 | else 1006 | fputs(buf, stderr); 1007 | 1008 | free(buf); 1009 | #else 1010 | fprintf(stderr, _("%s: option `-W %s' is ambiguous\n"), 1011 | argv[0], argv[optind]); 1012 | #endif 1013 | } 1014 | nextchar += strlen(nextchar); 1015 | optind++; 1016 | return '?'; 1017 | } 1018 | if (pfound != NULL) 1019 | { 1020 | option_index = indfound; 1021 | if (*nameend) 1022 | { 1023 | /* Don't test has_arg with >, because some C compilers don't 1024 | allow it to be used on enums. */ 1025 | if (pfound->has_arg) 1026 | optarg = nameend + 1; 1027 | else 1028 | { 1029 | if (print_errors) 1030 | { 1031 | #if defined _LIBC && defined USE_IN_LIBIO 1032 | char *buf; 1033 | 1034 | __asprintf(&buf, _("\ 1035 | %s: option `-W %s' doesn't allow an argument\n"), 1036 | argv[0], pfound->name); 1037 | 1038 | if (_IO_fwide(stderr, 0) > 0) 1039 | __fwprintf(stderr, L"%s", buf); 1040 | else 1041 | fputs(buf, stderr); 1042 | 1043 | free(buf); 1044 | #else 1045 | fprintf(stderr, _("\ 1046 | %s: option `-W %s' doesn't allow an argument\n"), 1047 | argv[0], pfound->name); 1048 | #endif 1049 | } 1050 | 1051 | nextchar += strlen(nextchar); 1052 | return '?'; 1053 | } 1054 | } 1055 | else if (pfound->has_arg == 1) 1056 | { 1057 | if (optind < argc) 1058 | optarg = argv[optind++]; 1059 | else 1060 | { 1061 | if (print_errors) 1062 | { 1063 | #if defined _LIBC && defined USE_IN_LIBIO 1064 | char *buf; 1065 | 1066 | __asprintf(&buf, _("\ 1067 | %s: option `%s' requires an argument\n"), 1068 | argv[0], argv[optind - 1]); 1069 | 1070 | if (_IO_fwide(stderr, 0) > 0) 1071 | __fwprintf(stderr, L"%s", buf); 1072 | else 1073 | fputs(buf, stderr); 1074 | 1075 | free(buf); 1076 | #else 1077 | fprintf(stderr, 1078 | _("%s: option `%s' requires an argument\n"), 1079 | argv[0], argv[optind - 1]); 1080 | #endif 1081 | } 1082 | nextchar += strlen(nextchar); 1083 | return optstring[0] == ':' ? ':' : '?'; 1084 | } 1085 | } 1086 | nextchar += strlen(nextchar); 1087 | if (longind != NULL) 1088 | *longind = option_index; 1089 | if (pfound->flag) 1090 | { 1091 | *(pfound->flag) = pfound->val; 1092 | return 0; 1093 | } 1094 | return pfound->val; 1095 | } 1096 | nextchar = NULL; 1097 | return 'W'; /* Let the application handle it. */ 1098 | } 1099 | if (temp[1] == ':') 1100 | { 1101 | if (temp[2] == ':') 1102 | { 1103 | /* This is an option that accepts an argument optionally. */ 1104 | if (*nextchar != '\0') 1105 | { 1106 | optarg = nextchar; 1107 | optind++; 1108 | } 1109 | else 1110 | optarg = NULL; 1111 | nextchar = NULL; 1112 | } 1113 | else 1114 | { 1115 | /* This is an option that requires an argument. */ 1116 | if (*nextchar != '\0') 1117 | { 1118 | optarg = nextchar; 1119 | /* If we end this ARGV-element by taking the rest as an arg, 1120 | we must advance to the next element now. */ 1121 | optind++; 1122 | } 1123 | else if (optind == argc) 1124 | { 1125 | if (print_errors) 1126 | { 1127 | /* 1003.2 specifies the format of this message. */ 1128 | #if defined _LIBC && defined USE_IN_LIBIO 1129 | char *buf; 1130 | 1131 | __asprintf(&buf, 1132 | _("%s: option requires an argument -- %c\n"), 1133 | argv[0], c); 1134 | 1135 | if (_IO_fwide(stderr, 0) > 0) 1136 | __fwprintf(stderr, L"%s", buf); 1137 | else 1138 | fputs(buf, stderr); 1139 | 1140 | free(buf); 1141 | #else 1142 | fprintf(stderr, 1143 | _("%s: option requires an argument -- %c\n"), 1144 | argv[0], c); 1145 | #endif 1146 | } 1147 | optopt = c; 1148 | if (optstring[0] == ':') 1149 | c = ':'; 1150 | else 1151 | c = '?'; 1152 | } 1153 | else 1154 | /* We already incremented `optind' once; 1155 | increment it again when taking next ARGV-elt as argument. */ 1156 | optarg = argv[optind++]; 1157 | nextchar = NULL; 1158 | } 1159 | } 1160 | return c; 1161 | } 1162 | } 1163 | 1164 | int 1165 | getopt(argc, argv, optstring) 1166 | int argc; 1167 | char *const *argv; 1168 | const char *optstring; 1169 | { 1170 | return _getopt_internal(argc, argv, optstring, 1171 | (const struct option *) 0, 1172 | (int *)0, 1173 | 0); 1174 | } 1175 | 1176 | #endif /* Not ELIDE_CODE. */ 1177 | 1178 | 1179 | /* Compile with -DTEST to make an executable for use in testing 1180 | the above definition of `getopt'. */ 1181 | 1182 | /* #define TEST */ /* Pete Wilson mod 7/28/02 */ 1183 | #ifdef TEST 1184 | 1185 | #ifndef exit /* Pete Wilson mod 7/28/02 */ 1186 | int exit(int); /* Pete Wilson mod 7/28/02 */ 1187 | #endif /* Pete Wilson mod 7/28/02 */ 1188 | 1189 | int 1190 | main(argc, argv) 1191 | int argc; 1192 | char **argv; 1193 | { 1194 | int c; 1195 | int digit_optind = 0; 1196 | 1197 | while (1) 1198 | { 1199 | int this_option_optind = optind ? optind : 1; 1200 | 1201 | c = getopt(argc, argv, "abc:d:0123456789"); 1202 | if (c == -1) 1203 | break; 1204 | 1205 | switch (c) 1206 | { 1207 | case '0': 1208 | case '1': 1209 | case '2': 1210 | case '3': 1211 | case '4': 1212 | case '5': 1213 | case '6': 1214 | case '7': 1215 | case '8': 1216 | case '9': 1217 | if (digit_optind != 0 && digit_optind != this_option_optind) 1218 | printf("digits occur in two different argv-elements.\n"); 1219 | digit_optind = this_option_optind; 1220 | printf("option %c\n", c); 1221 | break; 1222 | 1223 | case 'a': 1224 | printf("option a\n"); 1225 | break; 1226 | 1227 | case 'b': 1228 | printf("option b\n"); 1229 | break; 1230 | 1231 | case 'c': 1232 | printf("option c with value `%s'\n", optarg); 1233 | break; 1234 | 1235 | case '?': 1236 | break; 1237 | 1238 | default: 1239 | printf("?? getopt returned character code 0%o ??\n", c); 1240 | } 1241 | } 1242 | 1243 | if (optind < argc) 1244 | { 1245 | printf("non-option ARGV-elements: "); 1246 | while (optind < argc) 1247 | printf("%s ", argv[optind++]); 1248 | printf("\n"); 1249 | } 1250 | 1251 | exit(0); 1252 | } 1253 | 1254 | #endif /* TEST */ 1255 | 1256 | 1257 | --------------------------------------------------------------------------------