Add DLL blocking hook for FM. (#359)

* Add DLL blocking hook for FM.

* Remove dynamic code optouts.
This commit is contained in:
dinhngtu
2024-02-09 06:23:22 +01:00
committed by GitHub
parent 8a3e07f799
commit 0d4d9fbf5e
7 changed files with 231 additions and 63 deletions

196
NanaZip.Shared/DllBlock.cpp Normal file
View File

@@ -0,0 +1,196 @@
/*
* PROJECT: NanaZip
* FILE: DllBlock.cpp
* PURPOSE: Implementation for DLL blocker
*
* LICENSE: The MIT License
*
* DEVELOPER: dinhngtu (contact@tudinh.xyz)
* MouriNaruto (KurikoMouri@outlook.jp)
*/
#include "DllBlock.h"
#ifdef NDEBUG
#include <Detours.h>
namespace
{
// The following definitions are part of the Process Hacker project - https://processhacker.sourceforge.io/
typedef enum _SECTION_INHERIT
{
ViewShare = 1,
ViewUnmap = 2
} SECTION_INHERIT;
typedef enum _SECTION_INFORMATION_CLASS
{
SectionBasicInformation, // q; SECTION_BASIC_INFORMATION
SectionImageInformation, // q; SECTION_IMAGE_INFORMATION
SectionRelocationInformation, // q; PVOID RelocationAddress // name:wow64:whNtQuerySection_SectionRelocationInformation // since WIN7
SectionOriginalBaseInformation, // PVOID BaseAddress
SectionInternalImageInformation, // SECTION_INTERNAL_IMAGE_INFORMATION // since REDSTONE2
MaxSectionInfoClass
} SECTION_INFORMATION_CLASS;
typedef struct _SECTION_BASIC_INFORMATION
{
PVOID BaseAddress;
ULONG AllocationAttributes;
LARGE_INTEGER MaximumSize;
} SECTION_BASIC_INFORMATION, * PSECTION_BASIC_INFORMATION;
typedef NTSTATUS(NTAPI* NtMapViewOfSectionType)(
_In_ HANDLE SectionHandle,
_In_ HANDLE ProcessHandle,
_Inout_ _At_(*BaseAddress, _Readable_bytes_(*ViewSize) _Writable_bytes_(*ViewSize) _Post_readable_byte_size_(*ViewSize)) PVOID* BaseAddress,
_In_ ULONG_PTR ZeroBits,
_In_ SIZE_T CommitSize,
_Inout_opt_ PLARGE_INTEGER SectionOffset,
_Inout_ PSIZE_T ViewSize,
_In_ SECTION_INHERIT InheritDisposition,
_In_ ULONG AllocationType,
_In_ ULONG Win32Protect);
typedef NTSTATUS(NTAPI* NtQuerySectionType)(
_In_ HANDLE SectionHandle,
_In_ SECTION_INFORMATION_CLASS SectionInformationClass,
_Out_writes_bytes_(SectionInformationLength) PVOID SectionInformation,
_In_ SIZE_T SectionInformationLength,
_Out_opt_ PSIZE_T ReturnLength);
typedef NTSTATUS(NTAPI* NtUnmapViewOfSectionType)(
_In_ HANDLE ProcessHandle,
_In_opt_ PVOID BaseAddress);
// End PHNT definitions
static constexpr NTSTATUS STATUS_ACCESS_DENIED = 0xC0000022;
static NtMapViewOfSectionType RealNtMapViewOfSection = NULL;
static NtQuerySectionType RealNtQuerySection = NULL;
static NtUnmapViewOfSectionType RealNtUnmapViewOfSection = NULL;
static bool DllNeedsBlocking(const char* dllName) {
if (!::_stricmp(dllName, "ExplorerPatcher.amd64.dll")) {
return true;
}
else if (!::_stricmp(dllName, "ExplorerPatcher.IA-32.dll")) {
return true;
}
return false;
}
static inline bool CheckExtents(size_t viewSize, size_t offset, size_t size) {
return offset < viewSize && size <= viewSize && offset + size <= viewSize;
}
static bool GetDllExportName(char(&dllName)[256], const char* base, size_t viewSize)
{
if (viewSize < sizeof(IMAGE_DOS_HEADER)) {
return false;
}
const IMAGE_DOS_HEADER* dosHdr = reinterpret_cast<const IMAGE_DOS_HEADER*>(base);
if (dosHdr->e_magic != IMAGE_DOS_SIGNATURE) {
return false;
}
if (dosHdr->e_lfanew < 0 || !CheckExtents(viewSize, dosHdr->e_lfanew, sizeof(IMAGE_NT_HEADERS))) {
return false;
}
const IMAGE_NT_HEADERS* ntHdr = reinterpret_cast<const IMAGE_NT_HEADERS*>(base + dosHdr->e_lfanew);
if (ntHdr->Signature != IMAGE_NT_SIGNATURE || ntHdr->OptionalHeader.NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_EXPORT)
return false;
const IMAGE_DATA_DIRECTORY* dirExport = &(ntHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);
if (dirExport->Size < sizeof(IMAGE_EXPORT_DIRECTORY) || !CheckExtents(viewSize, dirExport->VirtualAddress, sizeof(IMAGE_EXPORT_DIRECTORY))) {
return false;
}
const IMAGE_EXPORT_DIRECTORY* exports = reinterpret_cast<const IMAGE_EXPORT_DIRECTORY*>(base + dirExport->VirtualAddress);
// we don't know the export directory name size so assume that at least 256 bytes after the name are safe
if (!CheckExtents(viewSize, exports->Name, ARRAYSIZE(dllName))) {
return false;
}
const char* name = base + exports->Name;
if (strcpy_s(dllName, name)) {
return false;
}
return true;
}
static NTSTATUS NTAPI MyNtMapViewOfSection(
_In_ HANDLE SectionHandle,
_In_ HANDLE ProcessHandle,
_Inout_ _At_(*BaseAddress, _Readable_bytes_(*ViewSize) _Writable_bytes_(*ViewSize) _Post_readable_byte_size_(*ViewSize)) PVOID* BaseAddress,
_In_ ULONG_PTR ZeroBits,
_In_ SIZE_T CommitSize,
_Inout_opt_ PLARGE_INTEGER SectionOffset,
_Inout_ PSIZE_T ViewSize,
_In_ SECTION_INHERIT InheritDisposition,
_In_ ULONG AllocationType,
_In_ ULONG Win32Protect)
{
NTSTATUS ret, status;
if (!RealNtMapViewOfSection)
return STATUS_ACCESS_DENIED;
ret = RealNtMapViewOfSection(
SectionHandle,
ProcessHandle,
BaseAddress,
ZeroBits,
CommitSize,
SectionOffset,
ViewSize,
InheritDisposition,
AllocationType,
Win32Protect);
if (ret < 0) {
return ret;
}
if (!(Win32Protect == PAGE_EXECUTE ||
Win32Protect == PAGE_EXECUTE_READ ||
Win32Protect == PAGE_EXECUTE_READWRITE ||
Win32Protect == PAGE_EXECUTE_WRITECOPY)) {
return ret;
}
SECTION_BASIC_INFORMATION sbi = { 0 };
status = RealNtQuerySection(SectionHandle, SectionBasicInformation, &sbi, sizeof(sbi), NULL);
if (status < 0 || !(sbi.AllocationAttributes & SEC_IMAGE)) {
return ret;
}
char dllName[256] = { 0 };
if (!GetDllExportName(dllName, reinterpret_cast<const char*>(*BaseAddress), *ViewSize)) {
return ret;
}
bool needsBlocking = DllNeedsBlocking(dllName);
if (needsBlocking) {
RealNtUnmapViewOfSection(ProcessHandle, *BaseAddress);
return STATUS_ACCESS_DENIED;
}
return ret;
}
}
EXTERN_C BOOL WINAPI NanaZipBlockDlls()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
RealNtMapViewOfSection = static_cast<NtMapViewOfSectionType>(DetourFindFunction("ntdll.dll", "NtMapViewOfSection"));
RealNtQuerySection = static_cast<NtQuerySectionType>(DetourFindFunction("ntdll.dll", "NtQuerySection"));
RealNtUnmapViewOfSection = static_cast<NtUnmapViewOfSectionType>(DetourFindFunction("ntdll.dll", "NtUnmapViewOfSection"));
if (DetourAttach(&RealNtMapViewOfSection, MyNtMapViewOfSection) != NO_ERROR) {
DetourTransactionAbort();
return FALSE;
}
DetourTransactionCommit();
return TRUE;
}
#else
EXTERN_C BOOL WINAPI NanaZipBlockDlls()
{
return TRUE;
}
#endif

19
NanaZip.Shared/DllBlock.h Normal file
View File

@@ -0,0 +1,19 @@
/*
* PROJECT: NanaZip
* FILE: DllBlock.h
* PURPOSE: Definition for DLL blocker
*
* LICENSE: The MIT License
*
* DEVELOPER: dinhngtu (contact@tudinh.xyz)
* MouriNaruto (KurikoMouri@outlook.jp)
*/
#ifndef NANAZIP_SHARED_DLLBLOCK
#define NANAZIP_SHARED_DLLBLOCK
#include <Windows.h>
EXTERN_C BOOL WINAPI NanaZipBlockDlls();
#endif // !NANAZIP_SHARED_DLLBLOCK

View File

@@ -53,49 +53,19 @@ namespace
dwLength);
}
static BOOL SetThreadInformationWrapper(
_In_ HANDLE hThread,
_In_ THREAD_INFORMATION_CLASS ThreadInformationClass,
_In_ LPVOID ThreadInformation,
_In_ DWORD ThreadInformationSize)
{
static FARPROC CachedProcAddress = ([]() -> FARPROC
{
HMODULE ModuleHandle = ::GetKernel32ModuleHandle();
if (ModuleHandle)
{
return ::GetProcAddress(
ModuleHandle,
"SetThreadInformation");
}
return nullptr;
}());
if (!CachedProcAddress)
{
return FALSE;
}
using ProcType = decltype(::SetThreadInformation)*;
return reinterpret_cast<ProcType>(CachedProcAddress)(
hThread,
ThreadInformationClass,
ThreadInformation,
ThreadInformationSize);
}
static bool IsWindows8OrLater()
{
static bool CachedResult = ::MileIsWindowsVersionAtLeast(6, 2, 0);
return CachedResult;
}
#ifdef NDEBUG
static bool IsWindows8Point1OrLater()
{
static bool CachedResult = ::MileIsWindowsVersionAtLeast(6, 3, 0);
return CachedResult;
}
#endif
static bool IsWindows10OrLater()
{
@@ -135,7 +105,6 @@ EXTERN_C BOOL WINAPI NanaZipEnableMitigations()
{
PROCESS_MITIGATION_DYNAMIC_CODE_POLICY Policy = { 0 };
Policy.ProhibitDynamicCode = 1;
Policy.AllowThreadOptOut = 1;
if (!::SetProcessMitigationPolicyWrapper(
ProcessDynamicCodePolicy,
&Policy,
@@ -163,21 +132,6 @@ EXTERN_C BOOL WINAPI NanaZipEnableMitigations()
return TRUE;
}
EXTERN_C BOOL WINAPI NanaZipThreadDynamicCodeAllow()
{
if (!::IsWindows8Point1OrLater())
{
return TRUE;
}
DWORD ThreadPolicy = THREAD_DYNAMIC_CODE_ALLOW;
return ::SetThreadInformationWrapper(
::GetCurrentThread(),
ThreadDynamicCodePolicy,
&ThreadPolicy,
sizeof(DWORD));
}
EXTERN_C BOOL WINAPI NanaZipDisableChildProcesses()
{
if (!::IsWindows10_1709OrLater())

View File

@@ -15,7 +15,6 @@
#include <Windows.h>
EXTERN_C BOOL WINAPI NanaZipEnableMitigations();
EXTERN_C BOOL WINAPI NanaZipThreadDynamicCodeAllow();
EXTERN_C BOOL WINAPI NanaZipDisableChildProcesses();
#endif // !NANAZIP_SHARED_MITIGATIONS

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>{3B6BA400-CFE5-44E1-A8E3-2DF0CCC5492B}</ProjectGuid>
@@ -21,9 +21,11 @@
<None Include="NanaZip.Shared.Mitigations.props" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="DllBlock.h" />
<ClInclude Include="Mitigations.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="DllBlock.cpp" />
<ClCompile Include="Mitigations.cpp" />
</ItemGroup>
<ItemGroup>
@@ -32,4 +34,4 @@
</PackageReference>
</ItemGroup>
<Import Project="..\Mile.Project.Windows\Mile.Project.Cpp.targets" />
</Project>
</Project>

View File

@@ -9,6 +9,7 @@
#include "../../../../C/Alloc.h"
#ifdef _WIN32
#include "../../../../C/DllSecur.h"
#include "DllBlock.h"
#include "Mitigations.h"
#endif
@@ -672,17 +673,15 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */,
{
g_hInstance = hInstance;
if (!::NanaZipBlockDlls())
{
ErrorMessage("Cannot block DLL loading");
}
if (!::NanaZipEnableMitigations())
{
ErrorMessage("Cannot enable security mitigations");
}
#ifdef NDEBUG
// opt out of dynamic code policy on UI thread to prevent Explorer extension incompatibility
// ignore errors since they shouldn't be fatal
::NanaZipThreadDynamicCodeAllow();
#endif
try
{
try

View File

@@ -9,6 +9,7 @@
#include "../../../../C/Alloc.h"
#ifdef _WIN32
#include "../../../../C/DllSecur.h"
#include "DllBlock.h"
#include "Mitigations.h"
#endif
@@ -678,17 +679,15 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */,
{
g_hInstance = hInstance;
if (!::NanaZipBlockDlls())
{
ErrorMessage("Cannot block DLL loading");
}
if (!::NanaZipEnableMitigations())
{
ErrorMessage("Cannot enable security mitigations");
}
#ifdef NDEBUG
// opt out of dynamic code policy on UI thread to prevent Explorer extension incompatibility
// ignore errors since they shouldn't be fatal
::NanaZipThreadDynamicCodeAllow();
#endif
try
{
try