├── Images ├── Untitled.png ├── Gremlins-Gizmo-square.ico ├── Gremlins-Gizmo-square.png └── Screenshot 2022-12-16 133033.png ├── Gremlins ├── AuxTypes.h ├── ntcreatefiletypes.h ├── detour.h ├── LeaksTypes.h ├── AuxWrapper.h ├── ProcessHandle.h ├── privileges.h ├── Leaks.h ├── ntcreatefile.h ├── Gremlins.inf ├── ntdeviceiocontrolfile.h ├── hook.h ├── dispatchfunctions.h ├── resolve.h ├── ntcreatefile.cpp ├── ProcessHandleTypes.h ├── Leaks.cpp ├── AuxWrapper.cpp ├── detour.cpp ├── kutypes.h ├── ntdeviceiocontrolfile.cpp ├── privileges.cpp ├── ProcessHandle.cpp ├── resolve.cpp ├── hook.cpp ├── typesndefs.h ├── Gremlins.vcxproj.filters ├── dispatchfunctions.cpp ├── Source.cpp └── Gremlins.vcxproj ├── Gizmo ├── NtUndoc.h ├── ServiceController.h ├── DllHelper.h ├── ErrorHandler.h ├── BaseDriverclient.cpp ├── BaseDriverclient.h ├── types.h ├── ErrorHandler.cpp ├── Gizmo.vcxproj.filters ├── Gizmo.h ├── ServiceController.cpp ├── Source.cpp ├── Gizmo.cpp ├── Gizmo.vcxproj └── NtUndocTypes.h ├── .github └── workflows │ └── msbuild.yml ├── .gitattributes ├── Gremlins.sln ├── README.md └── .gitignore /Images/Untitled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ch3rn0byl/Gremlins/HEAD/Images/Untitled.png -------------------------------------------------------------------------------- /Images/Gremlins-Gizmo-square.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ch3rn0byl/Gremlins/HEAD/Images/Gremlins-Gizmo-square.ico -------------------------------------------------------------------------------- /Images/Gremlins-Gizmo-square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ch3rn0byl/Gremlins/HEAD/Images/Gremlins-Gizmo-square.png -------------------------------------------------------------------------------- /Gremlins/AuxTypes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define AUX_POOLTAG_DBG 'dWxA' 4 | #define AUX_POOLTAG 'rGxA' 5 | 6 | 7 | /// EOF -------------------------------------------------------------------------------- /Images/Screenshot 2022-12-16 133033.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ch3rn0byl/Gremlins/HEAD/Images/Screenshot 2022-12-16 133033.png -------------------------------------------------------------------------------- /Gremlins/ntcreatefiletypes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define FILE_ANY_ACCESS 0 4 | #define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS) 5 | #define FILE_READ_ACCESS ( 0x0001 ) // file & pipe 6 | #define FILE_WRITE_ACCESS ( 0x0002 ) // file & pipe 7 | 8 | 9 | /// EOF -------------------------------------------------------------------------------- /Gizmo/NtUndoc.h: -------------------------------------------------------------------------------- 1 | // NtUndoc.h : This file is used in Gizmo.h for resolving undocumented functions. 2 | // 3 | #pragma once 4 | #include "DllHelper.h" 5 | #include "NtUndocTypes.h" 6 | 7 | class NtUndoc 8 | { 9 | private: 10 | DllHelper m_dll{ L"ntdll.dll" }; 11 | 12 | public: 13 | _NtQuerySystemInformation NtQuerySystemInformation = m_dll["NtQuerySystemInformation"]; 14 | }; 15 | 16 | 17 | /// EOF -------------------------------------------------------------------------------- /Gremlins/detour.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace detour 5 | { 6 | _Success_(return >= 0) 7 | NTSTATUS hook( 8 | _In_ PVOID BaseAddress, 9 | _In_ PUINT8 patch, 10 | _In_ size_t szSize 11 | ); 12 | 13 | _Success_(return >= 0) 14 | NTSTATUS unhook( 15 | _In_ PVOID BaseAddress, 16 | _In_ PUINT8 Source, 17 | _In_ UINT8 szSize 18 | ); 19 | } 20 | 21 | 22 | /// EOF -------------------------------------------------------------------------------- /Gremlins/LeaksTypes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | typedef union _VIRTUAL_ADDR 5 | { 6 | struct 7 | { 8 | UINT64 Reserved : 63; // Reserved: I don't care about these bits 9 | UINT64 MSB : 1; // Most significant bit: used to check if kernel address 10 | }; 11 | ULARGE_INTEGER Address; 12 | UINT64 value; 13 | } VIRTUAL_ADDR, * PVIRTUAL_ADDR; 14 | 15 | 16 | /// EOF -------------------------------------------------------------------------------- /Gremlins/AuxWrapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "AuxTypes.h" 5 | 6 | class AuxWrapper 7 | { 8 | public: 9 | AuxWrapper(); 10 | 11 | /// 12 | /// The deconstructor is responsible for cleaning up and deallocating 13 | /// memory. 14 | /// 15 | ~AuxWrapper(); 16 | 17 | protected: 18 | PAUX_MODULE_EXTENDED_INFO m_LoadedModules; 19 | UINT32 m_NumberOfModules; 20 | 21 | private: 22 | ULONG m_SizeOfModules; 23 | }; 24 | 25 | 26 | /// EOF -------------------------------------------------------------------------------- /Gremlins/ProcessHandle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "ProcessHandleTypes.h" 4 | 5 | class ProcessHandle 6 | { 7 | public: 8 | ProcessHandle(); 9 | ~ProcessHandle(); 10 | 11 | ProcessHandle( 12 | _In_ HANDLE hFileHandle 13 | ); 14 | 15 | NTSTATUS AnalyzeHandle(); 16 | PSECURITY_DESCRIPTOR GetFileObjectSD(); 17 | 18 | protected: 19 | PFILE_OBJECT m_FileObject; 20 | 21 | private: 22 | HANDLE m_FileHandle; 23 | PUNICODE_STRING m_NameInformation; 24 | ULONG m_ReturnLength; 25 | }; 26 | 27 | 28 | /// EOF -------------------------------------------------------------------------------- /Gremlins/privileges.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "kutypes.h" 4 | 5 | class privileges 6 | { 7 | public: 8 | privileges(); 9 | ~privileges(); 10 | 11 | privileges( 12 | _In_ PSECURITY_DESCRIPTOR SecurityDescriptor 13 | ); 14 | 15 | _IRQL_requires_max_(APC_LEVEL) 16 | NTSTATUS 17 | IsLowIntegrityFriendly( 18 | _Out_ PBOOLEAN IsFriendly 19 | ); 20 | 21 | protected: 22 | private: 23 | PSECURITY_DESCRIPTOR m_SecurityDescriptor; 24 | PSID m_EveryoneSid; 25 | ULONG m_EveryoneSidLength; 26 | }; 27 | 28 | -------------------------------------------------------------------------------- /Gremlins/Leaks.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "AuxWrapper.h" 3 | #include "LeaksTypes.h" 4 | 5 | class Leaks : 6 | public AuxWrapper 7 | { 8 | public: 9 | Leaks( 10 | _In_reads_bytes_(BufferLen) PUINT8 Buffer, 11 | _In_ ULONG BufferLen 12 | ); 13 | 14 | ~Leaks(); 15 | 16 | _IRQL_requires_min_(PASSIVE_LEVEL) 17 | _Must_inspect_result_ 18 | UINT64 19 | DidKernelAddressLeak(); 20 | 21 | private: 22 | const PUINT8 m_Buffer; 23 | const ULONG m_BufferLen; 24 | }; 25 | 26 | 27 | /// EOF -------------------------------------------------------------------------------- /Gremlins/ntcreatefile.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "typesndefs.h" 3 | 4 | EXTERN_C 5 | NTSTATUS 6 | fn_hNtCreateFile( 7 | _Out_ PHANDLE FileHandle, 8 | _In_ ACCESS_MASK DesiredAccess, 9 | _In_ POBJECT_ATTRIBUTES ObjectAttributes, 10 | _Out_ PIO_STATUS_BLOCK IoStatusBlock, 11 | _In_opt_ PLARGE_INTEGER AllocationSize, 12 | _In_ ULONG FileAttributes, 13 | _In_ ULONG ShareAccess, 14 | _In_ ULONG CreateDisposition, 15 | _In_ ULONG CreateOptions, 16 | _In_opt_ PVOID EaBuffer, 17 | _In_ ULONG EaLength 18 | ); 19 | 20 | 21 | /// EOF -------------------------------------------------------------------------------- /Gremlins/Gremlins.inf: -------------------------------------------------------------------------------- 1 | ; 2 | ; Gremlins.inf 3 | ; 4 | 5 | [Version] 6 | Signature="$WINDOWS NT$" 7 | Class=System 8 | ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318} 9 | Provider=%ManufacturerName% 10 | DriverVer= 11 | CatalogFile=Gremlins.cat 12 | PnpLockDown=1 13 | 14 | [DestinationDirs] 15 | DefaultDestDir = 12 16 | 17 | 18 | [SourceDisksNames] 19 | 1 = %DiskName%,,,"" 20 | 21 | [SourceDisksFiles] 22 | 23 | 24 | [DefaultInstall.NT$ARCH$] 25 | 26 | 27 | [Strings] 28 | ManufacturerName="" ;TODO: Replace with your manufacturer name 29 | ClassName="" 30 | DiskName="Gremlins Source Disk" 31 | -------------------------------------------------------------------------------- /Gremlins/ntdeviceiocontrolfile.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "typesndefs.h" 3 | #include "ProcessHandle.h" 4 | #include "Leaks.h" 5 | #include "privileges.h" 6 | 7 | EXTERN_C 8 | NTSTATUS 9 | fn_hNtDeviceIoControlFile( 10 | _In_ HANDLE FileHandle, 11 | _In_opt_ HANDLE Event, 12 | _In_opt_ PIO_APC_ROUTINE ApcRoutine, 13 | _In_opt_ PVOID ApcContext, 14 | _Outptr_ PIO_STATUS_BLOCK IoStatusBlock, 15 | _In_ ULONG IoControlCode, 16 | _In_opt_ PVOID InputBuffer, 17 | _In_ ULONG InputBufferLength, 18 | _Out_opt_ PVOID OutputBuffer, 19 | _In_ ULONG OutputBufferLength 20 | ); 21 | 22 | 23 | /// EOF -------------------------------------------------------------------------------- /Gremlins/hook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "typesndefs.h" 3 | #include "detour.h" 4 | 5 | /// 6 | /// The hook namespace is responsible for checking if a function 7 | /// is hooked and for manipulating the LIST_ENTRY. 8 | /// 9 | namespace hook 10 | { 11 | _Success_(return != 0) 12 | bool isFunctionHookedByAddress( 13 | _In_ PVOID address 14 | ); 15 | 16 | _Success_(return != 0) 17 | bool isFunctionHookedByIndex( 18 | _In_ UINT16 index 19 | ); 20 | 21 | _Success_(return != 0) 22 | NTSTATUS unhookFunction( 23 | _In_ UINT16 index 24 | ); 25 | 26 | void cleanup(); 27 | } 28 | 29 | 30 | /// EOF -------------------------------------------------------------------------------- /Gremlins/dispatchfunctions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "typesndefs.h" 5 | #include "resolve.h" 6 | #include "hook.h" 7 | #include "ntdeviceiocontrolfile.h" 8 | 9 | NTSTATUS 10 | IsModuleInitialized( 11 | _In_ PINPUT_BUFFER& InputBuffer, 12 | _Out_ PULONG Information 13 | ); 14 | 15 | NTSTATUS 16 | InitializeModule(); 17 | 18 | NTSTATUS 19 | IsSyscallHooked( 20 | _In_ PINPUT_BUFFER& InputBuffer, 21 | _Out_ PULONG Information 22 | ); 23 | 24 | NTSTATUS 25 | HookSyscall( 26 | _In_ PINPUT_BUFFER& InputBuffer 27 | ); 28 | 29 | NTSTATUS 30 | UnhookSyscall( 31 | _In_ PINPUT_BUFFER InputBuffer 32 | ); 33 | 34 | 35 | /// EOF -------------------------------------------------------------------------------- /Gizmo/ServiceController.h: -------------------------------------------------------------------------------- 1 | // ServiceController.h : WIP MAY NOT GET USED AND WILL GET DELETED IF NOT!! 2 | // 3 | #pragma once 4 | #include 5 | #include 6 | 7 | #include "ErrorHandler.h" 8 | 9 | class ServiceController 10 | { 11 | public: 12 | ServiceController(); 13 | ~ServiceController(); 14 | 15 | BOOL IsServiceRunning(); 16 | BOOL StartKernelService(); 17 | 18 | private: 19 | std::unique_ptr m_pError; 20 | const wchar_t* m_wszServiceName; 21 | SC_HANDLE m_schSCManager; 22 | SC_HANDLE m_schService; 23 | BOOL m_bDoesServiceExist; 24 | 25 | void ServiceCleanUp(); 26 | }; 27 | 28 | 29 | /// EOF -------------------------------------------------------------------------------- /Gremlins/resolve.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | /// 5 | /// The resolve namespace will be responsible for dynamically 6 | /// resolving the System's Service Descriptor Table and for 7 | /// resolving the some of the sub functions used to forward 8 | /// requests from NtDeviceIoControlFile and NtCreateFile. 9 | /// 10 | namespace resolve 11 | { 12 | _Ret_maybenull_ 13 | NTSTATUS KiSystemServiceUser( 14 | _In_ UINT64 address, 15 | _Out_ PUINT64 result 16 | ); 17 | 18 | _Ret_maybenull_ 19 | NTSTATUS KeServiceDescriptorTable( 20 | _In_ UINT64 address, 21 | _Out_ PUINT64 result 22 | ); 23 | 24 | _Ret_maybenull_ 25 | NTSTATUS IopXxxControlFile( 26 | _In_ UINT64 address, 27 | _Out_ PUINT64 result 28 | ); 29 | 30 | _Ret_maybenull_ 31 | NTSTATUS IopCreateFile( 32 | _In_ UINT64 address, 33 | _Out_ PUINT64 result 34 | ); 35 | } 36 | 37 | 38 | /// EOF -------------------------------------------------------------------------------- /Gizmo/DllHelper.h: -------------------------------------------------------------------------------- 1 | // DllHelper.h : This file is used in NtUndoc.h. 2 | // 3 | #pragma once 4 | #include 5 | #include 6 | 7 | // 8 | // I was just a mere peasant before discovering RAII for GetProcAddress. Big 9 | // thanks to the following blogpost: 10 | // https://blog.benoitblanchon.fr/getprocaddress-like-a-boss/ 11 | // 12 | class ProcPtr 13 | { 14 | public: 15 | explicit ProcPtr(FARPROC ptr) : 16 | m_ptr(ptr) 17 | {} 18 | 19 | template >> 20 | operator T* () const 21 | { 22 | return reinterpret_cast(m_ptr); 23 | } 24 | 25 | private: 26 | FARPROC m_ptr; 27 | }; 28 | 29 | class DllHelper 30 | { 31 | public: 32 | explicit DllHelper(LPCTSTR filename) : 33 | m_hModule(LoadLibrary(filename)) 34 | {} 35 | 36 | ~DllHelper() 37 | { 38 | FreeLibrary(m_hModule); 39 | } 40 | 41 | ProcPtr operator[](LPCSTR proc_name) const { 42 | return ProcPtr(GetProcAddress(m_hModule, proc_name)); 43 | } 44 | 45 | private: 46 | HMODULE m_hModule; 47 | }; 48 | 49 | 50 | /// EOF -------------------------------------------------------------------------------- /Gremlins/ntcreatefile.cpp: -------------------------------------------------------------------------------- 1 | #include "ntcreatefile.h" 2 | 3 | _Use_decl_annotations_ 4 | NTSTATUS fn_hNtCreateFile( 5 | PHANDLE FileHandle, 6 | ACCESS_MASK DesiredAccess, 7 | POBJECT_ATTRIBUTES ObjectAttributes, 8 | PIO_STATUS_BLOCK IoStatusBlock, 9 | PLARGE_INTEGER AllocationSize, 10 | ULONG FileAttributes, 11 | ULONG ShareAccess, 12 | ULONG CreateDisposition, 13 | ULONG CreateOptions, 14 | PVOID EaBuffer, 15 | ULONG EaLength 16 | ) 17 | { 18 | KPROCESSOR_MODE kmPreviousMode = ExGetPreviousMode(); 19 | 20 | if (kmPreviousMode == UserMode) 21 | { 22 | // 23 | // Implement logic to suit your needs. 24 | // 25 | } 26 | 27 | return g_Globals->internal.IopCreateFile( 28 | FileHandle, 29 | DesiredAccess, 30 | ObjectAttributes, 31 | IoStatusBlock, 32 | AllocationSize, 33 | FileAttributes, 34 | ShareAccess, 35 | CreateDisposition, 36 | CreateOptions, 37 | EaBuffer, 38 | EaLength, 39 | CreateFileTypeNone, 40 | NULL, 41 | NULL, 42 | 0x20, 43 | NULL 44 | ); 45 | } 46 | 47 | 48 | /// EOF -------------------------------------------------------------------------------- /Gizmo/ErrorHandler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /// 9 | /// This class takes in an error code from GetLastError and 10 | /// converts it into a readable string. The return types are: 11 | /// 1. std::string 12 | /// 2. std::wstring 13 | /// 14 | class ErrorHandler 15 | { 16 | public: 17 | /// 18 | /// This constructor uses the value of GetLastError() to 19 | /// convert into a readable error. 20 | /// 21 | /// 22 | ErrorHandler( 23 | _In_ DWORD dwError 24 | ); 25 | 26 | ~ErrorHandler(); 27 | 28 | /// 29 | /// Returns the error as an ascii string. 30 | /// 31 | /// std::string 32 | std::string GetLastErrorAsStringA(); 33 | 34 | /// 35 | /// Returns the error as a wide char string. 36 | /// 37 | /// std::wstring 38 | std::wstring GetLastErrorAsStringW(); 39 | 40 | protected: 41 | std::wstring m_ErrorAsStringW; 42 | 43 | private: 44 | DWORD m_dwError; 45 | LPVOID m_lpMessageBuffer; 46 | 47 | }; 48 | 49 | 50 | /// EOF -------------------------------------------------------------------------------- /.github/workflows/msbuild.yml: -------------------------------------------------------------------------------- 1 | name: MSBuild 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | env: 10 | # Path to the solution file relative to the root of the project. 11 | SOLUTION_FILE_PATH: . 12 | 13 | # Configuration type to build. 14 | # You can convert this to a build matrix if you need coverage of multiple configuration types. 15 | # https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 16 | BUILD_CONFIGURATION: Release 17 | 18 | permissions: 19 | contents: read 20 | 21 | jobs: 22 | build: 23 | runs-on: windows-latest 24 | 25 | steps: 26 | - uses: actions/checkout@v3 27 | 28 | - name: Add MSBuild to PATH 29 | uses: microsoft/setup-msbuild@v1.0.2 30 | 31 | - name: Restore NuGet packages 32 | working-directory: ${{env.GITHUB_WORKSPACE}} 33 | run: nuget restore ${{env.SOLUTION_FILE_PATH}} 34 | 35 | - name: Build 36 | working-directory: ${{env.GITHUB_WORKSPACE}} 37 | # Add additional options to the MSBuild command line here (like platform or verbosity level). 38 | # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference 39 | run: msbuild /m /p:Configuration=${{env.BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}} 40 | -------------------------------------------------------------------------------- /Gizmo/BaseDriverclient.cpp: -------------------------------------------------------------------------------- 1 | #include "BaseDriverClient.h" 2 | 3 | BaseDriverClient::BaseDriverClient() : 4 | m_hFileHandle(INVALID_HANDLE_VALUE), 5 | m_pErro(nullptr) 6 | { 7 | } 8 | 9 | BaseDriverClient::~BaseDriverClient() 10 | { 11 | if (m_hFileHandle != INVALID_HANDLE_VALUE) 12 | { 13 | CloseHandle(m_hFileHandle); 14 | m_hFileHandle = INVALID_HANDLE_VALUE; 15 | } 16 | } 17 | 18 | BOOL BaseDriverClient::init(const wchar_t* testing) 19 | { 20 | m_hFileHandle = CreateFile( 21 | testing, 22 | GENERIC_READ | GENERIC_WRITE, 23 | FILE_SHARE_READ | FILE_SHARE_WRITE, 24 | NULL, 25 | OPEN_EXISTING, 26 | FILE_ATTRIBUTE_NORMAL, 27 | NULL 28 | ); 29 | if (m_hFileHandle == INVALID_HANDLE_VALUE) 30 | { 31 | m_pErro = std::make_unique(GetLastError()); 32 | return FALSE; 33 | } 34 | return TRUE; 35 | } 36 | 37 | _Use_decl_annotations_ 38 | BOOL 39 | BaseDriverClient::SendIoControlRequest( 40 | DWORD dwIoControlCode, 41 | LPVOID lpInBuffer, 42 | DWORD dwInBufferSize, 43 | LPVOID lpOutBuffer, 44 | DWORD dwOutBufferSize, 45 | LPDWORD lpBytesReturned 46 | ) 47 | { 48 | BOOL bStatus = DeviceIoControl( 49 | m_hFileHandle, 50 | dwIoControlCode, 51 | lpInBuffer, 52 | dwInBufferSize, 53 | lpOutBuffer, 54 | dwOutBufferSize, 55 | lpBytesReturned, 56 | NULL 57 | ); 58 | if (!bStatus) 59 | { 60 | m_pErro = std::make_unique(GetLastError()); 61 | } 62 | 63 | return bStatus; 64 | } 65 | 66 | 67 | /// EOF -------------------------------------------------------------------------------- /Gremlins/ProcessHandleTypes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | //================================================================================ 5 | // Definitions 6 | //================================================================================ 7 | constexpr ULONG ObReferenceTag = 'OgbD'; 8 | constexpr ULONG phPoolTagDbg = 'bDhP'; 9 | constexpr ULONG phPoolTag = 'yThP'; 10 | 11 | //================================================================================ 12 | // Types 13 | //================================================================================ 14 | typedef enum _OBJECT_INFORMATION_CLASS 15 | { 16 | ObjectBasicInformation = 0, 17 | ObjectNameInformation = 1, 18 | ObjectTypeInformation = 2, 19 | ObjectTypesInformation = 3, 20 | ObjectHandleFlagInformation = 4, 21 | ObjectSessionInformation = 5, 22 | ObjectSessionObjectInformation = 6, 23 | MaxObjectInfoClass = 7 24 | } OBJECT_INFORMATION_CLASS; 25 | 26 | //================================================================================ 27 | // Exported Functions 28 | //================================================================================ 29 | EXTERN_C 30 | NTSYSAPI 31 | NTSTATUS 32 | NTAPI 33 | ZwQueryObject( 34 | _In_opt_ HANDLE Handle, 35 | _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass, 36 | _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation, 37 | _In_ ULONG ObjectInformationLength, 38 | _Out_opt_ PULONG ReturnLength 39 | ); 40 | 41 | 42 | /// EOF -------------------------------------------------------------------------------- /Gizmo/BaseDriverclient.h: -------------------------------------------------------------------------------- 1 | // BaseDriverClient.h : This file is the base class for all driver interactions. Used by Gizmo.h. 2 | // 3 | #pragma once 4 | #include 5 | #include "ErrorHandler.h" 6 | 7 | class BaseDriverClient 8 | { 9 | public: 10 | BaseDriverClient(); 11 | ~BaseDriverClient(); 12 | 13 | protected: 14 | /// 15 | /// This method is a wrapper around CreateFileW. 16 | /// 17 | /// 18 | /// TRUE. If this method fails, reference GetLastError(). 19 | BOOL init(const wchar_t* testing); 20 | 21 | /// 22 | /// This method is a wrapper for DeviceIoControlFile. 23 | /// 24 | /// 25 | /// 26 | /// 27 | /// 28 | /// 29 | /// 30 | /// true. If this method fails, reference GetLastError(). 31 | BOOL SendIoControlRequest( 32 | _In_ DWORD dwIoControlCode, 33 | _In_reads_bytes_opt_(dwInBufferSize) LPVOID lpInBuffer = nullptr, 34 | _In_ DWORD dwInBufferSize = NULL, 35 | _Out_writes_bytes_to_opt_(dwOutBufferSize, *lpBytesReturned) LPVOID lpOutBuffer = nullptr, 36 | _In_ DWORD dwOutBufferSize = NULL, 37 | _Out_opt_ LPDWORD lpBytesReturned = nullptr 38 | ); 39 | 40 | private: 41 | HANDLE m_hFileHandle; 42 | std::unique_ptr m_pErro; 43 | 44 | }; 45 | 46 | 47 | /// EOF -------------------------------------------------------------------------------- /Gremlins/Leaks.cpp: -------------------------------------------------------------------------------- 1 | #include "Leaks.h" 2 | 3 | _Use_decl_annotations_ 4 | Leaks::Leaks(PUINT8 Buffer, ULONG BufferLen) : 5 | m_Buffer(Buffer), 6 | m_BufferLen(BufferLen) 7 | { 8 | } 9 | 10 | Leaks::~Leaks() 11 | { 12 | } 13 | 14 | _Use_decl_annotations_ 15 | UINT64 16 | Leaks::DidKernelAddressLeak() 17 | { 18 | VIRTUAL_ADDR va = { 0 }; 19 | ULARGE_INTEGER temp = { 0 }; 20 | 21 | if (m_Buffer == NULL) 22 | { 23 | return NULL; 24 | } 25 | 26 | // 27 | // Need to ensure the buffer is 8 bytes or bigger. If not, 28 | // an out-of-bounds read is totally possible. Ain't got time fo dat thang o thang. 29 | // 30 | if (m_BufferLen < 8) 31 | { 32 | return NULL; 33 | } 34 | 35 | if (m_LoadedModules) 36 | { 37 | // 38 | // Iterate through the entire buffer and check for any types of kernel 39 | // leaks. 40 | // 41 | for (ULONG i = 0; i < m_BufferLen; i++) 42 | { 43 | if (m_BufferLen - i >= 8) 44 | { 45 | va.value = *reinterpret_cast( 46 | m_Buffer + i 47 | ); 48 | 49 | // 50 | // Is this value a kernel address? 51 | // 52 | if (va.MSB) 53 | { 54 | for (UINT32 index = 0; index < m_NumberOfModules; index++) 55 | { 56 | temp.QuadPart = reinterpret_cast( 57 | m_LoadedModules[index].BasicInfo.ImageBase 58 | ); 59 | 60 | if (va.Address.HighPart == temp.HighPart) 61 | { 62 | return va.Address.QuadPart; 63 | } 64 | } 65 | } 66 | } 67 | } 68 | } 69 | 70 | return NULL; 71 | } 72 | 73 | 74 | /// EOF -------------------------------------------------------------------------------- /Gizmo/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | ///------------------------------------------------------------------------------------------------- 6 | /// Macaroo's 7 | ///------------------------------------------------------------------------------------------------- 8 | #define ENCODE_CTL(Function) ( \ 9 | ((0x8000) << 16) | \ 10 | ((FILE_READ_ACCESS) << 14) | \ 11 | ((Function) << 2) | \ 12 | (METHOD_BUFFERED) \ 13 | ) 14 | 15 | #define CTL_CODE( DeviceType, Function, Method, Access ) ( \ 16 | ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ 17 | ) 18 | 19 | ///------------------------------------------------------------------------------------------------- 20 | /// Definitions 21 | ///------------------------------------------------------------------------------------------------- 22 | #define METHOD_BUFFERED 0 23 | #define METHOD_IN_DIRECT 1 24 | #define METHOD_OUT_DIRECT 2 25 | #define METHOD_NEITHER 3 26 | 27 | // 28 | // Syscall signature for ntdll. 29 | // 30 | static UINT8 SyscallSig[] = { 31 | 0x4c, 0x8b, 0xd1, // mov r10, rcx 32 | 0xb8 // mov eax, ?? 33 | }; 34 | 35 | //==================================================== 36 | // Types: IOCTLs 37 | //==================================================== 38 | enum IOCTL_FUNCTION : INT32 39 | { 40 | IsInitialized = ENCODE_CTL(0x800), 41 | Initialize = ENCODE_CTL(0x801), 42 | IsHooked = ENCODE_CTL(0x802), 43 | Hook = ENCODE_CTL(0x803), 44 | Unhook = ENCODE_CTL(0x804) 45 | }; 46 | 47 | typedef struct _INPUT_BUFFER 48 | { 49 | UINT16 syscall; 50 | bool status; 51 | } INPUT_BUFFER, * PINPUT_BUFFER; 52 | 53 | 54 | /// EOF -------------------------------------------------------------------------------- /Gremlins/AuxWrapper.cpp: -------------------------------------------------------------------------------- 1 | #include "AuxWrapper.h" 2 | 3 | AuxWrapper::AuxWrapper() : 4 | m_LoadedModules(nullptr), 5 | m_SizeOfModules(NULL), 6 | m_NumberOfModules(NULL) 7 | { 8 | NTSTATUS Status = AuxKlibInitialize(); 9 | if (!NT_SUCCESS(Status)) 10 | { 11 | return; 12 | } 13 | 14 | // 15 | // Get the size of the buffer needed to hold all loaded modules on 16 | // a system. 17 | // 18 | Status = AuxKlibQueryModuleInformation( 19 | &m_SizeOfModules, 20 | sizeof(AUX_MODULE_EXTENDED_INFO), 21 | NULL 22 | ); 23 | if (!NT_SUCCESS(Status) || m_SizeOfModules == NULL) 24 | { 25 | return; 26 | } 27 | 28 | // 29 | // Get the number of modules loaded. 30 | // 31 | m_NumberOfModules = m_SizeOfModules / sizeof(AUX_MODULE_EXTENDED_INFO); 32 | 33 | m_LoadedModules = static_cast( 34 | #ifdef DBG 35 | ExAllocatePool2(POOL_FLAG_NON_PAGED | POOL_FLAG_SPECIAL_POOL, m_SizeOfModules, AUX_POOLTAG_DBG) 36 | #else 37 | ExAllocatePool2(POOL_FLAG_NON_PAGED, m_SizeOfModules, AUX_POOLTAG) 38 | #endif // DBG 39 | ); 40 | if (m_LoadedModules == NULL) 41 | { 42 | return; 43 | } 44 | 45 | // 46 | // m_LoadedModules is now allocated with enough bytes to capture all modules 47 | // on the system. Query again to populate the structure. 48 | // 49 | Status = AuxKlibQueryModuleInformation( 50 | &m_SizeOfModules, 51 | sizeof(AUX_MODULE_EXTENDED_INFO), 52 | m_LoadedModules 53 | ); 54 | } 55 | 56 | AuxWrapper::~AuxWrapper() 57 | { 58 | if (m_LoadedModules != nullptr) 59 | { 60 | RtlSecureZeroMemory(m_LoadedModules, m_SizeOfModules); 61 | 62 | #ifdef DBG 63 | ExFreePoolWithTag(m_LoadedModules, AUX_POOLTAG_DBG); 64 | #else 65 | ExFreePoolWithTag(m_LoadedModules, AUX_POOLTAG); 66 | #endif // DBG 67 | 68 | m_LoadedModules = nullptr; 69 | m_SizeOfModules = NULL; 70 | m_NumberOfModules = NULL; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Gizmo/ErrorHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "ErrorHandler.h" 2 | 3 | _Use_decl_annotations_ 4 | ErrorHandler::ErrorHandler(DWORD dwError) : 5 | m_dwError(dwError), 6 | m_lpMessageBuffer(nullptr), 7 | m_ErrorAsStringW() 8 | { 9 | LPCWSTR lpMessageString = nullptr; 10 | 11 | DWORD dwBufferLen = FormatMessage( 12 | FORMAT_MESSAGE_ALLOCATE_BUFFER | 13 | FORMAT_MESSAGE_FROM_SYSTEM | 14 | FORMAT_MESSAGE_IGNORE_INSERTS, 15 | NULL, 16 | m_dwError, 17 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 18 | reinterpret_cast(&m_lpMessageBuffer), 19 | NULL, 20 | NULL 21 | ); 22 | 23 | lpMessageString = static_cast( 24 | m_lpMessageBuffer 25 | ); 26 | 27 | // 28 | // Copy the buffer into the std::wstring datatype. 29 | // 30 | m_ErrorAsStringW.assign(lpMessageString); 31 | 32 | // 33 | // FormatMessage inserts newlines into the string. It is possible to use more 34 | // formatting flags to take them out, but my brain is too smooth to do so. For 35 | // now, just use erase and remove to take them out rather than dicking with 36 | // formatting to get it right. 37 | // 38 | m_ErrorAsStringW.erase( 39 | std::remove(m_ErrorAsStringW.begin(), m_ErrorAsStringW.end(), '\n'), 40 | m_ErrorAsStringW.end() 41 | ); 42 | } 43 | 44 | ErrorHandler::~ErrorHandler() 45 | { 46 | if (m_lpMessageBuffer != nullptr) 47 | { 48 | LocalFree(m_lpMessageBuffer); 49 | m_lpMessageBuffer = nullptr; 50 | } 51 | } 52 | 53 | std::string 54 | ErrorHandler::GetLastErrorAsStringA() 55 | { 56 | std::vector MessageBuffer(m_ErrorAsStringW.size()); 57 | 58 | std::use_facet>(std::locale{}).narrow( 59 | m_ErrorAsStringW.data(), 60 | m_ErrorAsStringW.data() + m_ErrorAsStringW.size(), 61 | '?', 62 | MessageBuffer.data() 63 | ); 64 | 65 | return std::string(MessageBuffer.data(), MessageBuffer.size()); 66 | } 67 | 68 | std::wstring 69 | ErrorHandler::GetLastErrorAsStringW() 70 | { 71 | return m_ErrorAsStringW; 72 | } 73 | 74 | 75 | /// EOF -------------------------------------------------------------------------------- /Gremlins/detour.cpp: -------------------------------------------------------------------------------- 1 | #include "detour.h" 2 | 3 | /// 4 | /// Hooks the region of memory specified. This is done by resolving the virtual 5 | /// addresses physical address and then mapping it into userspace with 6 | /// MmMapIoSpace as read/write. 7 | /// After the hook is placed, the mapped address gets unmapped with MmUnmapIoSpace. 8 | /// 9 | /// 10 | /// 11 | /// 12 | /// STATUS_SUCCESS 13 | /// STATUS_INSUFFICIENT_RESOURCES 14 | _Use_decl_annotations_ 15 | NTSTATUS 16 | detour::hook( 17 | PVOID BaseAddress, 18 | PUINT8 patch, 19 | size_t szSize 20 | ) 21 | { 22 | PHYSICAL_ADDRESS pa = MmGetPhysicalAddress(BaseAddress); 23 | 24 | PVOID mappedAddress = MmMapIoSpace(pa, 0x60, MmNonCached); 25 | if (mappedAddress == NULL) 26 | { 27 | return STATUS_INSUFFICIENT_RESOURCES; 28 | } 29 | 30 | RtlCopyMemory(mappedAddress, patch, szSize); 31 | 32 | MmUnmapIoSpace(mappedAddress, 0x60); 33 | 34 | return STATUS_SUCCESS; 35 | } 36 | 37 | /// 38 | /// Unhooks the region of memory specified. This function does the same thing as 39 | /// detour::hook, but copies the original bytes instead putting the function into its 40 | /// original state. 41 | /// 42 | /// 43 | /// 44 | /// 45 | /// STATUS_SUCCESS 46 | /// STATUS_INSUFFICIENT_RESOURCES 47 | _Use_decl_annotations_ 48 | NTSTATUS 49 | detour::unhook( 50 | PVOID BaseAddress, 51 | PUINT8 Source, 52 | UINT8 szSize 53 | ) 54 | { 55 | PHYSICAL_ADDRESS pa = MmGetPhysicalAddress(BaseAddress); 56 | 57 | PVOID mappedAddress = MmMapIoSpace(pa, 0x60, MmNonCached); 58 | if (mappedAddress == NULL) 59 | { 60 | return STATUS_INSUFFICIENT_RESOURCES; 61 | } 62 | 63 | RtlCopyMemory(mappedAddress, Source, szSize); 64 | 65 | MmUnmapIoSpace(mappedAddress, 0x60); 66 | 67 | return STATUS_SUCCESS; 68 | } 69 | 70 | 71 | /// EOF -------------------------------------------------------------------------------- /Gremlins/kutypes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | //================================================================================ 5 | // Definitions 6 | //================================================================================ 7 | constexpr ULONG kuPoolTagDbg = 'bDuK'; 8 | constexpr ULONG kuPoolTag = 'yTuK'; 9 | 10 | //================================================================================ 11 | // Types 12 | //================================================================================ 13 | #ifndef SID_IDENTIFIER_AUTHORITY_DEFINED 14 | #define SID_IDENTIFIER_AUTHORITY_DEFINED 15 | typedef struct _SID_IDENTIFIER_AUTHORITY { 16 | UCHAR Value[6]; 17 | } SID_IDENTIFIER_AUTHORITY, * PSID_IDENTIFIER_AUTHORITY; 18 | #endif 19 | 20 | #define SECURITY_WORLD_SID_AUTHORITY {0,0,0,0,0,1} 21 | 22 | typedef struct _ACE_HEADER { 23 | UCHAR AceType; 24 | UCHAR AceFlags; 25 | USHORT AceSize; 26 | } ACE_HEADER; 27 | 28 | typedef struct _ACCESS_ALLOWED_ACE { 29 | ACE_HEADER Header; 30 | ACCESS_MASK Mask; 31 | ULONG SidStart; 32 | } ACCESS_ALLOWED_ACE, * PACCESS_ALLOWED_ACE; 33 | 34 | //================================================================================ 35 | // Exported Functions 36 | //================================================================================ 37 | EXTERN_C_START 38 | NTSYSAPI 39 | NTSTATUS 40 | NTAPI 41 | RtlGetDaclSecurityDescriptor( 42 | _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 43 | _Out_ PBOOLEAN DaclPresent, 44 | _Outptr_result_maybenull_ PACL* Dacl, 45 | _Pre_ _Writable_elements_(1) 46 | _When_(!(*DaclPresent), _Post_invalid_) 47 | _When_((*DaclPresent), _Post_valid_) 48 | PBOOLEAN DaclDefaulted 49 | ); 50 | 51 | NTSYSAPI 52 | ULONG 53 | NTAPI 54 | RtlLengthRequiredSid( 55 | _In_ ULONG SubAuthorityCount 56 | ); 57 | 58 | NTSYSAPI 59 | NTSTATUS 60 | NTAPI 61 | RtlInitializeSid( 62 | _Out_ PSID Sid, 63 | _In_ PSID_IDENTIFIER_AUTHORITY IdentifierAuthority, 64 | _In_ UCHAR SubAuthorityCount 65 | ); 66 | 67 | NTSYSAPI 68 | NTSTATUS 69 | NTAPI 70 | RtlGetAce( 71 | _In_ PACL Acl, 72 | _In_ ULONG AceIndex, 73 | _Outptr_ PVOID* Ace 74 | ); 75 | 76 | NTSYSAPI 77 | BOOLEAN 78 | NTAPI 79 | RtlEqualSid( 80 | _In_ PSID Sid1, 81 | _In_ PSID Sid2 82 | ); 83 | EXTERN_C_END 84 | 85 | 86 | /// EOF -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /Gizmo/Gizmo.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {c9848c02-8ef7-4727-8e36-39b8ab50f4ea} 18 | 19 | 20 | {fa1376f1-cf34-4f10-8580-4cbf93acfc5c} 21 | 22 | 23 | {eb9a9c23-49c3-4154-a3d4-622eec9d81a6} 24 | 25 | 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files\Classes 32 | 33 | 34 | Source Files\Classes 35 | 36 | 37 | Source Files\Classes 38 | 39 | 40 | Source Files\Classes 41 | 42 | 43 | 44 | 45 | Header Files\Types 46 | 47 | 48 | Header Files\Classes 49 | 50 | 51 | Header Files\Classes 52 | 53 | 54 | Header Files\Classes 55 | 56 | 57 | Header Files\Classes 58 | 59 | 60 | Header Files\Classes 61 | 62 | 63 | Header Files\Classes 64 | 65 | 66 | Header Files\Types 67 | 68 | 69 | -------------------------------------------------------------------------------- /Gizmo/Gizmo.h: -------------------------------------------------------------------------------- 1 | // Gizmo.h : This file is the driver for Gremlins. All Gremlin interaction happens here. Used in main(). 2 | // 3 | #pragma once 4 | #include 5 | #include 6 | 7 | #include "types.h" 8 | #include "ErrorHandler.h" 9 | #include "BaseDriverclient.h" 10 | #include "NtUndoc.h" 11 | 12 | class Gizmo : 13 | public BaseDriverClient 14 | { 15 | public: 16 | /// 17 | /// The constructor is responsible for grabbing the handle to Gremlins 18 | /// to interact with the kernel. Once that is done, it will then 19 | /// initialize Gremlins to begin introspection and/or fuzzing (when implemented). 20 | /// 21 | Gizmo(); 22 | ~Gizmo(); 23 | 24 | /// 25 | /// This method will query the system for the machine's kernel debugging 26 | /// information via NtQuerySystemInformation. Two things will be checked: 27 | /// 1. Is debugging enabled. 28 | /// 2. Is a debugger present. 29 | /// 30 | /// TRUE. If debugging is not enabled or present, will return FALSE. 31 | BOOL IsBeingKernelDebugged(); 32 | 33 | /// 34 | /// This method will check if a chosen syscall is hooked. 35 | /// 36 | /// 37 | /// 38 | /// true. If this method fails, reference GetLastError(). 39 | bool IsSyscallHooked( 40 | _In_z_ LPCSTR lpProcName, 41 | _Inout_ PINPUT_BUFFER lpInputBuffer 42 | ); 43 | 44 | /// 45 | /// This method will hook the syscall via Gremlins. 46 | /// 47 | /// 48 | /// true. If this method fails, reference GetLastError(). 49 | bool HookSyscall( 50 | _In_ PINPUT_BUFFER lpInputBuffer 51 | ); 52 | 53 | /// 54 | /// This method gives the capability of unhooking the syscall. 55 | /// 56 | /// 57 | /// true. If this method fails, reference GetLastError(). 58 | bool UnhookSyscall( 59 | _In_ PINPUT_BUFFER lpInputBuffer 60 | ); 61 | 62 | /// 63 | /// If an error should occur, this method will return what happened 64 | /// in a std::wstring format. 65 | /// 66 | /// std::wstring 67 | std::wstring what(); 68 | 69 | protected: 70 | std::unique_ptr m_pNtUndoc; 71 | 72 | /// 73 | /// This method will resolve the syscall value by using GetProcAddress 74 | /// to resolve a function. It will scan for the syscall signature and if 75 | /// it was found, outputs it into the SyscallValue var. 76 | /// 77 | /// This method will only fail if the module was not found or if the syscall 78 | /// is already hooked. If it is hooked already, this indicates an AV is 79 | /// present on the system. 80 | /// 81 | /// 82 | /// 83 | /// true. May return ERROR_MOD_NOT_FOUND, ERROR_INVALID_MODULETYPE, or 84 | /// another value that can be checked via GetLastError() upon failure. 85 | bool ResolveSyscall( 86 | _In_z_ LPCSTR lpProcName, 87 | _Out_ PUINT16 SyscallValue 88 | ); 89 | 90 | private: 91 | const wchar_t* m_wszServiceName; 92 | std::unique_ptr m_pError; 93 | }; 94 | 95 | 96 | /// EOF -------------------------------------------------------------------------------- /Gremlins/ntdeviceiocontrolfile.cpp: -------------------------------------------------------------------------------- 1 | #include "ntdeviceiocontrolfile.h" 2 | 3 | _Use_decl_annotations_ 4 | NTSTATUS 5 | fn_hNtDeviceIoControlFile( 6 | HANDLE FileHandle, 7 | HANDLE Event, 8 | PIO_APC_ROUTINE ApcRoutine, 9 | PVOID ApcContext, 10 | PIO_STATUS_BLOCK IoStatusBlock, 11 | ULONG IoControlCode, 12 | PVOID InputBuffer, 13 | ULONG InputBufferLength, 14 | PVOID OutputBuffer, 15 | ULONG OutputBufferLength 16 | ) 17 | { 18 | NTSTATUS Status = STATUS_UNSUCCESSFUL; 19 | NTSTATUS hStatus = STATUS_UNSUCCESSFUL; 20 | 21 | BOOLEAN bIsFriendly = FALSE; 22 | 23 | UINT64 LeakedAddress = 0; 24 | 25 | Status = g_Globals->internal.IopXxxControlFile( 26 | FileHandle, 27 | Event, 28 | ApcRoutine, 29 | ApcContext, 30 | IoStatusBlock, 31 | IoControlCode, 32 | InputBuffer, 33 | InputBufferLength, 34 | OutputBuffer, 35 | OutputBufferLength, 36 | TRUE 37 | ); 38 | 39 | KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 40 | 41 | // 42 | // Only interested in calls coming from within usermode. 43 | // 44 | if (PreviousMode == UserMode) 45 | { 46 | // 47 | // The following tests are not taxing, therefore, these tests can be done with no performance 48 | // impact. If fuzz logic will be introduced, threads would need to be fired off otherwise the 49 | // system would come to a crawl. 50 | // 51 | ProcessHandle ph = ProcessHandle(FileHandle); 52 | 53 | // 54 | // Analyze the handle of the file object. 55 | // 56 | hStatus = ph.AnalyzeHandle(); 57 | if (NT_SUCCESS(hStatus)) 58 | { 59 | // 60 | // Do a quick leak test to see if there are any kernel address leaks. 61 | // 62 | Leaks LeakTesting = Leaks( 63 | static_cast(OutputBuffer), 64 | OutputBufferLength 65 | ); 66 | 67 | LeakedAddress = LeakTesting.DidKernelAddressLeak(); 68 | if (LeakedAddress != NULL) 69 | { 70 | // 71 | // TODO: extend the AUX wrapper to find out what module address was leaked. 72 | // 73 | LOG_INFO("[%ws::%d] Kernel address leaked: %p.\n", __FUNCTIONW__, __LINE__, LeakedAddress); 74 | } 75 | 76 | // 77 | // The privileges method is used to check if the device object in question is low 78 | // integrity friendly. Would be a potential SBX/AppContainer escape! 79 | // 80 | privileges p = privileges(ph.GetFileObjectSD()); 81 | 82 | hStatus = p.IsLowIntegrityFriendly(&bIsFriendly); 83 | if (NT_SUCCESS(hStatus)) 84 | { 85 | if (bIsFriendly) 86 | { 87 | LOG_INFO("[%ws::%d] SBX friendly.\n", __FUNCTIONW__, __LINE__); 88 | } 89 | } 90 | else 91 | { 92 | LOG_ERR("[%ws::%d] Failed with status 0x%08x.\n", __FUNCTIONW__, __LINE__, hStatus); 93 | } 94 | } 95 | else 96 | { 97 | LOG_ERR("[%ws::%d] Failed with status 0x%08x.\n", __FUNCTIONW__, __LINE__, hStatus); 98 | } 99 | } 100 | 101 | return Status; 102 | } 103 | 104 | 105 | /// EOF -------------------------------------------------------------------------------- /Gremlins/privileges.cpp: -------------------------------------------------------------------------------- 1 | #include "privileges.h" 2 | 3 | privileges::privileges() : 4 | m_SecurityDescriptor(nullptr), 5 | m_EveryoneSid(nullptr), 6 | m_EveryoneSidLength(NULL) 7 | { 8 | } 9 | 10 | privileges::~privileges() 11 | { 12 | if (m_EveryoneSid != nullptr && m_EveryoneSidLength > 0) 13 | { 14 | RtlSecureZeroMemory(m_EveryoneSid, m_EveryoneSidLength); 15 | 16 | #ifdef DBG 17 | ExFreePoolWithTag(m_EveryoneSid, kuPoolTagDbg); 18 | #else 19 | ExFreePoolWithTag(m_EveryoneSid, kuPoolTag); 20 | #endif // DBG 21 | m_EveryoneSid = nullptr; 22 | } 23 | 24 | m_EveryoneSidLength = NULL; 25 | } 26 | 27 | _Use_decl_annotations_ 28 | privileges::privileges(PSECURITY_DESCRIPTOR SecurityDescriptor) : 29 | m_SecurityDescriptor(SecurityDescriptor), 30 | m_EveryoneSid(nullptr), 31 | m_EveryoneSidLength(NULL) 32 | { 33 | } 34 | 35 | _Use_decl_annotations_ 36 | NTSTATUS privileges::IsLowIntegrityFriendly(PBOOLEAN IsFriendly) 37 | { 38 | SID_IDENTIFIER_AUTHORITY EveryoneSidAuthority = SECURITY_WORLD_SID_AUTHORITY; 39 | 40 | PACL pDacl = nullptr; 41 | PACCESS_ALLOWED_ACE pAllowedAce = nullptr; 42 | 43 | BOOLEAN bDaclPresent = NULL; 44 | BOOLEAN bDaclDefaulted = NULL; 45 | 46 | NTSTATUS Status = STATUS_UNSUCCESSFUL; 47 | 48 | *IsFriendly = FALSE; 49 | 50 | // 51 | // Get the DACL of the driver's security descriptor. If a Dacl is 52 | // not present, bail. 53 | // 54 | Status = RtlGetDaclSecurityDescriptor( 55 | m_SecurityDescriptor, 56 | &bDaclPresent, 57 | &pDacl, 58 | &bDaclDefaulted 59 | ); 60 | if (!NT_SUCCESS(Status) || !bDaclPresent) 61 | { 62 | return Status; 63 | } 64 | 65 | // 66 | // According to the MSDN, if the dacl is present and the dacl 67 | // is NULL, this means that all access is allowed to this object. Place 68 | // a breakpoint here to see what kind of goodies could lie ahead. I've 69 | // never seen this before so it should be interesting >:) 70 | // 71 | if (bDaclPresent && pDacl == NULL) 72 | { 73 | DbgPrint("This object allows all access!\n"); 74 | DbgBreakPoint(); 75 | } 76 | 77 | // 78 | // Get the size of the buffer needed to store the SID. 79 | // 80 | m_EveryoneSidLength = RtlLengthRequiredSid(1); 81 | 82 | m_EveryoneSid = static_cast( 83 | #ifdef DBG 84 | ExAllocatePool2(POOL_FLAG_NON_PAGED | POOL_FLAG_SPECIAL_POOL, m_EveryoneSidLength, kuPoolTagDbg) 85 | #else 86 | ExAllocatePool2(POOL_FLAG_NON_PAGED, m_EveryoneSidLength, kuPoolTag) 87 | #endif // DBG 88 | ); 89 | if (m_EveryoneSid == NULL) 90 | { 91 | return STATUS_MEMORY_NOT_ALLOCATED; 92 | } 93 | 94 | // 95 | // Initialize the SID 96 | // 97 | Status = RtlInitializeSid(m_EveryoneSid, &EveryoneSidAuthority, 1); 98 | if (!NT_SUCCESS(Status)) 99 | { 100 | return Status; 101 | } 102 | 103 | // 104 | // Now iterate through all the entries and check to see if we have 105 | // one that contains the everyone sid. If so, this object is low integrity 106 | // friendly. 107 | // 108 | for (USHORT i = 0; i < pDacl->AceCount; i++) 109 | { 110 | Status = RtlGetAce(pDacl, i, reinterpret_cast(&pAllowedAce)); 111 | if (NT_SUCCESS(Status) && pAllowedAce != nullptr) 112 | { 113 | if (RtlEqualSid(m_EveryoneSid, &pAllowedAce->SidStart)) 114 | { 115 | *IsFriendly = TRUE; 116 | break; 117 | } 118 | } 119 | } 120 | 121 | return Status; 122 | } 123 | -------------------------------------------------------------------------------- /Gremlins/ProcessHandle.cpp: -------------------------------------------------------------------------------- 1 | #include "ProcessHandle.h" 2 | 3 | ProcessHandle::ProcessHandle() : 4 | m_FileHandle(reinterpret_cast(-1)), 5 | m_FileObject(nullptr), 6 | m_NameInformation(nullptr), 7 | m_ReturnLength(NULL) 8 | { 9 | } 10 | 11 | ProcessHandle::~ProcessHandle() 12 | { 13 | // 14 | // Clean up the buffers that have been created. 15 | // 16 | if (m_NameInformation != nullptr && m_ReturnLength != NULL) 17 | { 18 | RtlSecureZeroMemory(m_NameInformation, m_ReturnLength); 19 | 20 | #ifdef DBG 21 | ExFreePoolWithTag(m_NameInformation, phPoolTagDbg); 22 | #else 23 | ExFreePoolWithTag(m_NameInformation, phPoolTag); 24 | #endif // DBG 25 | 26 | m_NameInformation = nullptr; 27 | m_ReturnLength = NULL; 28 | } 29 | 30 | // 31 | // If the file object was created, decrement the reference count since 32 | // we are finished using the object. 33 | // 34 | if (m_FileObject != nullptr) 35 | { 36 | #ifdef DBG 37 | ObDereferenceObjectWithTag(m_FileObject, ObReferenceTag); 38 | #else 39 | ObDereferenceObject(m_FileObject); 40 | #endif // DBG 41 | m_FileObject = nullptr; 42 | } 43 | } 44 | 45 | _Use_decl_annotations_ 46 | ProcessHandle::ProcessHandle(HANDLE hFileHandle) : 47 | m_FileHandle(hFileHandle), 48 | m_FileObject(nullptr), 49 | m_NameInformation(nullptr), 50 | m_ReturnLength(NULL) 51 | { 52 | } 53 | 54 | NTSTATUS ProcessHandle::AnalyzeHandle() 55 | { 56 | NTSTATUS Status = STATUS_UNSUCCESSFUL; 57 | 58 | // 59 | // Get the pointer to the object that the handle belongs to. 60 | // ObReferenceObjectByHandleWithTag increments the reference count of the 61 | // object that is identified. If debugging is needed, use dat hoe 62 | // !obtrace. 63 | // 64 | #ifdef DBG 65 | Status = ObReferenceObjectByHandleWithTag( 66 | m_FileHandle, 67 | NULL, 68 | NULL, 69 | UserMode, 70 | ObReferenceTag, 71 | reinterpret_cast(&m_FileObject), 72 | NULL 73 | ); 74 | #else 75 | Status = ObReferenceObjectByHandle( 76 | m_FileHandle, 77 | NULL, 78 | NULL, 79 | UserMode, 80 | reinterpret_cast(&m_FileObject), 81 | NULL 82 | ); 83 | #endif // DBG 84 | if (!NT_SUCCESS(Status) || m_FileObject == nullptr) 85 | { 86 | return Status; 87 | } 88 | 89 | // 90 | // Now start pulling information from the object. The DeviceObject will be 91 | // retrieved first to read from the flags. If the device object has the flag 92 | // DO_DEVICE_HAS_NAME, this means there's a name to get. 93 | // 94 | if (m_FileObject->DeviceObject->Flags & DO_DEVICE_HAS_NAME) 95 | { 96 | // 97 | // Resolve the size needed to allocate for the name of the device object. 98 | // The device name is of type PUNICODE_STRING. 99 | // 100 | do 101 | { 102 | Status = ZwQueryObject( 103 | m_FileHandle, 104 | ObjectNameInformation, 105 | m_NameInformation, 106 | m_ReturnLength, 107 | &m_ReturnLength 108 | ); 109 | if (!NT_SUCCESS(Status) && Status == STATUS_INFO_LENGTH_MISMATCH) 110 | { 111 | if (m_NameInformation != nullptr) 112 | { 113 | #ifdef DBG 114 | ExFreePoolWithTag(m_NameInformation, phPoolTagDbg); 115 | #else 116 | ExFreePoolWithTag(m_NameInformation, phPoolTag); 117 | #endif // DBG 118 | m_NameInformation = nullptr; 119 | } 120 | 121 | m_NameInformation = static_cast( 122 | #ifdef DBG 123 | ExAllocatePool2(POOL_FLAG_NON_PAGED | POOL_FLAG_SPECIAL_POOL, m_ReturnLength, phPoolTagDbg) 124 | #else 125 | ExAllocatePool2(POOL_FLAG_NON_PAGED, m_ReturnLength, phPoolTag) 126 | #endif // DBG 127 | ); 128 | if (m_NameInformation == NULL) 129 | { 130 | return STATUS_MEMORY_NOT_ALLOCATED; 131 | } 132 | } 133 | } while (!NT_SUCCESS(Status)); 134 | } 135 | 136 | return Status; 137 | } 138 | 139 | PSECURITY_DESCRIPTOR ProcessHandle::GetFileObjectSD() 140 | { 141 | return m_FileObject->DeviceObject->SecurityDescriptor; 142 | } 143 | 144 | 145 | /// EOF -------------------------------------------------------------------------------- /Gremlins.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31205.134 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Gremlins", "Gremlins\Gremlins.vcxproj", "{EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Gizmo", "Gizmo\Gizmo.vcxproj", "{5F7BAACC-C0D3-4027-86F3-F0DD0E9B3A4B}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|ARM = Debug|ARM 13 | Debug|ARM64 = Debug|ARM64 14 | Debug|x64 = Debug|x64 15 | Debug|x86 = Debug|x86 16 | Release|ARM = Release|ARM 17 | Release|ARM64 = Release|ARM64 18 | Release|x64 = Release|x64 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Debug|ARM.ActiveCfg = Debug|ARM 23 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Debug|ARM.Build.0 = Debug|ARM 24 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Debug|ARM.Deploy.0 = Debug|ARM 25 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Debug|ARM64.ActiveCfg = Debug|ARM64 26 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Debug|ARM64.Build.0 = Debug|ARM64 27 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Debug|ARM64.Deploy.0 = Debug|ARM64 28 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Debug|x64.ActiveCfg = Debug|x64 29 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Debug|x64.Build.0 = Debug|x64 30 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Debug|x64.Deploy.0 = Debug|x64 31 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Debug|x86.ActiveCfg = Debug|Win32 32 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Debug|x86.Build.0 = Debug|Win32 33 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Debug|x86.Deploy.0 = Debug|Win32 34 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Release|ARM.ActiveCfg = Release|ARM 35 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Release|ARM.Build.0 = Release|ARM 36 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Release|ARM.Deploy.0 = Release|ARM 37 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Release|ARM64.ActiveCfg = Release|ARM64 38 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Release|ARM64.Build.0 = Release|ARM64 39 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Release|ARM64.Deploy.0 = Release|ARM64 40 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Release|x64.ActiveCfg = Release|x64 41 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Release|x64.Build.0 = Release|x64 42 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Release|x64.Deploy.0 = Release|x64 43 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Release|x86.ActiveCfg = Release|Win32 44 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Release|x86.Build.0 = Release|Win32 45 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6}.Release|x86.Deploy.0 = Release|Win32 46 | {5F7BAACC-C0D3-4027-86F3-F0DD0E9B3A4B}.Debug|ARM.ActiveCfg = Debug|Win32 47 | {5F7BAACC-C0D3-4027-86F3-F0DD0E9B3A4B}.Debug|ARM64.ActiveCfg = Debug|Win32 48 | {5F7BAACC-C0D3-4027-86F3-F0DD0E9B3A4B}.Debug|x64.ActiveCfg = Debug|x64 49 | {5F7BAACC-C0D3-4027-86F3-F0DD0E9B3A4B}.Debug|x64.Build.0 = Debug|x64 50 | {5F7BAACC-C0D3-4027-86F3-F0DD0E9B3A4B}.Debug|x86.ActiveCfg = Debug|Win32 51 | {5F7BAACC-C0D3-4027-86F3-F0DD0E9B3A4B}.Debug|x86.Build.0 = Debug|Win32 52 | {5F7BAACC-C0D3-4027-86F3-F0DD0E9B3A4B}.Release|ARM.ActiveCfg = Release|Win32 53 | {5F7BAACC-C0D3-4027-86F3-F0DD0E9B3A4B}.Release|ARM64.ActiveCfg = Release|Win32 54 | {5F7BAACC-C0D3-4027-86F3-F0DD0E9B3A4B}.Release|x64.ActiveCfg = Release|x64 55 | {5F7BAACC-C0D3-4027-86F3-F0DD0E9B3A4B}.Release|x64.Build.0 = Release|x64 56 | {5F7BAACC-C0D3-4027-86F3-F0DD0E9B3A4B}.Release|x86.ActiveCfg = Release|Win32 57 | {5F7BAACC-C0D3-4027-86F3-F0DD0E9B3A4B}.Release|x86.Build.0 = Release|Win32 58 | EndGlobalSection 59 | GlobalSection(SolutionProperties) = preSolution 60 | HideSolutionNode = FALSE 61 | EndGlobalSection 62 | GlobalSection(ExtensibilityGlobals) = postSolution 63 | SolutionGuid = {1DF2D0B5-DED1-47F1-A212-8247506559D7} 64 | EndGlobalSection 65 | EndGlobal 66 | -------------------------------------------------------------------------------- /Gremlins/resolve.cpp: -------------------------------------------------------------------------------- 1 | #include "resolve.h" 2 | 3 | /// 4 | /// Resolves nt!KiSystemServiceUser by searching for the ret instruction: 5 | /// jmp nt!KiSystemServiceUser (fffff806`4a007500) 6 | /// ret 7 | /// The jmp instruction directly before is what I am after because of it jumping 8 | /// directly to nt!KiSystemServiceUser. 9 | /// 10 | /// 11 | /// 12 | /// STATUS_SUCCESS/STATUS_NOT_FOUND 13 | _Use_decl_annotations_ 14 | NTSTATUS resolve::KiSystemServiceUser(UINT64 address, PUINT64 result) 15 | { 16 | UINT8 value = 0; 17 | 18 | do 19 | { 20 | value = *reinterpret_cast(address); 21 | if (value == 0xc3) 22 | { 23 | UINT64 mask = 0xffffffff00000000; 24 | UINT32 offset = 0; 25 | 26 | RtlCopyMemory(&offset, reinterpret_cast(address - 4), sizeof(offset)); 27 | 28 | mask |= offset; 29 | 30 | *result = address + mask; 31 | return STATUS_SUCCESS; 32 | } 33 | address++; 34 | } while (true); 35 | 36 | return STATUS_NOT_FOUND; 37 | } 38 | 39 | /// 40 | /// Resolves nt!KeServiceDescriptorTable by searching for the following lea instruction: 41 | /// lea r10,[nt!KeServiceDescriptorTable (fffff806`4aa018c0)] 42 | /// This works because their is only one instance of it in the entire nt!KiSystemServiceUser. 43 | /// 44 | /// 45 | /// 46 | /// STATUS_SUCCESS/STATUS_NOT_FOUND 47 | _Use_decl_annotations_ 48 | NTSTATUS resolve::KeServiceDescriptorTable(UINT64 address, PUINT64 result) 49 | { 50 | UINT8 SsdtStub[] = { 51 | 0x4c, 0x8d, 0x15 52 | }; 53 | 54 | do 55 | { 56 | if (RtlCompareMemory(reinterpret_cast(address), SsdtStub, sizeof(SsdtStub)) == sizeof(SsdtStub)) 57 | { 58 | UINT32 offset = 0; 59 | 60 | address += sizeof(SsdtStub); 61 | 62 | RtlCopyMemory(&offset, reinterpret_cast(address), sizeof(offset)); 63 | 64 | address += offset + 4; 65 | *result = address; 66 | 67 | return STATUS_SUCCESS; 68 | } 69 | address++; 70 | } while (true); 71 | return STATUS_NOT_FOUND; 72 | } 73 | 74 | /// 75 | /// Resolves nt!IopXxxControlFile by searching for the following call instruction: 76 | /// call nt!IopXxxControlFile (fffff806`7cdfcc10) 77 | /// This works because there is only one instance of it in the entire nt!NtDeviceIoControlFile 78 | /// function. 79 | /// 80 | /// 81 | /// 82 | /// STATUS_SUCCESS/STATUS_NOT_FOUND 83 | _Use_decl_annotations_ 84 | NTSTATUS resolve::IopXxxControlFile(UINT64 address, PUINT64 result) 85 | { 86 | UINT8 value = 0; 87 | 88 | do 89 | { 90 | value = *reinterpret_cast(address); 91 | if (value == 0xe8) 92 | { 93 | UINT32 offset = 0; 94 | 95 | RtlCopyMemory(&offset, reinterpret_cast(address + 1), sizeof(offset)); 96 | 97 | *result = address + offset + 5; 98 | 99 | return STATUS_SUCCESS; 100 | } 101 | address++; 102 | } while (value != 0xc3); 103 | 104 | return STATUS_NOT_FOUND; 105 | } 106 | 107 | /// 108 | /// Resolves nt!IopCreateFile by searching for the following call instruction: 109 | /// call nt!IopCreateFile (fffff806`7ce6d230) 110 | /// This works because there is only one instance of it in the entire nt!NtDeviceIoControlFile 111 | /// function. 112 | /// 113 | /// 114 | /// 115 | /// STATUS_SUCCESS/STATUS_NOT_FOUND 116 | _Use_decl_annotations_ 117 | NTSTATUS resolve::IopCreateFile(UINT64 address, PUINT64 result) 118 | { 119 | UINT8 value = 0; 120 | 121 | do 122 | { 123 | value = *reinterpret_cast(address); 124 | if (value == 0xe8) 125 | { 126 | UINT32 offset = 0; 127 | 128 | RtlCopyMemory(&offset, reinterpret_cast(address + 1), sizeof(offset)); 129 | 130 | *result = address + offset + 5; 131 | 132 | return STATUS_SUCCESS; 133 | } 134 | address++; 135 | } while (true); 136 | } 137 | 138 | 139 | /// EOF -------------------------------------------------------------------------------- /Gremlins/hook.cpp: -------------------------------------------------------------------------------- 1 | #include "hook.h" 2 | 3 | /// 4 | /// Will check to see if the given function is hooked by its address. It will iterate 5 | /// through the LIST_ENTRY member of GLOBALS and check if there is a match. It will 6 | /// then return the "isHooked" member. 7 | /// 8 | /// 9 | /// true/false 10 | _Use_decl_annotations_ 11 | bool 12 | hook::isFunctionHookedByAddress( 13 | PVOID address 14 | ) 15 | { 16 | KIRQL OldIrql = 0; 17 | 18 | PLIST_ENTRY temp = nullptr; 19 | PHOOKED_SYSCALLS HookedSyscall = nullptr; 20 | 21 | ExAcquireSpinLock(&g_Globals->kSpinLock, &OldIrql); 22 | 23 | if (!IsListEmpty(&g_Globals->ListHead)) 24 | { 25 | temp = &g_Globals->ListHead; 26 | 27 | do 28 | { 29 | temp = temp->Flink; 30 | HookedSyscall = CONTAINING_RECORD(temp, HOOKED_SYSCALLS, entry); 31 | 32 | // 33 | // If an entry is found and it's our address, return the hook information. 34 | // 35 | if (HookedSyscall->address == address) 36 | { 37 | ExReleaseSpinLock(&g_Globals->kSpinLock, OldIrql); 38 | return HookedSyscall->IsHooked; 39 | } 40 | } while (temp->Flink != &g_Globals->ListHead); 41 | } 42 | 43 | ExReleaseSpinLock(&g_Globals->kSpinLock, OldIrql); 44 | return false; 45 | } 46 | 47 | _Use_decl_annotations_ 48 | bool 49 | hook::isFunctionHookedByIndex( 50 | UINT16 index 51 | ) 52 | { 53 | KIRQL OldIrql = 0; 54 | 55 | PLIST_ENTRY temp = nullptr; 56 | PHOOKED_SYSCALLS hooked = nullptr; 57 | 58 | ExAcquireSpinLock(&g_Globals->kSpinLock, &OldIrql); 59 | 60 | if (!IsListEmpty(&g_Globals->ListHead)) 61 | { 62 | temp = &g_Globals->ListHead; 63 | 64 | do 65 | { 66 | temp = temp->Flink; 67 | hooked = CONTAINING_RECORD(temp, HOOKED_SYSCALLS, entry); 68 | 69 | // 70 | // If an entry is found and it's our address, return the hook information. 71 | // 72 | if (hooked->Index == index) 73 | { 74 | ExReleaseSpinLock(&g_Globals->kSpinLock, OldIrql); 75 | return hooked->IsHooked; 76 | } 77 | } while (temp->Flink != &g_Globals->ListHead); 78 | } 79 | 80 | ExReleaseSpinLock(&g_Globals->kSpinLock, OldIrql); 81 | return false; 82 | } 83 | 84 | _Use_decl_annotations_ 85 | NTSTATUS 86 | hook::unhookFunction( 87 | UINT16 index 88 | ) 89 | { 90 | KIRQL OldIrql = 0; 91 | 92 | PLIST_ENTRY temp = nullptr; 93 | PHOOKED_SYSCALLS hooked = nullptr; 94 | 95 | NTSTATUS Status = STATUS_NOT_FOUND; 96 | 97 | ExAcquireSpinLock(&g_Globals->kSpinLock, &OldIrql); 98 | 99 | if (!IsListEmpty(&g_Globals->ListHead)) 100 | { 101 | temp = &g_Globals->ListHead; 102 | 103 | do 104 | { 105 | temp = temp->Flink; 106 | hooked = CONTAINING_RECORD(temp, HOOKED_SYSCALLS, entry); 107 | 108 | // 109 | // If an entry is found and it's our address, check if its hooked. If it is hooked, 110 | // unhook it. 111 | // 112 | if (hooked->Index == index && hooked->IsHooked) 113 | { 114 | Status = detour::unhook( 115 | hooked->address, 116 | hooked->original, 117 | sizeof(hooked->original) 118 | ); 119 | 120 | // 121 | // Since we are unhooking this entry, we no longer need it inside our list. 122 | // Safe to remove it. 123 | // 124 | RemoveEntryList(temp); 125 | 126 | // 127 | // Now the entry is removed, zero this region of memory and then free it. 128 | // 129 | RtlSecureZeroMemory(hooked, sizeof(HOOKED_SYSCALLS)); 130 | 131 | #ifdef DBG 132 | ExFreePoolWithTag(hooked, POOLTAG_DBG); 133 | #else 134 | ExFreePoolWithTag(hooked, POOLTAG); 135 | #endif // DBG 136 | 137 | ExReleaseSpinLock(&g_Globals->kSpinLock, OldIrql); 138 | 139 | return Status; 140 | } 141 | } while (temp->Flink != &g_Globals->ListHead); 142 | } 143 | 144 | ExReleaseSpinLock(&g_Globals->kSpinLock, OldIrql); 145 | return Status; 146 | } 147 | 148 | void 149 | hook::cleanup() 150 | { 151 | PLIST_ENTRY pe = nullptr; 152 | PHOOKED_SYSCALLS hooked = nullptr; 153 | 154 | do 155 | { 156 | pe = ExInterlockedRemoveHeadList( 157 | &g_Globals->ListHead, 158 | &g_Globals->kInterlockedSpinLock 159 | ); 160 | 161 | hooked = CONTAINING_RECORD(pe, HOOKED_SYSCALLS, entry); 162 | 163 | RtlSecureZeroMemory(hooked, sizeof(HOOKED_SYSCALLS)); 164 | 165 | #ifdef DBG 166 | ExFreePoolWithTag(hooked, POOLTAG_DBG); 167 | #else 168 | ExFreePoolWithTag(hooked, POOLTAG); 169 | #endif // DBG 170 | 171 | } while (!IsListEmpty(&g_Globals->ListHead)); 172 | } 173 | 174 | 175 | /// EOF -------------------------------------------------------------------------------- /Gizmo/ServiceController.cpp: -------------------------------------------------------------------------------- 1 | #include "ServiceController.h" 2 | 3 | void ServiceController::ServiceCleanUp() 4 | { 5 | SERVICE_STATUS_PROCESS ssp = { 0 }; 6 | 7 | DWORD dwBytesNeeded = NULL; 8 | DWORD dwWaitTime = NULL; 9 | 10 | bool bStatus = false; 11 | 12 | // 13 | // We should have the handle for the service controller, but 14 | // if the service handle is not populated, open a handle to the 15 | // service with delete, query, and stopping rights. 16 | // 17 | if (m_schSCManager != NULL && m_schService == NULL) 18 | { 19 | m_schService = OpenService( 20 | m_schSCManager, 21 | m_wszServiceName, 22 | DELETE | 23 | SERVICE_QUERY_STATUS | 24 | SERVICE_STOP 25 | ); 26 | } 27 | 28 | if (m_schSCManager != NULL && m_schService != NULL) 29 | { 30 | // 31 | // Check to see if the service is up and running. If so, 32 | // send the signal to stop it. 33 | // 34 | bStatus = ControlService( 35 | m_schService, 36 | SERVICE_CONTROL_STOP, 37 | reinterpret_cast(&ssp) 38 | ); 39 | if (bStatus) 40 | { 41 | // 42 | // Query the status of the service. If it is stopped, go ahead and 43 | // delete; otherwise, wait for the service to stop. 44 | // 45 | if (ssp.dwCurrentState != SERVICE_STOPPED) 46 | { 47 | // 48 | // Keep querying the state of the service until the service has 49 | // stopped. 50 | // 51 | while (ssp.dwCurrentState != SERVICE_STOPPED) 52 | { 53 | Sleep(ssp.dwWaitHint); 54 | 55 | bStatus = QueryServiceStatusEx( 56 | m_schService, 57 | SC_STATUS_PROCESS_INFO, 58 | reinterpret_cast(&ssp), 59 | sizeof(SERVICE_STATUS_PROCESS), 60 | &dwBytesNeeded 61 | ); 62 | if (!bStatus) 63 | { 64 | m_pError = std::make_unique(GetLastError()); 65 | throw std::runtime_error(m_pError->GetLastErrorAsStringA()); 66 | } 67 | } 68 | } 69 | 70 | // 71 | // Delete the service now that it's stopped. 72 | // 73 | //DeleteService(schService); 74 | } 75 | else if (!bStatus && GetLastError() == ERROR_SERVICE_NOT_ACTIVE) 76 | { 77 | // 78 | // If the service is not active, this means the service does exist so 79 | // we can delete it. 80 | // 81 | //DeleteService(schService); 82 | } 83 | } 84 | } 85 | 86 | ServiceController::ServiceController() : 87 | m_pError(nullptr), 88 | m_wszServiceName(L"Gremlins"), 89 | m_schSCManager(NULL), 90 | m_schService(NULL), 91 | m_bDoesServiceExist(TRUE) 92 | { 93 | // 94 | // Grab a handle to the service controller manager. 95 | // 96 | m_schSCManager = OpenSCManager( 97 | NULL, NULL, 98 | SC_MANAGER_ALL_ACCESS 99 | ); 100 | if (m_schSCManager == NULL) 101 | { 102 | m_pError = std::make_unique(GetLastError()); 103 | throw std::runtime_error(m_pError->GetLastErrorAsStringA()); 104 | } 105 | } 106 | 107 | ServiceController::~ServiceController() 108 | { 109 | // 110 | // Check if the service is running and if it is, stop it then 111 | // delete it. 112 | // 113 | /* 114 | ServiceCleanUp(); 115 | */ 116 | 117 | if (m_schService != NULL) 118 | { 119 | CloseServiceHandle(m_schService); 120 | m_schService = NULL; 121 | } 122 | 123 | if (m_schSCManager != NULL) 124 | { 125 | CloseServiceHandle(m_schSCManager); 126 | m_schSCManager = NULL; 127 | } 128 | } 129 | 130 | BOOL ServiceController::IsServiceRunning() 131 | { 132 | SERVICE_STATUS Status = { 0 }; 133 | 134 | m_schService = OpenService(m_schSCManager, m_wszServiceName, SC_MANAGER_ALL_ACCESS); 135 | if (m_schService == NULL) 136 | { 137 | if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST) 138 | { 139 | m_bDoesServiceExist = FALSE; 140 | } 141 | 142 | return FALSE; 143 | } 144 | 145 | if (!QueryServiceStatus(m_schService, &Status)) 146 | { 147 | return FALSE; 148 | } 149 | 150 | if (Status.dwCurrentState == SERVICE_RUNNING) 151 | { 152 | return TRUE; 153 | } 154 | 155 | return FALSE; 156 | } 157 | 158 | BOOL ServiceController::StartKernelService() 159 | { 160 | // 161 | // Check if the service exists. If it doesn't, create dat hoe. 162 | // 163 | if (!m_bDoesServiceExist) 164 | { 165 | m_schService = CreateService( 166 | m_schSCManager, 167 | m_wszServiceName, 168 | m_wszServiceName, 169 | GENERIC_EXECUTE | DELETE, 170 | SERVICE_KERNEL_DRIVER, 171 | SERVICE_DEMAND_START, 172 | SERVICE_ERROR_NORMAL, 173 | L"C:\\Users\\offensive\\Desktop\\Gremlins.sys", // TODO: dynamically fix dis hoe. 174 | NULL, NULL, NULL, NULL, NULL 175 | ); 176 | if (m_schService == NULL) 177 | { 178 | return FALSE; 179 | } 180 | } 181 | else 182 | { 183 | m_schService = OpenService(m_schSCManager, m_wszServiceName, SC_MANAGER_ALL_ACCESS); 184 | if (m_schService == NULL) 185 | { 186 | return FALSE; 187 | } 188 | } 189 | 190 | 191 | if (!StartService(m_schService, NULL, NULL)) 192 | { 193 | return FALSE; 194 | } 195 | 196 | return TRUE; 197 | } 198 | 199 | 200 | /// EOF -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Gremlins 2 | 3 | ![Gizmo](https://github.com/ch3rn0byl/Gremlins/blob/master/Images/Gremlins-Gizmo-square.png) 4 | 5 | This application and driver was made to aid for Research and Development purposes in regards to monitoring and fuzzing. The logic for fuzzing is not yet implemented. What this does _not_ do is bypass any security mitigations for malicious behavior. All work that has been put into it as of now has been developed targetting Windows Enterprise 21h2 x64. 6 | ## Requirements for Building Yourself 7 | 1. Visual Studio 8 | 2. Windows Driver Kit 9 | 10 | This was built using Visual Studio 2022, but could probably be used with older verions. 11 | 12 | ## Hooking 13 | Gremlins will hook `nt!NtDeviceIoControlFile` out of the box, but could also do others if implemented. Gizmo will resolve all syscalls for any target function you are interested in hooking. The hook is as follows: 14 | ``` 15 | mov rax, hooked_address 16 | jmp rax 17 | ``` 18 | 19 | The hooking implementation, itself, is bare minimum meaning it will only print the arguments and buffer if there is any. At this point, the function is yours to play with. 20 | 21 | ## How does this work? 22 | #### Usermode Application: Gizmo 23 | Gizmo is a usermode application will resolve the syscall for a function using LoadLibrary and then scan that region of memory until it hits the syscall signature. Once the syscall signature is found, it will extract that number and return it. The syscall value is of type UINT16. Gizmo will then forward that information to Gremlins. 24 | 25 | #### Kernel Driver: Gremlins 26 | Gremlins is a kernel driver that will do all the processing. Gremlins will do the following: 27 | 1. Check if it's initialized or not. 28 | 2. Initialize itself. What this will do is gather all the information needed for the other functions to work correctly. 29 | 3. Check if a given syscall is hooked. 30 | 4. If the syscall is not hooked, it will hook it. 31 | 5. If a syscall is hooked, it will restore it. 32 | Gremlins will first resolve `nt!KiSystemServiceUser` by querying the LSTAR register. Once that is found, it will search KiSystemServiceUser for `nt!KeServiceDescriptorTable`. From there, it has the values for the ServiceTableBase and the amount of services available. 33 | 34 | Gremlins will process the data from Gizmo and then retrieve the function that correlates to that specific syscall index. Gremlins will then convert the virtual address to physical address that way we can double map the physical address into userspace as Read/Write. The patch is applied and the secondary address is unmapped. The Nt function is now hooked, all without the need to modify CR0.[WP]. 35 | 36 | It uses a LIST_ENTRY to hold the hooked functions data. Doing it this way makes it easier for Gremlins to keep track of whats hooked and what is not hooked. The only limitation of the number of hooks you can use is limited to what you're willing to do and whatever the amount is, if any, of the amount of items LIST_ENTRY's can hold. 37 | 38 | ## How to use? 39 | Since this is purely for Research and Development purposes, I make use of debugging print statements to see the output of the system, therefore, being connected to your kernel debugger instance is a must; however, I don't enforce it in Gizmo. It will just pause but you will have no idea what is happening. You will be blind. 40 | 41 | A service will need to be created and started with the Service Controller Manager: 42 | ``` 43 | sc create gremlins binPath= /gremlins.sys type= kernel 44 | sc start gremlins 45 | ``` 46 | If you want it to automatically at boot, you can use: 47 | ``` 48 | sc create gremlins binPath= /gremlins.sys type= kernel start= auto 49 | ``` 50 | 51 | As for implementing additional syscalls, the following steps would need to take place to do so: 52 | 1. Implement your hooks and place the header(s) and cpp file(s) inside the "Hooks" filter for tidiness. 53 | 2. Add the syscall index number ![here](https://github.com/ch3rn0byl/Gremlins/blob/775a032539539ff5839fa1451d730a15afcf9637/Gremlins/typesndefs.h#L33). 54 | 3. Add a case statement for your hook ![here](https://github.com/ch3rn0byl/Gremlins/blob/775a032539539ff5839fa1451d730a15afcf9637/Gremlins/dispatchfunctions.cpp#L114). The `NtDeviceIoControlFile` example is an example of implementing it. 55 | 4. Draw the rest of the owl. 56 | 57 | Gremlins logs errors, warnings, tracing, and info messages. The error messages will always be viewed within the debugger. You will need to enable the proper bit mask to view the other messages. If you are interested in viewing warning messages, apply the mask: 58 | ``` 59 | ed nt!Kd_IHVDRIVER_Mask 2 60 | ``` 61 | If you are wanting to view traces only: 62 | ``` 63 | ed nt!Kd_IHVDRIVER_Mask 4 64 | ``` 65 | If you are wanting to view info only: 66 | ``` 67 | ed nt!Kd_IHVDRIVER_Mask 8 68 | ``` 69 | If you are wanting to view ALL the info: 70 | ``` 71 | ed nt!Kd_IHVDRIVER_Mask 8 | 4 | 2 72 | ``` 73 | 74 | After that is done, you will use Gizmo to interact with the driver: 75 | ``` 76 | Gizmo.exe --hook NtDeviceIoControlFile 77 | ``` 78 | 79 | or multiple hooks at the same time: 80 | ``` 81 | Gizmo.exe --hook NtDeviceIoControlFile NtCreateFile 82 | ``` 83 | 84 | ![Gizmo](https://github.com/ch3rn0byl/Gremlins/blob/master/Images/Untitled.png) 85 | 86 | After placing the hook... 87 | 88 | ![Stripe](https://github.com/ch3rn0byl/Gremlins/blob/master/Images/Screenshot%202022-12-16%20133033.png) 89 | 90 | ## TODO: 91 | - [ ] Implement the capability to monitor specific devices 92 | - [ ] Implement some fuzzing logic 93 | - [ ] Fix up Gizmo a lil bit 94 | - [ ] Implement other syscalls 95 | -------------------------------------------------------------------------------- /Gremlins/typesndefs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | //==================================================== 5 | // Macros 6 | //==================================================== 7 | #ifdef DBG 8 | #define LOG_ERR(format, ...) KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, format, __VA_ARGS__)) 9 | #define LOG_WARN(format, ...) KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_WARNING_LEVEL, format, __VA_ARGS__)) 10 | #define LOG_TRACE(format, ...) KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, format, __VA_ARGS__)) 11 | #define LOG_INFO(format, ...) KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, format, __VA_ARGS__)) 12 | #else 13 | #define LOG_ERR(format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, format, __VA_ARGS__) 14 | #define LOG_WARN(format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_WARNING_LEVEL, format, __VA_ARGS__) 15 | #define LOG_TRACE(format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, format, __VA_ARGS__) 16 | #define LOG_INFO(format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, format, __VA_ARGS__) 17 | #endif // DBG 18 | 19 | #define ENCODE_CTL(Function) ( \ 20 | ((0x8000) << 16) | \ 21 | ((FILE_READ_ACCESS) << 14) | \ 22 | ((Function) << 2) | \ 23 | (METHOD_BUFFERED) \ 24 | ) 25 | 26 | #define CTL_CODE( DeviceType, Function, Method, Access ) ( \ 27 | ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ 28 | ) 29 | 30 | //==================================================== 31 | // Types: Syscall Indexes 32 | //==================================================== 33 | enum SYSCALL_INDEX : INT16 34 | { 35 | NtDeviceIoControlFile = 7, 36 | NtCreateFile = 0x55 37 | }; 38 | 39 | //==================================================== 40 | // Types: IOCTLs 41 | //==================================================== 42 | enum IOCTL_FUNCTION : INT32 43 | { 44 | IsInitialized = ENCODE_CTL(0x800), 45 | Initialize = ENCODE_CTL(0x801), 46 | IsHooked = ENCODE_CTL(0x802), 47 | Hook = ENCODE_CTL(0x803), 48 | Unhook = ENCODE_CTL(0x804) 49 | }; 50 | 51 | //==================================================== 52 | // Types: Undocumented Functions 53 | //==================================================== 54 | typedef NTSTATUS(NTAPI* _IopXxxControlFile)( 55 | _In_ HANDLE FileHandle, 56 | _In_opt_ HANDLE Event, 57 | _In_opt_ PIO_APC_ROUTINE ApcRoutine, 58 | _In_opt_ PVOID ApcContext, 59 | _Out_ PIO_STATUS_BLOCK IoStatusBlock, 60 | _In_ ULONG IoControlCode, 61 | _In_opt_ PVOID InputBuffer, 62 | _In_ ULONG InputBufferLength, 63 | _Out_opt_ PVOID OutputBuffer, 64 | _In_ ULONG OutputBufferLength, 65 | _In_ BOOLEAN DeviceIoControl 66 | ); 67 | 68 | typedef NTSTATUS(NTAPI* _IopCreateFile)( 69 | _Out_ PHANDLE FileHandle, 70 | _In_ ACCESS_MASK DesiredAccess, 71 | _In_ POBJECT_ATTRIBUTES ObjectAttributes, 72 | _Out_ PIO_STATUS_BLOCK IoStatusBlock, 73 | _In_opt_ PLARGE_INTEGER AllocationSize, 74 | _In_ ULONG FileAttributes, 75 | _In_ ULONG ShareAccess, 76 | _In_ ULONG CreateDisposition, 77 | _In_ ULONG CreateOptions, 78 | _In_opt_ PVOID EaBuffer, 79 | _In_ ULONG EaLength, 80 | _In_ CREATE_FILE_TYPE CreateFileType, 81 | _In_opt_ PVOID ExtraCreateParameters, 82 | _In_ ULONG Options, 83 | _In_ ULONG Flags, 84 | _In_opt_ PDEVICE_OBJECT DeviceObject 85 | ); 86 | 87 | //==================================================== 88 | // Definitions 89 | //==================================================== 90 | typedef struct _INPUT_BUFFER 91 | { 92 | UINT16 syscall; 93 | bool status; 94 | //NTSTATUS Status; 95 | } INPUT_BUFFER, * PINPUT_BUFFER; 96 | 97 | struct KSERVICE_DESCRIPTOR_TABLE 98 | { 99 | PULONG ServicetableBase; 100 | PULONG ServiceCounterTableBase; 101 | ULONG NumberOfServices; 102 | PULONG ParamTablebase; 103 | }; 104 | 105 | struct GLOBALS_HEADER 106 | { 107 | LIST_ENTRY ListHead; 108 | 109 | // 110 | // I am using the ExInterlockedXXXList routines and the MSDN specifically 111 | // states that the lock used on those API's should only be used for them and to 112 | // not use their lock for any other purpose. You can use the same lock for multiple 113 | // lists, but this behavior increases lock contention. I ain't got time 114 | // fo dat. 115 | // 116 | KSPIN_LOCK kSpinLock; 117 | KSPIN_LOCK kInterlockedSpinLock; 118 | FAST_MUTEX fMutex; 119 | bool IsInitialized; 120 | UNICODE_STRING BinaryName; 121 | }; 122 | 123 | // 124 | // If there are any internal functions that get called in the syscall, throw 125 | // dem hoes up in here. 126 | // 127 | struct INTERNAL_NT 128 | { 129 | _IopCreateFile IopCreateFile; 130 | _IopXxxControlFile IopXxxControlFile; 131 | }; 132 | 133 | struct HOOKED_SYSCALLS 134 | { 135 | bool IsHooked; 136 | UINT16 Index; 137 | LIST_ENTRY entry; 138 | PVOID address; 139 | UINT8 original[16]; 140 | }; 141 | 142 | typedef HOOKED_SYSCALLS* PHOOKED_SYSCALLS; 143 | typedef KSERVICE_DESCRIPTOR_TABLE* PKSERVICE_DESCRIPTOR_TABLE; 144 | 145 | struct GLOBALS : GLOBALS_HEADER 146 | { 147 | PKSERVICE_DESCRIPTOR_TABLE ssdt; 148 | PHOOKED_SYSCALLS hooked; 149 | INTERNAL_NT internal; 150 | }; 151 | 152 | 153 | //==================================================== 154 | // Globals 155 | //==================================================== 156 | constexpr auto POOLTAG = 'nRhC'; 157 | constexpr auto POOLTAG_DBG = 'gBdC'; 158 | constexpr auto IA32_LSTAR_MSR = 0xc0000082; 159 | 160 | typedef GLOBALS* PGLOBALS; 161 | 162 | // 163 | // The stub for the hook encoded as follows: 164 | // mov rax, 0 165 | // jmp rax 166 | static UINT8 HookingStub[] = { 167 | 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 168 | 0xff, 0xe0 169 | }; 170 | 171 | extern PGLOBALS g_Globals; 172 | 173 | 174 | /// EOF -------------------------------------------------------------------------------- /Gremlins/Gremlins.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {8E41214B-6785-4CFE-B992-037D68949A14} 18 | inf;inv;inx;mof;mc; 19 | 20 | 21 | {38aeb4cd-7829-43f4-9406-ee59599222ca} 22 | 23 | 24 | {da800bce-0a49-4306-896e-3bcd5c1deb5c} 25 | 26 | 27 | {59600a13-debb-434a-83d9-bdcd1953357b} 28 | 29 | 30 | {d205988e-6a91-4324-91dc-221a5217ecfd} 31 | 32 | 33 | {64d452a2-bca4-4440-8fd3-2241c914b02c} 34 | 35 | 36 | {f53b6688-00dc-4e66-8a0a-01fa8f528256} 37 | 38 | 39 | {b1193764-5644-4732-9ca3-3335b067c6fa} 40 | 41 | 42 | {cd58dbc7-826c-4357-a9f6-584fdf1c946f} 43 | 44 | 45 | {0513ec47-cd02-4f4b-a987-cb71fcd11f1d} 46 | 47 | 48 | {720d2564-128a-437f-bc7c-a9de5b1d4e1b} 49 | 50 | 51 | {6cfb5422-5322-486d-b71a-d1b27d2a8ff7} 52 | 53 | 54 | 55 | 56 | Driver Files 57 | 58 | 59 | 60 | 61 | Source Files\Namespaces 62 | 63 | 64 | Source Files\Namespaces 65 | 66 | 67 | Source Files\Main driver functions 68 | 69 | 70 | Source Files 71 | 72 | 73 | Source Files\Namespaces 74 | 75 | 76 | Source Files\Classes 77 | 78 | 79 | Source Files\Classes 80 | 81 | 82 | Source Files\Classes 83 | 84 | 85 | Source Files\Classes 86 | 87 | 88 | Source Files\Hooks\Syscall Hooks 89 | 90 | 91 | Source Files\Hooks\Syscall Hooks 92 | 93 | 94 | 95 | 96 | Header Files\Namespaces 97 | 98 | 99 | Header Files\Namespaces 100 | 101 | 102 | Header Files\Hooks 103 | 104 | 105 | Header Files\Hooks 106 | 107 | 108 | Header Files\Main driver functions 109 | 110 | 111 | Header Files\Namespaces 112 | 113 | 114 | Header Files\Classes 115 | 116 | 117 | Header Files\Classes 118 | 119 | 120 | Header Files\Classes 121 | 122 | 123 | Header Files\Classes 124 | 125 | 126 | Header Files\Types 127 | 128 | 129 | Header Files\Types 130 | 131 | 132 | Header Files\Types 133 | 134 | 135 | Header Files\Types 136 | 137 | 138 | Source Files\Hooks\Hook Types 139 | 140 | 141 | Header Files\Types 142 | 143 | 144 | -------------------------------------------------------------------------------- /Gremlins/dispatchfunctions.cpp: -------------------------------------------------------------------------------- 1 | #include "dispatchfunctions.h" 2 | 3 | _Use_decl_annotations_ 4 | NTSTATUS 5 | IsModuleInitialized( 6 | PINPUT_BUFFER& InputBuffer, 7 | PULONG Information 8 | ) 9 | { 10 | InputBuffer->status = g_Globals->IsInitialized; 11 | *Information = sizeof(INPUT_BUFFER); 12 | 13 | return STATUS_SUCCESS; 14 | } 15 | 16 | NTSTATUS 17 | InitializeModule() 18 | { 19 | NTSTATUS Status = STATUS_UNSUCCESSFUL; 20 | 21 | UINT64 KiSystemServiceuser = 0; 22 | UINT64 KeServiceDescriptorTable = 0; 23 | 24 | // 25 | // Get the lstar address. 26 | // 27 | UINT64 Lstar = __readmsr(IA32_LSTAR_MSR); 28 | 29 | Status = resolve::KiSystemServiceUser(Lstar, &KiSystemServiceuser); 30 | if (!NT_SUCCESS(Status) || KiSystemServiceuser == NULL) 31 | { 32 | return Status; 33 | } 34 | else 35 | { 36 | LOG_TRACE("[%ws::%d] KiSystemServiceUser: %p.\n", __FUNCTIONW__, __LINE__, KiSystemServiceuser); 37 | } 38 | 39 | Status = resolve::KeServiceDescriptorTable(KiSystemServiceuser, &KeServiceDescriptorTable); 40 | if (!NT_SUCCESS(Status) || KiSystemServiceuser == NULL) 41 | { 42 | return Status; 43 | } 44 | else 45 | { 46 | LOG_TRACE("[%ws::%d] KeServiceDescriptorTable: %p.\n", __FUNCTIONW__, __LINE__, KeServiceDescriptorTable); 47 | } 48 | 49 | g_Globals->ssdt = reinterpret_cast( 50 | KeServiceDescriptorTable 51 | ); 52 | g_Globals->IsInitialized = true; 53 | 54 | LOG_TRACE("[%ws::%d] g_Globals has been initialized.\n", __FUNCTIONW__, __LINE__); 55 | 56 | return Status; 57 | } 58 | 59 | _Use_decl_annotations_ 60 | NTSTATUS 61 | IsSyscallHooked( 62 | PINPUT_BUFFER& InputBuffer, 63 | PULONG Information 64 | ) 65 | { 66 | // 67 | // Validate the user's input. 68 | // 69 | if (InputBuffer->syscall > g_Globals->ssdt->NumberOfServices || 70 | InputBuffer->syscall < 0) 71 | { 72 | return STATUS_INVALID_PARAMETER; 73 | } 74 | 75 | // TODO: Fix status type or add status type 76 | InputBuffer->status = hook::isFunctionHookedByIndex(InputBuffer->syscall); 77 | *Information = sizeof(INPUT_BUFFER); 78 | 79 | return STATUS_SUCCESS; 80 | } 81 | 82 | _Use_decl_annotations_ 83 | NTSTATUS 84 | HookSyscall( 85 | PINPUT_BUFFER& InputBuffer 86 | ) 87 | { 88 | // 89 | // Validate the user provided syscall. 90 | // 91 | if (InputBuffer->syscall > g_Globals->ssdt->NumberOfServices || 92 | InputBuffer->syscall < 0) 93 | { 94 | return STATUS_INVALID_PARAMETER; 95 | } 96 | 97 | UINT64 fnSyscall = 0; 98 | UINT64 fn_hSyscall = 0; 99 | 100 | NTSTATUS Status = STATUS_SUCCESS; 101 | 102 | // 103 | // The syscall number is used as an offset to the System Service Descriptor Table. 104 | // To resolve the function of the syscall, one must do the following: 105 | // 1. Reference the index with the syscall 106 | // 2. Shift it right by four. 107 | // 3. ?? 108 | // 4. Profit. 109 | // 110 | fnSyscall = reinterpret_cast(g_Globals->ssdt->ServicetableBase); 111 | fnSyscall += g_Globals->ssdt->ServicetableBase[InputBuffer->syscall] >> 4; 112 | 113 | switch (InputBuffer->syscall) 114 | { 115 | case NtDeviceIoControlFile: 116 | // 117 | // Check to make sure the function is not already hooked by querying 118 | // the address. 119 | // 120 | if (!hook::isFunctionHookedByAddress(reinterpret_cast(fnSyscall))) 121 | { 122 | g_Globals->hooked = static_cast( 123 | #ifdef DBG 124 | ExAllocatePool2(POOL_FLAG_NON_PAGED | POOL_FLAG_SPECIAL_POOL, sizeof(GLOBALS), POOLTAG_DBG) 125 | #else 126 | ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(GLOBALS), POOLTAG) 127 | #endif // DBG 128 | ); 129 | if (g_Globals->hooked == NULL) 130 | { 131 | Status = STATUS_MEMORY_NOT_ALLOCATED; 132 | LOG_ERR("[%ws::%d] Failed with status 0x%08x.\n", __FUNCTIONW__, __LINE__, Status); 133 | break; 134 | } 135 | 136 | LOG_TRACE("[%ws::%d] g_Globals->hooked allocated at %p.\n", __FUNCTIONW__, __LINE__, g_Globals->hooked); 137 | 138 | // 139 | // Save the original address of the NT function. 140 | // 141 | g_Globals->hooked->address = reinterpret_cast(fnSyscall); 142 | g_Globals->hooked->Index = InputBuffer->syscall; 143 | 144 | // 145 | // NtDeviceIoControlFile has an internal function it hits. Will need to 146 | // resolve IopXxxControlFile. 147 | // 148 | Status = resolve::IopXxxControlFile( 149 | reinterpret_cast(g_Globals->hooked->address), 150 | reinterpret_cast(&g_Globals->internal.IopXxxControlFile) 151 | ); 152 | if (!NT_SUCCESS(Status) || g_Globals->internal.IopXxxControlFile == NULL) 153 | { 154 | LOG_ERR("[%ws::%d] %p was not found.\n", __FUNCTIONW__, __LINE__, g_Globals->internal.IopXxxControlFile); 155 | Status = STATUS_NOT_FOUND; 156 | break; 157 | } 158 | 159 | fn_hSyscall = reinterpret_cast(fn_hNtDeviceIoControlFile); 160 | 161 | // 162 | // Copy enough memory of the function to restore afterwards. 163 | // 164 | RtlCopyMemory( 165 | g_Globals->hooked->original, 166 | g_Globals->hooked->address, 167 | sizeof(g_Globals->hooked->original) 168 | ); 169 | 170 | // 171 | // Patch the temp bytes that way RAX points to something useful. 172 | // 173 | RtlCopyMemory(HookingStub + 2, &fn_hSyscall, sizeof(fn_hSyscall)); 174 | 175 | Status = detour::hook(reinterpret_cast(fnSyscall), HookingStub, sizeof(HookingStub)); 176 | if (!NT_SUCCESS(Status)) 177 | { 178 | LOG_ERR("[%ws::%d] Failed with status 0x%08x.\n", __FUNCTIONW__, __LINE__, Status); 179 | break; 180 | } 181 | else 182 | { 183 | g_Globals->hooked->IsHooked = true; 184 | } 185 | 186 | // 187 | // Keep track of the functions that are hooked. Insert dem hoes into 188 | // the list entry. 189 | // 190 | ExInterlockedInsertTailList( 191 | &g_Globals->ListHead, 192 | &g_Globals->hooked->entry, 193 | &g_Globals->kInterlockedSpinLock 194 | ); 195 | 196 | LOG_TRACE("[%ws::%d] NtDeviceIoControlFile has been hooked.\n", __FUNCTIONW__, __LINE__); 197 | } 198 | break; 199 | default: 200 | Status = STATUS_NOT_IMPLEMENTED; 201 | break; 202 | } 203 | 204 | return Status; 205 | } 206 | 207 | _Use_decl_annotations_ 208 | NTSTATUS 209 | UnhookSyscall( 210 | PINPUT_BUFFER InputBuffer 211 | ) 212 | { 213 | // 214 | // Validate the user's provided syscall. 215 | // 216 | if (InputBuffer->syscall > g_Globals->ssdt->NumberOfServices || 217 | InputBuffer->syscall < 0) 218 | { 219 | return STATUS_INVALID_PARAMETER; 220 | } 221 | 222 | return hook::unhookFunction(InputBuffer->syscall); 223 | } 224 | 225 | 226 | /// EOF -------------------------------------------------------------------------------- /Gizmo/Source.cpp: -------------------------------------------------------------------------------- 1 | // Source.cpp : This file contains the 'main' function. Program execution begins and ends there. 2 | // 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | //#include "ServiceController.h" 10 | #include "Gizmo.h" 11 | 12 | void 13 | PrintUsage( 14 | _In_ const char* pszProgramName 15 | ) 16 | { 17 | std::wcout << "Usage: " << pszProgramName << " options syscall(s)" << std::endl; 18 | 19 | std::wcout << pszProgramName << " can be used for hooking all of the syscalls on a "; 20 | std::wcout << "target. You can hook one syscall at a time, or hook multiple syscalls "; 21 | std::wcout << "at a time. The syscalls are case-sensitive!" << std::endl; 22 | 23 | std::wcout << "\nOptions: " << std::endl; 24 | std::wcout << " -h, --hook\tHooks a syscall by name." << std::endl; 25 | std::wcout << " -r, --restore\tUnhooks a syscall by name." << std::endl; 26 | 27 | std::wcout << "\nThis application will crash (hopefully) the system. A kernel debugger "; 28 | std::wcout << "is required to be attached to a system to catch the crash as it occurs. "; 29 | std::wcout << std::endl; 30 | } 31 | 32 | void 33 | PrintBanner() 34 | { 35 | std::wcout << std::endl; 36 | std::wcout << " ,--, ,---. ,---. ,-. ,-..-. .-. .---. " << std::endl; 37 | std::wcout << " .' .' | .-.\\ | .-' |\\ /|| | |(|| \\| | ( .-._)" << std::endl; 38 | std::wcout << " | | __ | `-'/ | `-. |(\\ / || | (_)| | | (_) \\ " << std::endl; 39 | std::wcout << " \\ \\ ( _)| ( | .-' (_)\\/ || | | || |\\ | _ \\ \\ " << std::endl; 40 | std::wcout << " \\ `-) )| |\\ \\ | `--.| \\ / || `--. | || | |)|( `-' ) " << std::endl; 41 | std::wcout << " )\\____/ |_| \\)\\ /( __.'| |\\/| ||( __.'`-'/( (_) `----' " << std::endl; 42 | std::wcout << " (__) (__)(__) '-' '-'(_) (__) " << std::endl; 43 | std::wcout << " A Syscall Introspection Tool" << std::endl; 44 | std::wcout << std::endl; 45 | } 46 | 47 | int 48 | main( 49 | int argc, 50 | const char* argv[] 51 | ) 52 | { 53 | std::unique_ptr pGizmo = nullptr; 54 | 55 | std::vector HookThese{}; 56 | std::vector UnhookThese{}; 57 | INPUT_BUFFER lpInputBuffer{}; 58 | 59 | BOOL bIsKdAttached = FALSE; 60 | 61 | PSYSTEM_KERNEL_DEBUGGER_INFORMATION pIsKdAttached = nullptr; 62 | 63 | PrintBanner(); 64 | 65 | std::vector args(&argv[0], &argv[argc]); 66 | 67 | // 68 | // Process the arguments given. 69 | // 70 | for (std::vector::iterator i = args.begin(); i != args.end(); i++) 71 | { 72 | std::string argument = *i; 73 | 74 | if (argument == "--hook" || argument == "-h") 75 | { 76 | try 77 | { 78 | for (std::vector::const_iterator params = i + 1; params != args.end(); params++) 79 | { 80 | std::string function = *params; 81 | 82 | // 83 | // Grab all the arguments up until we reach the unhook argument 84 | // 85 | if (function == "-r" || function == "--restore") 86 | break; 87 | 88 | HookThese.push_back(function); 89 | } 90 | } 91 | catch (const std::exception&) 92 | { 93 | std::wcerr << "[!] Provide a syscall(s) to hook." << std::endl; 94 | return EXIT_FAILURE; 95 | } 96 | } 97 | else if (argument == "--restore" || argument == "-r") 98 | { 99 | try 100 | { 101 | for (std::vector::const_iterator params = i + 1; params != args.end(); params++) 102 | { 103 | std::string function = *params; 104 | 105 | // 106 | // Grab all the arguments up until we reach the unhook argument 107 | // 108 | if (function == "-h" || function == "--hook") 109 | break; 110 | 111 | UnhookThese.push_back(function); 112 | } 113 | } 114 | catch (const std::exception&) 115 | { 116 | std::wcerr << "[!] Provide a module's function name(s) to hook." << std::endl; 117 | return EXIT_FAILURE; 118 | } 119 | } 120 | } 121 | 122 | // 123 | // Validate user input. 124 | // 125 | if (HookThese.empty() && UnhookThese.empty()) 126 | { 127 | PrintUsage(argv[0]); 128 | return EXIT_FAILURE; 129 | } 130 | 131 | // 132 | // Now start initializing and interacting with Gremlins. 133 | // 134 | try 135 | { 136 | pGizmo = std::make_unique(); 137 | } 138 | catch (const std::exception&e) 139 | { 140 | std::wcerr << "[!] " << e.what() << std::endl; 141 | return EXIT_FAILURE; 142 | } 143 | 144 | // 145 | // Ensure the target is attached to a kernel debugger. Pause and wait for it to 146 | // be attached otherwise data that is intended on being displayed will not show. 147 | // 148 | do 149 | { 150 | bIsKdAttached = pGizmo->IsBeingKernelDebugged(); 151 | if (!bIsKdAttached) 152 | { 153 | std::wcerr << "[!] Not attached to a kernel debugger. Waiting..." << std::endl; 154 | system("pause"); 155 | } 156 | } while (!bIsKdAttached); 157 | 158 | /* 159 | // 160 | // The kernel debugger should be attached at this point. Start the driver up. 161 | // 162 | if (!pGizmo->IsServiceRunning()) 163 | { 164 | if (!pGizmo->StartKernelService()) 165 | { 166 | std::wcerr << "[!] Unable to start service." << std::endl; 167 | return EXIT_FAILURE; 168 | } 169 | } 170 | */ 171 | 172 | if (!HookThese.empty()) 173 | { 174 | for (const std::string& i : HookThese) 175 | { 176 | RtlSecureZeroMemory(&lpInputBuffer, sizeof(lpInputBuffer)); 177 | 178 | std::wcout << "[+] Hooking " << i.c_str() << "..."; 179 | if (pGizmo->IsSyscallHooked(i.c_str(), &lpInputBuffer) && !lpInputBuffer.status) 180 | { 181 | if (!pGizmo->HookSyscall(&lpInputBuffer)) 182 | { 183 | std::wcerr << "uh-oh!" << std::endl; 184 | std::wcerr << "[!] Unable to hook syscall " << i.c_str() << std::endl; 185 | } 186 | else 187 | { 188 | std::wcout << "done." << std::endl; 189 | } 190 | } 191 | else 192 | { 193 | std::wcerr << "uh-oh!" << std::endl; 194 | std::wcerr << "[!] " << i.c_str() << " is hooked already." << std::endl; 195 | } 196 | } 197 | } 198 | 199 | if (!UnhookThese.empty()) 200 | { 201 | for (const std::string& i : UnhookThese) 202 | { 203 | RtlSecureZeroMemory(&lpInputBuffer, sizeof(lpInputBuffer)); 204 | 205 | std::wcout << "[+] Restoring " << i.c_str() << "..."; 206 | if (pGizmo->IsSyscallHooked(i.c_str(), &lpInputBuffer) && lpInputBuffer.status) 207 | { 208 | if (!pGizmo->UnhookSyscall(&lpInputBuffer)) 209 | { 210 | std::wcerr << "uh-oh!" << std::endl; 211 | std::wcerr << "[!] Unable to hook syscall " << i.c_str() << std::endl; 212 | } 213 | else 214 | { 215 | std::wcout << "done." << std::endl; 216 | } 217 | } 218 | else 219 | { 220 | std::wcerr << "uh-oh!" << std::endl; 221 | std::wcerr << "[!] " << i.c_str() << " is not hooked." << std::endl; 222 | } 223 | } 224 | } 225 | 226 | std::wcout << "[+] Done." << std::endl; 227 | return EXIT_SUCCESS; 228 | } 229 | 230 | 231 | /// EOF -------------------------------------------------------------------------------- /Gizmo/Gizmo.cpp: -------------------------------------------------------------------------------- 1 | #include "Gizmo.h" 2 | 3 | Gizmo::Gizmo() : 4 | m_pNtUndoc(std::make_unique()), 5 | m_wszServiceName(L"\\\\.\\Gremlins"), 6 | m_pError(nullptr) 7 | { 8 | INPUT_BUFFER lpInputBuffer = {}; 9 | 10 | bool bStatus = init(m_wszServiceName); 11 | if (!bStatus) 12 | { 13 | m_pError = std::make_unique(GetLastError()); 14 | throw std::runtime_error(m_pError->GetLastErrorAsStringA()); 15 | } 16 | 17 | // 18 | // Check if Gremlins has been initialized. If it hasn't, do the damn thang. 19 | // 20 | bStatus = SendIoControlRequest( 21 | IsInitialized, 22 | &lpInputBuffer, 23 | sizeof(lpInputBuffer), 24 | &lpInputBuffer, 25 | sizeof(lpInputBuffer) 26 | ); 27 | if (bStatus) 28 | { 29 | // 30 | // If this is false, this indicates Gremlins is NOT initialized. Let's 31 | // start it up. 32 | // 33 | if (!lpInputBuffer.status) 34 | { 35 | bStatus = SendIoControlRequest(Initialize); 36 | if (!bStatus) 37 | { 38 | m_pError = std::make_unique(GetLastError()); 39 | throw std::runtime_error(m_pError->GetLastErrorAsStringA()); 40 | } 41 | } 42 | } 43 | else 44 | { 45 | m_pError = std::make_unique(GetLastError()); 46 | throw std::runtime_error(m_pError->GetLastErrorAsStringA()); 47 | } 48 | } 49 | 50 | Gizmo::~Gizmo() 51 | { 52 | } 53 | 54 | BOOL Gizmo::IsBeingKernelDebugged() 55 | { 56 | std::unique_ptr pSysKernBytes = nullptr; 57 | PSYSTEM_KERNEL_DEBUGGER_INFORMATION pIsKdAttached = nullptr; 58 | 59 | ULONG dwSysInfoLength = 0; 60 | 61 | NTSTATUS Status = STATUS_UNSUCCESSFUL; 62 | 63 | do 64 | { 65 | // 66 | // First time around will be NULL. This is to dynamically resolve the size needed 67 | // for the buffer. 68 | // 69 | pSysKernBytes = std::make_unique(dwSysInfoLength); 70 | 71 | Status = m_pNtUndoc->NtQuerySystemInformation( 72 | SystemKernelDebuggerInformation, 73 | pSysKernBytes.get(), 74 | dwSysInfoLength, 75 | &dwSysInfoLength 76 | ); 77 | if (!NT_SUCCESS(Status) && Status == STATUS_INFO_LENGTH_MISMATCH) 78 | { 79 | pSysKernBytes.reset(); 80 | } 81 | else 82 | { 83 | break; 84 | } 85 | } while (Status != STATUS_SUCCESS); 86 | 87 | pIsKdAttached = reinterpret_cast(pSysKernBytes.get()); 88 | if (!pIsKdAttached->DebuggerEnabled || pIsKdAttached->DebuggerNotPresent) 89 | { 90 | return FALSE; 91 | } 92 | 93 | return TRUE; 94 | } 95 | 96 | _Use_decl_annotations_ 97 | bool 98 | Gizmo::IsSyscallHooked( 99 | LPCSTR lpProcName, 100 | PINPUT_BUFFER lpInputBuffer 101 | ) 102 | { 103 | // 104 | // Resolve the syscall first. 105 | // 106 | bool bStatus = ResolveSyscall(lpProcName, &lpInputBuffer->syscall); 107 | if (!bStatus) 108 | { 109 | return bStatus; 110 | } 111 | 112 | // 113 | // Query Gremlins to check if the function is hooked or not. 114 | // 115 | bStatus = SendIoControlRequest( 116 | IsHooked, 117 | lpInputBuffer, 118 | sizeof(INPUT_BUFFER), 119 | lpInputBuffer, 120 | sizeof(INPUT_BUFFER) 121 | ); 122 | if (!bStatus) 123 | { 124 | m_pError = std::make_unique(GetLastError()); 125 | } 126 | 127 | return bStatus; 128 | } 129 | 130 | _Use_decl_annotations_ 131 | bool 132 | Gizmo::HookSyscall( 133 | PINPUT_BUFFER lpInputBuffer 134 | ) 135 | { 136 | bool bStatus = SendIoControlRequest(Hook, lpInputBuffer, sizeof(INPUT_BUFFER)); 137 | if (!bStatus) 138 | { 139 | m_pError = std::make_unique(GetLastError()); 140 | } 141 | 142 | return bStatus; 143 | } 144 | 145 | _Use_decl_annotations_ 146 | bool 147 | Gizmo::UnhookSyscall( 148 | PINPUT_BUFFER lpInputBuffer 149 | ) 150 | { 151 | bool bStatus = SendIoControlRequest(Unhook, lpInputBuffer, sizeof(INPUT_BUFFER)); 152 | if (!bStatus) 153 | { 154 | m_pError = std::make_unique(GetLastError()); 155 | } 156 | 157 | return bStatus; 158 | } 159 | 160 | std::wstring Gizmo::what() 161 | { 162 | return m_pError->GetLastErrorAsStringW(); 163 | } 164 | 165 | _Use_decl_annotations_ 166 | bool 167 | Gizmo::ResolveSyscall( 168 | LPCSTR lpProcName, 169 | PUINT16 SyscallValue 170 | ) 171 | { 172 | HMODULE hModule = NULL; 173 | FARPROC fpProcName = nullptr; 174 | 175 | bool bStatus = false; 176 | 177 | size_t length = 0; 178 | 179 | // 180 | // Grab a handle to ntdll because we're going to pull the export via 181 | // GetProcAddress. 182 | // 183 | hModule = GetModuleHandle(L"ntdll.dll"); 184 | if (hModule != NULL) 185 | { 186 | fpProcName = GetProcAddress(hModule, lpProcName); 187 | if (fpProcName != nullptr) 188 | { 189 | // 190 | // Once the function is located, the bytes should match the Syscall stub 191 | // which consists of the following: 192 | // mov r10, rcx 193 | // mov eax, some_number 194 | // 195 | // If the function does not start with that, i.e. a jmp (0xe9), chances 196 | // are AV exists on the system. Set the error accordingly and exit. 197 | // 198 | if (*reinterpret_cast(fpProcName) != 0xe9) 199 | { 200 | 201 | length = RtlCompareMemory(fpProcName, SyscallSig, sizeof(SyscallSig)); 202 | if (length == sizeof(SyscallSig)) 203 | { 204 | *SyscallValue = *reinterpret_cast( 205 | reinterpret_cast(fpProcName) + sizeof(SyscallSig) 206 | ); 207 | 208 | bStatus = true; 209 | } 210 | else 211 | { 212 | SetLastError(ERROR_MOD_NOT_FOUND); 213 | m_pError = std::make_unique(GetLastError()); 214 | } 215 | } 216 | else 217 | { 218 | SetLastError(ERROR_INVALID_MODULETYPE); 219 | m_pError = std::make_unique(GetLastError()); 220 | } 221 | } 222 | else 223 | { 224 | m_pError = std::make_unique(GetLastError()); 225 | } 226 | } 227 | else 228 | { 229 | m_pError = std::make_unique(GetLastError()); 230 | } 231 | 232 | if (hModule != NULL) 233 | { 234 | FreeLibrary(hModule); 235 | hModule = NULL; 236 | } 237 | 238 | if (fpProcName != NULL) 239 | { 240 | fpProcName = nullptr; 241 | } 242 | 243 | return bStatus; 244 | } 245 | 246 | 247 | /// EOF -------------------------------------------------------------------------------- /Gremlins/Source.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "typesndefs.h" 3 | #include "dispatchfunctions.h" 4 | #include "AuxWrapper.h" 5 | 6 | UNICODE_STRING g_DeviceName = RTL_CONSTANT_STRING(L"\\Device\\Gremlins"); 7 | UNICODE_STRING g_SymbolicName = RTL_CONSTANT_STRING(L"\\??\\Gremlins"); 8 | 9 | PGLOBALS g_Globals = nullptr; 10 | 11 | void banner() 12 | { 13 | // 14 | // Using LOG_ERR because it prints regardless of what flag you specify. 15 | // 16 | LOG_ERR("\n @ \n", NULL); 17 | LOG_ERR(" ,***((****((((* @@@@@@@@@@@ ,****,,,,**,,,. \n", NULL); 18 | LOG_ERR("****(############**((( @@@@@@@@@@@@@@@ .***,,((((((((((((/,,,,\n", NULL); 19 | LOG_ERR(" #################************,@@@@@@@@@,,,,,,,,,,,,*((((((((((((((((( \n", NULL); 20 | LOG_ERR(" ###################*************@@@,,,**,,,,*,*,((((((((((((((((((( \n", NULL); 21 | LOG_ERR(" #################******(/*******,,*,*,,,//,,,,*,((((((((((((((((( \n", NULL); 22 | LOG_ERR(" ################*****#***/##***.,*,((/***(,,*,,(((((((((((((((( \n", NULL); 23 | LOG_ERR(" ###############(*****##/##*,,*,,..,((*((,,,,,/((((((((((((((( \n", NULL); 24 | LOG_ERR(" ############****,**********,,,,,,,,,,,,,,,,(((((((((((( \n", NULL); 25 | LOG_ERR(" #####*******.%******,,,,,,,%.,,,,,,*((((( \n", NULL); 26 | LOG_ERR(" ,,,******....*%*%**.(.,,,,,,... \n", NULL); 27 | LOG_ERR(" ,,,,,,,,,,*********,,,,,,,,,,.......... \n", NULL); 28 | LOG_ERR(" ,,,,,,,,,/(/,,**,***,,,,.,,,.*/*......... \n", NULL); 29 | LOG_ERR(" .,,,,,,,,,,,#####*,,,,...,(((((........... \n", NULL); 30 | LOG_ERR(" ,,,,,,,,,,,,#######***.,,,(((((((............ \n", NULL); 31 | LOG_ERR(" , ,,,,##########(((((((((((.... . \n", NULL); 32 | LOG_ERR(" ########(((((* \n", NULL); 33 | LOG_ERR(" Gremlins: A Syscall Fuzzer \n\n", NULL); 34 | } 35 | 36 | _Function_class_(DRIVER_DISPATCH) 37 | _Dispatch_type_(IRP_MJ_DEVICE_CONTROL) 38 | _IRQL_requires_(PASSIVE_LEVEL) 39 | NTSTATUS 40 | DriverDispatchRoutine( 41 | _In_ PDEVICE_OBJECT, 42 | _In_ PIRP Irp 43 | ) 44 | { 45 | NTSTATUS Status = STATUS_NOT_IMPLEMENTED; 46 | 47 | ULONG Information = NULL; 48 | UINT32 IoControlCode = NULL; 49 | 50 | PIO_STACK_LOCATION IoStackLocation = nullptr; 51 | PINPUT_BUFFER InputBuffer = nullptr; 52 | 53 | IoStackLocation = IoGetCurrentIrpStackLocation(Irp); 54 | IoControlCode = IoStackLocation->Parameters.DeviceIoControl.IoControlCode; 55 | 56 | // 57 | // METHOD_BUFFERED is being used; therefore, access dat thang via SystemBuffer. 58 | // 59 | InputBuffer = static_cast( 60 | Irp->AssociatedIrp.SystemBuffer 61 | ); 62 | 63 | switch (IoControlCode) 64 | { 65 | case IsInitialized: 66 | Status = IsModuleInitialized(InputBuffer, &Information); 67 | break; 68 | case Initialize: 69 | Status = InitializeModule(); 70 | break; 71 | case IsHooked: 72 | Status = IsSyscallHooked(InputBuffer, &Information); 73 | break; 74 | case Hook: 75 | Status = HookSyscall(InputBuffer); 76 | break; 77 | case Unhook: 78 | Status = UnhookSyscall(InputBuffer); 79 | break; 80 | default: 81 | break; 82 | } 83 | 84 | Irp->IoStatus.Status = Status; 85 | Irp->IoStatus.Information = Information; 86 | 87 | IofCompleteRequest(Irp, IO_NO_INCREMENT); 88 | 89 | return STATUS_SUCCESS; 90 | } 91 | 92 | _Function_class_(DRIVER_DISPATCH) 93 | _Dispatch_type_(IRP_MJ_CREATE) 94 | _Dispatch_type_(IRP_MJ_CLOSE) 95 | _IRQL_requires_(PASSIVE_LEVEL) 96 | NTSTATUS 97 | DriverCreateClose( 98 | _In_ PDEVICE_OBJECT, 99 | _In_ PIRP Irp 100 | ) 101 | { 102 | Irp->IoStatus.Information = 0; 103 | Irp->IoStatus.Status = STATUS_SUCCESS; 104 | 105 | IofCompleteRequest(Irp, IO_NO_INCREMENT); 106 | 107 | return STATUS_SUCCESS; 108 | } 109 | 110 | _Function_class_(DRIVER_UNLOAD) 111 | _IRQL_requires_(PASSIVE_LEVEL) 112 | VOID 113 | DriverUnload( 114 | _In_ PDRIVER_OBJECT DriverObject 115 | ) 116 | { 117 | // 118 | // If g_Globals isn't empty, clear it and release the pool. 119 | // 120 | if (g_Globals != nullptr) 121 | { 122 | RtlSecureZeroMemory(g_Globals, sizeof(g_Globals)); 123 | #ifdef DBG 124 | ExFreePoolWithTag(g_Globals, POOLTAG_DBG); 125 | #else 126 | ExFreePoolWithTag(g_Globals, POOLTAG); 127 | #endif // DBG 128 | g_Globals = nullptr; 129 | } 130 | 131 | IoDeleteSymbolicLink(&g_SymbolicName); 132 | IoDeleteDevice(DriverObject->DeviceObject); 133 | 134 | LOG_TRACE("[%ws::%d] Completed successfully.\n", __FUNCTIONW__, __LINE__); 135 | } 136 | 137 | _Function_class_(DRIVER_INITIALIZE) 138 | _IRQL_requires_(PASSIVE_LEVEL) 139 | EXTERN_C 140 | NTSTATUS 141 | DriverEntry( 142 | _In_ PDRIVER_OBJECT DriverObject, 143 | _In_ PUNICODE_STRING 144 | ) 145 | { 146 | PDEVICE_OBJECT DeviceObject = nullptr; 147 | 148 | NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES; 149 | 150 | banner(); 151 | 152 | // 153 | // Allocate all the global variables. The buffer is initialized to zero. 154 | // 155 | g_Globals = static_cast( 156 | #ifdef DBG 157 | ExAllocatePool2(POOL_FLAG_NON_PAGED | POOL_FLAG_SPECIAL_POOL, sizeof(GLOBALS), POOLTAG_DBG) 158 | #else 159 | ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(GLOBALS), POOLTAG) 160 | #endif // DBG 161 | ); 162 | if (g_Globals == NULL) 163 | { 164 | LOG_ERR("[%ws::%d] Failed with 0x%08x.\n", __FUNCTIONW__, __LINE__, Status); 165 | return Status; 166 | } 167 | 168 | LOG_TRACE("[%ws::%d] g_Globals allocated at %p.\n", __FUNCTIONW__, __LINE__, g_Globals); 169 | 170 | // 171 | // Initialize the spinlocks, mutex, and list head. 172 | // 173 | // The kSpinLock is used for the ListHead. 174 | // The fMutex is used for printing information to the debugger. 175 | // 176 | KeInitializeSpinLock(&g_Globals->kSpinLock); 177 | KeInitializeSpinLock(&g_Globals->kInterlockedSpinLock); 178 | 179 | ExInitializeFastMutex(&g_Globals->fMutex); 180 | InitializeListHead(&g_Globals->ListHead); 181 | 182 | Status = IoCreateDevice( 183 | DriverObject, 184 | NULL, 185 | &g_DeviceName, 186 | FILE_DEVICE_UNKNOWN, 187 | FILE_DEVICE_SECURE_OPEN, 188 | TRUE, 189 | &DeviceObject 190 | ); 191 | if (!NT_SUCCESS(Status)) 192 | { 193 | LOG_ERR("[%ws::%d] Failed with 0x%08x.\n", __FUNCTIONW__, __LINE__, Status); 194 | 195 | if (DeviceObject) 196 | { 197 | IoDeleteDevice(DeviceObject); 198 | } 199 | return Status; 200 | } 201 | 202 | // 203 | // Create the symbolic link to interact with the driver. 204 | // 205 | Status = IoCreateSymbolicLink(&g_SymbolicName, &g_DeviceName); 206 | if (!NT_SUCCESS(Status)) 207 | { 208 | LOG_ERR("[%ws::%d] Failed with 0x%08x.\n", __FUNCTIONW__, __LINE__, Status); 209 | 210 | IoDeleteDevice(DeviceObject); 211 | return Status; 212 | } 213 | 214 | // 215 | // We are using METHOD BUFFERED. Reflect that in the flags. 216 | // 217 | DeviceObject->Flags |= DO_BUFFERED_IO; 218 | 219 | DriverObject->DriverUnload = DriverUnload; 220 | DriverObject->MajorFunction[IRP_MJ_CREATE] = 221 | DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverCreateClose; 222 | DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverDispatchRoutine; 223 | 224 | LOG_TRACE("[%ws::%d] Completed successfully.\n", __FUNCTIONW__, __LINE__); 225 | 226 | return Status; 227 | } 228 | 229 | 230 | /// EOF -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Oo]ut/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # ASP.NET Scaffolding 67 | ScaffoldingReadMe.txt 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # CodeRush personal settings 313 | .cr/personal 314 | 315 | # Python Tools for Visual Studio (PTVS) 316 | __pycache__/ 317 | *.pyc 318 | 319 | # Cake - Uncomment if you are using it 320 | # tools/** 321 | # !tools/packages.config 322 | 323 | # Tabs Studio 324 | *.tss 325 | 326 | # Telerik's JustMock configuration file 327 | *.jmconfig 328 | 329 | # BizTalk build output 330 | *.btp.cs 331 | *.btm.cs 332 | *.odx.cs 333 | *.xsd.cs 334 | 335 | # OpenCover UI analysis results 336 | OpenCover/ 337 | 338 | # Azure Stream Analytics local run output 339 | ASALocalRun/ 340 | 341 | # MSBuild Binary and Structured Log 342 | *.binlog 343 | 344 | # NVidia Nsight GPU debugger configuration file 345 | *.nvuser 346 | 347 | # MFractors (Xamarin productivity tool) working folder 348 | .mfractor/ 349 | 350 | # Local History for Visual Studio 351 | .localhistory/ 352 | 353 | # BeatPulse healthcheck temp database 354 | healthchecksdb 355 | 356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 357 | MigrationBackup/ 358 | 359 | # Ionide (cross platform F# VS Code tools) working folder 360 | .ionide/ 361 | 362 | # Fody - auto-generated XML schema 363 | FodyWeavers.xsd -------------------------------------------------------------------------------- /Gizmo/Gizmo.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {5f7baacc-c0d3-4027-86f3-f0dd0e9b3a4b} 25 | Gizmo 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | true 48 | 49 | 50 | Application 51 | false 52 | v143 53 | true 54 | Unicode 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | true 76 | 77 | 78 | false 79 | 80 | 81 | true 82 | 83 | 84 | false 85 | 86 | 87 | 88 | Level3 89 | true 90 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 91 | true 92 | MultiThreaded 93 | 94 | 95 | Console 96 | true 97 | 98 | 99 | 100 | 101 | Level3 102 | true 103 | true 104 | true 105 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | MultiThreaded 108 | 109 | 110 | Console 111 | true 112 | true 113 | true 114 | 115 | 116 | 117 | 118 | Level3 119 | true 120 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 121 | true 122 | MultiThreadedDebug 123 | 124 | 125 | Console 126 | DebugFull 127 | 128 | 129 | 130 | 131 | Level3 132 | true 133 | true 134 | true 135 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 136 | true 137 | MultiThreaded 138 | 139 | 140 | Console 141 | true 142 | true 143 | false 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /Gremlins/Gremlins.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | Debug 22 | ARM 23 | 24 | 25 | Release 26 | ARM 27 | 28 | 29 | Debug 30 | ARM64 31 | 32 | 33 | Release 34 | ARM64 35 | 36 | 37 | 38 | {EF955ED6-7D4F-474B-B00B-DB0526BEBFB6} 39 | {dd38f7fc-d7bd-488b-9242-7d8754cde80d} 40 | v4.5 41 | 12.0 42 | Debug 43 | Win32 44 | Gremlins 45 | $(LatestTargetPlatformVersion) 46 | 47 | 48 | 49 | Windows10 50 | true 51 | WindowsKernelModeDriver10.0 52 | Driver 53 | WDM 54 | 55 | 56 | Windows10 57 | false 58 | WindowsKernelModeDriver10.0 59 | Driver 60 | WDM 61 | 62 | 63 | Windows10 64 | true 65 | WindowsKernelModeDriver10.0 66 | Driver 67 | WDM 68 | 69 | 70 | Windows10 71 | false 72 | WindowsKernelModeDriver10.0 73 | Driver 74 | WDM 75 | 76 | 77 | Windows10 78 | true 79 | WindowsKernelModeDriver10.0 80 | Driver 81 | WDM 82 | 83 | 84 | Windows10 85 | false 86 | WindowsKernelModeDriver10.0 87 | Driver 88 | WDM 89 | 90 | 91 | Windows10 92 | true 93 | WindowsKernelModeDriver10.0 94 | Driver 95 | WDM 96 | 97 | 98 | Windows10 99 | false 100 | WindowsKernelModeDriver10.0 101 | Driver 102 | WDM 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | DbgengKernelDebugger 114 | 115 | 116 | DbgengKernelDebugger 117 | 118 | 119 | DbgengKernelDebugger 120 | 121 | 122 | DbgengKernelDebugger 123 | 124 | 125 | DbgengKernelDebugger 126 | 127 | 128 | DbgengKernelDebugger 129 | 130 | 131 | DbgengKernelDebugger 132 | 133 | 134 | DbgengKernelDebugger 135 | 136 | 137 | 138 | stdcpp17 139 | Level4 140 | true 141 | 5040;%(DisableSpecificWarnings) 142 | 143 | 144 | 145 | 146 | stdcpp17 147 | Level4 148 | true 149 | 5040;%(DisableSpecificWarnings) 150 | 151 | 152 | 153 | 154 | Default 155 | Level4 156 | true 157 | 4201;4748;%(DisableSpecificWarnings) 158 | 159 | 160 | DebugFull 161 | Aux_Klib.lib;%(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)ntoskrnl.lib;$(DDK_LIB_PATH)hal.lib;$(DDK_LIB_PATH)wmilib.lib 162 | 163 | 164 | SHA256 165 | 166 | 167 | 168 | 169 | stdcpp17 170 | Level4 171 | true 172 | 4201;4748;%(DisableSpecificWarnings) 173 | 174 | 175 | Aux_Klib.lib;%(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)ntoskrnl.lib;$(DDK_LIB_PATH)hal.lib;$(DDK_LIB_PATH)wmilib.lib 176 | false 177 | 178 | 179 | SHA256 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | -------------------------------------------------------------------------------- /Gizmo/NtUndocTypes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | //=============================================================================== 5 | // Definitions 6 | //=============================================================================== 7 | #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) 8 | #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) 9 | #define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) 10 | #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) 11 | 12 | //=============================================================================== 13 | // Enums 14 | //=============================================================================== 15 | enum SYSTEM_INFORMATION_CLASS 16 | { 17 | SystemBasicInformation = 0, 18 | SystemProcessorInformation = 1, 19 | SystemPerformanceInformation = 2, 20 | SystemTimeOfDayInformation = 3, 21 | SystemPathInformation = 4, 22 | SystemProcessInformation = 5, 23 | SystemCallCountInformation = 6, 24 | SystemDeviceInformation = 7, 25 | SystemProcessorPerformanceInformation = 8, 26 | SystemFlagsInformation = 9, 27 | SystemCallTimeInformation = 10, 28 | SystemModuleInformation = 11, 29 | SystemLocksInformation = 12, 30 | SystemStackTraceInformation = 13, 31 | SystemPagedPoolInformation = 14, 32 | SystemNonPagedPoolInformation = 15, 33 | SystemHandleInformation = 16, 34 | SystemObjectInformation = 17, 35 | SystemPageFileInformation = 18, 36 | SystemVdmInstemulInformation = 19, 37 | SystemVdmBopInformation = 20, 38 | SystemFileCacheInformation = 21, 39 | SystemPoolTagInformation = 22, 40 | SystemInterruptInformation = 23, 41 | SystemDpcBehaviorInformation = 24, 42 | SystemFullMemoryInformation = 25, 43 | SystemLoadGdiDriverInformation = 26, 44 | SystemUnloadGdiDriverInformation = 27, 45 | SystemTimeAdjustmentInformation = 28, 46 | SystemSummaryMemoryInformation = 29, 47 | SystemMirrorMemoryInformation = 30, 48 | SystemPerformanceTraceInformation = 31, 49 | SystemObsolete0 = 32, 50 | SystemExceptionInformation = 33, 51 | SystemCrashDumpStateInformation = 34, 52 | SystemKernelDebuggerInformation = 35, 53 | SystemContextSwitchInformation = 36, 54 | SystemRegistryQuotaInformation = 37, 55 | SystemExtendServiceTableInformation = 38, 56 | SystemPrioritySeperation = 39, 57 | SystemVerifierAddDriverInformation = 40, 58 | SystemVerifierRemoveDriverInformation = 41, 59 | SystemProcessorIdleInformation = 42, 60 | SystemLegacyDriverInformation = 43, 61 | SystemCurrentTimeZoneInformation = 44, 62 | SystemLookasideInformation = 45, 63 | SystemTimeSlipNotification = 46, 64 | SystemSessionCreate = 47, 65 | SystemSessionDetach = 48, 66 | SystemSessionInformation = 49, 67 | SystemRangeStartInformation = 50, 68 | SystemVerifierInformation = 51, 69 | SystemVerifierThunkExtend = 52, 70 | SystemSessionProcessInformation = 53, 71 | SystemLoadGdiDriverInSystemSpace = 54, 72 | SystemNumaProcessorMap = 55, 73 | SystemPrefetcherInformation = 56, 74 | SystemExtendedProcessInformation = 57, 75 | SystemRecommendedSharedDataAlignment = 58, 76 | SystemComPlusPackage = 59, 77 | SystemNumaAvailableMemory = 60, 78 | SystemProcessorPowerInformation = 61, 79 | SystemEmulationBasicInformation = 62, 80 | SystemEmulationProcessorInformation = 63, 81 | SystemExtendedHandleInformation = 64, 82 | SystemLostDelayedWriteInformation = 65, 83 | SystemBigPoolInformation = 66, 84 | SystemSessionPoolTagInformation = 67, 85 | SystemSessionMappedViewInformation = 68, 86 | SystemHotpatchInformation = 69, 87 | SystemObjectSecurityMode = 70, 88 | SystemWatchdogTimerHandler = 71, 89 | SystemWatchdogTimerInformation = 72, 90 | SystemLogicalProcessorInformation = 73, 91 | SystemWow64SharedInformationObsolete = 74, 92 | SystemRegisterFirmwareTableInformationHandler = 75, 93 | SystemFirmwareTableInformation = 76, 94 | SystemModuleInformationEx = 77, 95 | SystemVerifierTriageInformation = 78, 96 | SystemSuperfetchInformation = 79, 97 | SystemMemoryListInformation = 80, 98 | SystemFileCacheInformationEx = 81, 99 | SystemThreadPriorityClientIdInformation = 82, 100 | SystemProcessorIdleCycleTimeInformation = 83, 101 | SystemVerifierCancellationInformation = 84, 102 | SystemProcessorPowerInformationEx = 85, 103 | SystemRefTraceInformation = 86, 104 | SystemSpecialPoolInformation = 87, 105 | SystemProcessIdInformation = 88, 106 | SystemErrorPortInformation = 89, 107 | SystemBootEnvironmentInformation = 90, 108 | SystemHypervisorInformation = 91, 109 | SystemVerifierInformationEx = 92, 110 | SystemTimeZoneInformation = 93, 111 | SystemImageFileExecutionOptionsInformation = 94, 112 | SystemCoverageInformation = 95, 113 | SystemPrefetchPatchInformation = 96, 114 | SystemVerifierFaultsInformation = 97, 115 | SystemSystemPartitionInformation = 98, 116 | SystemSystemDiskInformation = 99, 117 | SystemProcessorPerformanceDistribution = 100, 118 | SystemNumaProximityNodeInformation = 101, 119 | SystemDynamicTimeZoneInformation = 102, 120 | SystemCodeIntegrityInformation = 103, 121 | SystemProcessorMicrocodeUpdateInformation = 104, 122 | SystemProcessorBrandString = 105, 123 | SystemVirtualAddressInformation = 106, 124 | SystemLogicalProcessorAndGroupInformation = 107, 125 | SystemProcessorCycleTimeInformation = 108, 126 | SystemStoreInformation = 109, 127 | SystemRegistryAppendString = 110, 128 | SystemAitSamplingValue = 111, 129 | SystemVhdBootInformation = 112, 130 | SystemCpuQuotaInformation = 113, 131 | SystemNativeBasicInformation = 114, 132 | SystemErrorPortTimeouts = 115, 133 | SystemLowPriorityIoInformation = 116, 134 | SystemBootEntropyInformation = 117, 135 | SystemVerifierCountersInformation = 118, 136 | SystemPagedPoolInformationEx = 119, 137 | SystemSystemPtesInformationEx = 120, 138 | SystemNodeDistanceInformation = 121, 139 | SystemAcpiAuditInformation = 122, 140 | SystemBasicPerformanceInformation = 123, 141 | SystemQueryPerformanceCounterInformation = 124, 142 | SystemSessionBigPoolInformation = 125, 143 | SystemBootGraphicsInformation = 126, 144 | SystemScrubPhysicalMemoryInformation = 127, 145 | SystemBadPageInformation = 128, 146 | SystemProcessorProfileControlArea = 129, 147 | SystemCombinePhysicalMemoryInformation = 130, 148 | SystemEntropyInterruptTimingInformation = 131, 149 | SystemConsoleInformation = 132, 150 | SystemPlatformBinaryInformation = 133, 151 | SystemPolicyInformation = 134, 152 | SystemHypervisorProcessorCountInformation = 135, 153 | SystemDeviceDataInformation = 136, 154 | SystemDeviceDataEnumerationInformation = 137, 155 | SystemMemoryTopologyInformation = 138, 156 | SystemMemoryChannelInformation = 139, 157 | SystemBootLogoInformation = 140, 158 | SystemProcessorPerformanceInformationEx = 141, 159 | SystemCriticalProcessErrorLogInformation = 142, 160 | SystemSecureBootPolicyInformation = 143, 161 | SystemPageFileInformationEx = 144, 162 | SystemSecureBootInformation = 145, 163 | SystemEntropyInterruptTimingRawInformation = 146, 164 | SystemPortableWorkspaceEfiLauncherInformation = 147, 165 | SystemFullProcessInformation = 148, 166 | SystemKernelDebuggerInformationEx = 149, 167 | SystemBootMetadataInformation = 150, 168 | SystemSoftRebootInformation = 151, 169 | SystemElamCertificateInformation = 152, 170 | SystemOfflineDumpConfigInformation = 153, 171 | SystemProcessorFeaturesInformation = 154, 172 | SystemRegistryReconciliationInformation = 155, 173 | SystemEdidInformation = 156, 174 | SystemManufacturingInformation = 157, 175 | SystemEnergyEstimationConfigInformation = 158, 176 | SystemHypervisorDetailInformation = 159, 177 | SystemProcessorCycleStatsInformation = 160, 178 | SystemVmGenerationCountInformation = 161, 179 | SystemTrustedPlatformModuleInformation = 162, 180 | SystemKernelDebuggerFlags = 163, 181 | SystemCodeIntegrityPolicyInformation = 164, 182 | SystemIsolatedUserModeInformation = 165, 183 | SystemHardwareSecurityTestInterfaceResultsInformation = 166, 184 | SystemSingleModuleInformation = 167, 185 | SystemAllowedCpuSetsInformation = 168, 186 | SystemVsmProtectionInformation = 169, 187 | SystemInterruptCpuSetsInformation = 170, 188 | SystemSecureBootPolicyFullInformation = 171, 189 | SystemCodeIntegrityPolicyFullInformation = 172, 190 | SystemAffinitizedInterruptProcessorInformation = 173, 191 | SystemRootSiloInformation = 174, 192 | SystemCpuSetInformation = 175, 193 | SystemCpuSetTagInformation = 176, 194 | SystemWin32WerStartCallout = 177, 195 | SystemSecureKernelProfileInformation = 178, 196 | SystemCodeIntegrityPlatformManifestInformation = 179, 197 | SystemInterruptSteeringInformation = 180, 198 | SystemSupportedProcessorArchitectures = 181, 199 | SystemMemoryUsageInformation = 182, 200 | SystemCodeIntegrityCertificateInformation = 183, 201 | SystemPhysicalMemoryInformation = 184, 202 | SystemControlFlowTransition = 185, 203 | SystemKernelDebuggingAllowed = 186, 204 | SystemActivityModerationExeState = 187, 205 | SystemActivityModerationUserSettings = 188, 206 | SystemCodeIntegrityPoliciesFullInformation = 189, 207 | SystemCodeIntegrityUnlockInformation = 190, 208 | SystemIntegrityQuotaInformation = 191, 209 | SystemFlushInformation = 192, 210 | SystemProcessorIdleMaskInformation = 193, 211 | SystemSecureDumpEncryptionInformation = 194, 212 | SystemWriteConstraintInformation = 195, 213 | SystemKernelVaShadowInformation = 196, 214 | SystemHypervisorSharedPageInformation = 197, 215 | SystemFirmwareBootPerformanceInformation = 198, 216 | SystemCodeIntegrityVerificationInformation = 199, 217 | SystemFirmwarePartitionInformation = 200, 218 | SystemSpeculationControlInformation = 201, 219 | SystemDmaGuardPolicyInformation = 202, 220 | SystemEnclaveLaunchControlInformation = 203, 221 | SystemWorkloadAllowedCpuSetsInformation = 204, 222 | SystemCodeIntegrityUnlockModeInformation = 205, 223 | SystemLeapSecondInformation = 206, 224 | SystemFlags2Information = 207, 225 | SystemSecurityModelInformation = 208, 226 | SystemCodeIntegritySyntheticCacheInformation = 209, 227 | SystemFeatureConfigurationInformation = 210, 228 | SystemFeatureConfigurationSectionInformation = 211, 229 | SystemFeatureUsageSubscriptionInformation = 212, 230 | SystemSecureSpeculationControlInformation = 213, 231 | SystemSpacesBootInformation = 214, 232 | SystemFwRamdiskInformation = 215, 233 | SystemWheaIpmiHardwareInformation = 216, 234 | SystemDifSetRuleClassInformation = 217, 235 | SystemDifClearRuleClassInformation = 218, 236 | SystemDifApplyPluginVerificationOnDriver = 219, 237 | SystemDifRemovePluginVerificationOnDriver = 220, 238 | SystemShadowStackInformation = 221, 239 | SystemBuildVersionInformation = 222, 240 | SystemPoolLimitInformation = 223, 241 | SystemCodeIntegrityAddDynamicStore = 224, 242 | SystemCodeIntegrityClearDynamicStores = 225, 243 | SystemPoolZeroingInformation = 227, 244 | MaxSystemInfoClass = 228 245 | }; 246 | 247 | //=============================================================================== 248 | // Types 249 | //=============================================================================== 250 | 251 | typedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION 252 | { 253 | BOOLEAN DebuggerEnabled; 254 | BOOLEAN DebuggerNotPresent; 255 | } SYSTEM_KERNEL_DEBUGGER_INFORMATION, * PSYSTEM_KERNEL_DEBUGGER_INFORMATION; 256 | 257 | typedef NTSTATUS(NTAPI* _NtQuerySystemInformation)( 258 | _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, 259 | _Out_writes_bytes_(SystemInformationLength) PVOID SystemInformation, 260 | _In_ ULONG SystemInformationLength, 261 | _Out_opt_ PULONG ReturnLength 262 | ); 263 | 264 | 265 | /// EOF --------------------------------------------------------------------------------