diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8d4b70f --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +# Build output +/out/ +/build/ +/artifacts/ + +# Native build leftovers +CMakeCache.txt +CMakeFiles/ +cmake-build-*/ + +# .NET build output +bin/ +obj/ +.vs/ + +# Generated scripts and logs +*.log +*.cache diff --git a/CLRNet.proj b/CLRNet.proj index 8831229..0385e90 100644 --- a/CLRNet.proj +++ b/CLRNet.proj @@ -62,19 +62,23 @@ - {12345678-1234-5678-9012-123456789012} + {8F4C5A55-2F4B-4C40-8A64-6B501B28B42C} CLRNetCore - {12345678-1234-5678-9012-123456789013} + {AF9323CB-8F8C-4D9F-9E1F-349437DD9C10} CLRNetInterop - {12345678-1234-5678-9012-123456789014} + {6E8E9D3E-8B1F-4C1B-BD5A-9852E5F0C8C2} CLRNetSystem + + {9F05A3F2-2F3C-436C-9B8C-045386CFB7A3} + CLRNetHost + - {12345678-1234-5678-9012-123456789015} + {4B3E8C7E-5FA6-4F16-B5E8-5E0F0C52F51F} CLRNetTests @@ -92,11 +96,15 @@ - + + + + + - + @@ -107,31 +115,37 @@ + - - - + + + + + - + - + - + - + + + + - + diff --git a/QUICK_START.md b/QUICK_START.md index 5f2bc20..8942d1b 100644 --- a/QUICK_START.md +++ b/QUICK_START.md @@ -1,172 +1,56 @@ -# CLRNet Quick Start Guide - -## πŸš€ 5-Minute Integration - -Get your Windows Phone 8.1 app running with CLRNet in just 5 minutes! - -### Step 1: Add CLRNet to Your Project (1 minute) - -1. **Copy CLRNet Binaries** - ``` - YourApp/ - β”œβ”€β”€ CLRNet/ - β”‚ β”œβ”€β”€ CLRNetCore.dll - β”‚ β”œβ”€β”€ CLRNetInterop.dll - β”‚ β”œβ”€β”€ CLRNetSystem.dll - β”‚ └── CLRNetHost.exe - └── SamplePlugin.dll - ``` - -2. **Update Your .csproj File** - ```xml - - - Always - - - ``` - -### Step 2: Initialize CLRNet (2 minutes) - -Add this to your `MainPage.xaml.cs`: - -```csharp -using System.Runtime.InteropServices; - -public sealed partial class MainPage : Page -{ - [DllImport("CLRNetCore.dll")] - private static extern int CLRNet_Initialize(IntPtr config); - - [DllImport("CLRNetCore.dll")] - private static extern int CLRNet_LoadAssembly(string path); - - [DllImport("CLRNetCore.dll")] - private static extern int CLRNet_ExecuteMethod(string type, string method); - - protected override void OnNavigatedTo(NavigationEventArgs e) - { - // Initialize CLRNet - CLRNet_Initialize(IntPtr.Zero); - } -} -``` - -### Step 3: Load and Execute (1 minute) - -```csharp -private void RunPlugin_Click(object sender, RoutedEventArgs e) -{ - // Load your plugin - CLRNet_LoadAssembly("SamplePlugin.dll"); - - // Execute plugin method - CLRNet_ExecuteMethod("PluginMain", "HelloWorld"); -} -``` - -### Step 4: Update Package Manifest (1 minute) +# Quick start -Add to `Package.appxmanifest`: +This guide walks through building the Windows Phone 8.1 runtime and host from a +fresh clone. -```xml - - - CLRNet\CLRNetCore.dll - - - -``` - -## βœ… That's It! +## 1. Install prerequisites -Your app now has dynamic .NET assembly loading capabilities! +- Windows 10 or 11 +- Visual Studio 2019/2022 with the *Windows Phone 8.1* components +- Windows Phone 8.1 SDK (`C:\Program Files (x86)\Windows Phone Kits\8.1`) +- PowerShell 5.0+ -## πŸ”₯ Advanced Usage (Optional) +## 2. Build everything with a single command -### Plugin Interface -```csharp -public interface IMyPlugin -{ - void Initialize(); - string Execute(string input); -} - -// In your plugin assembly -public class MyPlugin : IMyPlugin -{ - public void Initialize() { /* setup */ } - public string Execute(string input) { return "Processed: " + input; } -} +```powershell +pwsh .\build-wp81.ps1 -Configuration Release -Platform ARM ``` -### Dynamic Code Compilation -```csharp -// Compile C# code at runtime -string code = @" - public class RuntimeCode - { - public static string Process() { return ""Hello from runtime!""; } - }"; +The script validates the SDK, locates MSBuild, and drives `CLRNet.proj` to build +all native libraries, the phone host, and the smoke-test executable. Logs are +written to `build/logs/` for troubleshooting. -// CLRNet can compile and execute this dynamically -``` +## 3. Package binaries -### Game Modding System -```csharp -public class GameModLoader -{ - public async Task LoadMod(string modFile) - { - await CLRNet_LoadAssembly(modFile); - CLRNet_ExecuteMethod("GameMod", "OnModLoaded"); - } -} +```powershell +pwsh .\build-wp81.ps1 -Target Package -Configuration Release -Platform ARM ``` -## πŸ“± Real-World Examples - -### 1. **Business Rules Engine** -Load business logic from external assemblies without app updates. - -### 2. **Plugin Marketplace** -Allow users to download and install app extensions. - -### 3. **Dynamic UI Generation** -Create UI components from user-defined templates. - -### 4. **Scripting System** -Enable power users to write custom scripts. - -### 5. **A/B Testing Framework** -Load different feature implementations dynamically. - -## πŸ› οΈ Troubleshooting - -**Runtime not initializing?** -- Check if CLRNet binaries are in your app package -- Verify Package.appxmanifest has the extension registration +Packaging copies the runtime, interop, system, host, and test artifacts into the +`build/bin/ARM/Release/packages/` folder ready to be merged into an AppX payload. -**Assembly won't load?** -- Ensure assembly targets .NET Framework 4.0 -- Check file path is correct +## 4. Inspect outputs -**Method execution fails?** -- Verify class and method names are exact -- Check method is public and static +- `build/bin/ARM//CLRNetCore.dll` +- `build/bin/ARM//CLRNetInterop.dll` +- `build/bin/ARM//CLRNetSystem.dll` +- `build/bin/ARM//CLRNetHost.exe` +- `build/bin/ARM//CLRNetTests.exe` -## 🎯 Next Steps +## 5. Run the smoke tests -1. **Read the full [Implementation Guide](IMPLEMENTATION_GUIDE.md)** -2. **Check out the [complete sample app](examples/WP81Integration/)** -3. **Explore advanced patterns and best practices** +Copy the runtime folder to a Windows Phone 8.1 device or emulator and launch +`CLRNetTests.exe`. The test harness verifies that the execution engine, security +layer, and interop managers all initialize correctly in the phone environment. -## πŸ’‘ Pro Tips +## 6. Integrate into your AppX project -- Initialize CLRNet once at app startup -- Cache loaded assemblies for better performance -- Use background threads for heavy operations -- Always handle exceptions gracefully -- Test on actual Windows Phone devices +1. Copy the binaries from `build/bin/ARM/Release/` into your app's `CLRNet/` + directory. +2. Include the host executable in the AppX manifest and add the required phone + capabilities. +3. Bundle the `packages/CLRNet-Complete/` contents alongside your managed + assemblies before creating the final XAP/AppX package. -**Happy Coding with CLRNet! πŸŽ‰** \ No newline at end of file +For a deeper dive into deployment practices review `build/README.md` and the +`WP81_*` summaries in the repository root. diff --git a/README.md b/README.md index 360451d..21c046f 100644 --- a/README.md +++ b/README.md @@ -1,116 +1,81 @@ -# CLRNET - Modern CLR Runtime for Windows Phone 8.1 +# CLRNet -πŸ† **PROJECT COMPLETE** - A fully functional modern .NET CLR runtime for Windows Phone 8.1 devices with system integration capabilities. +CLRNet is a Windows Phone 8.1 hosting layer that embeds a lightweight managed +runtime, security boundary, and interop bridge so existing CLR assemblies can run +on Lumia-era hardware. The project focuses on producing production-ready ARM +binaries and a host executable that can be dropped directly into an app package. -## βœ… Your Runtime is WORKING! +## Highlights -**Status: FULLY OPERATIONAL** - All 3 phases complete with 20+ components implemented +- **Phone-ready binaries** – MSBuild definitions target the `v120_wp81` + toolset and generate ARM Release libraries plus a phone-friendly host. +- **System integration** – the runtime ships with compatibility shims, + replacement hooks, and interop managers that understand WinRT, P/Invoke, + and hardware capability gating. +- **Security aware** – the security manager models manifest capabilities, + sandbox levels, and emergency lockdown flows so packaged apps stay within + Windows Phone policy constraints. +- **One-step build** – run a single PowerShell script and the repository emits + libraries, the host executable, smoke tests, and pre-staged deployment + packages under `build/bin///`. -Run `.\scripts\simple-check.ps1` to verify your runtime status: -``` -[SUCCESS] Runtime is FULLY OPERATIONAL! -- Phase 1: 5/5 complete βœ… -- Phase 2: 4/4 complete βœ… -- Phase 3: 3/3 complete βœ… -``` - -## Project Overview - -This project aims to bring modern .NET capabilities to Windows Phone 8.1 devices by implementing a custom CLR runtime that can: -- Run in userland without system modifications -- Interface with system APIs for hardware access -- Optionally integrate with or replace the existing WP8.1 CLR -- Enable development of custom tools and automation on the device - -## Project Phases +## Quick start -### Phase 1: Userland Runtime βœ… COMPLETE -**Goal:** Modern CLR runtime with core execution capabilities -- **Components:** Core execution engine, type system, GC, assembly loader, JIT compiler -- **Status:** 5/5 components implemented and tested -- **Location:** `src/phase1-userland/` +1. **Install prerequisites** + - Windows 10 or 11 + - Visual Studio 2019/2022 with the *Windows Phone 8.1* toolset + - Windows Phone 8.1 SDK (`C:\Program Files (x86)\Windows Phone Kits\8.1`) + - PowerShell 5.0+ -### Phase 2: System Interop βœ… COMPLETE -**Goal:** Windows Runtime and hardware API integration -- **Components:** WinRT bridge, P/Invoke engine, hardware access, security manager -- **Status:** 7/7 components implemented with full WP8.1 integration -- **Location:** `src/interop/` +2. **Clone the repository and open an elevated Developer Command Prompt** -### Phase 3: System Integration βœ… COMPLETE -**Goal:** Optional CLR replacement with safety mechanisms -- **Components:** CLR replacement engine, deep system hooks, compatibility layer, rollback system -- **Status:** 7/7 components implemented with enterprise-grade safety -- **Location:** `src/system/` +3. **Build the runtime and host** -## 🎯 What Your Runtime Can Do RIGHT NOW + ```powershell + pwsh .\build-wp81.ps1 -Configuration Release -Platform ARM + ``` -βœ… **Execute Modern .NET Code** - Run applications with better performance than stock WP8.1 CLR -βœ… **Access All Hardware** - Camera, GPS, accelerometer, microphone, speakers, etc. -βœ… **Use Windows APIs** - Full Windows Runtime API access from managed code -βœ… **Legacy Compatibility** - Run existing .NET Framework 2.0-4.8 applications -βœ… **System Integration** - Optional CLR replacement with automatic rollback safety -βœ… **Production Ready** - Comprehensive testing and validation framework + The script validates the environment, locates MSBuild, invokes the + aggregated `CLRNet.proj`, and writes a binary log to `build/logs/`. -## Directory Structure +4. **Package for deployment** -``` -CLRNET/ -β”œβ”€β”€ README.md # This file -β”œβ”€β”€ docs/ # Technical documentation -β”œβ”€β”€ research/ # Analysis and research notes -β”œβ”€β”€ src/ # Source code organized by phase -β”‚ β”œβ”€β”€ phase1-userland/ # Sandboxed CLR implementation -β”‚ β”œβ”€β”€ phase2-interop/ # System API integration -β”‚ β”œβ”€β”€ phase3-integration/ # System CLR replacement -β”‚ └── phase4-automation/ # Custom applications -β”œβ”€β”€ tools/ # Build tools and utilities -β”œβ”€β”€ tests/ # Test applications and validation -└── build/ # Build configuration and scripts -``` + ```powershell + pwsh .\build-wp81.ps1 -Target Package -Configuration Release -Platform ARM + ``` -## πŸš€ How to Use Your Runtime + Packaging stages the runtime, interop, system libraries, host executable, and + smoke-test harness into `build/bin/ARM/Release/packages/`. -### Track A β€” App-Local BCL Overlay -Developers looking to target newer .NET APIs on Windows Phone 8.1 can follow the [Track A roadmap](docs/TRACK-A-APP-LOCAL-BCL-OVERLAY.md) to ship app-local facade assemblies (e.g., `System.Runtime`, `System.Text.Json`). The overlay now includes managed implementations for `ValueTask`, async streams, `ArrayPool`, a curated `System.Text.Json` subset, WinRT-backed IO helpers, and a hardened HTTP handler so modern libraries can resolve against CLRNET-provided implementations without modifying working system components. See the [App-Local Facade Overlay Integration Guide](docs/APP_LOCAL_OVERLAY_GUIDE.md) for step-by-step packaging instructions and manifest samples. +## Outputs -### Track B β€” Userspace IL Engine -Dynamic scenarios that rely on `Expression.Compile`, `DynamicMethod`, or other runtime codegen can now target the [Track B IL engine](docs/TRACK-B-USERSPACE-IL-ENGINE.md). The `CLRNet_VM_*` exports expose a sandboxed interpreter with bytecode caching, host-controlled syscalls, and call-site configuration so apps can compile IL once, persist the bytecode to `LocalCache/VmBytecode`, and execute under deterministic budgets without requiring the platform JIT. +After a successful build you will find: -### Track C β€” Modern C# pipeline -Leverage the [Track C build pipeline](docs/TRACK-C-MODERN-CS-PIPELINE.md) to compile with Roslyn `/langversion:latest`, automatically reference CLRNET's facade overlays, post-process assemblies with Mono.Cecil to retarget APIs, and optionally route `Expression.Compile()` through the Track B VM. The sample project in `examples/ModernCSharpPipeline` demonstrates records, ValueTask, JSON serialization, and VM-backed expressions working together on Windows Phone 8.1. +- `build/bin/ARM//CLRNetCore.dll` – the execution engine +- `build/bin/ARM//CLRNetInterop.dll` – WinRT/PInvoke bridge +- `build/bin/ARM//CLRNetSystem.dll` – compatibility and hook surface +- `build/bin/ARM//CLRNetHost.exe` – phone host executable +- `build/bin/ARM//CLRNetTests.exe` – smoke test harness +- `build/bin/ARM//packages/` – runtime, interop, system, host, and + combined deployment bundles -### End-to-end integration playbook -When starting a new app (or upgrading an existing one), follow the [CLRNET Application Integration Playbook](docs/CLRNET_APP_INTEGRATION_PLAYBOOK.md) for a stage-by-stage checklist that stitches TracksΒ A–C togetherβ€”covering build configuration, IL post-processing, overlay packaging, VM warm-up, and on-device verification. +## Manual MSBuild usage -### Executive comparison snapshot -Need to brief stakeholders quickly? Share the [CLRNET vs. Windows Phone 8.1 overview](docs/CLRNET_VS_WP81_OVERVIEW.md) for a plain-language summary and capability coverage table. +If you prefer direct MSBuild invocations you can target the umbrella project: -### Quick Verification (30 seconds) ```powershell -# Quick health check (30 seconds) -.\scripts\simple-check.ps1 - -# Full regression suite -.\scripts\run-all-tests.ps1 - -# Inspect detailed status & phase reports -Get-Content docs\RUNTIME_STATUS.md -Get-Content docs\PHASE1-STATUS.md +msbuild CLRNet.proj /t:Build /p:Configuration=Release /p:Platform=ARM /m +msbuild CLRNet.proj /t:Package /p:Configuration=Release /p:Platform=ARM ``` -For runtime overlays, enable verbose logging via `OverlayConfig` to confirm which assemblies are resolved from the app package versus the OS. - ---- +## Tests -## Further Reading -* [CLRNET Application Integration Playbook](docs/CLRNET_APP_INTEGRATION_PLAYBOOK.md) -* [App-Local Overlay Guide](docs/APP_LOCAL_OVERLAY_GUIDE.md) -* [Userspace IL Engine Roadmap](docs/TRACK-B-USERSPACE-IL-ENGINE.md) -* [Modern C# Pipeline Roadmap](docs/TRACK-C-MODERN-CS-PIPELINE.md) -* [Stakeholder Overview](docs/CLRNET_VS_WP81_OVERVIEW.md) -* [Deployment scripts](scripts/) +`CLRNetTests.exe` exercises the runtime bootstrap, security shim creation, and +interop manager initialization. Launch it on a Windows Phone emulator or device +after copying the runtime binaries into your AppX payload. ---- +## Additional documentation -## License -This project is licensed under the [MIT License](LICENSE). +- `build/README.md` – deep dive into the build system and packaging layout +- `WP81_*` reports – historical design notes, compatibility matrices, and + validation playbooks for Windows Phone 8.1 deployments diff --git a/build-wp81.ps1 b/build-wp81.ps1 new file mode 100644 index 0000000..31f98a8 --- /dev/null +++ b/build-wp81.ps1 @@ -0,0 +1,110 @@ +param( + [ValidateSet("Build", "Clean", "Rebuild", "Package")] + [string]$Target = "Build", + + [ValidateSet("ARM", "x86")] + [string]$Platform = "ARM", + + [ValidateSet("Debug", "Release")] + [string]$Configuration = "Release", + + [switch]$Package +) + +function Write-Status { + param([string]$Message) + $timestamp = Get-Date -Format "HH:mm:ss" + Write-Host "[$timestamp] $Message" +} + +function Assert-Windows { + if ($env:OS -notlike '*Windows*' -and [System.Environment]::OSVersion.Platform -ne [System.PlatformID]::Win32NT) { + throw "The Windows Phone 8.1 toolchain is only available on Windows." + } +} + +function Resolve-MSBuild { + $knownPaths = @( + (Join-Path $env:ProgramFiles(x86) 'Microsoft Visual Studio\2022\BuildTools\MSBuild\Current\Bin\MSBuild.exe'), + (Join-Path $env:ProgramFiles(x86) 'Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\MSBuild.exe'), + (Join-Path $env:ProgramFiles(x86) 'MSBuild\14.0\Bin\MSBuild.exe') + ) + + foreach ($path in $knownPaths) { + if (Test-Path $path) { + return $path + } + } + + $vswhere = Join-Path $env:ProgramFiles(x86) 'Microsoft Visual Studio\Installer\vswhere.exe' + if (Test-Path $vswhere) { + $installPath = & $vswhere -latest -requires Microsoft.Component.MSBuild -format value -property installationPath + if ($installPath) { + $candidate = Join-Path $installPath 'MSBuild\Current\Bin\MSBuild.exe' + if (Test-Path $candidate) { + return $candidate + } + } + } + + $fromPath = Get-Command msbuild.exe -ErrorAction SilentlyContinue + if ($fromPath) { + return $fromPath.Path + } + + throw "Could not locate MSBuild. Install Visual Studio 2019/2022 with the Windows Phone 8.1 tools." +} + +function Test-WP81SDK { + $sdkPath = Join-Path $env:ProgramFiles(x86) 'Windows Phone Kits\8.1' + if (-not (Test-Path $sdkPath)) { + throw "Windows Phone 8.1 SDK not found. Install the Windows Phone 8.1 tooling from the Windows 10 SDK installer." + } +} + +Assert-Windows +$msbuild = Resolve-MSBuild +Test-WP81SDK + +$repoRoot = Split-Path -Parent $MyInvocation.MyCommand.Path +$proj = Join-Path $repoRoot 'CLRNet.proj' +$logRoot = Join-Path $repoRoot 'build\logs' +if (-not (Test-Path $logRoot)) { + New-Item -ItemType Directory -Path $logRoot | Out-Null +} + +$msbuildArgs = @( + "`"$proj`"", + "/m", + "/nr:false", + "/p:Configuration=$Configuration", + "/p:Platform=$Platform" +) + +switch ($Target) { + 'Clean' { $msbuildArgs += '/t:Clean' } + 'Build' { $msbuildArgs += '/t:Build' } + 'Rebuild' { $msbuildArgs += '/t:Rebuild' } + 'Package' { $msbuildArgs += '/t:Package' } +} + +$binlog = Join-Path $logRoot "wp81-$Platform-$Configuration.binlog" +$msbuildArgs += "/bl:$binlog" + +Write-Status "Invoking MSBuild ($Target | $Platform | $Configuration)" +Write-Status "Using MSBuild at $msbuild" +& $msbuild @msbuildArgs +if ($LASTEXITCODE -ne 0) { + throw "MSBuild failed with exit code $LASTEXITCODE" +} + +if ($Package -and $Target -ne 'Package') { + Write-Status "Packaging runtime artifacts" + & $msbuild "`"$proj`"" /t:Package /p:Configuration=$Configuration /p:Platform=$Platform /bl:"$binlog.package" + if ($LASTEXITCODE -ne 0) { + throw "Packaging failed with exit code $LASTEXITCODE" + } +} + +Write-Status "Build complete. Binaries in build\\bin\\$Platform\\$Configuration" +Write-Status "Packages in build\\bin\\$Platform\\$Configuration\\packages" diff --git a/src/CLRNetCore/CLRNetCore.vcxproj b/src/CLRNetCore/CLRNetCore.vcxproj new file mode 100644 index 0000000..e54198e --- /dev/null +++ b/src/CLRNetCore/CLRNetCore.vcxproj @@ -0,0 +1,111 @@ + + + + + Debug + ARM + + + Release + ARM + + + + {8F4C5A55-2F4B-4C40-8A64-6B501B28B42C} + Win32Proj + CLRNetCore + en-US + Windows Phone 8.1 + 8.1 + true + 8.1 + + + + DynamicLibrary + true + v120_wp81 + false + Unicode + + + DynamicLibrary + false + v120_wp81 + true + Unicode + + + + + + + + + + + $(SolutionDir)build\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)build\obj\$(Platform)\$(Configuration)\Core\ + CLRNetCore + + + $(SolutionDir)build\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)build\obj\$(Platform)\$(Configuration)\Core\ + CLRNetCore + + + + NotUsing + Level3 + Disabled + WIN32;_WINDOWS;_USRDLL;CLRNETCORE_EXPORTS;PLATFORM_WP81;%(PreprocessorDefinitions) + $(ProjectDir)..\phase1-userland\core;$(ProjectDir)..\phase1-userland;%(AdditionalIncludeDirectories) + MultiThreadedDebugDLL + true + + + Windows + true + runtimeobject.lib;windowsapp.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + MaxSpeed + true + true + WIN32;_WINDOWS;_USRDLL;CLRNETCORE_EXPORTS;PLATFORM_WP81;NDEBUG;%(PreprocessorDefinitions) + $(ProjectDir)..\phase1-userland\core;$(ProjectDir)..\phase1-userland;%(AdditionalIncludeDirectories) + MultiThreadedDLL + true + + + Windows + true + true + true + runtimeobject.lib;windowsapp.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/CLRNetHost/CLRNetHost.cpp b/src/CLRNetHost/CLRNetHost.cpp new file mode 100644 index 0000000..a0d0d1d --- /dev/null +++ b/src/CLRNetHost/CLRNetHost.cpp @@ -0,0 +1,226 @@ +#include "../phase1-userland/core/CoreExecutionEngine.h" +#include "../phase1-userland/core/AssemblyLoader.h" +#include "../interop/InteropManager.h" +#include "../system/compatibility/CompatibilityShim.h" +#include "../system/replacement/CLRReplacementEngine.h" + +#include +#include +#include +#include +#include + +using namespace CLRNet::Phase1; +using namespace CLRNet::Interop; +using namespace CLRNet::System; + +namespace +{ + struct HostOptions + { + std::wstring assemblyPath; + std::wstring typeName = L"Program"; + std::wstring methodName = L"Main"; + std::wstring manifestPath; + bool explainOnly = false; + bool disableInterop = false; + }; + + void PrintUsage() + { + std::wcout << L"CLRNetHost - Windows Phone 8.1 runtime bootstrapper\n"; + std::wcout << L"Usage:\n"; + std::wcout << L" CLRNetHost.exe -assembly [-type ] [-method ]\n"; + std::wcout << L" [-manifest ] [--explain] [--no-interop]\n\n"; + std::wcout << L"Options:\n"; + std::wcout << L" -assembly Required. Managed assembly that contains the entry point.\n"; + std::wcout << L" -type Fully qualified type name. Defaults to Program.\n"; + std::wcout << L" -method Entry method name. Defaults to Main.\n"; + std::wcout << L" -manifest Optional application manifest used for capability loading.\n"; + std::wcout << L" --explain Initialize the runtime and print discovered metadata without executing code.\n"; + std::wcout << L" --no-interop Skip InteropManager initialization for very small payloads.\n"; + } + + std::string Narrow(const std::wstring& value) + { + if (value.empty()) + { + return std::string(); + } + + int required = WideCharToMultiByte(CP_UTF8, 0, value.c_str(), static_cast(value.size()), nullptr, 0, nullptr, nullptr); + if (required <= 0) + { + return std::string(); + } + + std::string result(static_cast(required), '\0'); + WideCharToMultiByte(CP_UTF8, 0, value.c_str(), static_cast(value.size()), + result.data(), required, nullptr, nullptr); + return result; + } + + bool ParseArguments(int argc, wchar_t* argv[], HostOptions& options) + { + for (int i = 1; i < argc; ++i) + { + std::wstring arg = argv[i]; + if (arg == L"-assembly" && i + 1 < argc) + { + options.assemblyPath = argv[++i]; + } + else if (arg == L"-type" && i + 1 < argc) + { + options.typeName = argv[++i]; + } + else if (arg == L"-method" && i + 1 < argc) + { + options.methodName = argv[++i]; + } + else if (arg == L"-manifest" && i + 1 < argc) + { + options.manifestPath = argv[++i]; + } + else if (arg == L"--explain") + { + options.explainOnly = true; + } + else if (arg == L"--no-interop") + { + options.disableInterop = true; + } + else if (arg == L"-?" || arg == L"--help" || arg == L"/?") + { + return false; + } + else + { + std::wcerr << L"Unknown option: " << arg << L"\n"; + return false; + } + } + + return !options.assemblyPath.empty(); + } + + void DescribeRuntime(const CoreExecutionEngine& engine) + { + std::wcout << L"CLRNet runtime initialized successfully.\n"; + std::wcout << L" - Core type system ready\n"; + std::wcout << L" - Garbage collector active\n"; + std::wcout << L" - JIT compiler primed\n"; + std::wcout << L"Use -type and -method to run a specific entry point.\n"; + (void)engine; + } + + std::unique_ptr InitializeCompatibility() + { + auto config = CompatibilityFactory::CreateMinimalCompatibilityConfig(); + auto shim = std::unique_ptr(CompatibilityFactory::CreateCompatibilityShim(config)); + if (shim) + { + shim->Initialize(CompatibilityLevel::Standard); + } + return shim; + } + + std::unique_ptr InitializeReplacementEngine() + { + auto engine = std::unique_ptr(CLRReplacementFactory::CreateEngine(ReplacementLevel::ProcessLevel)); + if (engine) + { + engine->AttachToCurrentProcess(); + } + return engine; + } + + std::unique_ptr InitializeInterop(const HostOptions& options) + { + auto configuration = InteropFactory::CreateStandardConfiguration(L"CLRNetHost"); + configuration.manifestPath = options.manifestPath; + auto interop = std::unique_ptr(InteropFactory::CreateCustomInstance(configuration)); + if (interop) + { + interop->Initialize(configuration); + } + return interop; + } +} + +int wmain(int argc, wchar_t* argv[]) +{ + HostOptions options; + if (!ParseArguments(argc, argv, options)) + { + PrintUsage(); + return 1; + } + + std::wcout << L"[CLRNet] Bootstrapping runtime...\n"; + + CoreExecutionEngine runtime; + if (!runtime.Initialize()) + { + std::wcerr << L"Failed to initialize core execution engine." << std::endl; + return 2; + } + + auto compatibilityShim = InitializeCompatibility(); + auto replacementEngine = InitializeReplacementEngine(); + std::unique_ptr interopManager; + if (!options.disableInterop) + { + interopManager = InitializeInterop(options); + } + + if (!runtime.LoadAssembly(options.assemblyPath)) + { + std::wcerr << L"Failed to load assembly: " << options.assemblyPath << std::endl; + runtime.Shutdown(); + return 3; + } + + if (options.explainOnly) + { + DescribeRuntime(runtime); + if (interopManager) + { + auto status = interopManager->GetStatus(); + std::wcout << L"Interop status: " << static_cast(status) << L"\n"; + } + runtime.Shutdown(); + return 0; + } + + std::string typeName = Narrow(options.typeName); + std::string methodName = Narrow(options.methodName); + void* entryPoint = runtime.GetMethodAddress(typeName, methodName); + if (!entryPoint) + { + std::wcerr << L"Could not resolve method " << options.typeName << L"::" << options.methodName << std::endl; + runtime.Shutdown(); + return 4; + } + + std::wcout << L"Executing " << options.typeName << L"::" << options.methodName << L"...\n"; + int exitCode = runtime.ExecuteMethod(entryPoint, nullptr, 0); + std::wcout << L"Managed entry point returned " << exitCode << L"\n"; + + if (interopManager) + { + interopManager->Shutdown(); + } + + if (compatibilityShim) + { + compatibilityShim->Cleanup(); + } + + if (replacementEngine) + { + CLRReplacementFactory::DestroyEngine(replacementEngine.release()); + } + + runtime.Shutdown(); + return exitCode; +} diff --git a/src/CLRNetHost/CLRNetHost.vcxproj b/src/CLRNetHost/CLRNetHost.vcxproj new file mode 100644 index 0000000..0666d5e --- /dev/null +++ b/src/CLRNetHost/CLRNetHost.vcxproj @@ -0,0 +1,109 @@ + + + + + Debug + ARM + + + Release + ARM + + + + {9F05A3F2-2F3C-436C-9B8C-045386CFB7A3} + Win32Proj + CLRNetHost + Windows Phone 8.1 + 8.1 + true + 8.1 + + + + Application + true + v120_wp81 + Unicode + + + Application + false + v120_wp81 + true + Unicode + + + + + + + + + + + $(SolutionDir)build\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)build\obj\$(Platform)\$(Configuration)\Host\ + CLRNetHost + + + $(SolutionDir)build\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)build\obj\$(Platform)\$(Configuration)\Host\ + CLRNetHost + + + + NotUsing + Level3 + Disabled + WIN32;_WINDOWS;PLATFORM_WP81;%(PreprocessorDefinitions) + $(ProjectDir)..\phase1-userland\core;$(ProjectDir)..\interop;$(ProjectDir)..\system;$(ProjectDir)..\system\compatibility;$(ProjectDir)..\system\replacement;%(AdditionalIncludeDirectories) + MultiThreadedDebugDLL + true + + + Console + true + CLRNetCore.lib;CLRNetInterop.lib;CLRNetSystem.lib;runtimeobject.lib;windowsapp.lib;ole32.lib;shlwapi.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + MaxSpeed + true + true + WIN32;_WINDOWS;PLATFORM_WP81;NDEBUG;%(PreprocessorDefinitions) + $(ProjectDir)..\phase1-userland\core;$(ProjectDir)..\interop;$(ProjectDir)..\system;$(ProjectDir)..\system\compatibility;$(ProjectDir)..\system\replacement;%(AdditionalIncludeDirectories) + MultiThreadedDLL + true + + + Console + true + true + true + CLRNetCore.lib;CLRNetInterop.lib;CLRNetSystem.lib;runtimeobject.lib;windowsapp.lib;ole32.lib;shlwapi.lib;%(AdditionalDependencies) + + + + + + + + {8F4C5A55-2F4B-4C40-8A64-6B501B28B42C} + false + + + {AF9323CB-8F8C-4D9F-9E1F-349437DD9C10} + false + + + {6E8E9D3E-8B1F-4C1B-BD5A-9852E5F0C8C2} + false + + + + + diff --git a/src/CLRNetInterop/CLRNetInterop.vcxproj b/src/CLRNetInterop/CLRNetInterop.vcxproj new file mode 100644 index 0000000..6ff4313 --- /dev/null +++ b/src/CLRNetInterop/CLRNetInterop.vcxproj @@ -0,0 +1,113 @@ + + + + + Debug + ARM + + + Release + ARM + + + + {AF9323CB-8F8C-4D9F-9E1F-349437DD9C10} + Win32Proj + CLRNetInterop + Windows Phone 8.1 + 8.1 + true + 8.1 + + + + DynamicLibrary + true + v120_wp81 + Unicode + + + DynamicLibrary + false + v120_wp81 + true + Unicode + + + + + + + + + + + $(SolutionDir)build\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)build\obj\$(Platform)\$(Configuration)\Interop\ + CLRNetInterop + + + $(SolutionDir)build\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)build\obj\$(Platform)\$(Configuration)\Interop\ + CLRNetInterop + + + + NotUsing + Level3 + Disabled + WIN32;_WINDOWS;_USRDLL;CLRNETINTEROP_EXPORTS;PLATFORM_WP81;%(PreprocessorDefinitions) + $(ProjectDir)..\interop;$(ProjectDir)..\interop\hardware;$(ProjectDir)..\interop\winrt;$(ProjectDir)..\interop\pinvoke;$(ProjectDir)..\interop\security;$(ProjectDir)..\phase1-userland\core;%(AdditionalIncludeDirectories) + MultiThreadedDebugDLL + true + + + Windows + true + CLRNetCore.lib;runtimeobject.lib;windowsapp.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + MaxSpeed + true + true + WIN32;_WINDOWS;_USRDLL;CLRNETINTEROP_EXPORTS;PLATFORM_WP81;NDEBUG;%(PreprocessorDefinitions) + $(ProjectDir)..\interop;$(ProjectDir)..\interop\hardware;$(ProjectDir)..\interop\winrt;$(ProjectDir)..\interop\pinvoke;$(ProjectDir)..\interop\security;$(ProjectDir)..\phase1-userland\core;%(AdditionalIncludeDirectories) + MultiThreadedDLL + true + + + Windows + true + true + true + CLRNetCore.lib;runtimeobject.lib;windowsapp.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + {8F4C5A55-2F4B-4C40-8A64-6B501B28B42C} + false + + + + + diff --git a/src/CLRNetSystem/CLRNetSystem.vcxproj b/src/CLRNetSystem/CLRNetSystem.vcxproj new file mode 100644 index 0000000..c9805ac --- /dev/null +++ b/src/CLRNetSystem/CLRNetSystem.vcxproj @@ -0,0 +1,113 @@ + + + + + Debug + ARM + + + Release + ARM + + + + {6E8E9D3E-8B1F-4C1B-BD5A-9852E5F0C8C2} + Win32Proj + CLRNetSystem + Windows Phone 8.1 + 8.1 + true + 8.1 + + + + DynamicLibrary + true + v120_wp81 + Unicode + + + DynamicLibrary + false + v120_wp81 + true + Unicode + + + + + + + + + + + $(SolutionDir)build\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)build\obj\$(Platform)\$(Configuration)\System\ + CLRNetSystem + + + $(SolutionDir)build\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)build\obj\$(Platform)\$(Configuration)\System\ + CLRNetSystem + + + + NotUsing + Level3 + Disabled + WIN32;_WINDOWS;_USRDLL;CLRNETSYSTEM_EXPORTS;PLATFORM_WP81;%(PreprocessorDefinitions) + $(ProjectDir)..\system;$(ProjectDir)..\system\compatibility;$(ProjectDir)..\system\hooks;$(ProjectDir)..\system\replacement;$(ProjectDir)..\system\safety;$(ProjectDir)..\phase1-userland\core;%(AdditionalIncludeDirectories) + MultiThreadedDebugDLL + true + + + Windows + true + CLRNetCore.lib;CLRNetInterop.lib;runtimeobject.lib;windowsapp.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + MaxSpeed + true + true + WIN32;_WINDOWS;_USRDLL;CLRNETSYSTEM_EXPORTS;PLATFORM_WP81;NDEBUG;%(PreprocessorDefinitions) + $(ProjectDir)..\system;$(ProjectDir)..\system\compatibility;$(ProjectDir)..\system\hooks;$(ProjectDir)..\system\replacement;$(ProjectDir)..\system\safety;$(ProjectDir)..\phase1-userland\core;%(AdditionalIncludeDirectories) + MultiThreadedDLL + true + + + Windows + true + true + true + CLRNetCore.lib;CLRNetInterop.lib;runtimeobject.lib;windowsapp.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + {8F4C5A55-2F4B-4C40-8A64-6B501B28B42C} + false + + + {AF9323CB-8F8C-4D9F-9E1F-349437DD9C10} + false + + + + + diff --git a/src/host/CLRNetHost.cpp b/src/host/CLRNetHost.cpp deleted file mode 100644 index ec0735b..0000000 --- a/src/host/CLRNetHost.cpp +++ /dev/null @@ -1,345 +0,0 @@ -// CLRNet Runtime Host - Main Entry Point for CLR Runtime -// This executable hosts the modern .NET runtime for Windows Phone 8.1 - -#include -#include -#include -#include - -// CLRNet Core Runtime Headers -#ifdef CLRNET_CORE_AVAILABLE -#include "../phase1-userland/core/CoreExecutionEngine.h" -#include "../phase1-userland/core/TypeSystem.h" -#include "../phase1-userland/core/GarbageCollector.h" -#include "../phase1-userland/core/AssemblyLoader.h" -#include "../phase1-userland/core/SimpleJIT.h" -#endif - -// CLRNet Interop Headers -#ifdef CLRNET_INTEROP_AVAILABLE -#include "../interop/InteropManager.h" -#include "../interop/winrt/WinRTBridge.h" -#include "../interop/hardware/HardwareAccess.h" -#endif - -// CLRNet System Headers -#ifdef CLRNET_SYSTEM_AVAILABLE -#include "../system/replacement/CLRReplacementEngine.h" -#include "../system/hooks/DeepSystemHooks.h" -#include "../system/compatibility/CompatibilityShim.h" -#endif - -using namespace std; - -// Forward declarations -int InitializeRuntime(); -int ExecuteAssembly(const wstring& assemblyPath); -void DisplayRuntimeInfo(); -void DisplayUsage(); -void DisplayStartupBanner(); - -// Global runtime components -#ifdef CLRNET_CORE_AVAILABLE -using namespace CLRNet::Core; -static unique_ptr g_executionEngine; -static unique_ptr g_typeSystem; -static unique_ptr g_garbageCollector; -static unique_ptr g_assemblyLoader; -static unique_ptr g_jitCompiler; -#endif - -int wmain(int argc, wchar_t* argv[]) -{ - DisplayStartupBanner(); - - // Parse command line arguments - if (argc < 2) { - DisplayUsage(); - return 1; - } - - wstring command = argv[1]; - - if (command == L"--info" || command == L"-i") { - DisplayRuntimeInfo(); - return 0; - } - else if (command == L"--help" || command == L"-h") { - DisplayUsage(); - return 0; - } - else if (command == L"--execute" || command == L"-e") { - if (argc < 3) { - wcout << L"[ERROR] No assembly specified for execution" << endl; - return 1; - } - - // Initialize runtime - if (InitializeRuntime() != 0) { - wcout << L"[ERROR] Failed to initialize CLRNet runtime" << endl; - return 1; - } - - // Execute specified assembly - wstring assemblyPath = argv[2]; - return ExecuteAssembly(assemblyPath); - } - else { - wcout << L"[ERROR] Unknown command: " << command << endl; - DisplayUsage(); - return 1; - } -} - -void DisplayStartupBanner() -{ - wcout << L"===============================================" << endl; - wcout << L" CLRNet Runtime Host v1.0.0 " << endl; - wcout << L" Modern .NET Runtime for Windows Phone 8.1 " << endl; - wcout << L"===============================================" << endl; - wcout << endl; -} - -void DisplayUsage() -{ - wcout << L"Usage: CLRNetHost.exe [command] [options]" << endl; - wcout << endl; - wcout << L"Commands:" << endl; - wcout << L" --execute, -e Execute a .NET assembly" << endl; - wcout << L" --info, -i Display runtime information" << endl; - wcout << L" --help, -h Display this help message" << endl; - wcout << endl; - wcout << L"Examples:" << endl; - wcout << L" CLRNetHost.exe -e MyApp.exe" << endl; - wcout << L" CLRNetHost.exe -i" << endl; - wcout << endl; -} - -void DisplayRuntimeInfo() -{ - wcout << L"CLRNet Runtime Information:" << endl; - wcout << L"===========================" << endl; - wcout << endl; - -#ifdef CLRNET_CORE_AVAILABLE - wcout << L"Core Runtime: AVAILABLE" << endl; - wcout << L"- Execution Engine: Yes" << endl; - wcout << L"- Type System: Yes" << endl; - wcout << L"- Garbage Collector: Yes" << endl; - wcout << L"- Assembly Loader: Yes" << endl; - wcout << L"- JIT Compiler: Yes" << endl; -#else - wcout << L"Core Runtime: NOT AVAILABLE" << endl; -#endif - -#ifdef CLRNET_INTEROP_AVAILABLE - wcout << L"System Interop: AVAILABLE" << endl; - wcout << L"- WinRT Bridge: Yes" << endl; - wcout << L"- Hardware Access: Yes" << endl; - wcout << L"- P/Invoke Engine: Yes" << endl; -#else - wcout << L"System Interop: NOT AVAILABLE" << endl; -#endif - -#ifdef CLRNET_SYSTEM_AVAILABLE - wcout << L"System Integration: AVAILABLE" << endl; - wcout << L"- CLR Replacement: Yes" << endl; - wcout << L"- System Hooks: Yes" << endl; - wcout << L"- Compatibility: Yes" << endl; -#else - wcout << L"System Integration: NOT AVAILABLE" << endl; -#endif - - wcout << endl; - wcout << L"Runtime Features:" << endl; - wcout << L"- Target Platform: Windows Phone 8.1 ARM" << endl; - wcout << L"- Runtime Version: 1.0.0" << endl; - wcout << L"- Build Date: " << __DATE__ << L" " << __TIME__ << endl; - wcout << L"- Architecture: " << -#ifdef _M_ARM - L"ARM" -#elif defined(_M_X64) - L"x64" -#elif defined(_M_IX86) - L"x86" -#else - L"Unknown" -#endif - << endl; - - wcout << endl; - wcout << L"Performance Characteristics:" << endl; - wcout << L"- Startup Time: <200ms (vs 500ms+ legacy CLR)" << endl; - wcout << L"- Memory Usage: ~15MB base (vs 25MB+ legacy CLR)" << endl; - wcout << L"- JIT Performance: 50+ methods/sec (vs 20-30 legacy CLR)" << endl; - wcout << L"- GC Pause Times: <5ms (vs 10ms+ legacy CLR)" << endl; - wcout << endl; -} - -int InitializeRuntime() -{ - wcout << L"[INFO] Initializing CLRNet Runtime..." << endl; - -#ifdef CLRNET_CORE_AVAILABLE - try { - // Initialize Core Execution Engine - wcout << L"[INIT] Core Execution Engine..." << endl; - g_executionEngine = make_unique(); - if (!g_executionEngine->Initialize()) { - wcout << L"[ERROR] Failed to initialize Core Execution Engine" << endl; - return 1; - } - - // Initialize Type System - wcout << L"[INIT] Type System..." << endl; - g_typeSystem = make_unique(); - if (!g_typeSystem->Initialize()) { - wcout << L"[ERROR] Failed to initialize Type System" << endl; - return 1; - } - - // Initialize Garbage Collector - wcout << L"[INIT] Garbage Collector..." << endl; - g_garbageCollector = make_unique(); - if (!g_garbageCollector->Initialize()) { - wcout << L"[ERROR] Failed to initialize Garbage Collector" << endl; - return 1; - } - - // Initialize Assembly Loader - wcout << L"[INIT] Assembly Loader..." << endl; - g_assemblyLoader = make_unique(g_typeSystem.get()); - if (!g_assemblyLoader->Initialize()) { - wcout << L"[ERROR] Failed to initialize Assembly Loader" << endl; - return 1; - } - - g_assemblyLoader->RefreshOverlayConfiguration(); - - // Initialize JIT Compiler - wcout << L"[INIT] JIT Compiler..." << endl; - g_jitCompiler = make_unique(); - if (!g_jitCompiler->Initialize()) { - wcout << L"[ERROR] Failed to initialize JIT Compiler" << endl; - return 1; - } - - wcout << L"[SUCCESS] Core runtime initialized successfully" << endl; - } - catch (const exception& e) { - wcout << L"[ERROR] Exception during runtime initialization: " << e.what() << endl; - return 1; - } -#else - wcout << L"[WARNING] Core runtime not available in this build" << endl; -#endif - -#ifdef CLRNET_INTEROP_AVAILABLE - try { - wcout << L"[INIT] System interop layer..." << endl; - // Initialize interop components here - wcout << L"[SUCCESS] Interop layer initialized" << endl; - } - catch (const exception& e) { - wcout << L"[WARNING] Interop initialization failed: " << e.what() << endl; - } -#endif - -#ifdef CLRNET_SYSTEM_AVAILABLE - try { - wcout << L"[INIT] System integration layer..." << endl; - // Initialize system integration components here - wcout << L"[SUCCESS] System integration initialized" << endl; - } - catch (const exception& e) { - wcout << L"[WARNING] System integration initialization failed: " << e.what() << endl; - } -#endif - - wcout << L"[SUCCESS] CLRNet Runtime initialization complete!" << endl; - wcout << endl; - return 0; -} - -int ExecuteAssembly(const wstring& assemblyPath) -{ - wcout << L"[EXEC] Loading assembly: " << assemblyPath << endl; - -#ifdef CLRNET_CORE_AVAILABLE - if (!g_assemblyLoader || !g_executionEngine) { - wcout << L"[ERROR] Runtime not properly initialized" << endl; - return 1; - } - - try { - // Load the assembly - wcout << L"[LOAD] Loading assembly..." << endl; - auto assembly = g_assemblyLoader->LoadAssembly(assemblyPath); - if (!assembly.IsValid()) { - wcout << L"[ERROR] Failed to load assembly: " << assemblyPath << endl; - return 1; - } - - wcout << L"[SUCCESS] Assembly loaded successfully" << endl; - wcout << L"[INFO] Assembly: " << assembly.GetName() << endl; - wcout << L"[INFO] Version: " << assembly.GetVersion() << endl; - - // Find entry point - wcout << L"[ENTRY] Locating entry point..." << endl; - auto entryPoint = assembly.GetEntryPoint(); - if (!entryPoint.IsValid()) { - wcout << L"[ERROR] No entry point found in assembly" << endl; - return 1; - } - - wcout << L"[SUCCESS] Entry point found: " << entryPoint.GetName() << endl; - - // Execute entry point - wcout << L"[EXEC] Executing assembly..." << endl; - wcout << L"===============================================" << endl; - - int result = g_executionEngine->ExecuteMethod(entryPoint); - - wcout << L"===============================================" << endl; - wcout << L"[COMPLETE] Assembly execution finished with exit code: " << result << endl; - - // Display runtime statistics - auto stats = g_executionEngine->GetRuntimeStatistics(); - wcout << endl; - wcout << L"Runtime Statistics:" << endl; - wcout << L"- Methods compiled: " << stats.methodsCompiled << endl; - wcout << L"- Memory allocated: " << stats.totalMemoryAllocated << L" bytes" << endl; - wcout << L"- GC collections: " << stats.gcCollections << endl; - wcout << L"- Execution time: " << stats.executionTimeMs << L" ms" << endl; - - return result; - } - catch (const exception& e) { - wcout << L"[ERROR] Exception during assembly execution: " << e.what() << endl; - return 1; - } -#else - wcout << L"[ERROR] Core runtime not available - cannot execute assemblies" << endl; - wcout << L"[INFO] This build of CLRNet only supports runtime information display" << endl; - return 1; -#endif -} - -// Entry point for DLL builds (if needed) -#ifdef _USRDLL -BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) -{ - switch (ul_reason_for_call) - { - case DLL_PROCESS_ATTACH: - break; - case DLL_THREAD_ATTACH: - break; - case DLL_THREAD_DETACH: - break; - case DLL_PROCESS_DETACH: - break; - } - return TRUE; -} -#endif \ No newline at end of file diff --git a/src/interop/security/SecurityManager.cpp b/src/interop/security/SecurityManager.cpp new file mode 100644 index 0000000..1657e95 --- /dev/null +++ b/src/interop/security/SecurityManager.cpp @@ -0,0 +1,1146 @@ +#include "SecurityManager.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#pragma comment(lib, "shlwapi.lib") + +namespace CLRNet { +namespace Interop { + +#ifndef RETURN_IF_FAILED +#define RETURN_IF_FAILED(expr) \ + do { \ + HRESULT _hrTemp = (expr); \ + if (FAILED(_hrTemp)) { \ + return _hrTemp; \ + } \ + } while (0) +#endif + +namespace +{ + std::wstring NormalizePathSlow(const std::wstring& path) + { + if (path.empty()) + { + return std::wstring(); + } + + wchar_t buffer[MAX_PATH] = {0}; + if (PathCanonicalizeW(buffer, path.c_str())) + { + return std::wstring(buffer); + } + + return path; + } +} + +// CapabilityManager Implementation +CapabilityManager::CapabilityManager() +{ + InitializeCriticalSection(&m_criticalSection); + InitializeSystemRestrictions(); +} + +CapabilityManager::~CapabilityManager() +{ + DeleteCriticalSection(&m_criticalSection); +} + +HRESULT CapabilityManager::Initialize() +{ + InitializeSystemRestrictions(); + return S_OK; +} + +HRESULT CapabilityManager::LoadApplicationCapabilities(const std::wstring& applicationId, + const std::wstring& manifestPath) +{ + if (applicationId.empty()) + { + return E_INVALIDARG; + } + + std::vector capabilities; + HRESULT hr = ParseManifestFile(manifestPath, &capabilities); + if (FAILED(hr)) + { + return hr; + } + + EnterCriticalSection(&m_criticalSection); + m_applicationCapabilities[applicationId] = capabilities; + LeaveCriticalSection(&m_criticalSection); + return S_OK; +} + +HRESULT CapabilityManager::DeclareCapability(const std::wstring& applicationId, + SystemCapability capability, + const std::wstring& justification, + bool isRequired) +{ + if (applicationId.empty()) + { + return E_INVALIDARG; + } + + CapabilityDeclaration declaration{}; + declaration.capability = capability; + declaration.isRequired = isRequired; + declaration.justification = justification; + declaration.userConsent = false; + GetSystemTimeAsFileTime(&declaration.declaredTime); + declaration.version = L"1.0"; + + HRESULT hr = ValidateCapabilityDeclaration(declaration); + if (FAILED(hr)) + { + return hr; + } + + EnterCriticalSection(&m_criticalSection); + auto& list = m_applicationCapabilities[applicationId]; + auto it = std::find_if(list.begin(), list.end(), + [capability](const CapabilityDeclaration& item) + { + return item.capability == capability; + }); + + if (it == list.end()) + { + list.push_back(declaration); + } + else + { + *it = declaration; + } + + LeaveCriticalSection(&m_criticalSection); + return S_OK; +} + +bool CapabilityManager::IsCapabilityDeclared(const std::wstring& applicationId, + SystemCapability capability) const +{ + EnterCriticalSection(const_cast(&m_criticalSection)); + auto it = m_applicationCapabilities.find(applicationId); + bool declared = false; + if (it != m_applicationCapabilities.end()) + { + declared = std::any_of(it->second.begin(), it->second.end(), + [capability](const CapabilityDeclaration& item) + { + return item.capability == capability; + }); + } + LeaveCriticalSection(const_cast(&m_criticalSection)); + return declared; +} + +std::vector CapabilityManager::GetDeclaredCapabilities(const std::wstring& applicationId) const +{ + std::vector capabilities; + EnterCriticalSection(const_cast(&m_criticalSection)); + auto it = m_applicationCapabilities.find(applicationId); + if (it != m_applicationCapabilities.end()) + { + for (const auto& entry : it->second) + { + capabilities.push_back(entry.capability); + } + } + LeaveCriticalSection(const_cast(&m_criticalSection)); + return capabilities; +} + +HRESULT CapabilityManager::ValidateCapabilityDeclaration(const CapabilityDeclaration& declaration) +{ + if (IsSystemRestricted(declaration.capability) && declaration.isRequired) + { + return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); + } + + return S_OK; +} + +HRESULT CapabilityManager::GetCapabilityRequirements(SystemCapability capability, + bool* requiresUserConsent, + bool* requiresAdminApproval, + bool* requiresSystemAccess) +{ + if (!requiresUserConsent || !requiresAdminApproval || !requiresSystemAccess) + { + return E_INVALIDARG; + } + + *requiresUserConsent = false; + *requiresAdminApproval = false; + *requiresSystemAccess = false; + + switch (capability) + { + case SystemCapability::Location: + case SystemCapability::Webcam: + case SystemCapability::Microphone: + *requiresUserConsent = true; + break; + case SystemCapability::EnterpriseAuthentication: + case SystemCapability::SharedUserCertificates: + *requiresAdminApproval = true; + *requiresSystemAccess = true; + break; + default: + break; + } + + return S_OK; +} + +bool CapabilityManager::IsSystemRestricted(SystemCapability capability) const +{ + return m_systemRestrictedCapabilities.find(capability) != m_systemRestrictedCapabilities.end(); +} + +HRESULT CapabilityManager::ParseManifestFile(const std::wstring& manifestPath, + std::vector* capabilities) +{ + if (!capabilities) + { + return E_INVALIDARG; + } + + capabilities->clear(); + + if (manifestPath.empty()) + { + return S_OK; + } + + std::wifstream stream(manifestPath); + if (!stream.is_open()) + { + return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + } + + std::wstring line; + while (std::getline(stream, line)) + { + auto capabilityPos = line.find(L"Capability"); + auto namePos = line.find(L"Name="); + if (capabilityPos == std::wstring::npos || namePos == std::wstring::npos) + { + continue; + } + + auto quoteStart = line.find(L'"', namePos); + auto quoteEnd = line.find(L'"', quoteStart + 1); + if (quoteStart == std::wstring::npos || quoteEnd == std::wstring::npos) + { + continue; + } + + std::wstring token = line.substr(quoteStart + 1, quoteEnd - quoteStart - 1); + auto capability = SecurityUtils::StringToCapability(token); + if (capability != SystemCapability::InternetClient || token == L"ID_CAP_NETWORKING") + { + CapabilityDeclaration declaration{}; + declaration.capability = capability; + declaration.isRequired = true; + declaration.justification = L"Manifest declared capability"; + declaration.userConsent = false; + GetSystemTimeAsFileTime(&declaration.declaredTime); + declaration.version = L"1.0"; + capabilities->push_back(declaration); + } + } + + return S_OK; +} + +void CapabilityManager::InitializeSystemRestrictions() +{ + m_systemRestrictedCapabilities.clear(); + m_systemRestrictedCapabilities.insert(SystemCapability::EnterpriseAuthentication); + m_systemRestrictedCapabilities.insert(SystemCapability::SharedUserCertificates); +} + +std::wstring CapabilityManager::GetCapabilityName(SystemCapability capability) const +{ + return SecurityUtils::CapabilityToString(capability); +} + +// SandboxManager Implementation +SandboxManager::SandboxManager() +{ + InitializeCriticalSection(&m_criticalSection); +} + +SandboxManager::~SandboxManager() +{ + DeleteCriticalSection(&m_criticalSection); +} + +HRESULT SandboxManager::Initialize() +{ + EnterCriticalSection(&m_criticalSection); + m_allowedPaths.clear(); + m_blockedPaths.clear(); + m_allowedRegistryKeys.clear(); + LeaveCriticalSection(&m_criticalSection); + return S_OK; +} + +HRESULT SandboxManager::SetSandboxLevel(const std::wstring& applicationId, SandboxLevel level) +{ + EnterCriticalSection(&m_criticalSection); + m_applicationSandboxLevels[applicationId] = level; + LeaveCriticalSection(&m_criticalSection); + return S_OK; +} + +SandboxLevel SandboxManager::GetSandboxLevel(const std::wstring& applicationId) const +{ + EnterCriticalSection(const_cast(&m_criticalSection)); + auto it = m_applicationSandboxLevels.find(applicationId); + SandboxLevel level = SandboxLevel::Standard; + if (it != m_applicationSandboxLevels.end()) + { + level = it->second; + } + LeaveCriticalSection(const_cast(&m_criticalSection)); + return level; +} + +bool SandboxManager::IsFilePathAllowed(const std::wstring& applicationId, + const std::wstring& filePath, + DWORD) const +{ + auto normalized = NormalizePath(filePath); + EnterCriticalSection(const_cast(&m_criticalSection)); + bool allowed = !IsPathInBlockedList(normalized); + if (allowed && !m_allowedPaths.empty()) + { + allowed = IsPathInAllowedList(normalized); + } + LeaveCriticalSection(const_cast(&m_criticalSection)); + + if (!allowed && SandboxLevel::Maximum == GetSandboxLevel(applicationId)) + { + return false; + } + + return allowed; +} + +bool SandboxManager::IsRegistryKeyAllowed(const std::wstring& applicationId, + const std::wstring& keyPath, + DWORD) const +{ + auto normalized = NormalizePathSlow(keyPath); + EnterCriticalSection(const_cast(&m_criticalSection)); + bool allowed = m_allowedRegistryKeys.empty() || + m_allowedRegistryKeys.find(normalized) != m_allowedRegistryKeys.end(); + LeaveCriticalSection(const_cast(&m_criticalSection)); + + if (!allowed && SandboxLevel::Maximum == GetSandboxLevel(applicationId)) + { + return false; + } + + return allowed; +} + +bool SandboxManager::IsNetworkAccessAllowed(const std::wstring& applicationId, + const std::wstring&, + UINT16) const +{ + auto level = GetSandboxLevel(applicationId); + return level != SandboxLevel::Maximum; +} + +bool SandboxManager::IsProcessCreationAllowed(const std::wstring& applicationId, + const std::wstring&) const +{ + auto level = GetSandboxLevel(applicationId); + return level == SandboxLevel::None || level == SandboxLevel::Basic; +} + +HRESULT SandboxManager::AddAllowedPath(const std::wstring& path) +{ + EnterCriticalSection(&m_criticalSection); + m_allowedPaths.insert(NormalizePath(path)); + LeaveCriticalSection(&m_criticalSection); + return S_OK; +} + +HRESULT SandboxManager::AddBlockedPath(const std::wstring& path) +{ + EnterCriticalSection(&m_criticalSection); + m_blockedPaths.insert(NormalizePath(path)); + LeaveCriticalSection(&m_criticalSection); + return S_OK; +} + +HRESULT SandboxManager::ConfigureFileSystemIsolation(const std::wstring&) +{ + return S_OK; +} + +HRESULT SandboxManager::ConfigureNetworkIsolation(const std::wstring&) +{ + return S_OK; +} + +HRESULT SandboxManager::ConfigureRegistryIsolation(const std::wstring&) +{ + return S_OK; +} + +bool SandboxManager::IsPathInAllowedList(const std::wstring& path) const +{ + return m_allowedPaths.find(path) != m_allowedPaths.end(); +} + +bool SandboxManager::IsPathInBlockedList(const std::wstring& path) const +{ + return m_blockedPaths.find(path) != m_blockedPaths.end(); +} + +std::wstring SandboxManager::NormalizePath(const std::wstring& path) const +{ + return NormalizePathSlow(path); +} + +// PermissionPromptManager Implementation +PermissionPromptManager::PermissionPromptManager() + : m_allowPrompts(true) +{ + InitializeCriticalSection(&m_criticalSection); +} + +PermissionPromptManager::~PermissionPromptManager() +{ + DeleteCriticalSection(&m_criticalSection); +} + +HRESULT PermissionPromptManager::Initialize() +{ + return S_OK; +} + +HRESULT PermissionPromptManager::ShowPermissionPrompt(const PermissionPrompt& prompt) +{ + if (!m_allowPrompts) + { + return S_OK; + } + + auto remembered = GetRememberedChoice(prompt.capability); + if (remembered == PermissionPromptResult::Allow || remembered == PermissionPromptResult::AlwaysAllow) + { + if (prompt.callback) + { + prompt.callback(remembered); + } + return S_OK; + } + + // Simulate user approval by default in headless scenarios + if (prompt.callback) + { + prompt.callback(PermissionPromptResult::Allow); + } + + return S_OK; +} + +HRESULT PermissionPromptManager::ShowPermissionPromptAsync(const PermissionPrompt& prompt) +{ + return ShowPermissionPrompt(prompt); +} + +PermissionPromptResult PermissionPromptManager::GetRememberedChoice(SystemCapability capability) const +{ + EnterCriticalSection(const_cast(&m_criticalSection)); + auto it = m_rememberedChoices.find(capability); + auto result = (it != m_rememberedChoices.end()) ? it->second : PermissionPromptResult::Cancel; + LeaveCriticalSection(const_cast(&m_criticalSection)); + return result; +} + +HRESULT PermissionPromptManager::SetRememberedChoice(SystemCapability capability, + PermissionPromptResult result) +{ + EnterCriticalSection(&m_criticalSection); + m_rememberedChoices[capability] = result; + LeaveCriticalSection(&m_criticalSection); + return S_OK; +} + +HRESULT PermissionPromptManager::ClearRememberedChoices() +{ + EnterCriticalSection(&m_criticalSection); + m_rememberedChoices.clear(); + LeaveCriticalSection(&m_criticalSection); + return S_OK; +} + +void PermissionPromptManager::SetPromptsEnabled(bool enabled) +{ + m_allowPrompts = enabled; +} + +std::wstring PermissionPromptManager::GetCapabilityDisplayName(SystemCapability capability) const +{ + return SecurityUtils::CapabilityToString(capability); +} + +std::wstring PermissionPromptManager::GetCapabilityDescription(SystemCapability capability) const +{ + return L"Access to " + SecurityUtils::CapabilityToString(capability); +} + +std::wstring PermissionPromptManager::GetCapabilityRiskLevel(SystemCapability) const +{ + return L"Medium"; +} + +PermissionPromptResult PermissionPromptManager::ShowNativePrompt(const PermissionPrompt&) const +{ + return PermissionPromptResult::Allow; +} + +HRESULT PermissionPromptManager::CreatePromptDialog(const PermissionPrompt&, HWND*) +{ + return S_OK; +} + +std::wstring PermissionPromptManager::GeneratePromptMessage(const PermissionPrompt& prompt) const +{ + return L"Application requests access to " + GetCapabilityDisplayName(prompt.capability); +} + +std::wstring PermissionPromptManager::GenerateDetailedExplanation(SystemCapability capability) const +{ + return L"Access required for " + GetCapabilityDisplayName(capability); +} + +// SecurityEnforcer Implementation +SecurityEnforcer::SecurityEnforcer() + : m_enforcementEnabled(true) + , m_defaultSecurityLevel(SecurityLevel::Partial) + , m_defaultSandboxLevel(SandboxLevel::Standard) +{ + InitializeCriticalSection(&m_criticalSection); +} + +SecurityEnforcer::~SecurityEnforcer() +{ + Shutdown(); + DeleteCriticalSection(&m_criticalSection); +} + +HRESULT SecurityEnforcer::Initialize() +{ + m_capabilityManager = std::make_unique(); + m_sandboxManager = std::make_unique(); + m_promptManager = std::make_unique(); + + RETURN_IF_FAILED(m_capabilityManager->Initialize()); + RETURN_IF_FAILED(m_sandboxManager->Initialize()); + RETURN_IF_FAILED(m_promptManager->Initialize()); + + return S_OK; +} + +void SecurityEnforcer::Shutdown() +{ + EnterCriticalSection(&m_criticalSection); + m_securityContexts.clear(); + m_violationLog.clear(); + LeaveCriticalSection(&m_criticalSection); +} + +HRESULT SecurityEnforcer::CreateSecurityContext(const std::wstring& applicationId, + const std::wstring& manifestPath, + SecurityContext* context) +{ + if (!context || applicationId.empty()) + { + return E_INVALIDARG; + } + + SecurityContext newContext{}; + newContext.applicationId = applicationId; + newContext.publisherId = L"Unknown"; + newContext.level = m_defaultSecurityLevel; + newContext.sandboxLevel = m_defaultSandboxLevel; + newContext.isDebugging = false; + GetSystemTimeAsFileTime(&newContext.createdTime); + + RETURN_IF_FAILED(m_capabilityManager->LoadApplicationCapabilities(applicationId, manifestPath)); + auto declared = m_capabilityManager->GetDeclaredCapabilities(applicationId); + newContext.declaredCapabilities.insert(declared.begin(), declared.end()); + newContext.grantedCapabilities = newContext.declaredCapabilities; + + EnterCriticalSection(&m_criticalSection); + m_securityContexts[applicationId] = newContext; + *context = newContext; + LeaveCriticalSection(&m_criticalSection); + + return S_OK; +} + +HRESULT SecurityEnforcer::SetSecurityContext(const std::wstring& applicationId, + const SecurityContext& context) +{ + if (applicationId.empty()) + { + return E_INVALIDARG; + } + + RETURN_IF_FAILED(ValidateSecurityContext(context)); + + EnterCriticalSection(&m_criticalSection); + m_securityContexts[applicationId] = context; + LeaveCriticalSection(&m_criticalSection); + return S_OK; +} + +const SecurityContext* SecurityEnforcer::GetSecurityContext(const std::wstring& applicationId) const +{ + EnterCriticalSection(const_cast(&m_criticalSection)); + auto it = m_securityContexts.find(applicationId); + const SecurityContext* context = (it != m_securityContexts.end()) ? &it->second : nullptr; + LeaveCriticalSection(const_cast(&m_criticalSection)); + return context; +} + +HRESULT SecurityEnforcer::CheckCapabilityAccess(const std::wstring& applicationId, + SystemCapability capability, + bool promptIfNeeded) +{ + auto context = GetSecurityContext(applicationId); + if (!context) + { + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + } + + HRESULT hr = EnforceCapabilityAccess(*context, capability); + if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) && promptIfNeeded) + { + PermissionPrompt prompt{}; + prompt.capability = capability; + prompt.applicationName = applicationId; + prompt.message = L"Runtime permission required"; + prompt.canRemember = true; + prompt.isOneTime = false; + prompt.callback = [this, applicationId, capability](PermissionPromptResult result) + { + if (result == PermissionPromptResult::Allow || result == PermissionPromptResult::AlwaysAllow) + { + EnterCriticalSection(&m_criticalSection); + auto& ctx = m_securityContexts[applicationId]; + ctx.grantedCapabilities.insert(capability); + LeaveCriticalSection(&m_criticalSection); + } + }; + + m_promptManager->ShowPermissionPrompt(prompt); + hr = S_OK; + } + + return hr; +} + +HRESULT SecurityEnforcer::ValidateSystemCall(const std::wstring& applicationId, + const std::wstring& functionName, + void*) +{ + if (!IsSystemLevelOperation(functionName)) + { + return S_OK; + } + + return CheckCapabilityAccess(applicationId, SystemCapability::EnterpriseAuthentication, false); +} + +HRESULT SecurityEnforcer::ValidateFileAccess(const std::wstring& applicationId, + const std::wstring& filePath, + DWORD desiredAccess) +{ + if (!m_sandboxManager->IsFilePathAllowed(applicationId, filePath, desiredAccess)) + { + return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); + } + + return S_OK; +} + +HRESULT SecurityEnforcer::ValidateNetworkAccess(const std::wstring& applicationId, + const std::wstring& hostname, + UINT16 port) +{ + if (!m_sandboxManager->IsNetworkAccessAllowed(applicationId, hostname, port)) + { + return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); + } + + return CheckCapabilityAccess(applicationId, SystemCapability::InternetClient, false); +} + +HRESULT SecurityEnforcer::ValidateRegistryAccess(const std::wstring& applicationId, + const std::wstring& keyPath, + DWORD desiredAccess) +{ + if (!m_sandboxManager->IsRegistryKeyAllowed(applicationId, keyPath, desiredAccess)) + { + return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); + } + + return S_OK; +} + +HRESULT SecurityEnforcer::LogSecurityViolation(const std::wstring& applicationId, + SecurityViolationType violationType, + const std::wstring& description, + SystemCapability attemptedCapability) +{ + SecurityViolation violation{}; + violation.type = violationType; + violation.description = description; + violation.source = applicationId; + violation.attemptedCapability = attemptedCapability; + GetSystemTimeAsFileTime(&violation.timestamp); + violation.wasBlocked = true; + + EnterCriticalSection(&m_criticalSection); + m_violationLog.push_back(violation); + LeaveCriticalSection(&m_criticalSection); + + return S_OK; +} + +HRESULT SecurityEnforcer::SetEnforcementLevel(SecurityLevel level) +{ + m_defaultSecurityLevel = level; + return S_OK; +} + +HRESULT SecurityEnforcer::SetDefaultSandboxLevel(SandboxLevel level) +{ + m_defaultSandboxLevel = level; + return S_OK; +} + +HRESULT SecurityEnforcer::EnableEnforcement(bool enabled) +{ + m_enforcementEnabled = enabled; + return S_OK; +} + +std::vector SecurityEnforcer::GetSecurityViolations(const std::wstring& applicationId) const +{ + std::vector violations; + EnterCriticalSection(const_cast(&m_criticalSection)); + for (const auto& violation : m_violationLog) + { + if (violation.source == applicationId) + { + violations.push_back(violation); + } + } + LeaveCriticalSection(const_cast(&m_criticalSection)); + return violations; +} + +HRESULT SecurityEnforcer::GenerateSecurityReport(const std::wstring& filePath) const +{ + std::wofstream stream(filePath); + if (!stream.is_open()) + { + return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); + } + + stream << L"CLRNet Security Report\n"; + stream << L"=====================\n\n"; + + EnterCriticalSection(const_cast(&m_criticalSection)); + for (const auto& entry : m_securityContexts) + { + stream << L"Application: " << entry.first << L"\n"; + stream << L" Security Level: " << SecurityUtils::SecurityLevelToString(entry.second.level) << L"\n"; + stream << L" Sandbox: " << static_cast(entry.second.sandboxLevel) << L"\n"; + } + + if (!m_violationLog.empty()) + { + stream << L"\nRecorded Violations:\n"; + for (const auto& violation : m_violationLog) + { + stream << L" - App: " << violation.source << L", Capability: " + << SecurityUtils::CapabilityToString(violation.attemptedCapability) + << L", Description: " << violation.description << L"\n"; + } + } + LeaveCriticalSection(const_cast(&m_criticalSection)); + + return S_OK; +} + +HRESULT SecurityEnforcer::EmergencyLockdown(const std::wstring& applicationId) +{ + RETURN_IF_FAILED(SetDefaultSandboxLevel(SandboxLevel::Maximum)); + RETURN_IF_FAILED(EnableEnforcement(true)); + return LogSecurityViolation(applicationId, SecurityViolationType::SecurityViolation, + L"Emergency lockdown engaged", SystemCapability::InternetClient); +} + +HRESULT SecurityEnforcer::RestoreFromLockdown(const std::wstring& applicationId) +{ + RETURN_IF_FAILED(SetDefaultSandboxLevel(SandboxLevel::Standard)); + return LogSecurityViolation(applicationId, SecurityViolationType::SecurityViolation, + L"Security lockdown released", SystemCapability::InternetClient); +} + +HRESULT SecurityEnforcer::EnforceCapabilityAccess(const SecurityContext& context, + SystemCapability capability) +{ + if (!m_enforcementEnabled) + { + return S_OK; + } + + if (context.grantedCapabilities.find(capability) != context.grantedCapabilities.end()) + { + return S_OK; + } + + if (context.declaredCapabilities.find(capability) != context.declaredCapabilities.end()) + { + HandleCapabilityViolation(context.applicationId, capability); + return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); + } + + HandleCapabilityViolation(context.applicationId, capability); + return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); +} + +HRESULT SecurityEnforcer::HandleCapabilityViolation(const std::wstring& applicationId, + SystemCapability capability) +{ + std::wstringstream description; + description << L"Capability violation for " << SecurityUtils::CapabilityToString(capability); + return LogSecurityViolation(applicationId, SecurityViolationType::CapabilityViolation, description.str(), capability); +} + +bool SecurityEnforcer::IsSystemLevelOperation(const std::wstring& functionName) const +{ + static const std::vector systemPrefixes = + { + L"Nt", L"Zw", L"Rtl" + }; + + for (const auto& prefix : systemPrefixes) + { + if (functionName.rfind(prefix, 0) == 0) + { + return true; + } + } + + return false; +} + +HRESULT SecurityEnforcer::ValidateSecurityContext(const SecurityContext& context) +{ + if (context.applicationId.empty()) + { + return E_INVALIDARG; + } + + return S_OK; +} + +void SecurityEnforcer::UpdateContextFromManifest(const std::wstring& manifestPath, + SecurityContext* context) +{ + if (!context) + { + return; + } + + if (manifestPath.empty()) + { + return; + } + + if (SUCCEEDED(m_capabilityManager->LoadApplicationCapabilities(context->applicationId, manifestPath))) + { + auto caps = m_capabilityManager->GetDeclaredCapabilities(context->applicationId); + context->declaredCapabilities.insert(caps.begin(), caps.end()); + } +} + +// SecurityManagerFactory Implementation +SecurityEnforcer* SecurityManagerFactory::CreateInstance() +{ + auto instance = new SecurityEnforcer(); + if (FAILED(instance->Initialize())) + { + delete instance; + return nullptr; + } + return instance; +} + +void SecurityManagerFactory::DestroyInstance(SecurityEnforcer* instance) +{ + delete instance; +} + +SecurityContext SecurityManagerFactory::CreateStandardAppContext(const std::wstring& applicationId) +{ + SecurityContext context{}; + context.applicationId = applicationId; + context.level = SecurityLevel::Partial; + context.sandboxLevel = SandboxLevel::Standard; + context.createdTime.dwLowDateTime = 0; + context.createdTime.dwHighDateTime = 0; + return context; +} + +SecurityContext SecurityManagerFactory::CreateTrustedAppContext(const std::wstring& applicationId) +{ + SecurityContext context = CreateStandardAppContext(applicationId); + context.level = SecurityLevel::Trusted; + return context; +} + +SecurityContext SecurityManagerFactory::CreateSandboxedContext(const std::wstring& applicationId) +{ + SecurityContext context = CreateStandardAppContext(applicationId); + context.sandboxLevel = SandboxLevel::Enhanced; + return context; +} + +// SecurityUtils Implementation +std::wstring SecurityUtils::CapabilityToString(SystemCapability capability) +{ + switch (capability) + { + case SystemCapability::InternetClient: return L"InternetClient"; + case SystemCapability::InternetClientServer: return L"InternetClientServer"; + case SystemCapability::PrivateNetworkClientServer: return L"PrivateNetworkClientServer"; + case SystemCapability::Location: return L"Location"; + case SystemCapability::Webcam: return L"Webcam"; + case SystemCapability::Microphone: return L"Microphone"; + case SystemCapability::MusicLibrary: return L"MusicLibrary"; + case SystemCapability::PicturesLibrary: return L"PicturesLibrary"; + case SystemCapability::VideosLibrary: return L"VideosLibrary"; + case SystemCapability::RemovableStorage: return L"RemovableStorage"; + case SystemCapability::PhoneDialer: return L"PhoneDialer"; + case SystemCapability::SMS: return L"SMS"; + case SystemCapability::Contacts: return L"Contacts"; + case SystemCapability::Calendar: return L"Calendar"; + case SystemCapability::AppointmentsSystem: return L"AppointmentsSystem"; + case SystemCapability::ContactsSystem: return L"ContactsSystem"; + case SystemCapability::EmailSystem: return L"EmailSystem"; + case SystemCapability::GameBarServices: return L"GameBarServices"; + case SystemCapability::Bluetooth: return L"Bluetooth"; + case SystemCapability::WiFiControl: return L"WiFiControl"; + case SystemCapability::EnterpriseAuthentication: return L"EnterpriseAuthentication"; + case SystemCapability::SharedUserCertificates: return L"SharedUserCertificates"; + default: return L"InternetClient"; + } +} + +SystemCapability SecurityUtils::StringToCapability(const std::wstring& capabilityName) +{ + std::wstring normalized = capabilityName; + std::transform(normalized.begin(), normalized.end(), normalized.begin(), ::towupper); + + if (normalized == L"ID_CAP_NETWORKING" || normalized == L"INTERNETCLIENT") + { + return SystemCapability::InternetClient; + } + if (normalized == L"ID_CAP_NETWORKING_ADMIN" || normalized == L"INTERNETCLIENTSERVER") + { + return SystemCapability::InternetClientServer; + } + if (normalized == L"ID_CAP_PROXIMITY" || normalized == L"PRIVATENETWORKCLIENTSERVER") + { + return SystemCapability::PrivateNetworkClientServer; + } + if (normalized == L"ID_CAP_LOCATION" || normalized == L"LOCATION") + { + return SystemCapability::Location; + } + if (normalized == L"ID_CAP_ISV_CAMERA" || normalized == L"WEBCAM") + { + return SystemCapability::Webcam; + } + if (normalized == L"ID_CAP_MICROPHONE" || normalized == L"MICROPHONE") + { + return SystemCapability::Microphone; + } + if (normalized == L"ID_CAP_MEDIALIB_AUDIO" || normalized == L"MUSICLIBRARY") + { + return SystemCapability::MusicLibrary; + } + if (normalized == L"ID_CAP_MEDIALIB_PHOTO" || normalized == L"PICTURESLIBRARY") + { + return SystemCapability::PicturesLibrary; + } + if (normalized == L"ID_CAP_MEDIALIB_VIDEO" || normalized == L"VIDEOSLIBRARY") + { + return SystemCapability::VideosLibrary; + } + if (normalized == L"ID_CAP_REMOVABLE_STORAGE" || normalized == L"REMOVABLESTORAGE") + { + return SystemCapability::RemovableStorage; + } + if (normalized == L"ID_CAP_PHONEDIALER" || normalized == L"PHONEDIALER") + { + return SystemCapability::PhoneDialer; + } + if (normalized == L"ID_CAP_SMS" || normalized == L"SMS") + { + return SystemCapability::SMS; + } + if (normalized == L"ID_CAP_CONTACTS" || normalized == L"CONTACTS") + { + return SystemCapability::Contacts; + } + if (normalized == L"ID_CAP_APPOINTMENTS" || normalized == L"CALENDAR") + { + return SystemCapability::Calendar; + } + if (normalized == L"ENTERPRISEAUTHENTICATION") + { + return SystemCapability::EnterpriseAuthentication; + } + if (normalized == L"SHAREDUSERCERTIFICATES") + { + return SystemCapability::SharedUserCertificates; + } + + return SystemCapability::InternetClient; +} + +std::wstring SecurityUtils::SecurityLevelToString(SecurityLevel level) +{ + switch (level) + { + case SecurityLevel::Untrusted: return L"Untrusted"; + case SecurityLevel::Partial: return L"Partial"; + case SecurityLevel::Trusted: return L"Trusted"; + case SecurityLevel::System: return L"System"; + case SecurityLevel::Administrator: return L"Administrator"; + default: return L"Untrusted"; + } +} + +SecurityLevel SecurityUtils::StringToSecurityLevel(const std::wstring& levelName) +{ + std::wstring normalized = levelName; + std::transform(normalized.begin(), normalized.end(), normalized.begin(), ::towupper); + if (normalized == L"PARTIAL") + { + return SecurityLevel::Partial; + } + if (normalized == L"TRUSTED") + { + return SecurityLevel::Trusted; + } + if (normalized == L"SYSTEM") + { + return SecurityLevel::System; + } + if (normalized == L"ADMINISTRATOR") + { + return SecurityLevel::Administrator; + } + return SecurityLevel::Untrusted; +} + +bool SecurityUtils::IsSecurePath(const std::wstring& path) +{ + auto normalized = NormalizePathSlow(path); + return normalized.find(L"\\AppData\\Local") != std::wstring::npos; +} + +std::wstring SecurityUtils::GetSecureAppDataPath(const std::wstring& applicationId) +{ + std::wstring base = L"\\AppData\\Local\\"; + return base + applicationId; +} + +bool SecurityUtils::IsSystemPath(const std::wstring& path) +{ + auto normalized = NormalizePathSlow(path); + return normalized.rfind(L"C:\\Windows", 0) == 0 || normalized.rfind(L"C:\\Program Files", 0) == 0; +} + +HRESULT SecurityUtils::GenerateSecurityToken(const SecurityContext& context, std::wstring* token) +{ + if (!token) + { + return E_INVALIDARG; + } + + std::wstringstream stream; + stream << context.applicationId << L"|" << static_cast(context.level) + << L"|" << static_cast(context.sandboxLevel) + << L"|" << context.declaredCapabilities.size(); + *token = stream.str(); + return S_OK; +} + +HRESULT SecurityUtils::ValidateSecurityToken(const std::wstring& token, SecurityContext* context) +{ + if (!context) + { + return E_INVALIDARG; + } + + std::wistringstream stream(token); + std::wstring applicationId; + std::wstring level; + std::wstring sandbox; + std::wstring capabilityCount; + + if (!std::getline(stream, applicationId, L'|')) + { + return E_INVALIDARG; + } + if (!std::getline(stream, level, L'|')) + { + return E_INVALIDARG; + } + if (!std::getline(stream, sandbox, L'|')) + { + return E_INVALIDARG; + } + if (!std::getline(stream, capabilityCount, L'|')) + { + return E_INVALIDARG; + } + + context->applicationId = applicationId; + context->level = static_cast(std::stoi(level)); + context->sandboxLevel = static_cast(std::stoi(sandbox)); + return S_OK; +} + +} // namespace Interop +} // namespace CLRNet diff --git a/tests/CLRNetTests/CLRNetTests.vcxproj b/tests/CLRNetTests/CLRNetTests.vcxproj new file mode 100644 index 0000000..d293c06 --- /dev/null +++ b/tests/CLRNetTests/CLRNetTests.vcxproj @@ -0,0 +1,109 @@ + + + + + Debug + ARM + + + Release + ARM + + + + {4B3E8C7E-5FA6-4F16-B5E8-5E0F0C52F51F} + Win32Proj + CLRNetTests + Windows Phone 8.1 + 8.1 + true + 8.1 + + + + Application + true + v120_wp81 + Unicode + + + Application + false + v120_wp81 + true + Unicode + + + + + + + + + + + $(SolutionDir)build\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)build\obj\$(Platform)\$(Configuration)\Tests\ + CLRNetTests + + + $(SolutionDir)build\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)build\obj\$(Platform)\$(Configuration)\Tests\ + CLRNetTests + + + + NotUsing + Level3 + Disabled + WIN32;_WINDOWS;PLATFORM_WP81;%(PreprocessorDefinitions) + $(ProjectDir)..\..\src\phase1-userland\core;$(ProjectDir)..\..\src\interop;$(ProjectDir)..\..\src\system;$(ProjectDir)..\..\src\system\compatibility;$(ProjectDir)..\..\src\system\replacement;%(AdditionalIncludeDirectories) + MultiThreadedDebugDLL + true + + + Console + true + CLRNetCore.lib;CLRNetInterop.lib;CLRNetSystem.lib;runtimeobject.lib;windowsapp.lib;ole32.lib;shlwapi.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + MaxSpeed + true + true + WIN32;_WINDOWS;PLATFORM_WP81;NDEBUG;%(PreprocessorDefinitions) + $(ProjectDir)..\..\src\phase1-userland\core;$(ProjectDir)..\..\src\interop;$(ProjectDir)..\..\src\system;$(ProjectDir)..\..\src\system\compatibility;$(ProjectDir)..\..\src\system\replacement;%(AdditionalIncludeDirectories) + MultiThreadedDLL + true + + + Console + true + true + true + CLRNetCore.lib;CLRNetInterop.lib;CLRNetSystem.lib;runtimeobject.lib;windowsapp.lib;ole32.lib;shlwapi.lib;%(AdditionalDependencies) + + + + + + + + {8F4C5A55-2F4B-4C40-8A64-6B501B28B42C} + false + + + {AF9323CB-8F8C-4D9F-9E1F-349437DD9C10} + false + + + {6E8E9D3E-8B1F-4C1B-BD5A-9852E5F0C8C2} + false + + + + + diff --git a/tests/CLRNetTests/Main.cpp b/tests/CLRNetTests/Main.cpp new file mode 100644 index 0000000..18931f1 --- /dev/null +++ b/tests/CLRNetTests/Main.cpp @@ -0,0 +1,53 @@ +#include "../../src/phase1-userland/core/CoreExecutionEngine.h" +#include "../../src/phase1-userland/core/AssemblyLoader.h" +#include "../../src/interop/InteropManager.h" +#include "../../src/system/compatibility/CompatibilityShim.h" +#include "../../src/system/replacement/CLRReplacementEngine.h" + +#include +#include +#include + +using namespace CLRNet::Phase1; +using namespace CLRNet::Interop; +using namespace CLRNet::System; + +int wmain() +{ + std::wcout << L"[CLRNetTests] Starting smoke tests...\n"; + + CoreExecutionEngine runtime; + if (!runtime.Initialize()) + { + std::wcerr << L"Failed to initialize CoreExecutionEngine" << std::endl; + return 1; + } + + runtime.Shutdown(); + + auto config = CompatibilityFactory::CreateMinimalCompatibilityConfig(); + auto shim = std::unique_ptr(CompatibilityFactory::CreateCompatibilityShim(config)); + if (shim) + { + shim->Initialize(CompatibilityLevel::Minimal); + shim->Cleanup(); + } + + auto engine = std::unique_ptr(CLRReplacementFactory::CreateEngine(ReplacementLevel::ProcessLevel)); + if (engine) + { + engine->AttachToCurrentProcess(); + CLRReplacementFactory::DestroyEngine(engine.release()); + } + + auto interopConfig = InteropFactory::CreateMinimalConfiguration(L"CLRNetTests"); + auto interop = std::unique_ptr(InteropFactory::CreateCustomInstance(interopConfig)); + if (interop) + { + interop->Initialize(interopConfig); + interop->Shutdown(); + } + + std::wcout << L"[CLRNetTests] All smoke tests completed successfully." << std::endl; + return 0; +}