1417 lines
46 KiB
C
1417 lines
46 KiB
C
/*
|
|
* Copyright 2004-2020 Sandboxie Holdings, LLC
|
|
* Copyright 2021-2024 David Xanatos, xanasoft.com
|
|
*
|
|
* This program 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 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
//---------------------------------------------------------------------------
|
|
// DLL Load Monitor
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
#include "dll.h"
|
|
#include "sbieapi.h"
|
|
#include "core/drv/api_flags.h"
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Defines
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
#define LDR_NUM_CALLBACKS 8
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Structures and Types
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
typedef struct tagDLL {
|
|
const WCHAR *nameW;
|
|
BOOLEAN(*init_func)(HMODULE);
|
|
int state;
|
|
} DLL;
|
|
|
|
typedef struct _LDR_DLL_LOADED_NOTIFICATION_DATA {
|
|
ULONG Flags; //Reserved.
|
|
PCUNICODE_STRING FullDllName; //The full path name of the DLL module.
|
|
PCUNICODE_STRING BaseDllName; //The base file name of the DLL module.
|
|
PVOID DllBase; //A pointer to the base address for the DLL in memory.
|
|
ULONG SizeOfImage; //The size of the DLL image, in bytes.
|
|
} LDR_DLL_LOADED_NOTIFICATION_DATA, *PLDR_DLL_LOADED_NOTIFICATION_DATA;
|
|
|
|
typedef struct _LDR_DLL_UNLOADED_NOTIFICATION_DATA {
|
|
ULONG Flags; //Reserved.
|
|
PCUNICODE_STRING FullDllName; //The full path name of the DLL module.
|
|
PCUNICODE_STRING BaseDllName; //The base file name of the DLL module.
|
|
PVOID DllBase; //A pointer to the base address for the DLL in memory.
|
|
ULONG SizeOfImage; //The size of the DLL image, in bytes.
|
|
} LDR_DLL_UNLOADED_NOTIFICATION_DATA, *PLDR_DLL_UNLOADED_NOTIFICATION_DATA;
|
|
|
|
typedef union _LDR_DLL_NOTIFICATION_DATA {
|
|
LDR_DLL_LOADED_NOTIFICATION_DATA Loaded;
|
|
LDR_DLL_UNLOADED_NOTIFICATION_DATA Unloaded;
|
|
} LDR_DLL_NOTIFICATION_DATA, *PLDR_DLL_NOTIFICATION_DATA;
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Functions
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
static void Ldr_CallOneDllCallback(const UCHAR *ImageNameA, ULONG_PTR ImageBase, BOOL LoadState);
|
|
static void Ldr_CallOneDllCallbackXP(const UCHAR *ImageNameA, ULONG_PTR ImageBase, BOOL LoadState);
|
|
static void Ldr_CallDllCallbacks(void);
|
|
|
|
static NTSTATUS Ldr_LdrLoadDll(WCHAR *PathString, ULONG *DllFlags, UNICODE_STRING *ModuleName, HANDLE *ModuleHandle);
|
|
static NTSTATUS Ldr_Win10_LdrLoadDll(WCHAR *PathString, ULONG *DllFlags, UNICODE_STRING *ModuleName, HANDLE *ModuleHandle);
|
|
static NTSTATUS Ldr_LdrUnloadDll(HANDLE ModuleHandle);
|
|
|
|
static ULONG_PTR Ldr_LdrResolveDelayLoadedAPI(
|
|
HMODULE ImageBase, ULONG_PTR DelayImportDescriptor,
|
|
ULONG_PTR UnknownParameter1, ULONG_PTR UnknownParameter2,
|
|
ULONG_PTR UnknownParameter3, ULONG_PTR UnknownParameter4);
|
|
|
|
static NTSTATUS Ldr_LdrQueryImageFileExecutionOptions(
|
|
UNICODE_STRING *SubKey, const WCHAR *ValueName, ULONG Type,
|
|
void *Buffer, ULONG BufferSize, ULONG *ReturnedLength);
|
|
|
|
static ULONG_PTR Ldr_NtApphelpCacheControl(
|
|
ULONG_PTR Unknown1, ULONG_PTR Unknown2);
|
|
|
|
void Ldr_MyDllCallbackA(const CHAR *ImageName, HMODULE ImageBase, BOOL LoadState);
|
|
void Ldr_MyDllCallbackW(const WCHAR *ImageName, HMODULE ImageBase, BOOL LoadState);
|
|
void Ldr_MyDllCallbackNew(const WCHAR *ImageName, HMODULE ImageBase, BOOL LoadState);
|
|
|
|
static void *Ldr_GetProcAddr_2(const WCHAR *DllName, const WCHAR *ProcName);
|
|
|
|
static void *Ldr_GetProcAddr_3(ULONG_PTR DllBase, const WCHAR *ProcName);
|
|
|
|
static NTSTATUS Ldr_NtLoadDriver(UNICODE_STRING *RegistryPath);
|
|
|
|
static BOOL LdrCheckImmersive();
|
|
|
|
//static NTSTATUS Ldr_LdrRegisterDllNotification(ULONG Flags, void * NotificationFunction, PVOID Context, PVOID *Cookie);
|
|
//static NTSTATUS Ldr_LdrUnregisterDllNotification(void * Cookie);
|
|
|
|
static void CALLBACK Ldr_LdrDllNotification(ULONG NotificationReason, PLDR_DLL_NOTIFICATION_DATA NotificationData, void * Context);
|
|
|
|
static void Ldr_LoadSkipList();
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
ULONG Ldr_SetDdagState_W8(ULONG_PTR BaseAddress, ULONG NewState); // ldr_init
|
|
|
|
//---------------------------------------------------------------------------
|
|
typedef NTSTATUS(NTAPI *P_LdrRegisterDllNotification)(ULONG Flags, void * NotificationFunction, PVOID Context, PVOID *Cookie);
|
|
typedef NTSTATUS(NTAPI *P_LdrUnregisterDllNotification)(void * Cookie);
|
|
|
|
typedef NTSTATUS(*P_LdrLockLoaderLock)(ULONG Flags, ULONG *State, ULONG_PTR *Cookie);
|
|
|
|
typedef NTSTATUS(*P_LdrUnlockLoaderLock)(ULONG Flags, ULONG_PTR Cookie);
|
|
|
|
typedef NTSTATUS(*P_LdrLoadDll)(
|
|
WCHAR *PathString, ULONG *DllFlags,
|
|
UNICODE_STRING *ModuleName, HANDLE *ModuleHandle);
|
|
|
|
typedef NTSTATUS(*P_LdrUnloadDll)(
|
|
HANDLE ModuleHandle);
|
|
|
|
typedef ULONG_PTR(*P_LdrResolveDelayLoadedAPI)(
|
|
HMODULE ImageBase, ULONG_PTR DelayImportDescriptor,
|
|
ULONG_PTR UnknownParameter1, ULONG_PTR UnknownParameter2,
|
|
ULONG_PTR UnknownParameter3, ULONG_PTR UnknownParameter4);
|
|
|
|
typedef NTSTATUS(*P_LdrQueryImageFileExecutionOptions)(
|
|
UNICODE_STRING *SubKey, const WCHAR *ValueName, ULONG Type,
|
|
void *Buffer, ULONG BufferSize, ULONG *ReturnedLength);
|
|
|
|
typedef ULONG_PTR(*P_NtApphelpCacheControl)(
|
|
ULONG_PTR Unknown1, ULONG_PTR Unknown2);
|
|
|
|
typedef NTSTATUS(*P_NtTerminateProcess)(HANDLE ProcessHandle, NTSTATUS ExitStatus);
|
|
|
|
typedef NTSTATUS(*P_NtLoadDriver)(UNICODE_STRING *RegistryPath);
|
|
|
|
typedef void(*P_LdrDllCallback)(const UCHAR *ImageName, HMODULE ImageBase, BOOL LoadState);
|
|
typedef void(*P_LdrDllCallbackW)(const WCHAR *ImageName, HMODULE ImageBase, BOOL LoadState);
|
|
typedef void(*P_Ldr_CallOneDllCallback)(const UCHAR *ImageNameA, ULONG_PTR ImageBase, BOOL LoadState);
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
static P_LdrRegisterDllNotification __sys_LdrRegisterDllNotification = NULL;
|
|
static P_LdrUnregisterDllNotification __sys_LdrUnregisterDllNotification = NULL;
|
|
|
|
static P_NtTerminateProcess __sys_NtTerminateProcess = NULL;
|
|
|
|
static P_LdrLockLoaderLock __sys_LdrLockLoaderLock = NULL;
|
|
static P_LdrUnlockLoaderLock __sys_LdrUnlockLoaderLock = NULL;
|
|
|
|
static P_LdrLoadDll __sys_LdrLoadDll = NULL;
|
|
static P_LdrUnloadDll __sys_LdrUnloadDll = NULL;
|
|
|
|
static P_LdrResolveDelayLoadedAPI __sys_LdrResolveDelayLoadedAPI = NULL;
|
|
|
|
static P_LdrQueryImageFileExecutionOptions __sys_LdrQueryImageFileExecutionOptions = NULL;
|
|
static P_NtApphelpCacheControl __sys_NtApphelpCacheControl = NULL;
|
|
|
|
static P_NtLoadDriver __sys_NtLoadDriver = NULL;
|
|
|
|
P_LdrGetDllHandleEx __sys_LdrGetDllHandleEx = NULL;
|
|
|
|
static P_Ldr_CallOneDllCallback __my_Ldr_CallOneDllCallback = NULL;
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Variables
|
|
//---------------------------------------------------------------------------
|
|
|
|
static DLL Ldr_Dlls[] = {
|
|
{ L"advapi32.dll", AdvApi_Init, 0},
|
|
{ L"crypt32.dll", Crypt_Init, 0},
|
|
{ L"ole32.dll", Ole_Init, 0}, // COM, OLE
|
|
{ L"combase.dll", Com_Init_ComBase, 0}, // COM
|
|
{ L"rpcrt4.dll", RpcRt_Init, 0}, // RPC, epmapper
|
|
{ L"sechost.dll", SecHost_Init, 0}, // SCM
|
|
{ L"shell32.dll", SH32_Init, 0},
|
|
{ L"shcore.dll", Taskbar_SHCore_Init, 0}, // win 8, [Get/Set]CurrentProcessExplicitAppUserModelID
|
|
{ L"wtsapi32.dll", Terminal_Init_WtsApi, 0},
|
|
{ L"winsta.dll", Terminal_Init_WinSta, 0},
|
|
{ L"MsCorEE.dll", MsCorEE_Init, 0}, // .net framework
|
|
{ L"win32u.dll", Win32_Init, 0},
|
|
{ L"user32.dll", Gui_Init, 0},
|
|
{ L"imm32.dll", Gui_Init_IMM32, 0},
|
|
{ L"gdi32.dll", Gdi_Init, 0},
|
|
{ L"gdi32full.dll", Gdi_Full_Init, 0},
|
|
{ L"d3d9.dll", Gui_Init_D3D9, 0},
|
|
{ L"sxs.dll", Sxs_Init, 0}, // add message to SxsInstallW
|
|
{ L"ws2_32.dll", WSA_Init, 0}, // network restrictions
|
|
{ L"iphlpapi.dll", IpHlp_Init, 0}, // ping support
|
|
{ L"msi.dll", Scm_MsiDll, 0}, // msi installer
|
|
{ L"secur32.dll", Lsa_Init_Secur32, 0}, // xp, vista - LsaRegisterLogonProcess
|
|
{ L"sspicli.dll", Lsa_Init_SspiCli, 0}, // win 7 - LsaRegisterLogonProcess
|
|
{ L"netapi32.dll", NetApi_Init, 0}, // xp, vista - NetUseAdd
|
|
{ L"wkscli.dll", NetApi_Init_WksCli, 0}, // win 7 - NetUseAdd
|
|
{ L"pstorec.dll", Pst_Init, 0}, // Protected Storage
|
|
{ L"winspool.drv", Gdi_Init_Spool, 0}, // print spooler workaround for 32 bit
|
|
// Disabled functionality:
|
|
{ L"userenv.dll", UserEnv_Init, 0}, // disable some GPO stuff
|
|
{ L"sfc_os.dll", Sfc_Init, 0}, // disable SFC
|
|
{ L"Pdh.dll", Pdh_Init, 0}, // disable Performance Counters
|
|
{ L"wevtapi.dll", EvtApi_Init, 0}, // disable EvtIntAssertConfig
|
|
{ L"cfgmgr32.dll", Setup_Init_CfgMgr32, 0}, // CM_Add_Driver_PackageW
|
|
// Workarounds:
|
|
{ L"setupapi.dll", Setup_Init_SetupApi, 0}, // VerifyCatalogFile
|
|
{ L"zipfldr.dll", SH32_Init_ZipFldr, 0},
|
|
{ L"uxtheme.dll", SH32_Init_UxTheme, 0}, // explorer.exe, SetWindowThemeAttribute
|
|
{ L"hnetcfg.dll", HNet_Init, 0}, // firewall workaround
|
|
{ L"winnsi.dll", NsiRpc_Init, 0}, // WININET workaround
|
|
{ L"advpack.dll", Proc_Init_AdvPack, 0}, // fix for IE
|
|
{ L"dwrite.dll", Scm_DWriteDll, 0}, // hack for IE 9, make sure FontCache is running
|
|
{ L"ComDlg32.dll", ComDlg32_Init, 0}, // fix for opera.exe
|
|
{ L"ntmarta.dll", Ntmarta_Init, 0}, // workaround for chrome and acrobat reader
|
|
// Non Windows DLLs:
|
|
{ L"osppc.dll", Scm_OsppcDll, 0}, // ensure osppsvc is running
|
|
{ L"mso.dll", File_MsoDll, 0}, // hack for File_IsRecoverable
|
|
{ L"agcore.dll", Custom_SilverlightAgCore, 0}, // msft silverlight - deprecated
|
|
|
|
// $Workaround$ - 3rd party fix
|
|
#ifndef _M_ARM64
|
|
// Non Microsoft DLLs:
|
|
{ L"acscmonitor.dll", Acscmonitor_Init, 0},
|
|
{ L"IDMIECC.dll", Custom_InternetDownloadManager, 0},
|
|
{ L"snxhk.dll", Custom_Avast_SnxHk, 0},
|
|
{ L"snxhk64.dll", Custom_Avast_SnxHk, 0},
|
|
{ L"sysfer.dll", Custom_SYSFER_DLL, 0},
|
|
#endif
|
|
#ifdef _WIN64
|
|
{ L"dgapi64.dll", DigitalGuardian_Init, 0},
|
|
#else
|
|
{ L"dgapi.dll", DigitalGuardian_Init, 0},
|
|
#endif _WIN64
|
|
{ NULL, NULL, 0}
|
|
};
|
|
|
|
static ULONG_PTR *Ldr_Callbacks = 0;
|
|
|
|
static CRITICAL_SECTION Ldr_LoadedModules_CritSec;
|
|
static void *Ldr_LoadedModules = NULL;
|
|
static void *LdrLoaderCookie = NULL;
|
|
static volatile BOOLEAN Ldr_LdrLoadDll_Invoked = FALSE;
|
|
|
|
static BOOLEAN Ldr_DynamicImageDetection = FALSE;
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "ldr_init.c"
|
|
|
|
|
|
NTSTATUS Ldr_NtTerminateProcess(HANDLE ProcessHandle, NTSTATUS ExitStatus)
|
|
{
|
|
NTSTATUS rc;
|
|
|
|
// ProcessHandle is optional. Unregister callback when current process is terminating
|
|
if (!ProcessHandle
|
|
|| ProcessHandle == NtCurrentProcess()
|
|
|| GetCurrentProcessId() == GetProcessId(ProcessHandle)
|
|
)
|
|
{
|
|
__sys_LdrUnregisterDllNotification(LdrLoaderCookie);
|
|
}
|
|
|
|
rc = __sys_NtTerminateProcess(ProcessHandle, ExitStatus);
|
|
|
|
return rc;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
void CALLBACK Ldr_LdrDllNotification(ULONG NotificationReason, PLDR_DLL_NOTIFICATION_DATA NotificationData, void * Context)
|
|
{
|
|
ULONG_PTR LdrCookie = 0;
|
|
NTSTATUS status = 0;
|
|
|
|
if (NotificationReason == 1) {
|
|
status = __sys_LdrLockLoaderLock(0, NULL, &LdrCookie);
|
|
Ldr_MyDllCallbackNew(NotificationData->Loaded.BaseDllName->Buffer, (HMODULE)NotificationData->Loaded.DllBase, TRUE);
|
|
__sys_LdrUnlockLoaderLock(0, LdrCookie);
|
|
}
|
|
else if (NotificationReason == 2) {
|
|
Ldr_MyDllCallbackNew(NotificationData->Unloaded.BaseDllName->Buffer, (HMODULE)NotificationData->Loaded.DllBase, FALSE);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//_FX NTSTATUS Ldr_LdrRegisterDllNotification(ULONG Flags, void * NotificationFunction, PVOID Context, PVOID *Cookie)
|
|
//{
|
|
// NTSTATUS status = 0;
|
|
// status = __sys_LdrRegisterDllNotification(0, ((void *)Ldr_LdrDllNotification), NULL, Cookie);
|
|
// return status;
|
|
//}
|
|
//
|
|
//_FX NTSTATUS Ldr_LdrUnregisterDllNotification(void * Cookie)
|
|
//{
|
|
// return STATUS_SUCCESS;
|
|
//}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// LdrCheckImmersive
|
|
//---------------------------------------------------------------------------
|
|
|
|
//A Microsoft update adds an extra level of integrity checking for "immersive processes" in the win32k driver for
|
|
//windows 8.0 and higher. Microsoft determines a process as immersive by the existence of a PE Header
|
|
//section name ".imrsiv".
|
|
//
|
|
//The following windows updates adds this functionality: KB3081455 for Windows 10 & KB3087039 Windows 8.x.
|
|
//(see JIRA: SBIE-1)
|
|
//
|
|
//The LdrCheckImmersive function counters the new logic in win32k.sys by changing the .imrisv section name in an
|
|
//immersive process to .Imrisv. This will bypass the forced integrity check for immersive processes in win32k.sys
|
|
//so the sandboxie untrusted level will pass the integrity check.
|
|
//
|
|
//
|
|
//win32k.sys/win32kbase.sys code:
|
|
//PE header section name check in the following win32k.sys/win32kbase.sys function:
|
|
//UserProcessImmersiveType(_WIN32_PROCESS_CALLOUT_PARAMETERS *,void *,_PROCESS_IMMERSIVE_TYPE *,ulong *,int *)
|
|
//The reverse engineered code of the "immersive" PE section name check loop of this function is as follows:
|
|
//
|
|
//PE_Section_Name = GetFirstSectioName(PE)
|
|
//while (PE_SectionName) {
|
|
// /*if PE_Section_Name == ".imrsiv" */
|
|
// if(!RtlCompareMemory(PE_Section_Name,".imrsiv",8)) {
|
|
// if(integrityLevel < 0x2000) {
|
|
// return 0xc0000001; /* this breaks sandboxie */
|
|
// }
|
|
// else {
|
|
// return TRUE;
|
|
// }
|
|
// }
|
|
// PE_Section_Name = GetNextSectioname();
|
|
//}
|
|
//return TRUE;
|
|
//; ---------------------------------------------------------------------------
|
|
|
|
BOOL LdrCheckImmersive()
|
|
{
|
|
IMAGE_DOS_HEADER *dos_hdr = 0;
|
|
IMAGE_NT_HEADERS *nt_hdrs = 0;
|
|
IMAGE_SECTION_HEADER *section = 0;
|
|
int i;
|
|
|
|
UCHAR * bindata = (UCHAR *)GET_PEB_IMAGE_BASE;
|
|
dos_hdr = (IMAGE_DOS_HEADER *)bindata;
|
|
if (dos_hdr->e_magic == 'MZ' || dos_hdr->e_magic == 'ZM') {
|
|
nt_hdrs = (IMAGE_NT_HEADERS *)((UCHAR *)dos_hdr + dos_hdr->e_lfanew);
|
|
if (nt_hdrs->Signature != IMAGE_NT_SIGNATURE) { // 'PE\0\0'
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
section = IMAGE_FIRST_SECTION(nt_hdrs);
|
|
|
|
for (i = 0; i < nt_hdrs->FileHeader.NumberOfSections; i++) {
|
|
if (!memcmp(section[i].Name, ".imrsiv", 8)) {
|
|
void *RegionBase = section[i].Name;
|
|
SIZE_T RegionSize = 8;
|
|
ULONG OldProtect;
|
|
ULONG dummy_prot;
|
|
|
|
NtProtectVirtualMemory(NtCurrentProcess(), &RegionBase, &RegionSize, PAGE_EXECUTE_READWRITE, &OldProtect);
|
|
section[i].Name[1] -= 0x20;
|
|
NtProtectVirtualMemory(NtCurrentProcess(), &RegionBase, &RegionSize, OldProtect, &dummy_prot);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Ldr_Init
|
|
//---------------------------------------------------------------------------
|
|
|
|
_FX BOOLEAN Ldr_Init()
|
|
{
|
|
HMODULE module = Dll_Ntdll;
|
|
|
|
UCHAR *ReadImageFileExecOptions;
|
|
|
|
//
|
|
// get access to the loader lock manipulation routines,
|
|
// available on Windows XP and later
|
|
//
|
|
|
|
|
|
if (Ldr_Callbacks) {
|
|
return TRUE;
|
|
}
|
|
__sys_LdrLockLoaderLock = (P_LdrLockLoaderLock)GetProcAddress(Dll_Ntdll, "LdrLockLoaderLock");
|
|
|
|
__sys_LdrUnlockLoaderLock = (P_LdrUnlockLoaderLock)GetProcAddress(Dll_Ntdll, "LdrUnlockLoaderLock");
|
|
|
|
//
|
|
// initialize data
|
|
//
|
|
|
|
InitializeCriticalSection(&Ldr_LoadedModules_CritSec);
|
|
|
|
Ldr_Callbacks = Dll_Alloc(sizeof(ULONG_PTR) * LDR_NUM_CALLBACKS);
|
|
memzero(Ldr_Callbacks, sizeof(ULONG_PTR) * LDR_NUM_CALLBACKS);
|
|
|
|
Ldr_LoadSkipList();
|
|
|
|
|
|
if (Dll_OsBuild >= 6000) { // Windows Vista and later
|
|
SbieDll_RegisterDllCallback(Ldr_MyDllCallbackA);
|
|
__my_Ldr_CallOneDllCallback = Ldr_CallOneDllCallback;
|
|
}
|
|
else { // Windows XP
|
|
SbieDll_RegisterDllCallback(Ldr_MyDllCallbackW);
|
|
__my_Ldr_CallOneDllCallback = Ldr_CallOneDllCallbackXP;
|
|
}
|
|
|
|
//
|
|
// hook entrypoints
|
|
//
|
|
|
|
Ldr_DynamicImageDetection = Config_GetSettingsForImageName_bool(L"DynamicImageDetection", TRUE);
|
|
|
|
if (Dll_OsBuild >= 9600) { // Windows 8.1 and later
|
|
NTSTATUS rc = 0;
|
|
|
|
void *NtTerminateProcess = (P_NtTerminateProcess)GetProcAddress(Dll_Ntdll, "NtTerminateProcess");
|
|
__sys_LdrRegisterDllNotification = (P_LdrRegisterDllNotification)GetProcAddress(Dll_Ntdll, "LdrRegisterDllNotification");
|
|
__sys_LdrUnregisterDllNotification = (P_LdrUnregisterDllNotification)GetProcAddress(Dll_Ntdll, "LdrUnregisterDllNotification");
|
|
|
|
/* needed for future update */
|
|
//void *LdrRegisterDllNotification = (P_LdrRegisterDllNotification)GetProcAddress(Dll_Ntdll,"LdrRegisterDllNotification");
|
|
//void *LdrUnregisterDllNotification = (P_LdrUnregisterDllNotification)GetProcAddress(Dll_Ntdll,"LdrUnregisterDllNotification");
|
|
//SBIEDLL_HOOK(Ldr_,LdrRegisterDllNotification);
|
|
//SBIEDLL_HOOK(Ldr_,LdrUnregisterDllNotification);
|
|
if (__sys_LdrRegisterDllNotification) {
|
|
rc = __sys_LdrRegisterDllNotification(0, ((void *)Ldr_LdrDllNotification), NULL, &LdrLoaderCookie);
|
|
}
|
|
if (rc) {
|
|
return FALSE;
|
|
}
|
|
|
|
SBIEDLL_HOOK(Ldr_, NtTerminateProcess);
|
|
SBIEDLL_HOOK(Ldr_Win10_, LdrLoadDll);
|
|
}
|
|
else { // Windows 8 and before
|
|
SBIEDLL_HOOK(Ldr_, LdrLoadDll);
|
|
SBIEDLL_HOOK(Ldr_, LdrUnloadDll);
|
|
SBIEDLL_HOOK(Ldr_, LdrQueryImageFileExecutionOptions);
|
|
|
|
if (Dll_OsBuild >= 8400) {
|
|
|
|
P_LdrResolveDelayLoadedAPI LdrResolveDelayLoadedAPI =
|
|
(P_LdrResolveDelayLoadedAPI)GetProcAddress(
|
|
Dll_Ntdll, "LdrResolveDelayLoadedAPI");
|
|
|
|
P_NtApphelpCacheControl NtApphelpCacheControl =
|
|
(P_NtApphelpCacheControl)GetProcAddress(
|
|
Dll_Ntdll, "NtApphelpCacheControl");
|
|
|
|
SBIEDLL_HOOK(Ldr_, LdrResolveDelayLoadedAPI);
|
|
SBIEDLL_HOOK(Ldr_, NtApphelpCacheControl);
|
|
}
|
|
}
|
|
SBIEDLL_HOOK(Ldr_, NtLoadDriver);
|
|
|
|
|
|
//
|
|
// set PEB.ReadImageFileExecOptions to non-zero to force ntdll to call
|
|
// LdrQueryImageFileExecutionOptions so we can call Ldr_CallDllCallbacks
|
|
//
|
|
// on Windows 8, we use a hook on NtApphelpCacheControl instead
|
|
//
|
|
|
|
if (Dll_OsBuild < 8400) { // Windows 7 and older
|
|
|
|
ReadImageFileExecOptions = (UCHAR *)(NtCurrentPeb() + 1);
|
|
|
|
if (!(*ReadImageFileExecOptions))
|
|
*ReadImageFileExecOptions = '*';
|
|
}
|
|
else {
|
|
LdrCheckImmersive();
|
|
}
|
|
|
|
|
|
//
|
|
// set PEB.ProcessParameters->LoaderThreads = 0
|
|
//
|
|
|
|
if (SbieApi_QueryConfBool(NULL, L"NoParallelLoading", FALSE)) {
|
|
RTL_USER_PROCESS_PARAMETERS* ProcessParms = Proc_GetRtlUserProcessParameters();
|
|
ProcessParms->LoaderThreads = 0;
|
|
}
|
|
|
|
//
|
|
// do some more initializations based on the executable image,
|
|
// and inject code at the program entrypoint
|
|
//
|
|
|
|
|
|
// Ronen fix --
|
|
//
|
|
// load inject DLLs
|
|
//
|
|
|
|
// Ldr_LoadInjectDlls();
|
|
|
|
//
|
|
// initialize manifest
|
|
//
|
|
|
|
Ldr_Inject_Init(FALSE);
|
|
Sxs_ActivateDefaultManifest((void *)Ldr_ImageBase);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// SbieDll_RegisterDllCallback
|
|
//---------------------------------------------------------------------------
|
|
|
|
_FX BOOLEAN SbieDll_RegisterDllCallback(void *Callback)
|
|
{
|
|
NTSTATUS status = 0;
|
|
ULONG_PTR LdrCookie;
|
|
ULONG i;
|
|
BOOLEAN ok = FALSE;
|
|
ULONG state = 2;
|
|
|
|
if (Dll_OsBuild < 9600) {
|
|
status = __sys_LdrLockLoaderLock(0, NULL, &LdrCookie);
|
|
}
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
for (i = 0; i < LDR_NUM_CALLBACKS; ++i) {
|
|
|
|
if (!Ldr_Callbacks[i]) {
|
|
|
|
Ldr_Callbacks[i] = (ULONG_PTR)Callback;
|
|
ok = TRUE;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Dll_OsBuild < 9600) {
|
|
__sys_LdrUnlockLoaderLock(0, LdrCookie);
|
|
}
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Ldr_CallOneDllCallback
|
|
//---------------------------------------------------------------------------
|
|
|
|
_FX void Ldr_CallOneDllCallback(const UCHAR *ImageNameA, ULONG_PTR ImageBase, BOOL LoadState)
|
|
{
|
|
ULONG i;
|
|
|
|
for (i = 0; i < LDR_NUM_CALLBACKS; ++i) {
|
|
ULONG_PTR callback = Ldr_Callbacks[i];
|
|
if (!callback)
|
|
break;
|
|
__try {
|
|
((P_LdrDllCallback)callback)(ImageNameA, (HMODULE)ImageBase, LoadState);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
_FX void Ldr_CallOneDllCallbackXP(const UCHAR *ImageNameA, ULONG_PTR ImageBase, BOOL LoadState)
|
|
{
|
|
ULONG i;
|
|
|
|
WCHAR ImageNameW[512];
|
|
WCHAR *NameW = ImageNameW;
|
|
for (i = 0; i < 511 && ImageNameA[i]; ++i)
|
|
NameW[i] = ImageNameA[i];
|
|
NameW[i] = L'\0';
|
|
|
|
for (i = 0; i < LDR_NUM_CALLBACKS; ++i) {
|
|
|
|
ULONG_PTR callback = Ldr_Callbacks[i];
|
|
if (!callback)
|
|
break;
|
|
|
|
__try {
|
|
((P_LdrDllCallbackW)callback)(ImageNameW, (HMODULE)ImageBase, LoadState);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Ldr_CallDllCallbacks
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX void Ldr_CallDllCallbacks(void)
|
|
{
|
|
static ULONG CallDepth = 0;
|
|
|
|
NTSTATUS status;
|
|
void *buf;
|
|
ULONG len1, len2;
|
|
|
|
struct _SYSTEM_MODULE_INFORMATION *OldList, *NewList;
|
|
ULONG i, iOld, iNew;
|
|
MODULE_INFO *pOld, *pNew;
|
|
BOOLEAN found;
|
|
|
|
//
|
|
// if this is a recursive call to Ldr_CallDllCallbacks, then a callback
|
|
// function, which we already invoked through this function, has loaded
|
|
// another DLL, causing control to reach this function again. in this
|
|
// case just let the other Ldr_CallDllCallbacks handle it
|
|
//
|
|
|
|
if (InterlockedIncrement(&CallDepth) != 1)
|
|
return;
|
|
|
|
//
|
|
// get the most current list of modules loaded into the process
|
|
//
|
|
|
|
len1 = 1024 * 32;
|
|
buf = NULL;
|
|
|
|
//Ldr_inCallBack++;
|
|
|
|
for (i = 0; i < 6; ++i) {
|
|
|
|
buf = Dll_Alloc(len1);
|
|
status = LdrQueryProcessModuleInformation(buf, len1, &len2);
|
|
if (NT_SUCCESS(status))
|
|
break;
|
|
|
|
Dll_Free(buf);
|
|
buf = NULL;
|
|
|
|
if (status != STATUS_INFO_LENGTH_MISMATCH)
|
|
break;
|
|
|
|
len1 = len2 + 1024;
|
|
}
|
|
|
|
if (!buf) {
|
|
SbieApi_Log(2205, L"LoadedModules [%08X]", status);
|
|
return;
|
|
}
|
|
|
|
OldList = (struct _SYSTEM_MODULE_INFORMATION *)Ldr_LoadedModules;
|
|
|
|
NewList = (struct _SYSTEM_MODULE_INFORMATION *)buf;
|
|
|
|
//
|
|
// check each module that appears in the 'old' list against
|
|
// the 'new' list and invoke 'unload' callbacks
|
|
//
|
|
|
|
if (OldList) {
|
|
|
|
for (iOld = 0; iOld < OldList->ModuleCount; ++iOld) {
|
|
|
|
pOld = &OldList->ModuleInfo[iOld];
|
|
|
|
found = FALSE;
|
|
|
|
for (iNew = 0; iNew < NewList->ModuleCount; ++iNew) {
|
|
|
|
pNew = &NewList->ModuleInfo[iNew];
|
|
|
|
if (pOld->ImageBaseAddress == pNew->ImageBaseAddress &&
|
|
strcmp(pOld->Path, pNew->Path) == 0) {
|
|
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
|
|
__my_Ldr_CallOneDllCallback(pOld->Path + pOld->NameOffset,
|
|
pNew->ImageBaseAddress, FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// check each module that appears in the 'new' list against
|
|
// the 'old' list and invoke 'load' callbacks
|
|
//
|
|
|
|
for (iNew = 0; iNew < NewList->ModuleCount; ++iNew) {
|
|
|
|
pNew = &NewList->ModuleInfo[iNew];
|
|
|
|
found = FALSE;
|
|
|
|
if (OldList) {
|
|
|
|
for (iOld = 0; iOld < OldList->ModuleCount; ++iOld) {
|
|
|
|
pOld = &OldList->ModuleInfo[iOld];
|
|
|
|
if (pOld->ImageBaseAddress == pNew->ImageBaseAddress &&
|
|
strcmp(pOld->Path, pNew->Path) == 0) {
|
|
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
|
|
ULONG OldState = Ldr_SetDdagState_W8(pNew->ImageBaseAddress, 9);
|
|
|
|
ANSI_STRING ansi;
|
|
UNICODE_STRING uni;
|
|
RtlInitString(&ansi, pNew->Path);
|
|
RtlAnsiStringToUnicodeString(&uni, &ansi, TRUE);
|
|
if (iNew == 0 && *uni.Buffer)
|
|
*uni.Buffer = L'*';
|
|
_wcslwr(uni.Buffer);
|
|
SbieApi_MonitorPut(MONITOR_IMAGE, uni.Buffer);
|
|
RtlFreeUnicodeString(&uni);
|
|
|
|
__my_Ldr_CallOneDllCallback(pNew->Path + pNew->NameOffset,
|
|
pNew->ImageBaseAddress, TRUE);
|
|
|
|
if (OldState)
|
|
Ldr_SetDdagState_W8(pNew->ImageBaseAddress, OldState);
|
|
}
|
|
}
|
|
|
|
//
|
|
// finish. note that if CallDepth > 1 at this point, then we had a
|
|
// recursive invocation that did not do anything, and we should check
|
|
// if any new modules have been loaded
|
|
//
|
|
|
|
EnterCriticalSection(&Ldr_LoadedModules_CritSec);
|
|
|
|
Ldr_LoadedModules = NewList;
|
|
|
|
LeaveCriticalSection(&Ldr_LoadedModules_CritSec);
|
|
|
|
if (OldList && OldList != NewList)
|
|
Dll_Free(OldList);
|
|
|
|
if (InterlockedExchange(&CallDepth, 0) > 1) {
|
|
|
|
Ldr_CallDllCallbacks();
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Ldr_CallDllCallbacks_WithLock
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX void Ldr_CallDllCallbacks_WithLock(void)
|
|
{
|
|
ULONG_PTR LdrCookie = 0;
|
|
NTSTATUS status = 0;
|
|
ULONG state = 2;
|
|
|
|
status = __sys_LdrLockLoaderLock(0, NULL, &LdrCookie);
|
|
if (NT_SUCCESS(status)) {
|
|
Ldr_CallDllCallbacks();
|
|
__sys_LdrUnlockLoaderLock(0, LdrCookie);
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Ldr_LdrLoadDllImpl
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX NTSTATUS Ldr_LdrLoadDllImpl(
|
|
WCHAR* PathString,
|
|
ULONG* DllFlags,
|
|
UNICODE_STRING* ModuleName,
|
|
HANDLE* ModuleHandle)
|
|
{
|
|
NTSTATUS status = 0;
|
|
|
|
//WCHAR text[4096];
|
|
//Sbie_snwprintf(text, ARRAYSIZE(text), L"%s (loading...)", (ModuleName && ModuleName->Buffer) ? ModuleName->Buffer : PathString);
|
|
//SbieApi_MonitorPutMsg(MONITOR_IMAGE, text);
|
|
|
|
status = __sys_LdrLoadDll(PathString, DllFlags, ModuleName, ModuleHandle);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
WCHAR text[4096];
|
|
Sbie_snwprintf(text, ARRAYSIZE(text), L"%s (load failed 0x%08X)", (ModuleName && ModuleName->Buffer) ? ModuleName->Buffer : PathString, status);
|
|
SbieApi_MonitorPutMsg(MONITOR_IMAGE, text);
|
|
}
|
|
|
|
//Sbie_snwprintf(text, ARRAYSIZE(text), L"%s (... 0x%08X)", (ModuleName && ModuleName->Buffer) ? ModuleName->Buffer : PathString, status);
|
|
//SbieApi_MonitorPutMsg(MONITOR_IMAGE, text);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Ldr_LdrLoadDll
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX NTSTATUS Ldr_LdrLoadDll(
|
|
WCHAR *PathString,
|
|
ULONG *DllFlags,
|
|
UNICODE_STRING *ModuleName,
|
|
HANDLE *ModuleHandle)
|
|
{
|
|
//
|
|
// load the DLL and invoke callbacks
|
|
//
|
|
|
|
ULONG_PTR LdrCookie = 0;
|
|
NTSTATUS status = 0;
|
|
ULONG state = 2;
|
|
|
|
status = __sys_LdrLockLoaderLock(0, &state, &LdrCookie);
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
status = Ldr_LdrLoadDllImpl(PathString, DllFlags, ModuleName, ModuleHandle);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
Ldr_CallDllCallbacks();
|
|
Ldr_LdrLoadDll_Invoked = TRUE;
|
|
}
|
|
__sys_LdrUnlockLoaderLock(0, LdrCookie);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Ldr_Win10_LdrLoadDll
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX NTSTATUS Ldr_Win10_LdrLoadDll(
|
|
WCHAR *PathString,
|
|
ULONG *DllFlags,
|
|
UNICODE_STRING *ModuleName,
|
|
HANDLE *ModuleHandle)
|
|
{
|
|
//
|
|
// load the DLL
|
|
//
|
|
|
|
return Ldr_LdrLoadDllImpl(PathString, DllFlags, ModuleName, ModuleHandle);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Ldr_LdrUnloadDll
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX NTSTATUS Ldr_LdrUnloadDll(HANDLE ModuleHandle)
|
|
{
|
|
NTSTATUS status = 0;
|
|
ULONG_PTR LdrCookie = 0;
|
|
ULONG state = 2;
|
|
DWORD tid;
|
|
|
|
//
|
|
// prevent unloading of SbieDll
|
|
//
|
|
|
|
tid = GetCurrentThreadId();
|
|
if (ModuleHandle == Dll_Instance)
|
|
return STATUS_SUCCESS;
|
|
//
|
|
// unload the DLL
|
|
//
|
|
status = __sys_LdrLockLoaderLock(0, NULL, &LdrCookie);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
status = __sys_LdrUnloadDll(ModuleHandle);
|
|
|
|
if (Ldr_LdrLoadDll_Invoked) {
|
|
|
|
//
|
|
// since static dlls can't be freed, there is no real point
|
|
// to call Ldr_CallDllCallbacks before any dynamic dll has
|
|
// ever loaded
|
|
//
|
|
// more importantly, apphelp.dll (the shim engine) can call
|
|
// LdrUnloadDll on aclayers.dll, before ntdll starts to
|
|
// initialize static dlls, and that is too early to call
|
|
// Ldr_CallDllCallbacks and run our module init routines
|
|
//
|
|
|
|
Ldr_CallDllCallbacks();
|
|
}
|
|
|
|
__sys_LdrUnlockLoaderLock(0, LdrCookie);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Ldr_LdrResolveDelayLoadedAPI
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX ULONG_PTR Ldr_LdrResolveDelayLoadedAPI(
|
|
HMODULE ImageBase, ULONG_PTR DelayImportDescriptor,
|
|
ULONG_PTR UnknownParameter1, ULONG_PTR UnknownParameter2,
|
|
ULONG_PTR UnknownParameter3, ULONG_PTR UnknownParameter4)
|
|
{
|
|
//
|
|
// load the DLL and invoke callbacks
|
|
//
|
|
ULONG_PTR result;
|
|
|
|
result = __sys_LdrResolveDelayLoadedAPI(
|
|
ImageBase, DelayImportDescriptor, UnknownParameter1,
|
|
UnknownParameter2, UnknownParameter3, UnknownParameter4);
|
|
|
|
Ldr_CallDllCallbacks_WithLock();
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Ldr_LdrQueryImageFileExecutionOptions
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX NTSTATUS Ldr_LdrQueryImageFileExecutionOptions(
|
|
UNICODE_STRING *SubKey, const WCHAR *ValueName, ULONG Type,
|
|
void *Buffer, ULONG BufferSize, ULONG *ReturnedLength)
|
|
{
|
|
|
|
NTSTATUS rc;
|
|
//
|
|
// our Ldr_CallDllCallbacks misses static import DLLs because these are
|
|
// loaded using the unexported LdrpLoadDll function which we can't hook.
|
|
// however LdrpRunInitializeRoutines (also unexported) calls the exported
|
|
// LdrQueryImageFileExecutionOptions before running init routines, so
|
|
// this is a good opportunity to call our DLL callbacks
|
|
//
|
|
|
|
Ldr_CallDllCallbacks(); // loader lock held by ntdll
|
|
|
|
//
|
|
// if we caused PEB.ReadImageFileExecOptions to be non-zero, we will restore
|
|
// the zero value in Ldr_Inject_Entry and return STATUS_OBJECT_NAME_NOT_FOUND
|
|
// here to prevent recursive call in __sys_LdrQueryImageFileExecutionOptions
|
|
//
|
|
if (Dll_OsBuild < 8400) {
|
|
|
|
UCHAR *ReadImageFileExecOptions = (UCHAR *)(NtCurrentPeb() + 1);
|
|
if (*ReadImageFileExecOptions == '*')
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
}
|
|
|
|
rc = __sys_LdrQueryImageFileExecutionOptions(
|
|
SubKey, ValueName, Type, Buffer, BufferSize, ReturnedLength);
|
|
return rc;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Ldr_NtApphelpCacheControl
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX ULONG_PTR Ldr_NtApphelpCacheControl(
|
|
ULONG_PTR Unknown1, ULONG_PTR Unknown2)
|
|
{
|
|
ULONG_PTR rc;
|
|
//
|
|
// invoke DLL callbacks
|
|
//
|
|
Ldr_CallDllCallbacks_WithLock();
|
|
rc = __sys_NtApphelpCacheControl(Unknown1, Unknown2);
|
|
return rc;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Ldr_DetectImageType
|
|
//---------------------------------------------------------------------------
|
|
|
|
BOOL Ldr_CheckFirefoxDll(const WCHAR* dll_path)
|
|
{
|
|
//_wcsicmp(dll_path, L"xul.dll") == 0;
|
|
return _wcsicmp(dll_path, L"mozglue.dll") == 0;
|
|
}
|
|
|
|
BOOL Ldr_CheckChromeDll(const WCHAR* dll_path)
|
|
{
|
|
if (_wcsicmp(dll_path, L"chrome_elf.dll") == 0)
|
|
return TRUE;
|
|
|
|
//
|
|
// Some Chromium based browsers like Microsoft Edge or Vivaldi rename the dll
|
|
// from chrome_elf.dll to msedge_elf.dll
|
|
//
|
|
|
|
SIZE_T dll_len = wcslen(dll_path);
|
|
SIZE_T exe_len = wcslen(Dll_ImageName);
|
|
if ((dll_len - 8) == (exe_len - 4))
|
|
return _wcsnicmp(Dll_ImageName, dll_path, exe_len - 4) == 0;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
_FX void Ldr_DetectImageType(const CHAR *ImageName)
|
|
{
|
|
//
|
|
// Electron apps can have arbitrary names, but need to be treated like the Chrome browser
|
|
// hence we try to detect them by the DLL names they load during runtime
|
|
//
|
|
|
|
if (Ldr_DynamicImageDetection && Dll_ImageType == DLL_IMAGE_UNSPECIFIED) // && !Dll_EntryComplete
|
|
{
|
|
if (Ldr_CheckFirefoxDll(ImageName)) {
|
|
Dll_ImageType = DLL_IMAGE_MOZILLA_FIREFOX;
|
|
}
|
|
else if (Ldr_CheckChromeDll(ImageName)) {
|
|
Dll_ImageType = DLL_IMAGE_GOOGLE_CHROME;
|
|
}
|
|
|
|
if (Dll_ImageType != DLL_IMAGE_UNSPECIFIED) {
|
|
|
|
WCHAR msg[128];
|
|
Sbie_snwprintf(msg, 128, L"Detected web browser image");
|
|
SbieApi_MonitorPutMsg(MONITOR_IMAGE | MONITOR_TRACE, msg);
|
|
|
|
SbieApi_QueryProcessInfoEx(0, 'spit', Dll_ImageType);
|
|
|
|
if (Dll_RestrictedToken || Dll_AppContainerToken) {
|
|
|
|
Dll_ChromeSandbox = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Ldr_MyDllCallbacks (A,W,New)
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX void Ldr_MyDllCallbackA(const CHAR *ImageName, HMODULE ImageBase, BOOL LoadState) // Windows Vista, 7, 8.0
|
|
{
|
|
WCHAR ImageNameW[128];
|
|
Sbie_snwprintf(ImageNameW, ARRAYSIZE(ImageNameW), L"%S", ImageName);
|
|
|
|
Ldr_MyDllCallbackNew(ImageNameW, ImageBase, LoadState);
|
|
}
|
|
|
|
|
|
_FX void Ldr_MyDllCallbackW(const WCHAR *ImageName, HMODULE ImageBase, BOOL LoadState) // Windows XP
|
|
{
|
|
Ldr_MyDllCallbackNew(ImageName, ImageBase, LoadState);
|
|
}
|
|
|
|
|
|
_FX void Ldr_MyDllCallbackNew(const WCHAR *ImageName, HMODULE ImageBase, BOOL LoadState) // Windows 8.1 and later
|
|
{
|
|
WCHAR text[4096];
|
|
if(LoadState)
|
|
Sbie_snwprintf(text, ARRAYSIZE(text), L"%s (loaded)", ImageName);
|
|
else
|
|
Sbie_snwprintf(text, ARRAYSIZE(text), L"%s (unloaded)", ImageName);
|
|
SbieApi_MonitorPutMsg(MONITOR_IMAGE, text);
|
|
|
|
//
|
|
// invoke our sub-modules as necessary
|
|
//
|
|
|
|
DLL *dll = Ldr_Dlls;
|
|
while (dll->nameW) {
|
|
BOOLEAN ok;
|
|
if (_wcsicmp(ImageName, dll->nameW) == 0 && (dll->state & 2) == 0) {
|
|
if (LoadState) {
|
|
if (!dll->state) {
|
|
EnterCriticalSection(&Ldr_LoadedModules_CritSec);
|
|
dll->state = 1;
|
|
LeaveCriticalSection(&Ldr_LoadedModules_CritSec);
|
|
ok = dll->init_func(ImageBase);
|
|
if (!ok)
|
|
SbieApi_Log(2318, dll->nameW);
|
|
}
|
|
}
|
|
else {
|
|
if (dll->state) {
|
|
//SbieDll_UnHookModule(ImageBase);
|
|
EnterCriticalSection(&Ldr_LoadedModules_CritSec);
|
|
dll->state = 0;
|
|
LeaveCriticalSection(&Ldr_LoadedModules_CritSec);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
++dll;
|
|
}
|
|
|
|
if (LoadState)
|
|
SbieDll_TraceModule(ImageBase);
|
|
else
|
|
SbieDll_UnHookModule(ImageBase);
|
|
|
|
if (LoadState)
|
|
Ldr_DetectImageType(ImageName);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Ldr_GetProcAddr
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX void *Ldr_GetProcAddrOld(const WCHAR *DllName, const WCHAR *ProcNameW)
|
|
{
|
|
NTSTATUS status;
|
|
void *proc = Ldr_GetProcAddr_2(DllName, ProcNameW);
|
|
|
|
if (!proc) {
|
|
// if (Dll_Windows < 10) {
|
|
ULONG_PTR LdrCookie;
|
|
ULONG state = 0, i = 0;
|
|
|
|
for (i = 0; i < 20; ++i) {
|
|
status = __sys_LdrLockLoaderLock(2 /*try*/, &state, &LdrCookie);
|
|
if (NT_SUCCESS(status) && (state <= 1))
|
|
break;
|
|
else {
|
|
NtYieldExecution();
|
|
}
|
|
}
|
|
|
|
if (i < 20 && state <= 1) {
|
|
HMODULE DllBase;
|
|
DllBase = GetModuleHandle(DllName);
|
|
if (!DllBase) {
|
|
DllBase = LoadLibrary(DllName);
|
|
}
|
|
if (DllBase) {
|
|
|
|
proc = Ldr_GetProcAddr_3((ULONG_PTR)DllBase, ProcNameW);
|
|
}
|
|
|
|
if (state == 1) // if lock was really taken
|
|
__sys_LdrUnlockLoaderLock(0, LdrCookie);
|
|
}
|
|
|
|
}
|
|
|
|
return proc;
|
|
}
|
|
|
|
|
|
_FX void *Ldr_GetProcAddrNew(const WCHAR *DllName, const WCHAR *ProcNameW, char * ProcNameA)
|
|
{
|
|
NTSTATUS status;
|
|
void *proc = NULL;
|
|
// char buffer[768];
|
|
// sprintf(buffer,"GetProcAddrNew: DllName = %S, ProcW = %S, ProcA = %s\n",DllName,ProcNameW,ProcNameA);
|
|
// OutputDebugStringA(buffer);
|
|
|
|
if (Dll_OsBuild < 9600) { // Windows 8.0 or earlier
|
|
proc = Ldr_GetProcAddr_2(DllName, ProcNameW);
|
|
if (!proc) {
|
|
ULONG_PTR LdrCookie;
|
|
ULONG state = 0, i = 0;
|
|
|
|
for (i = 0; i < 20; ++i) {
|
|
status = __sys_LdrLockLoaderLock(2 /*try*/, &state, &LdrCookie);
|
|
if (NT_SUCCESS(status) && (state <= 1))
|
|
break;
|
|
else {
|
|
NtYieldExecution();
|
|
}
|
|
}
|
|
|
|
if (i < 20 && state <= 1) {
|
|
HMODULE DllBase;
|
|
DllBase = GetModuleHandle(DllName);
|
|
if (!DllBase) {
|
|
DllBase = LoadLibrary(DllName);
|
|
}
|
|
if (DllBase) {
|
|
|
|
proc = Ldr_GetProcAddr_3((ULONG_PTR)DllBase, ProcNameW);
|
|
}
|
|
|
|
if (state == 1) // if lock was really taken
|
|
__sys_LdrUnlockLoaderLock(0, LdrCookie);
|
|
}
|
|
}
|
|
}
|
|
else { // Windows 8.1 and later
|
|
HMODULE DllBase;
|
|
DllBase = GetModuleHandle(DllName);
|
|
if (!DllBase) {
|
|
DllBase = LoadLibrary(DllName);
|
|
}
|
|
if (DllBase) {
|
|
proc = GetProcAddress(DllBase, ProcNameA);
|
|
}
|
|
|
|
}
|
|
return proc;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Ldr_GetProcAddr_2
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX void *Ldr_GetProcAddr_2(const WCHAR *DllName, const WCHAR *ProcName)
|
|
{
|
|
void *proc = NULL;
|
|
struct _SYSTEM_MODULE_INFORMATION *list;
|
|
ULONG i, j;
|
|
const ULONG n = wcslen(DllName);
|
|
|
|
EnterCriticalSection(&Ldr_LoadedModules_CritSec);
|
|
|
|
list = (struct _SYSTEM_MODULE_INFORMATION *)Ldr_LoadedModules;
|
|
if (list) {
|
|
|
|
for (i = 0; i < list->ModuleCount; ++i) {
|
|
|
|
const MODULE_INFO *mod = &list->ModuleInfo[i];
|
|
const UCHAR *name = &mod->Path[mod->NameOffset];
|
|
for (j = 0; j < n; ++j) {
|
|
if (tolower(name[j]) != towlower(DllName[j]))
|
|
break;
|
|
}
|
|
if (j == n) {
|
|
|
|
proc = Ldr_GetProcAddr_3(mod->ImageBaseAddress, ProcName);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&Ldr_LoadedModules_CritSec);
|
|
|
|
return proc;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Ldr_GetProcAddr_3
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX void *Ldr_GetProcAddr_3(ULONG_PTR DllBase, const WCHAR *ProcName)
|
|
{
|
|
void *proc = NULL;
|
|
ULONG i, j;
|
|
const ULONG n = wcslen(ProcName);
|
|
|
|
IMAGE_OPTIONAL_HEADER *OptHdr = Ldr_OptionalHeader(DllBase);
|
|
if (OptHdr->NumberOfRvaAndSizes) {
|
|
|
|
const IMAGE_DATA_DIRECTORY *dir0 = &OptHdr->DataDirectory[0];
|
|
if (dir0->VirtualAddress && dir0->Size) {
|
|
|
|
IMAGE_EXPORT_DIRECTORY *exports = (IMAGE_EXPORT_DIRECTORY *)
|
|
((UCHAR *)DllBase + dir0->VirtualAddress);
|
|
|
|
ULONG *names = (ULONG *)
|
|
((UCHAR *)DllBase + exports->AddressOfNames);
|
|
|
|
for (i = 0; i < exports->NumberOfNames; ++i) {
|
|
|
|
UCHAR *name = (UCHAR *)DllBase + names[i];
|
|
for (j = 0; j < n; ++j) {
|
|
if (tolower(name[j]) != towlower(ProcName[j]))
|
|
break;
|
|
}
|
|
if (j == n) {
|
|
|
|
USHORT *ordinals = (USHORT *)
|
|
((UCHAR *)DllBase + exports->AddressOfNameOrdinals);
|
|
if (ordinals[i] < exports->NumberOfFunctions) {
|
|
|
|
ULONG *functions = (ULONG *)
|
|
((UCHAR *)DllBase + exports->AddressOfFunctions);
|
|
|
|
proc = (UCHAR *)DllBase + functions[ordinals[i]];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (proc && (ULONG_PTR)proc >= (ULONG_PTR)exports
|
|
&& (ULONG_PTR)proc < (ULONG_PTR)exports + dir0->Size) {
|
|
|
|
//
|
|
// don't handle forwarded exports
|
|
//
|
|
|
|
SbieApi_Log(2205, L"EXPORT %s", proc);
|
|
proc = NULL;
|
|
}
|
|
}
|
|
}
|
|
return proc;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Ldr_NtLoadDriver
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX NTSTATUS Ldr_NtLoadDriver(UNICODE_STRING *RegistryPath)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = __sys_NtLoadDriver(RegistryPath);
|
|
if (status == STATUS_PRIVILEGE_NOT_HELD) {
|
|
|
|
WCHAR *DriverName = NULL;
|
|
|
|
// if we got a legitimate UNICODE_STRING then try to display
|
|
// the driver name. note that Kerio Personal Firewall passes
|
|
// an invalid parameter (RegistryPath = 0xFFFFFFxx)
|
|
|
|
if (RegistryPath &&
|
|
(((ULONG)(ULONG_PTR)RegistryPath) & 0xFFFFFF00) != 0xFFFFFF00
|
|
&& RegistryPath->Buffer) {
|
|
|
|
DriverName = wcsrchr(RegistryPath->Buffer, L'\\');
|
|
if (DriverName)
|
|
++DriverName;
|
|
}
|
|
|
|
if (DriverName)
|
|
SbieApi_Log(2103, L"%S [%S] (NtLoadDriver)", DriverName, Dll_BoxName);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Ldr_LoadSkipList
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX void Ldr_LoadSkipList()
|
|
{
|
|
WCHAR buf[128];
|
|
ULONG index = 0;
|
|
while (1) { // for each setting
|
|
NTSTATUS status = SbieApi_QueryConfAsIs(NULL, L"DllSkipHook", index, buf, sizeof(buf));
|
|
++index;
|
|
if (NT_SUCCESS(status)) {
|
|
DLL *dll = Ldr_Dlls;
|
|
while (dll->nameW) { // find dll entry
|
|
if (_wcsicmp(buf, dll->nameW) == 0) {
|
|
dll->state |= 2;
|
|
break;
|
|
}
|
|
++dll;
|
|
}
|
|
}
|
|
else if (status != STATUS_BUFFER_TOO_SMALL)
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// SbieDll_IsDllSkipHook
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
_FX BOOLEAN SbieDll_IsDllSkipHook(const WCHAR* ImageName)
|
|
{
|
|
DLL *dll = Ldr_Dlls;
|
|
while (dll->nameW) {
|
|
if (_wcsicmp(ImageName, dll->nameW) == 0)
|
|
return (dll->state & 2) != 0;
|
|
++dll;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|