├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── client ├── client.vcxproj ├── client.vcxproj.filters ├── common.hpp ├── main.cpp ├── memory.cpp ├── memory.hpp ├── sock.cpp ├── sock.hpp ├── utils.cpp ├── utils.hpp └── xorstr.hpp ├── driver ├── berkeley.c ├── berkeley.h ├── common.h ├── driver.inf ├── driver.vcxproj ├── driver.vcxproj.filters ├── imports.h ├── intdefs.h ├── ksocket.c ├── ksocket.h ├── main.c ├── server.c ├── server.h ├── utils.c └── utils.h └── kersock.sln /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | [Aa][Rr][Mm]/ 24 | [Aa][Rr][Mm]64/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Ll]og/ 29 | 30 | # Visual Studio 2015/2017 cache/options directory 31 | .vs/ 32 | # Uncomment if you have tasks that create the project's static files in wwwroot 33 | #wwwroot/ 34 | 35 | # Visual Studio 2017 auto generated files 36 | Generated\ Files/ 37 | 38 | # MSTest test Results 39 | [Tt]est[Rr]esult*/ 40 | [Bb]uild[Ll]og.* 41 | 42 | # NUNIT 43 | *.VisualState.xml 44 | TestResult.xml 45 | 46 | # Build Results of an ATL Project 47 | [Dd]ebugPS/ 48 | [Rr]eleasePS/ 49 | dlldata.c 50 | 51 | # Benchmark Results 52 | BenchmarkDotNet.Artifacts/ 53 | 54 | # .NET Core 55 | project.lock.json 56 | project.fragment.lock.json 57 | artifacts/ 58 | 59 | # StyleCop 60 | StyleCopReport.xml 61 | 62 | # Files built by Visual Studio 63 | *_i.c 64 | *_p.c 65 | *_h.h 66 | *.ilk 67 | *.meta 68 | *.obj 69 | *.iobj 70 | *.pch 71 | *.pdb 72 | *.ipdb 73 | *.pgc 74 | *.pgd 75 | *.rsp 76 | *.sbr 77 | *.tlb 78 | *.tli 79 | *.tlh 80 | *.tmp 81 | *.tmp_proj 82 | *_wpftmp.csproj 83 | *.log 84 | *.vspscc 85 | *.vssscc 86 | .builds 87 | *.pidb 88 | *.svclog 89 | *.scc 90 | 91 | # Chutzpah Test files 92 | _Chutzpah* 93 | 94 | # Visual C++ cache files 95 | ipch/ 96 | *.aps 97 | *.ncb 98 | *.opendb 99 | *.opensdf 100 | *.sdf 101 | *.cachefile 102 | *.VC.db 103 | *.VC.VC.opendb 104 | 105 | # Visual Studio profiler 106 | *.psess 107 | *.vsp 108 | *.vspx 109 | *.sap 110 | 111 | # Visual Studio Trace Files 112 | *.e2e 113 | 114 | # TFS 2012 Local Workspace 115 | $tf/ 116 | 117 | # Guidance Automation Toolkit 118 | *.gpState 119 | 120 | # ReSharper is a .NET coding add-in 121 | _ReSharper*/ 122 | *.[Rr]e[Ss]harper 123 | *.DotSettings.user 124 | 125 | # JustCode is a .NET coding add-in 126 | .JustCode 127 | 128 | # TeamCity is a build add-in 129 | _TeamCity* 130 | 131 | # DotCover is a Code Coverage Tool 132 | *.dotCover 133 | 134 | # AxoCover is a Code Coverage Tool 135 | .axoCover/* 136 | !.axoCover/settings.json 137 | 138 | # Visual Studio code coverage results 139 | *.coverage 140 | *.coveragexml 141 | 142 | # NCrunch 143 | _NCrunch_* 144 | .*crunch*.local.xml 145 | nCrunchTemp_* 146 | 147 | # MightyMoose 148 | *.mm.* 149 | AutoTest.Net/ 150 | 151 | # Web workbench (sass) 152 | .sass-cache/ 153 | 154 | # Installshield output folder 155 | [Ee]xpress/ 156 | 157 | # DocProject is a documentation generator add-in 158 | DocProject/buildhelp/ 159 | DocProject/Help/*.HxT 160 | DocProject/Help/*.HxC 161 | DocProject/Help/*.hhc 162 | DocProject/Help/*.hhk 163 | DocProject/Help/*.hhp 164 | DocProject/Help/Html2 165 | DocProject/Help/html 166 | 167 | # Click-Once directory 168 | publish/ 169 | 170 | # Publish Web Output 171 | *.[Pp]ublish.xml 172 | *.azurePubxml 173 | # Note: Comment the next line if you want to checkin your web deploy settings, 174 | # but database connection strings (with potential passwords) will be unencrypted 175 | *.pubxml 176 | *.publishproj 177 | 178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 179 | # checkin your Azure Web App publish settings, but sensitive information contained 180 | # in these scripts will be unencrypted 181 | PublishScripts/ 182 | 183 | # NuGet Packages 184 | *.nupkg 185 | # The packages folder can be ignored because of Package Restore 186 | **/[Pp]ackages/* 187 | # except build/, which is used as an MSBuild target. 188 | !**/[Pp]ackages/build/ 189 | # Uncomment if necessary however generally it will be regenerated when needed 190 | #!**/[Pp]ackages/repositories.config 191 | # NuGet v3's project.json files produces more ignorable files 192 | *.nuget.props 193 | *.nuget.targets 194 | 195 | # Microsoft Azure Build Output 196 | csx/ 197 | *.build.csdef 198 | 199 | # Microsoft Azure Emulator 200 | ecf/ 201 | rcf/ 202 | 203 | # Windows Store app package directories and files 204 | AppPackages/ 205 | BundleArtifacts/ 206 | Package.StoreAssociation.xml 207 | _pkginfo.txt 208 | *.appx 209 | 210 | # Visual Studio cache files 211 | # files ending in .cache can be ignored 212 | *.[Cc]ache 213 | # but keep track of directories ending in .cache 214 | !?*.[Cc]ache/ 215 | 216 | # Others 217 | ClientBin/ 218 | ~$* 219 | *~ 220 | *.dbmdl 221 | *.dbproj.schemaview 222 | *.jfm 223 | *.pfx 224 | *.publishsettings 225 | orleans.codegen.cs 226 | 227 | # Including strong name files can present a security risk 228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 229 | #*.snk 230 | 231 | # Since there are multiple workflows, uncomment next line to ignore bower_components 232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 233 | #bower_components/ 234 | 235 | # RIA/Silverlight projects 236 | Generated_Code/ 237 | 238 | # Backup & report files from converting an old project file 239 | # to a newer Visual Studio version. Backup files are not needed, 240 | # because we have git ;-) 241 | _UpgradeReport_Files/ 242 | Backup*/ 243 | UpgradeLog*.XML 244 | UpgradeLog*.htm 245 | ServiceFabricBackup/ 246 | *.rptproj.bak 247 | 248 | # SQL Server files 249 | *.mdf 250 | *.ldf 251 | *.ndf 252 | 253 | # Business Intelligence projects 254 | *.rdl.data 255 | *.bim.layout 256 | *.bim_*.settings 257 | *.rptproj.rsuser 258 | *- Backup*.rdl 259 | 260 | # Microsoft Fakes 261 | FakesAssemblies/ 262 | 263 | # GhostDoc plugin setting file 264 | *.GhostDoc.xml 265 | 266 | # Node.js Tools for Visual Studio 267 | .ntvs_analysis.dat 268 | node_modules/ 269 | 270 | # Visual Studio 6 build log 271 | *.plg 272 | 273 | # Visual Studio 6 workspace options file 274 | *.opt 275 | 276 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 277 | *.vbw 278 | 279 | # Visual Studio LightSwitch build output 280 | **/*.HTMLClient/GeneratedArtifacts 281 | **/*.DesktopClient/GeneratedArtifacts 282 | **/*.DesktopClient/ModelManifest.xml 283 | **/*.Server/GeneratedArtifacts 284 | **/*.Server/ModelManifest.xml 285 | _Pvt_Extensions 286 | 287 | # Paket dependency manager 288 | .paket/paket.exe 289 | paket-files/ 290 | 291 | # FAKE - F# Make 292 | .fake/ 293 | 294 | # JetBrains Rider 295 | .idea/ 296 | *.sln.iml 297 | 298 | # CodeRush personal settings 299 | .cr/personal 300 | 301 | # Python Tools for Visual Studio (PTVS) 302 | __pycache__/ 303 | *.pyc 304 | 305 | # Cake - Uncomment if you are using it 306 | # tools/** 307 | # !tools/packages.config 308 | 309 | # Tabs Studio 310 | *.tss 311 | 312 | # Telerik's JustMock configuration file 313 | *.jmconfig 314 | 315 | # BizTalk build output 316 | *.btp.cs 317 | *.btm.cs 318 | *.odx.cs 319 | *.xsd.cs 320 | 321 | # OpenCover UI analysis results 322 | OpenCover/ 323 | 324 | # Azure Stream Analytics local run output 325 | ASALocalRun/ 326 | 327 | # MSBuild Binary and Structured Log 328 | *.binlog 329 | 330 | # NVidia Nsight GPU debugger configuration file 331 | *.nvuser 332 | 333 | # MFractors (Xamarin productivity tool) working folder 334 | .mfractor/ 335 | 336 | # Local History for Visual Studio 337 | .localhistory/ 338 | 339 | # BeatPulse healthcheck temp database 340 | healthchecksdb -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Deputation 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kernel_sockets_memory 2 | Kernel-based memory hacking framework communicating with a kernel driver via sockets, it allows for memory reading, writing, allocation, freeing, protection changing without a valid user-mode handle. 3 | Kernel-mode sockets kindly provided by wbenny's KSOCKET framework. Credits to him. https://github.com/wbenny/ksocket 4 | 5 | Some simple features like service unloading and complete disconnection (and cleanup) have been omitted from the project to prevent abuse by pay-to-cheat services that would abuse it for monetary gain. I'll leave these as an exercise to the reader. 6 | 7 | # Notes 8 | The driver was written entirely in C, while the client was written in C++. The part of the project meant to be used by people who have no idea how it works behind the scenes (the ``memory::virtual_controller_t`` class) is well documented. xorstr class from JustasMasiluis. Credits to him. https://github.com/JustasMasiulis/xorstr 9 | 10 | # Loading the driver 11 | The driver can be loaded regularly and also via DSE-bypass techniques like manual mapping, as it doesn't use any ``__try{} __except() {}`` blocks nor tries doing anything patchguard-unfriendly. Once loaded, the driver spawns a new thread for every client that would like to connect. 12 | 13 | # Client 14 | The client connects and sends packets with the regular wsa socket api present in windows. The idea to use unions for the socket structures was taken from r6s-external-nuklear-socket by alxbrn. Credits to him. https://github.com/alxbrn/r6s-external-nuklear-socket 15 | 16 | # Tests 17 | A small subset of "tests" showing simply how to use the provided ``memory::virtual_controller_t`` class is present in the main() function of the client. 18 | 19 | # Getting started 20 | - Download VS2019 with the relevant C++ packages and the W10 SDK. 21 | - Download the Windows WDK and install its relevant extension. 22 | - Clone the project. 23 | - Build. 24 | 25 | # How to use 26 | - Create the driver's service by executing "``sc create ksocketsmem type= kernel binPath= "C:\Path\To\Your\File.sys"``" in an elevated command prompt. 27 | - Start the driver's service by executing "``sc start ksocketsmem``" in an elevated command prompt. 28 | - Open the client. 29 | -------------------------------------------------------------------------------- /client/client.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | 16.0 15 | Win32Proj 16 | {81699472-e045-4df8-99a1-72936ee445ee} 17 | client 18 | 10.0 19 | 20 | 21 | 22 | Application 23 | true 24 | v142 25 | Unicode 26 | 27 | 28 | Application 29 | false 30 | v142 31 | true 32 | Unicode 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | true 48 | 49 | 50 | false 51 | 52 | 53 | 54 | Level3 55 | true 56 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 57 | true 58 | MultiThreadedDebug 59 | stdcpp17 60 | 61 | 62 | Console 63 | true 64 | 65 | 66 | 67 | 68 | Level3 69 | true 70 | true 71 | true 72 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 73 | true 74 | MultiThreaded 75 | stdcpp17 76 | 77 | 78 | Console 79 | true 80 | true 81 | true 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /client/client.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | 32 | 33 | Header Files 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | -------------------------------------------------------------------------------- /client/common.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #pragma comment(lib, "Ws2_32") 20 | 21 | #define log(...) std::printf(__VA_ARGS__) 22 | 23 | #include "xorstr.hpp" 24 | #include "sock.hpp" 25 | #include "utils.hpp" 26 | #include "memory.hpp" -------------------------------------------------------------------------------- /client/main.cpp: -------------------------------------------------------------------------------- 1 | #include "common.hpp" 2 | 3 | int main(void) 4 | { 5 | auto ksock = std::make_shared(55123); 6 | log("KSOCK connected on port %d\n", ksock->port); 7 | auto process = std::make_shared(ksock, utils::get_process_id("client.exe"), L"client.exe"); 8 | 9 | log("Testing ksock connection using the virtual controller.\n"); 10 | 11 | auto secret = 0x1337u; 12 | 13 | log("Base address (main module): %p\n", process->get_base()); 14 | log("Size (main module): %p\n", process->get_size()); 15 | log("Base address (ntdll.dll): %p\n", process->get_base(L"ntdll.dll")); 16 | log("Size (ntdll.dll): %p\n", process->get_size(L"ntdll.dll")); 17 | log("Read (reading secret): %p\n", process->read(reinterpret_cast(&secret))); 18 | log("Write (changing secret): %p\n", process->write(reinterpret_cast(&secret), 0xCAFEBABE)); 19 | log("Read 2 (reading secret): %p\n", process->read(reinterpret_cast(&secret))); 20 | 21 | auto region = process->allocate(PAGE_EXECUTE_READWRITE, MEM_COMMIT | MEM_RESERVE, 0x1000); 22 | log("Allocation: %p\n", region); 23 | 24 | // The two values should be the same, since the old protection was PAGE_EXECUTE_READWRITE 25 | log("Protection: %p - %p\n", process->protect(region, PAGE_READWRITE, 0x1000), PAGE_EXECUTE_READWRITE); 26 | 27 | process->free(region, 0x1000); 28 | ksock->disconnect(); 29 | 30 | // So you can read results even if you double clicked. 31 | std::cin.get(); 32 | 33 | return 0; 34 | } -------------------------------------------------------------------------------- /client/memory.cpp: -------------------------------------------------------------------------------- 1 | #include "common.hpp" 2 | 3 | memory::virtual_controller_t::virtual_controller_t(std::shared_ptr& server, uint32_t pid, const wchar_t* name) 4 | { 5 | this->server = server; 6 | this->pid = pid; 7 | this->name = std::wstring(name); 8 | } 9 | 10 | memory::virtual_controller_t::~virtual_controller_t() 11 | { 12 | } 13 | 14 | uint64_t memory::virtual_controller_t::get_base() 15 | { 16 | return server->get_base(this->pid, this->name.data()); 17 | } 18 | 19 | uint64_t memory::virtual_controller_t::get_base(const wchar_t* module_name) 20 | { 21 | return server->get_base(this->pid, module_name); 22 | } 23 | 24 | uint64_t memory::virtual_controller_t::get_size() 25 | { 26 | return server->get_size(this->pid, this->name.data()); 27 | } 28 | 29 | uint64_t memory::virtual_controller_t::get_size(const wchar_t* module_name) 30 | { 31 | return server->get_size(this->pid, module_name); 32 | } 33 | 34 | uint64_t memory::virtual_controller_t::allocate(uint32_t protection, uint32_t allocation_type, size_t size) 35 | { 36 | return this->server->zw_allocate_virtual_memory(this->pid, protection, allocation_type, size); 37 | } 38 | 39 | void memory::virtual_controller_t::free(uint64_t target_address, size_t size) 40 | { 41 | this->server->zw_free_vritual_memory(this->pid, target_address, size); 42 | } 43 | 44 | uint64_t memory::virtual_controller_t::protect(uint64_t target_address, uint32_t protection, size_t size) 45 | { 46 | return this->server->zw_protect_virtual_memory(this->pid, target_address, protection, size); 47 | } 48 | -------------------------------------------------------------------------------- /client/memory.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace memory 4 | { 5 | class virtual_controller_t 6 | { 7 | protected: 8 | std::shared_ptr server; 9 | 10 | public: 11 | uint32_t pid; 12 | std::wstring name; 13 | 14 | /// 15 | /// Instantiate the virtual memory controller. 16 | /// 17 | /// A ksock_t shared instance. 18 | /// The process id you want the virtual controller to bind to. 19 | /// Process executable's name. 20 | virtual_controller_t(std::shared_ptr& server, uint32_t pid, const wchar_t* name); 21 | 22 | /// 23 | /// Destructor. Unimplemented as of now. 24 | /// 25 | ~virtual_controller_t(); 26 | 27 | /// 28 | /// Get the process' main module base. 29 | /// 30 | /// The main module's base. 31 | uint64_t get_base(); 32 | 33 | /// 34 | /// Get a process module's base address. 35 | /// 36 | /// The name of the module of which you want to retrieve the base address. 37 | /// The base address of the specified module. 38 | uint64_t get_base(const wchar_t* module_name); 39 | 40 | /// 41 | /// Get the process' main module's size. 42 | /// 43 | /// The main module's size. 44 | uint64_t get_size(); 45 | 46 | /// 47 | /// Get a process module's size. 48 | /// 49 | /// The name of the module of which you want to retrieve the size. 50 | /// The size of the module. 51 | uint64_t get_size(const wchar_t* module_name); 52 | 53 | /// 54 | /// Write to the process' virtual memory. 55 | /// 56 | /// The data type of the data you want to write. 57 | /// The address you want the data to be written to. 58 | /// The data you want to write. 59 | /// The amount of bytes written. 60 | template 61 | inline size_t write(uint64_t address, t value) 62 | { 63 | auto buffer = value; 64 | 65 | return this->server->mm_copy_virtual_memory(GetCurrentProcessId(), 66 | reinterpret_cast(&buffer), this->pid, address, sizeof(t)); 67 | } 68 | 69 | /// 70 | /// Reads virtual memory from the process. 71 | /// 72 | /// The data type located at the address. 73 | /// The address that you want to read. 74 | /// The data read. 75 | template 76 | inline t read(uint64_t address) 77 | { 78 | t buffer; 79 | 80 | this->server->mm_copy_virtual_memory(this->pid, address, GetCurrentProcessId(), 81 | reinterpret_cast(&buffer), sizeof(t)); 82 | 83 | return buffer; 84 | } 85 | 86 | /// 87 | /// Issue a kernel memory allocation. Pages will have the specified allocation type and protection. 88 | /// 89 | /// The pages' protection. 90 | /// The allocation's type. 91 | /// The allocation's size. 92 | /// The base address of the allocated memory zone. 93 | uint64_t allocate(uint32_t protection, uint32_t allocation_type, size_t size); 94 | 95 | /// 96 | /// Frees memory with the MEM_RELEASE free type. 97 | /// 98 | /// The base adddress of the allocation to free. 99 | /// The size of the memory allocation to free. 100 | void free(uint64_t target_address, size_t size); 101 | 102 | /// 103 | /// Changes a memory zone's protection. 104 | /// 105 | /// The address of which the protection will be changed. (Affects an entire 106 | /// page), standard PAGE_SIZE is 0x1000. 107 | /// The new protection. 108 | /// The amount of bytes to be affected, starting from the specified target address. 109 | /// The old protection. 110 | uint64_t protect(uint64_t target_address, uint32_t protection, size_t size); 111 | }; 112 | } 113 | 114 | -------------------------------------------------------------------------------- /client/sock.cpp: -------------------------------------------------------------------------------- 1 | #include "common.hpp" 2 | 3 | connection::ksock_t::ksock_t(uint16_t port) 4 | { 5 | WSAStartup(MAKEWORD(2, 2), &this->wsa_data); 6 | 7 | this->connection = this->connect(port); 8 | this->port = port; 9 | } 10 | 11 | connection::ksock_t::~ksock_t() 12 | { 13 | WSACleanup(); 14 | } 15 | 16 | SOCKET connection::ksock_t::connect(uint16_t port) 17 | { 18 | SOCKADDR_IN address = {}; 19 | 20 | address.sin_family = AF_INET; 21 | address.sin_addr.s_addr = htonl(server_ip); 22 | address.sin_port = htons(port); 23 | 24 | const auto sockfd = socket(AF_INET, SOCK_STREAM, 0); 25 | 26 | if (sockfd != INVALID_SOCKET) 27 | { 28 | if (::connect(sockfd, reinterpret_cast(&address), sizeof(address)) == SOCKET_ERROR) 29 | { 30 | closesocket(sockfd); 31 | return INVALID_SOCKET; 32 | } 33 | else 34 | { 35 | return sockfd; 36 | } 37 | } 38 | else 39 | { 40 | return sockfd; 41 | } 42 | } 43 | 44 | void connection::ksock_t::disconnect() 45 | { 46 | closesocket(connection); 47 | } 48 | 49 | bool connection::ksock_t::send_data(data_packet_t& packet, uint64_t& result) 50 | { 51 | data_packet_t response = {}; 52 | 53 | if (send(this->connection, reinterpret_cast(&packet), sizeof(packet), 0) == SOCKET_ERROR) 54 | { 55 | return false; 56 | } 57 | 58 | const auto recv_result = recv(this->connection, reinterpret_cast(&response), sizeof(packet), 0); 59 | 60 | if (recv_result < sizeof(packet_header_t) || response.header.magic_header != magic_header_value 61 | || response.header.type != e_packet_type::completed) 62 | { 63 | return false; 64 | } 65 | 66 | result = response.data.response.data; 67 | 68 | return true; 69 | } 70 | 71 | uint64_t connection::ksock_t::ping(int32_t value) 72 | { 73 | data_packet_t ping = {}; 74 | 75 | ping.header.magic_header = magic_header_value; 76 | ping.header.type = e_packet_type::ping; 77 | ping.data.ping.ping_magic = value; 78 | 79 | auto result = 0ull; 80 | 81 | if (this->send_data(ping, result)) 82 | { 83 | return result; 84 | } 85 | 86 | return 0; 87 | } 88 | 89 | uint64_t connection::ksock_t::get_base(uint32_t target_pid, const wchar_t* module_name) 90 | { 91 | std::wstring buffer = module_name; 92 | 93 | data_packet_t get_base = {}; 94 | 95 | get_base.header.magic_header = magic_header_value; 96 | get_base.header.type = e_packet_type::packet_get_base; 97 | get_base.data.get_base.target_pid = target_pid; 98 | 99 | memset(&get_base.data.get_base.module_name[0], 0, 64 * sizeof(wchar_t)); 100 | memcpy(&get_base.data.get_base.module_name[0], const_cast(buffer.data()), 101 | (std::wcslen(buffer.data()) + 1) * sizeof(wchar_t)); 102 | 103 | auto result = 0ull; 104 | 105 | if (this->send_data(get_base, result)) 106 | { 107 | return result; 108 | } 109 | 110 | return 0; 111 | } 112 | 113 | uint64_t connection::ksock_t::get_size(uint32_t target_pid, const wchar_t* module_name) 114 | { 115 | std::wstring buffer = module_name; 116 | 117 | data_packet_t get_size = {}; 118 | 119 | get_size.header.magic_header = magic_header_value; 120 | get_size.header.type = e_packet_type::packet_get_size; 121 | get_size.data.get_size.target_pid = target_pid; 122 | 123 | memset(&get_size.data.get_size.module_name[0], 0, 64 * sizeof(wchar_t)); 124 | memcpy(&get_size.data.get_size.module_name[0], const_cast(buffer.data()), 125 | (std::wcslen(buffer.data()) + 1) * sizeof(wchar_t)); 126 | 127 | auto result = 0ull; 128 | 129 | if (this->send_data(get_size, result)) 130 | { 131 | return result; 132 | } 133 | 134 | return 0; 135 | } 136 | 137 | uint64_t connection::ksock_t::mm_copy_virtual_memory(uint32_t source_pid, uintptr_t source_address, 138 | uint32_t target_pid, uintptr_t target_address, size_t size) 139 | { 140 | data_packet_t copy_memory = {}; 141 | 142 | copy_memory.header.magic_header = magic_header_value; 143 | copy_memory.header.type = e_packet_type::packet_copy_memory; 144 | copy_memory.data.copy_memory.source_pid = source_pid; 145 | copy_memory.data.copy_memory.source_address = source_address; 146 | copy_memory.data.copy_memory.target_pid = target_pid; 147 | copy_memory.data.copy_memory.target_address = target_address; 148 | copy_memory.data.copy_memory.size = size; 149 | 150 | auto result = 0ull; 151 | 152 | if (this->send_data(copy_memory, result)) 153 | { 154 | return result; 155 | } 156 | 157 | return 0; 158 | } 159 | 160 | uint64_t connection::ksock_t::zw_allocate_virtual_memory(uint32_t target_pid, uint32_t protection, 161 | uint32_t allocation_type, size_t size) 162 | { 163 | data_packet_t allocate_memory = {}; 164 | 165 | allocate_memory.header.magic_header = magic_header_value; 166 | allocate_memory.header.type = e_packet_type::packet_allocate; 167 | allocate_memory.data.allocate_memory.target_pid = target_pid; 168 | allocate_memory.data.allocate_memory.protection = protection; 169 | allocate_memory.data.allocate_memory.allocation_type = allocation_type; 170 | allocate_memory.data.allocate_memory.size = size; 171 | 172 | auto result = 0ull; 173 | 174 | if (this->send_data(allocate_memory, result)) 175 | { 176 | return result; 177 | } 178 | 179 | return 0; 180 | } 181 | 182 | uint64_t connection::ksock_t::zw_free_vritual_memory(uint32_t target_pid, uint64_t target_address, size_t size) 183 | { 184 | data_packet_t free_memory = {}; 185 | 186 | free_memory.header.magic_header = magic_header_value; 187 | free_memory.header.type = e_packet_type::packet_free; 188 | free_memory.data.free_memory.target_pid = target_pid; 189 | free_memory.data.free_memory.target_address = target_address; 190 | free_memory.data.free_memory.size = size; 191 | 192 | auto result = 0ull; 193 | 194 | if (this->send_data(free_memory, result)) 195 | { 196 | return result; 197 | } 198 | 199 | return 0; 200 | } 201 | 202 | uint64_t connection::ksock_t::zw_protect_virtual_memory(uint32_t target_pid, uint64_t target_address, uint32_t protection, size_t size) 203 | { 204 | data_packet_t protect_memory = {}; 205 | 206 | protect_memory.header.magic_header = magic_header_value; 207 | protect_memory.header.type = e_packet_type::packet_protect; 208 | protect_memory.data.protect_memory.target_pid = target_pid; 209 | protect_memory.data.protect_memory.target_address = target_address; 210 | protect_memory.data.protect_memory.new_protection = protection; 211 | protect_memory.data.protect_memory.size = size; 212 | 213 | auto result = 0ull; 214 | 215 | if (this->send_data(protect_memory, result)) 216 | { 217 | return result; 218 | } 219 | 220 | return 0; 221 | } 222 | -------------------------------------------------------------------------------- /client/sock.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace connection 4 | { 5 | constexpr auto magic_header_value = 0x59da412859da4128; 6 | constexpr auto server_ip = 0x7F000001; // localhost 7 | 8 | enum class e_packet_type : uint32_t 9 | { 10 | packet_get_base, 11 | packet_get_size, 12 | packet_copy_memory, 13 | packet_allocate, 14 | packet_free, 15 | packet_protect, 16 | completed, 17 | ping 18 | }; 19 | 20 | struct packet_header_t 21 | { 22 | uint64_t magic_header; 23 | e_packet_type type; 24 | }; 25 | 26 | struct packet_response_t 27 | { 28 | uint64_t data; 29 | }; 30 | 31 | struct packet_ping_t 32 | { 33 | int32_t ping_magic; 34 | }; 35 | 36 | struct packet_copy_memory_t 37 | { 38 | uint32_t source_pid; 39 | uint64_t source_address; 40 | uint32_t target_pid; 41 | uint64_t target_address; 42 | size_t size; 43 | }; 44 | 45 | struct packet_allocate_memory_t 46 | { 47 | uint32_t target_pid; 48 | uint32_t protection; 49 | uint32_t allocation_type; 50 | size_t size; 51 | }; 52 | 53 | struct packet_free_memory_t 54 | { 55 | uint32_t target_pid; 56 | uint64_t target_address; 57 | size_t size; 58 | }; 59 | 60 | struct packet_get_base_t 61 | { 62 | uint32_t target_pid; 63 | wchar_t module_name[64]; 64 | }; 65 | 66 | struct packet_get_size_t 67 | { 68 | uint32_t target_pid; 69 | wchar_t module_name[64]; 70 | }; 71 | 72 | struct packet_protect_memory_t 73 | { 74 | uint32_t target_pid; 75 | uint64_t target_address; 76 | uint32_t new_protection; 77 | size_t size; 78 | }; 79 | 80 | struct data_packet_t 81 | { 82 | packet_header_t header; 83 | 84 | union 85 | { 86 | packet_response_t response; 87 | packet_ping_t ping; 88 | packet_copy_memory_t copy_memory; 89 | packet_allocate_memory_t allocate_memory; 90 | packet_free_memory_t free_memory; 91 | packet_protect_memory_t protect_memory; 92 | packet_get_base_t get_base; 93 | packet_get_size_t get_size; 94 | } data; 95 | }; 96 | 97 | class ksock_t 98 | { 99 | protected: 100 | WSADATA wsa_data; 101 | SOCKET connection; 102 | 103 | public: 104 | uint16_t port; 105 | 106 | ksock_t(uint16_t port); 107 | ~ksock_t(); 108 | 109 | SOCKET connect(uint16_t port); 110 | void disconnect(); 111 | 112 | bool send_data(data_packet_t& packet, uint64_t& result); 113 | 114 | uint64_t ping(int32_t value); 115 | 116 | uint64_t get_base(uint32_t target_pid, const wchar_t* module_name); 117 | uint64_t get_size(uint32_t target_pid, const wchar_t* module_name); 118 | 119 | uint64_t mm_copy_virtual_memory(uint32_t source_pid, uintptr_t source_address, uint32_t target_pid, 120 | uintptr_t target_address, size_t size); 121 | 122 | uint64_t zw_allocate_virtual_memory(uint32_t target_pid, uint32_t protection, uint32_t allocation_type, size_t size); 123 | uint64_t zw_free_vritual_memory(uint32_t target_pid, uint64_t target_address, size_t size); 124 | uint64_t zw_protect_virtual_memory(uint32_t target_pid, uint64_t target_address, uint32_t protection, size_t size); 125 | }; 126 | } -------------------------------------------------------------------------------- /client/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "common.hpp" 2 | 3 | uint32_t utils::get_process_id(const char* exe_name) 4 | { 5 | auto snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 6 | 7 | if (snapshot_handle == INVALID_HANDLE_VALUE) 8 | { 9 | return 0; 10 | } 11 | 12 | PROCESSENTRY32 pe = { 0 }; 13 | pe.dwSize = sizeof(PROCESSENTRY32); 14 | 15 | for (auto success = Process32First(snapshot_handle, &pe); success == true; success = Process32Next(snapshot_handle, &pe)) 16 | { 17 | auto wide_name = std::wstring(pe.szExeFile); 18 | auto ascii_name = std::string(wide_name.begin(), wide_name.end()); 19 | 20 | if (!ascii_name.compare(exe_name)) 21 | { 22 | CloseHandle(snapshot_handle); 23 | return pe.th32ProcessID; 24 | } 25 | } 26 | 27 | CloseHandle(snapshot_handle); 28 | return NULL; 29 | } 30 | -------------------------------------------------------------------------------- /client/utils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace utils 4 | { 5 | uint32_t get_process_id(const char* exe_name); 6 | } -------------------------------------------------------------------------------- /client/xorstr.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | * Copyright 2017 - 2020 Justas Masiulis 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef JM_XORSTR_HPP 20 | #define JM_XORSTR_HPP 21 | 22 | #define xorstr(str) ::jm::xor_string([]() { return str; }, std::integral_constant{}, std::make_index_sequence<::jm::detail::_buffer_size()>{}) 23 | #define xorstr_(str) xorstr(str).crypt_get() 24 | 25 | #ifdef _MSC_VER 26 | #define XORSTR_FORCEINLINE __forceinline 27 | #else 28 | #define XORSTR_FORCEINLINE __attribute__((always_inline)) inline 29 | #endif 30 | 31 | #if defined(__clang__) || defined(__GNUC__) 32 | #define JM_XORSTR_LOAD_FROM_REG(x) ::jm::detail::load_from_reg(x) 33 | #else 34 | #define JM_XORSTR_LOAD_FROM_REG(x) (x) 35 | #endif 36 | 37 | namespace jm 38 | { 39 | 40 | namespace detail 41 | { 42 | 43 | template 44 | XORSTR_FORCEINLINE constexpr std::size_t _buffer_size() 45 | { 46 | return ((Size / 16) + (Size % 16 != 0)) * 2; 47 | } 48 | 49 | template 50 | XORSTR_FORCEINLINE constexpr std::uint32_t key4() noexcept 51 | { 52 | std::uint32_t value = Seed; 53 | for (char c : __TIME__) 54 | value = static_cast((value ^ c) * 16777619ull); 55 | return value; 56 | } 57 | 58 | template 59 | XORSTR_FORCEINLINE constexpr std::uint64_t key8() 60 | { 61 | constexpr auto first_part = key4<2166136261 + S>(); 62 | constexpr auto second_part = key4(); 63 | return (static_cast(first_part) << 32) | second_part; 64 | } 65 | 66 | // loads up to 8 characters of string into uint64 and xors it with the key 67 | template 68 | XORSTR_FORCEINLINE constexpr std::uint64_t 69 | load_xored_str8(std::uint64_t key, std::size_t idx, const CharT* str) noexcept 70 | { 71 | using cast_type = typename std::make_unsigned::type; 72 | constexpr auto value_size = sizeof(CharT); 73 | constexpr auto idx_offset = 8 / value_size; 74 | 75 | std::uint64_t value = key; 76 | for (std::size_t i = 0; i < idx_offset && i + idx * idx_offset < N; ++i) 77 | value ^= 78 | (std::uint64_t{ static_cast(str[i + idx * idx_offset]) } 79 | << ((i % idx_offset) * 8 * value_size)); 80 | 81 | return value; 82 | } 83 | 84 | // forces compiler to use registers instead of stuffing constants in rdata 85 | XORSTR_FORCEINLINE std::uint64_t load_from_reg(std::uint64_t value) noexcept 86 | { 87 | #if defined(__clang__) || defined(__GNUC__) 88 | asm("" : "=r"(value) : "0"(value) : ); 89 | #endif 90 | return value; 91 | } 92 | 93 | template 94 | struct uint64_v 95 | { 96 | constexpr static std::uint64_t value = V; 97 | }; 98 | 99 | } // namespace detail 100 | 101 | template 102 | class xor_string; 103 | 104 | template 105 | class xor_string, std::index_sequence> 106 | { 107 | #ifndef JM_XORSTR_DISABLE_AVX_INTRINSICS 108 | constexpr static inline std::uint64_t alignment = ((Size > 16) ? 32 : 16); 109 | #else 110 | constexpr static inline std::uint64_t alignment = 16; 111 | #endif 112 | 113 | alignas(alignment) std::uint64_t _storage[sizeof...(Keys)]; 114 | 115 | public: 116 | using value_type = CharT; 117 | using size_type = std::size_t; 118 | using pointer = CharT*; 119 | using const_pointer = const CharT*; 120 | 121 | template 122 | XORSTR_FORCEINLINE xor_string(L l, std::integral_constant, std::index_sequence) noexcept 123 | : _storage{ JM_XORSTR_LOAD_FROM_REG(detail::uint64_v(Keys, Indices, l())>::value)... } 124 | {} 125 | 126 | XORSTR_FORCEINLINE constexpr size_type size() const noexcept 127 | { 128 | return Size - 1; 129 | } 130 | 131 | XORSTR_FORCEINLINE void crypt() noexcept 132 | { 133 | #if defined(__clang__) 134 | alignas(alignment) 135 | std::uint64_t arr[]{ JM_XORSTR_LOAD_FROM_REG(Keys)... }; 136 | std::uint64_t* keys = 137 | (std::uint64_t*)JM_XORSTR_LOAD_FROM_REG((std::uint64_t)arr); 138 | #else 139 | alignas(alignment) std::uint64_t keys[]{ JM_XORSTR_LOAD_FROM_REG(Keys)... }; 140 | #endif 141 | 142 | #ifndef JM_XORSTR_DISABLE_AVX_INTRINSICS 143 | ((Indices >= sizeof(_storage) / 32 ? static_cast(0) : _mm256_store_si256( 144 | reinterpret_cast<__m256i*>(_storage) + Indices, 145 | _mm256_xor_si256( 146 | _mm256_load_si256(reinterpret_cast(_storage) + Indices), 147 | _mm256_load_si256(reinterpret_cast(keys) + Indices)))), ...); 148 | 149 | if constexpr (sizeof(_storage) % 32 != 0) 150 | _mm_store_si128( 151 | reinterpret_cast<__m128i*>(_storage + sizeof...(Keys) - 2), 152 | _mm_xor_si128(_mm_load_si128(reinterpret_cast(_storage + sizeof...(Keys) - 2)), 153 | _mm_load_si128(reinterpret_cast(keys + sizeof...(Keys) - 2)))); 154 | #else 155 | ((Indices >= sizeof(_storage) / 16 ? static_cast(0) : _mm_store_si128( 156 | reinterpret_cast<__m128i*>(_storage) + Indices, 157 | _mm_xor_si128(_mm_load_si128(reinterpret_cast(_storage) + Indices), 158 | _mm_load_si128(reinterpret_cast(keys) + Indices)))), ...); 159 | #endif 160 | } 161 | 162 | XORSTR_FORCEINLINE const_pointer get() const noexcept 163 | { 164 | return reinterpret_cast(_storage); 165 | } 166 | 167 | XORSTR_FORCEINLINE pointer get() noexcept 168 | { 169 | return reinterpret_cast(_storage); 170 | } 171 | 172 | XORSTR_FORCEINLINE pointer crypt_get() noexcept 173 | { 174 | // crypt() function inlined by hand, because MSVC linker chokes when you have a lot of strings 175 | // on 32 bit builds, so don't blame me for shit code :pepekms: 176 | #if defined(__clang__) 177 | alignas(alignment) 178 | std::uint64_t arr[]{ JM_XORSTR_LOAD_FROM_REG(Keys)... }; 179 | std::uint64_t* keys = 180 | (std::uint64_t*)JM_XORSTR_LOAD_FROM_REG((std::uint64_t)arr); 181 | #else 182 | alignas(alignment) std::uint64_t keys[]{ JM_XORSTR_LOAD_FROM_REG(Keys)... }; 183 | #endif 184 | 185 | #ifndef JM_XORSTR_DISABLE_AVX_INTRINSICS 186 | ((Indices >= sizeof(_storage) / 32 ? static_cast(0) : _mm256_store_si256( 187 | reinterpret_cast<__m256i*>(_storage) + Indices, 188 | _mm256_xor_si256( 189 | _mm256_load_si256(reinterpret_cast(_storage) + Indices), 190 | _mm256_load_si256(reinterpret_cast(keys) + Indices)))), ...); 191 | 192 | if constexpr (sizeof(_storage) % 32 != 0) 193 | _mm_store_si128( 194 | reinterpret_cast<__m128i*>(_storage + sizeof...(Keys) - 2), 195 | _mm_xor_si128(_mm_load_si128(reinterpret_cast(_storage + sizeof...(Keys) - 2)), 196 | _mm_load_si128(reinterpret_cast(keys + sizeof...(Keys) - 2)))); 197 | #else 198 | ((Indices >= sizeof(_storage) / 16 ? static_cast(0) : _mm_store_si128( 199 | reinterpret_cast<__m128i*>(_storage) + Indices, 200 | _mm_xor_si128(_mm_load_si128(reinterpret_cast(_storage) + Indices), 201 | _mm_load_si128(reinterpret_cast(keys) + Indices)))), ...); 202 | #endif 203 | return (pointer)(_storage); 204 | } 205 | }; 206 | 207 | template 208 | xor_string(L l, std::integral_constant, std::index_sequence)->xor_string< 209 | std::remove_const_t>, 210 | Size, 211 | std::integer_sequence()...>, 212 | std::index_sequence>; 213 | 214 | } // namespace jm 215 | 216 | #endif // include guard 217 | -------------------------------------------------------------------------------- /driver/berkeley.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | ////////////////////////////////////////////////////////////////////////// 4 | // Definitions. 5 | ////////////////////////////////////////////////////////////////////////// 6 | 7 | #define MEMORY_TAG ' bsK' 8 | #define SOCKETFD_MAX 128 9 | #define TO_SOCKETFD(index) ((index % SOCKETFD_MAX) + 1) 10 | #define FROM_SOCKETFD(sockfd) ((sockfd) - 1) 11 | 12 | ////////////////////////////////////////////////////////////////////////// 13 | // Function prototypes. 14 | ////////////////////////////////////////////////////////////////////////// 15 | 16 | NTSTATUS 17 | NTAPI 18 | KspUtilAddrInfoToAddrInfoEx( 19 | _In_ PADDRINFOA AddrInfo, 20 | _Out_ PADDRINFOEXW * AddrInfoEx 21 | ); 22 | 23 | NTSTATUS 24 | NTAPI 25 | KspUtilAddrInfoExToAddrInfo( 26 | _In_ PADDRINFOEXW AddrInfoEx, 27 | _Out_ PADDRINFOA* AddrInfo 28 | ); 29 | 30 | VOID 31 | NTAPI 32 | KspUtilFreeAddrInfo( 33 | _In_ PADDRINFOA AddrInfo 34 | ); 35 | 36 | VOID 37 | NTAPI 38 | KspUtilFreeAddrInfoEx( 39 | _In_ PADDRINFOEXW AddrInfo 40 | ); 41 | 42 | ////////////////////////////////////////////////////////////////////////// 43 | // Variables. 44 | ////////////////////////////////////////////////////////////////////////// 45 | 46 | // 47 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!! 48 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!! 49 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!! 50 | // 51 | // This is complete bollocks and ideally it should be replaced with 52 | // something like RTL_AVL_TABLE. 53 | // 54 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!! 55 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!! 56 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!! 57 | // 58 | 59 | PKSOCKET KsArray[SOCKETFD_MAX] = { 0 }; 60 | ULONG KsIndex = 0; 61 | 62 | ////////////////////////////////////////////////////////////////////////// 63 | // Private functions. 64 | ////////////////////////////////////////////////////////////////////////// 65 | 66 | NTSTATUS 67 | NTAPI 68 | KspUtilAddrInfoToAddrInfoEx( 69 | _In_ PADDRINFOA AddrInfo, 70 | _Out_ PADDRINFOEXW* AddrInfoEx 71 | ) 72 | { 73 | NTSTATUS Status; 74 | 75 | // 76 | // Convert NULL input into NULL output. 77 | // 78 | 79 | if (AddrInfo == NULL) 80 | { 81 | *AddrInfoEx = NULL; 82 | return STATUS_SUCCESS; 83 | } 84 | 85 | // 86 | // Allocate memory for the output structure. 87 | // 88 | 89 | PADDRINFOEXW Result = ExAllocatePoolWithTag(PagedPool, sizeof(ADDRINFOEXW), MEMORY_TAG); 90 | 91 | if (Result == NULL) 92 | { 93 | Status = STATUS_INSUFFICIENT_RESOURCES; 94 | goto Error1; 95 | } 96 | 97 | // 98 | // Copy numeric values. 99 | // 100 | 101 | RtlZeroMemory(Result, sizeof(ADDRINFOEXW)); 102 | Result->ai_flags = AddrInfo->ai_flags; 103 | Result->ai_family = AddrInfo->ai_family; 104 | Result->ai_socktype = AddrInfo->ai_socktype; 105 | Result->ai_protocol = AddrInfo->ai_protocol; 106 | Result->ai_addrlen = AddrInfo->ai_addrlen; 107 | 108 | // 109 | // Copy canonical name. 110 | // 111 | 112 | ANSI_STRING CanonicalNameAnsi; 113 | UNICODE_STRING CanonicalNameUnicode; 114 | 115 | if (AddrInfo->ai_canonname) 116 | { 117 | RtlInitAnsiString(&CanonicalNameAnsi, AddrInfo->ai_canonname); 118 | 119 | Status = RtlAnsiStringToUnicodeString(&CanonicalNameUnicode, &CanonicalNameAnsi, TRUE); 120 | 121 | if (!NT_SUCCESS(Status)) 122 | { 123 | goto Error2; 124 | } 125 | 126 | Result->ai_canonname = CanonicalNameUnicode.Buffer; 127 | } 128 | 129 | // 130 | // Copy address. 131 | // 132 | 133 | Result->ai_addr = AddrInfo->ai_addr; 134 | 135 | // 136 | // Copy the next structure (recursively). 137 | // 138 | 139 | PADDRINFOEXW NextAddrInfo; 140 | Status = KspUtilAddrInfoToAddrInfoEx(AddrInfo->ai_next, &NextAddrInfo); 141 | 142 | if (!NT_SUCCESS(Status)) 143 | { 144 | goto Error3; 145 | } 146 | 147 | Result->ai_next = NextAddrInfo; 148 | 149 | // 150 | // All done! 151 | // 152 | 153 | *AddrInfoEx = Result; 154 | 155 | return Status; 156 | 157 | Error3: 158 | RtlFreeAnsiString(&CanonicalNameAnsi); 159 | 160 | Error2: 161 | ExFreePoolWithTag(Result, MEMORY_TAG); 162 | 163 | Error1: 164 | return Status; 165 | } 166 | 167 | NTSTATUS 168 | NTAPI 169 | KspUtilAddrInfoExToAddrInfo( 170 | _In_ PADDRINFOEXW AddrInfoEx, 171 | _Out_ PADDRINFOA* AddrInfo 172 | ) 173 | { 174 | NTSTATUS Status; 175 | 176 | // 177 | // Convert NULL input into NULL output. 178 | // 179 | 180 | if (AddrInfoEx == NULL) 181 | { 182 | *AddrInfo = NULL; 183 | return STATUS_SUCCESS; 184 | } 185 | 186 | // 187 | // Allocate memory for the output structure. 188 | // 189 | 190 | PADDRINFOA Result = ExAllocatePoolWithTag(PagedPool, sizeof(ADDRINFOA), MEMORY_TAG); 191 | 192 | if (Result == NULL) 193 | { 194 | Status = STATUS_INSUFFICIENT_RESOURCES; 195 | goto Error1; 196 | } 197 | 198 | // 199 | // Copy numeric values. 200 | // 201 | 202 | RtlZeroMemory(Result, sizeof(ADDRINFOA)); 203 | Result->ai_flags = AddrInfoEx->ai_flags; 204 | Result->ai_family = AddrInfoEx->ai_family; 205 | Result->ai_socktype = AddrInfoEx->ai_socktype; 206 | Result->ai_protocol = AddrInfoEx->ai_protocol; 207 | Result->ai_addrlen = AddrInfoEx->ai_addrlen; 208 | 209 | // 210 | // Copy canonical name. 211 | // 212 | 213 | UNICODE_STRING CanonicalNameUnicode; 214 | ANSI_STRING CanonicalNameAnsi; 215 | 216 | if (AddrInfoEx->ai_canonname) 217 | { 218 | RtlInitUnicodeString(&CanonicalNameUnicode, AddrInfoEx->ai_canonname); 219 | Status = RtlUnicodeStringToAnsiString(&CanonicalNameAnsi, &CanonicalNameUnicode, TRUE); 220 | 221 | if (!NT_SUCCESS(Status)) 222 | { 223 | goto Error2; 224 | } 225 | 226 | Result->ai_canonname = CanonicalNameAnsi.Buffer; 227 | } 228 | 229 | // 230 | // Copy address. 231 | // 232 | 233 | Result->ai_addr = AddrInfoEx->ai_addr; 234 | 235 | // 236 | // Copy the next structure (recursively). 237 | // 238 | 239 | PADDRINFOA NextAddrInfo; 240 | Status = KspUtilAddrInfoExToAddrInfo(AddrInfoEx->ai_next, &NextAddrInfo); 241 | 242 | if (!NT_SUCCESS(Status)) 243 | { 244 | goto Error3; 245 | } 246 | 247 | Result->ai_next = NextAddrInfo; 248 | 249 | // 250 | // All done! 251 | // 252 | 253 | *AddrInfo = Result; 254 | 255 | return Status; 256 | 257 | Error3: 258 | RtlFreeAnsiString(&CanonicalNameAnsi); 259 | 260 | Error2: 261 | ExFreePoolWithTag(Result, MEMORY_TAG); 262 | 263 | Error1: 264 | return Status; 265 | } 266 | 267 | VOID 268 | NTAPI 269 | KspUtilFreeAddrInfo( 270 | _In_ PADDRINFOA AddrInfo 271 | ) 272 | { 273 | // 274 | // Free all structures recursively. 275 | // 276 | 277 | if (AddrInfo->ai_next) 278 | { 279 | KspUtilFreeAddrInfo(AddrInfo->ai_next); 280 | } 281 | 282 | // 283 | // Free the canonical name buffer. 284 | // 285 | 286 | if (AddrInfo->ai_canonname) 287 | { 288 | ANSI_STRING CanonicalName; 289 | RtlInitAnsiString(&CanonicalName, AddrInfo->ai_canonname); 290 | RtlFreeAnsiString(&CanonicalName); 291 | } 292 | 293 | // 294 | // Finally, free the structure itself. 295 | // 296 | 297 | ExFreePoolWithTag(AddrInfo, MEMORY_TAG); 298 | } 299 | 300 | VOID 301 | NTAPI 302 | KspUtilFreeAddrInfoEx( 303 | _In_ PADDRINFOEXW AddrInfo 304 | ) 305 | { 306 | // 307 | // Free all structures recursively. 308 | // 309 | 310 | if (AddrInfo->ai_next) 311 | { 312 | KspUtilFreeAddrInfoEx(AddrInfo->ai_next); 313 | } 314 | 315 | // 316 | // Free the canonical name buffer. 317 | // 318 | 319 | if (AddrInfo->ai_canonname) 320 | { 321 | UNICODE_STRING CanonicalName; 322 | RtlInitUnicodeString(&CanonicalName, AddrInfo->ai_canonname); 323 | RtlFreeUnicodeString(&CanonicalName); 324 | } 325 | 326 | // 327 | // Finally, free the structure itself. 328 | // 329 | 330 | ExFreePoolWithTag(AddrInfo, MEMORY_TAG); 331 | } 332 | 333 | ////////////////////////////////////////////////////////////////////////// 334 | // Public functions. 335 | ////////////////////////////////////////////////////////////////////////// 336 | 337 | uint32_t htonl(uint32_t hostlong) 338 | { 339 | return RtlUlongByteSwap(hostlong); 340 | } 341 | 342 | uint16_t htons(uint16_t hostshort) 343 | { 344 | return RtlUshortByteSwap(hostshort); 345 | } 346 | 347 | uint32_t ntohl(uint32_t netlong) 348 | { 349 | return RtlUlongByteSwap(netlong); 350 | } 351 | 352 | uint16_t ntohs(uint16_t netshort) 353 | { 354 | return RtlUshortByteSwap(netshort); 355 | } 356 | 357 | int getaddrinfo(const char* node, const char* service, const struct addrinfo* hints, struct addrinfo** res) 358 | { 359 | NTSTATUS Status; 360 | 361 | // 362 | // Convert node name to the UNICODE_STRING (if present). 363 | // 364 | 365 | ANSI_STRING NodeNameAnsi; 366 | UNICODE_STRING NodeNameUnicode; 367 | PUNICODE_STRING NodeName = NULL; 368 | 369 | if (node) 370 | { 371 | RtlInitAnsiString(&NodeNameAnsi, node); 372 | Status = RtlAnsiStringToUnicodeString(&NodeNameUnicode, &NodeNameAnsi, TRUE); 373 | 374 | if (!NT_SUCCESS(Status)) 375 | { 376 | goto Error1; 377 | } 378 | 379 | NodeName = &NodeNameUnicode; 380 | } 381 | 382 | // 383 | // Convert service name to the UNICODE_STRING (if present). 384 | // 385 | 386 | ANSI_STRING ServiceNameAnsi; 387 | UNICODE_STRING ServiceNameUnicode; 388 | PUNICODE_STRING ServiceName = NULL; 389 | 390 | if (service) 391 | { 392 | RtlInitAnsiString(&ServiceNameAnsi, service); 393 | Status = RtlAnsiStringToUnicodeString(&ServiceNameUnicode, &ServiceNameAnsi, TRUE); 394 | 395 | if (!NT_SUCCESS(Status)) 396 | { 397 | goto Error2; 398 | } 399 | 400 | ServiceName = &ServiceNameUnicode; 401 | } 402 | 403 | // 404 | // Convert "struct addrinfo" to the "ADDRINFOEXW". 405 | // 406 | 407 | PADDRINFOEXW Hints; 408 | Status = KspUtilAddrInfoToAddrInfoEx((PADDRINFOA)hints, &Hints); 409 | 410 | if (!NT_SUCCESS(Status)) 411 | { 412 | goto Error3; 413 | } 414 | 415 | // 416 | // All data is prepared, call the underlying API. 417 | // 418 | 419 | PADDRINFOEXW Result; 420 | Status = KsGetAddrInfo(NodeName, ServiceName, Hints, &Result); 421 | 422 | // 423 | // Free the memory of the converted "Hints". 424 | // 425 | 426 | KspUtilFreeAddrInfoEx(Hints); 427 | 428 | if (!NT_SUCCESS(Status)) 429 | { 430 | goto Error3; 431 | } 432 | 433 | // 434 | // Convert the result "ADDRINFOEXW" to the "struct addrinfo". 435 | // 436 | 437 | Status = KspUtilAddrInfoExToAddrInfo(Result, res); 438 | 439 | // 440 | // Free the original result. 441 | // 442 | 443 | KsFreeAddrInfo(Result); 444 | 445 | if (!NT_SUCCESS(Status)) 446 | { 447 | goto Error3; 448 | } 449 | 450 | return STATUS_SUCCESS; 451 | 452 | Error3: 453 | RtlFreeUnicodeString(&ServiceNameUnicode); 454 | 455 | Error2: 456 | RtlFreeUnicodeString(&NodeNameUnicode); 457 | 458 | Error1: 459 | return Status; 460 | } 461 | 462 | void freeaddrinfo(struct addrinfo* res) 463 | { 464 | // 465 | // Call our implementation. 466 | // 467 | 468 | KspUtilFreeAddrInfo(res); 469 | } 470 | 471 | int socket_connection(int domain, int type, int protocol) 472 | { 473 | NTSTATUS Status; 474 | PKSOCKET Socket; 475 | 476 | Status = KsCreateConnectionSocket( 477 | &Socket, 478 | (ADDRESS_FAMILY)domain, 479 | (USHORT)type, 480 | (ULONG)protocol 481 | ); 482 | 483 | if (NT_SUCCESS(Status)) 484 | { 485 | int sockfd = TO_SOCKETFD(KsIndex++); 486 | 487 | KsArray[FROM_SOCKETFD(sockfd)] = Socket; 488 | 489 | return sockfd; 490 | } 491 | 492 | return -1; 493 | } 494 | 495 | int socket_listen(int domain, int type, int protocol) 496 | { 497 | NTSTATUS Status; 498 | PKSOCKET Socket; 499 | 500 | // 501 | // WskSocket() returns STATUS_PROTOCOL_UNREACHABLE (0xC000023E) 502 | // when Protocol == 0, so coerce this value to IPPROTO_TCP here. 503 | // 504 | 505 | Status = KsCreateListenSocket( 506 | &Socket, 507 | (ADDRESS_FAMILY)domain, 508 | (USHORT)type, 509 | protocol ? (ULONG)protocol : IPPROTO_TCP 510 | ); 511 | 512 | if (NT_SUCCESS(Status)) 513 | { 514 | int sockfd = TO_SOCKETFD(KsIndex++); 515 | 516 | KsArray[FROM_SOCKETFD(sockfd)] = Socket; 517 | 518 | return sockfd; 519 | } 520 | 521 | return -1; 522 | } 523 | 524 | int socket_datagram(int domain, int type, int protocol) 525 | { 526 | NTSTATUS Status; 527 | PKSOCKET Socket; 528 | 529 | Status = KsCreateDatagramSocket( 530 | &Socket, 531 | (ADDRESS_FAMILY)domain, 532 | (USHORT)type, 533 | (ULONG)protocol 534 | ); 535 | 536 | if (NT_SUCCESS(Status)) 537 | { 538 | int sockfd = TO_SOCKETFD(KsIndex++); 539 | 540 | KsArray[FROM_SOCKETFD(sockfd)] = Socket; 541 | 542 | return sockfd; 543 | } 544 | 545 | return -1; 546 | } 547 | 548 | int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen) 549 | { 550 | UNREFERENCED_PARAMETER(addrlen); 551 | 552 | NTSTATUS Status; 553 | PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)]; 554 | 555 | Status = KsConnect(Socket, (PSOCKADDR)addr); 556 | 557 | return NT_SUCCESS(Status) 558 | ? 0 559 | : -1; 560 | } 561 | 562 | int listen(int sockfd, int backlog) 563 | { 564 | UNREFERENCED_PARAMETER(sockfd); 565 | UNREFERENCED_PARAMETER(backlog); 566 | return 0; 567 | } 568 | 569 | int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen) 570 | { 571 | UNREFERENCED_PARAMETER(addrlen); 572 | 573 | NTSTATUS Status; 574 | PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)]; 575 | 576 | Status = KsBind(Socket, (PSOCKADDR)addr); 577 | 578 | return NT_SUCCESS(Status) 579 | ? 0 580 | : -1; 581 | } 582 | 583 | int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen) 584 | { 585 | NTSTATUS Status; 586 | PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)]; 587 | 588 | PKSOCKET NewSocket; 589 | Status = KsAccept(Socket, &NewSocket, NULL, (PSOCKADDR)addr); 590 | *addrlen = sizeof(SOCKADDR); 591 | 592 | if (NT_SUCCESS(Status)) 593 | { 594 | int newsockfd = TO_SOCKETFD(KsIndex++); 595 | 596 | KsArray[FROM_SOCKETFD(newsockfd)] = NewSocket; 597 | 598 | return newsockfd; 599 | } 600 | 601 | return -1; 602 | } 603 | 604 | int send(int sockfd, const void* buf, size_t len, int flags) 605 | { 606 | NTSTATUS Status; 607 | PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)]; 608 | 609 | ULONG Length = (ULONG)len; 610 | Status = KsSend(Socket, (PVOID)buf, &Length, (ULONG)flags); 611 | 612 | return NT_SUCCESS(Status) 613 | ? (int)Length 614 | : -1; 615 | } 616 | 617 | int sendto(int sockfd, const void* buf, size_t len, int flags, const struct sockaddr* dest_addr, socklen_t addrlen) 618 | { 619 | UNREFERENCED_PARAMETER(addrlen); 620 | 621 | NTSTATUS Status; 622 | PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)]; 623 | 624 | ULONG Length = (ULONG)len; 625 | Status = KsSendTo(Socket, (PVOID)buf, &Length, (ULONG)flags, (PSOCKADDR)dest_addr); 626 | Status = KsSendTo(Socket, (PVOID)buf, &Length, (ULONG)flags, (PSOCKADDR)dest_addr); 627 | 628 | return NT_SUCCESS(Status) 629 | ? (int)Length 630 | : -1; 631 | } 632 | 633 | int recv(int sockfd, void* buf, size_t len, int flags) 634 | { 635 | NTSTATUS Status; 636 | PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)]; 637 | 638 | ULONG Length = (ULONG)len; 639 | Status = KsRecv(Socket, (PVOID)buf, &Length, (ULONG)flags); 640 | 641 | return NT_SUCCESS(Status) 642 | ? (int)Length 643 | : -1; 644 | } 645 | 646 | int recvfrom(int sockfd, void* buf, size_t len, int flags, struct sockaddr* src_addr, socklen_t* addrlen) 647 | { 648 | UNREFERENCED_PARAMETER(addrlen); 649 | 650 | NTSTATUS Status; 651 | PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)]; 652 | 653 | ULONG Length = (ULONG)len; 654 | Status = KsSendTo(Socket, (PVOID)buf, &Length, (ULONG)flags, (PSOCKADDR)src_addr); 655 | *addrlen = sizeof(SOCKADDR); 656 | 657 | return NT_SUCCESS(Status) 658 | ? (int)Length 659 | : -1; 660 | } 661 | 662 | int closesocket(int sockfd) 663 | { 664 | NTSTATUS Status; 665 | PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)]; 666 | 667 | Status = KsCloseSocket(Socket); 668 | 669 | KsArray[FROM_SOCKETFD(sockfd)] = NULL; 670 | 671 | return NT_SUCCESS(Status) 672 | ? 0 673 | : -1; 674 | } -------------------------------------------------------------------------------- /driver/berkeley.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | typedef int socklen_t; 8 | typedef intptr_t ssize_t; 9 | 10 | uint32_t htonl(uint32_t hostlong); 11 | uint16_t htons(uint16_t hostshort); 12 | uint32_t ntohl(uint32_t netlong); 13 | uint16_t ntohs(uint16_t netshort); 14 | 15 | int getaddrinfo(const char* node, const char* service, const struct addrinfo* hints, struct addrinfo** res); 16 | void freeaddrinfo(struct addrinfo* res); 17 | 18 | int socket_connection(int domain, int type, int protocol); 19 | int socket_listen(int domain, int type, int protocol); 20 | int socket_datagram(int domain, int type, int protocol); 21 | int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen); 22 | int listen(int sockfd, int backlog); 23 | int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen); 24 | int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen); 25 | int send(int sockfd, const void* buf, size_t len, int flags); 26 | int sendto(int sockfd, const void* buf, size_t len, int flags, const struct sockaddr* dest_addr, socklen_t addrlen); 27 | int recv(int sockfd, void* buf, size_t len, int flags); 28 | int recvfrom(int sockfd, void* buf, size_t len, int flags, struct sockaddr* src_addr, socklen_t* addrlen); 29 | int closesocket(int sockfd); 30 | 31 | #define socket socket_connection 32 | 33 | #ifdef __cplusplus 34 | } 35 | #endif -------------------------------------------------------------------------------- /driver/common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define log(...) DbgPrintEx(0, 0, __VA_ARGS__); 8 | 9 | #include "intdefs.h" 10 | #include "imports.h" 11 | #include "utils.h" 12 | #include "berkeley.h" 13 | #include "ksocket.h" 14 | #include "server.h" -------------------------------------------------------------------------------- /driver/driver.inf: -------------------------------------------------------------------------------- 1 | ; 2 | ; driver.inf 3 | ; 4 | 5 | [Version] 6 | Signature="$WINDOWS NT$" 7 | Class=Sample ; TODO: edit Class 8 | ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} ; TODO: edit ClassGuid 9 | Provider=%ManufacturerName% 10 | CatalogFile=driver.cat 11 | DriverVer= ; TODO: set DriverVer in stampinf property pages 12 | PnpLockDown=1 13 | 14 | [DestinationDirs] 15 | DefaultDestDir = 12 16 | driver_Device_CoInstaller_CopyFiles = 11 17 | 18 | ; ================= Class section ===================== 19 | 20 | [ClassInstall32] 21 | Addreg=SampleClassReg 22 | 23 | [SampleClassReg] 24 | HKR,,,0,%ClassName% 25 | HKR,,Icon,,-5 26 | 27 | [SourceDisksNames] 28 | 1 = %DiskName%,,,"" 29 | 30 | [SourceDisksFiles] 31 | driver.sys = 1,, 32 | WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames 33 | 34 | ;***************************************** 35 | ; Install Section 36 | ;***************************************** 37 | 38 | [Manufacturer] 39 | %ManufacturerName%=Standard,NT$ARCH$ 40 | 41 | [Standard.NT$ARCH$] 42 | %driver.DeviceDesc%=driver_Device, Root\driver ; TODO: edit hw-id 43 | 44 | [driver_Device.NT] 45 | CopyFiles=Drivers_Dir 46 | 47 | [Drivers_Dir] 48 | driver.sys 49 | 50 | ;-------------- Service installation 51 | [driver_Device.NT.Services] 52 | AddService = driver,%SPSVCINST_ASSOCSERVICE%, driver_Service_Inst 53 | 54 | ; -------------- driver driver install sections 55 | [driver_Service_Inst] 56 | DisplayName = %driver.SVCDESC% 57 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER 58 | StartType = 3 ; SERVICE_DEMAND_START 59 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL 60 | ServiceBinary = %12%\driver.sys 61 | 62 | ; 63 | ;--- driver_Device Coinstaller installation ------ 64 | ; 65 | 66 | [driver_Device.NT.CoInstallers] 67 | AddReg=driver_Device_CoInstaller_AddReg 68 | CopyFiles=driver_Device_CoInstaller_CopyFiles 69 | 70 | [driver_Device_CoInstaller_AddReg] 71 | HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller" 72 | 73 | [driver_Device_CoInstaller_CopyFiles] 74 | WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll 75 | 76 | [driver_Device.NT.Wdf] 77 | KmdfService = driver, driver_wdfsect 78 | [driver_wdfsect] 79 | KmdfLibraryVersion = $KMDFVERSION$ 80 | 81 | [Strings] 82 | SPSVCINST_ASSOCSERVICE= 0x00000002 83 | ManufacturerName="" ;TODO: Replace with your manufacturer name 84 | ClassName="Samples" ; TODO: edit ClassName 85 | DiskName = "driver Installation Disk" 86 | driver.DeviceDesc = "driver Device" 87 | driver.SVCDESC = "driver Service" 88 | -------------------------------------------------------------------------------- /driver/driver.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | {6AA61830-4BA3-4097-B4FF-EA62F47D98D6} 15 | {1bc93793-694f-48fe-9372-81e2b05556fd} 16 | v4.5 17 | 12.0 18 | Debug 19 | Win32 20 | driver 21 | 22 | 23 | 24 | Windows10 25 | true 26 | WindowsKernelModeDriver10.0 27 | Driver 28 | KMDF 29 | Universal 30 | 31 | 32 | Windows10 33 | false 34 | WindowsKernelModeDriver10.0 35 | Driver 36 | KMDF 37 | Universal 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | DbgengKernelDebugger 49 | 50 | 51 | DbgengKernelDebugger 52 | 53 | 54 | 55 | false 56 | 57 | 58 | Netio.lib;%(AdditionalDependencies) 59 | 60 | 61 | 62 | 63 | false 64 | 65 | 66 | Netio.lib;%(AdditionalDependencies) 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /driver/driver.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {8E41214B-6785-4CFE-B992-037D68949A14} 18 | inf;inv;inx;mof;mc; 19 | 20 | 21 | {c0533627-79fb-48cb-84cf-812855aa3f3b} 22 | 23 | 24 | 25 | 26 | Driver Files 27 | 28 | 29 | 30 | 31 | Source Files 32 | 33 | 34 | Header Files\ksocket 35 | 36 | 37 | Header Files\ksocket 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files\ksocket 58 | 59 | 60 | Header Files\ksocket 61 | 62 | 63 | Header Files 64 | 65 | 66 | Header Files 67 | 68 | 69 | -------------------------------------------------------------------------------- /driver/imports.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef enum _SYSTEM_INFORMATION_CLASS 4 | { 5 | SystemBasicInformation = 0x0, 6 | SystemProcessorInformation = 0x1, 7 | SystemPerformanceInformation = 0x2, 8 | SystemTimeOfDayInformation = 0x3, 9 | SystemPathInformation = 0x4, 10 | SystemProcessInformation = 0x5, 11 | SystemCallCountInformation = 0x6, 12 | SystemDeviceInformation = 0x7, 13 | SystemProcessorPerformanceInformation = 0x8, 14 | SystemFlagsInformation = 0x9, 15 | SystemCallTimeInformation = 0xa, 16 | SystemModuleInformation = 0xb, 17 | SystemLocksInformation = 0xc, 18 | SystemStackTraceInformation = 0xd, 19 | SystemPagedPoolInformation = 0xe, 20 | SystemNonPagedPoolInformation = 0xf, 21 | SystemHandleInformation = 0x10, 22 | SystemObjectInformation = 0x11, 23 | SystemPageFileInformation = 0x12, 24 | SystemVdmInstemulInformation = 0x13, 25 | SystemVdmBopInformation = 0x14, 26 | SystemFileCacheInformation = 0x15, 27 | SystemPoolTagInformation = 0x16, 28 | SystemInterruptInformation = 0x17, 29 | SystemDpcBehaviorInformation = 0x18, 30 | SystemFullMemoryInformation = 0x19, 31 | SystemLoadGdiDriverInformation = 0x1a, 32 | SystemUnloadGdiDriverInformation = 0x1b, 33 | SystemTimeAdjustmentInformation = 0x1c, 34 | SystemSummaryMemoryInformation = 0x1d, 35 | SystemMirrorMemoryInformation = 0x1e, 36 | SystemPerformanceTraceInformation = 0x1f, 37 | SystemObsolete0 = 0x20, 38 | SystemExceptionInformation = 0x21, 39 | SystemCrashDumpStateInformation = 0x22, 40 | SystemKernelDebuggerInformation = 0x23, 41 | SystemContextSwitchInformation = 0x24, 42 | SystemRegistryQuotaInformation = 0x25, 43 | SystemExtendServiceTableInformation = 0x26, 44 | SystemPrioritySeperation = 0x27, 45 | SystemVerifierAddDriverInformation = 0x28, 46 | SystemVerifierRemoveDriverInformation = 0x29, 47 | SystemProcessorIdleInformation = 0x2a, 48 | SystemLegacyDriverInformation = 0x2b, 49 | SystemCurrentTimeZoneInformation = 0x2c, 50 | SystemLookasideInformation = 0x2d, 51 | SystemTimeSlipNotification = 0x2e, 52 | SystemSessionCreate = 0x2f, 53 | SystemSessionDetach = 0x30, 54 | SystemSessionInformation = 0x31, 55 | SystemRangeStartInformation = 0x32, 56 | SystemVerifierInformation = 0x33, 57 | SystemVerifierThunkExtend = 0x34, 58 | SystemSessionProcessInformation = 0x35, 59 | SystemLoadGdiDriverInSystemSpace = 0x36, 60 | SystemNumaProcessorMap = 0x37, 61 | SystemPrefetcherInformation = 0x38, 62 | SystemExtendedProcessInformation = 0x39, 63 | SystemRecommendedSharedDataAlignment = 0x3a, 64 | SystemComPlusPackage = 0x3b, 65 | SystemNumaAvailableMemory = 0x3c, 66 | SystemProcessorPowerInformation = 0x3d, 67 | SystemEmulationBasicInformation = 0x3e, 68 | SystemEmulationProcessorInformation = 0x3f, 69 | SystemExtendedHandleInformation = 0x40, 70 | SystemLostDelayedWriteInformation = 0x41, 71 | SystemBigPoolInformation = 0x42, 72 | SystemSessionPoolTagInformation = 0x43, 73 | SystemSessionMappedViewInformation = 0x44, 74 | SystemHotpatchInformation = 0x45, 75 | SystemObjectSecurityMode = 0x46, 76 | SystemWatchdogTimerHandler = 0x47, 77 | SystemWatchdogTimerInformation = 0x48, 78 | SystemLogicalProcessorInformation = 0x49, 79 | SystemWow64SharedInformationObsolete = 0x4a, 80 | SystemRegisterFirmwareTableInformationHandler = 0x4b, 81 | SystemFirmwareTableInformation = 0x4c, 82 | SystemModuleInformationEx = 0x4d, 83 | SystemVerifierTriageInformation = 0x4e, 84 | SystemSuperfetchInformation = 0x4f, 85 | SystemMemoryListInformation = 0x50, 86 | SystemFileCacheInformationEx = 0x51, 87 | SystemThreadPriorityClientIdInformation = 0x52, 88 | SystemProcessorIdleCycleTimeInformation = 0x53, 89 | SystemVerifierCancellationInformation = 0x54, 90 | SystemProcessorPowerInformationEx = 0x55, 91 | SystemRefTraceInformation = 0x56, 92 | SystemSpecialPoolInformation = 0x57, 93 | SystemProcessIdInformation = 0x58, 94 | SystemErrorPortInformation = 0x59, 95 | SystemBootEnvironmentInformation = 0x5a, 96 | SystemHypervisorInformation = 0x5b, 97 | SystemVerifierInformationEx = 0x5c, 98 | SystemTimeZoneInformation = 0x5d, 99 | SystemImageFileExecutionOptionsInformation = 0x5e, 100 | SystemCoverageInformation = 0x5f, 101 | SystemPrefetchPatchInformation = 0x60, 102 | SystemVerifierFaultsInformation = 0x61, 103 | SystemSystemPartitionInformation = 0x62, 104 | SystemSystemDiskInformation = 0x63, 105 | SystemProcessorPerformanceDistribution = 0x64, 106 | SystemNumaProximityNodeInformation = 0x65, 107 | SystemDynamicTimeZoneInformation = 0x66, 108 | SystemCodeIntegrityInformation = 0x67, 109 | SystemProcessorMicrocodeUpdateInformation = 0x68, 110 | SystemProcessorBrandString = 0x69, 111 | SystemVirtualAddressInformation = 0x6a, 112 | SystemLogicalProcessorAndGroupInformation = 0x6b, 113 | SystemProcessorCycleTimeInformation = 0x6c, 114 | SystemStoreInformation = 0x6d, 115 | SystemRegistryAppendString = 0x6e, 116 | SystemAitSamplingValue = 0x6f, 117 | SystemVhdBootInformation = 0x70, 118 | SystemCpuQuotaInformation = 0x71, 119 | SystemNativeBasicInformation = 0x72, 120 | SystemErrorPortTimeouts = 0x73, 121 | SystemLowPriorityIoInformation = 0x74, 122 | SystemBootEntropyInformation = 0x75, 123 | SystemVerifierCountersInformation = 0x76, 124 | SystemPagedPoolInformationEx = 0x77, 125 | SystemSystemPtesInformationEx = 0x78, 126 | SystemNodeDistanceInformation = 0x79, 127 | SystemAcpiAuditInformation = 0x7a, 128 | SystemBasicPerformanceInformation = 0x7b, 129 | SystemQueryPerformanceCounterInformation = 0x7c, 130 | SystemSessionBigPoolInformation = 0x7d, 131 | SystemBootGraphicsInformation = 0x7e, 132 | SystemScrubPhysicalMemoryInformation = 0x7f, 133 | SystemBadPageInformation = 0x80, 134 | SystemProcessorProfileControlArea = 0x81, 135 | SystemCombinePhysicalMemoryInformation = 0x82, 136 | SystemEntropyInterruptTimingInformation = 0x83, 137 | SystemConsoleInformation = 0x84, 138 | SystemPlatformBinaryInformation = 0x85, 139 | SystemThrottleNotificationInformation = 0x86, 140 | SystemHypervisorProcessorCountInformation = 0x87, 141 | SystemDeviceDataInformation = 0x88, 142 | SystemDeviceDataEnumerationInformation = 0x89, 143 | SystemMemoryTopologyInformation = 0x8a, 144 | SystemMemoryChannelInformation = 0x8b, 145 | SystemBootLogoInformation = 0x8c, 146 | SystemProcessorPerformanceInformationEx = 0x8d, 147 | SystemSpare0 = 0x8e, 148 | SystemSecureBootPolicyInformation = 0x8f, 149 | SystemPageFileInformationEx = 0x90, 150 | SystemSecureBootInformation = 0x91, 151 | SystemEntropyInterruptTimingRawInformation = 0x92, 152 | SystemPortableWorkspaceEfiLauncherInformation = 0x93, 153 | SystemFullProcessInformation = 0x94, 154 | SystemKernelDebuggerInformationEx = 0x95, 155 | SystemBootMetadataInformation = 0x96, 156 | SystemSoftRebootInformation = 0x97, 157 | SystemElamCertificateInformation = 0x98, 158 | SystemOfflineDumpConfigInformation = 0x99, 159 | SystemProcessorFeaturesInformation = 0x9a, 160 | SystemRegistryReconciliationInformation = 0x9b, 161 | MaxSystemInfoClass = 0x9c, 162 | } SYSTEM_INFORMATION_CLASS; 163 | 164 | typedef struct _SYSTEM_MODULE // Information Class 11 165 | { 166 | ULONG_PTR Reserved[2]; 167 | PVOID Base; 168 | ULONG Size; 169 | ULONG Flags; 170 | USHORT Index; 171 | USHORT Unknown; 172 | USHORT LoadCount; 173 | USHORT ModuleNameOffset; 174 | CHAR ImageName[256]; 175 | } SYSTEM_MODULE, * PSYSTEM_MODULE; 176 | 177 | NTKERNELAPI NTSTATUS MmCopyVirtualMemory( 178 | IN PEPROCESS SourceProcess, 179 | IN PVOID SourceAddress, 180 | IN PEPROCESS TargetProcess, 181 | IN PVOID TargetAddress, 182 | IN SIZE_T BufferSize, 183 | IN KPROCESSOR_MODE PreviousMode, 184 | OUT PSIZE_T ReturnSize 185 | ); 186 | 187 | NTKERNELAPI PVOID PsGetProcessSectionBaseAddress( 188 | IN PEPROCESS Process 189 | ); 190 | 191 | NTKERNELAPI NTSTATUS ZwQuerySystemInformation( 192 | SYSTEM_INFORMATION_CLASS SystemInformationClass, 193 | PVOID SystemInformation, 194 | ULONG SystemInformationLength, 195 | PULONG ReturnLength 196 | ); 197 | 198 | NTSYSCALLAPI NTSTATUS NTAPI ZwProtectVirtualMemory(HANDLE ProcessHandle, PVOID* BaseAddress, PSIZE_T RegionSize, ULONG NewAccessProtection, PULONG OldAccessProtection); 199 | 200 | NTSYSAPI ULONG RtlRandomEx( 201 | PULONG Seed 202 | ); 203 | 204 | NTKERNELAPI PPEB NTAPI PsGetProcessPeb(PEPROCESS Process); 205 | 206 | typedef struct _PEB_LDR_DATA 207 | { 208 | ULONG Length; 209 | UCHAR Initialized; 210 | PVOID SsHandle; 211 | LIST_ENTRY InLoadOrderModuleList; 212 | LIST_ENTRY InMemoryOrderModuleList; 213 | LIST_ENTRY InInitializationOrderModuleList; 214 | } PEB_LDR_DATA, * PPEB_LDR_DATA; 215 | 216 | typedef struct _LDR_DATA_TABLE_ENTRY 217 | { 218 | LIST_ENTRY InLoadOrderLinks; 219 | LIST_ENTRY InMemoryOrderLinks; 220 | LIST_ENTRY InInitializationOrderLinks; 221 | PVOID DllBase; 222 | PVOID EntryPoint; 223 | ULONG SizeOfImage; 224 | UNICODE_STRING FullDllName; 225 | UNICODE_STRING BaseDllName; 226 | ULONG Flags; 227 | USHORT LoadCount; 228 | USHORT TlsIndex; 229 | LIST_ENTRY HashLinks; 230 | ULONG TimeDateStamp; 231 | } LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; 232 | 233 | typedef struct _PEB 234 | { 235 | UCHAR InheritedAddressSpace; 236 | UCHAR ReadImageFileExecOptions; 237 | UCHAR BeingDebugged; 238 | UCHAR BitField; 239 | PVOID Mutant; 240 | PVOID ImageBaseAddress; 241 | PPEB_LDR_DATA Ldr; 242 | PVOID ProcessParameters; 243 | PVOID SubSystemData; 244 | PVOID ProcessHeap; 245 | PVOID FastPebLock; 246 | PVOID AtlThunkSListPtr; 247 | PVOID IFEOKey; 248 | PVOID CrossProcessFlags; 249 | PVOID KernelCallbackTable; 250 | ULONG SystemReserved; 251 | ULONG AtlThunkSListPtr32; 252 | PVOID ApiSetMap; 253 | } PEB, * PPEB; -------------------------------------------------------------------------------- /driver/intdefs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef int SOCKET; 4 | 5 | #define INVALID_SOCKET (SOCKET)(-1) 6 | #define SOCKET_ERROR -1 7 | 8 | typedef __int8 int8_t; 9 | typedef __int16 int16_t; 10 | typedef __int32 int32_t; 11 | typedef __int64 int64_t; 12 | 13 | typedef unsigned __int8 uint8_t; 14 | typedef unsigned __int16 uint16_t; 15 | typedef unsigned __int32 uint32_t; 16 | typedef unsigned __int64 uint64_t; 17 | 18 | typedef uint8_t bool; -------------------------------------------------------------------------------- /driver/ksocket.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | ////////////////////////////////////////////////////////////////////////// 4 | // Definitions. 5 | ////////////////////////////////////////////////////////////////////////// 6 | 7 | #define MEMORY_TAG ' sK' 8 | 9 | ////////////////////////////////////////////////////////////////////////// 10 | // Structures. 11 | ////////////////////////////////////////////////////////////////////////// 12 | 13 | typedef struct _KSOCKET_ASYNC_CONTEXT 14 | { 15 | KEVENT CompletionEvent; 16 | PIRP Irp; 17 | } KSOCKET_ASYNC_CONTEXT, * PKSOCKET_ASYNC_CONTEXT; 18 | 19 | typedef struct _KSOCKET 20 | { 21 | PWSK_SOCKET WskSocket; 22 | 23 | union 24 | { 25 | PVOID WskDispatch; 26 | 27 | PWSK_PROVIDER_CONNECTION_DISPATCH WskConnectionDispatch; 28 | PWSK_PROVIDER_LISTEN_DISPATCH WskListenDispatch; 29 | PWSK_PROVIDER_DATAGRAM_DISPATCH WskDatagramDispatch; 30 | #if (NTDDI_VERSION >= NTDDI_WIN10_RS2) 31 | PWSK_PROVIDER_STREAM_DISPATCH WskStreamDispatch; 32 | #endif 33 | }; 34 | 35 | KSOCKET_ASYNC_CONTEXT AsyncContext; 36 | } KSOCKET, * PKSOCKET; 37 | 38 | ////////////////////////////////////////////////////////////////////////// 39 | // Variables. 40 | ////////////////////////////////////////////////////////////////////////// 41 | 42 | WSK_REGISTRATION WskRegistration; 43 | WSK_PROVIDER_NPI WskProvider; 44 | WSK_CLIENT_DISPATCH WskDispatch = { MAKE_WSK_VERSION(1,0), 0, NULL }; 45 | 46 | ////////////////////////////////////////////////////////////////////////// 47 | // Function prototypes. 48 | ////////////////////////////////////////////////////////////////////////// 49 | 50 | NTSTATUS 51 | NTAPI 52 | KspAsyncContextAllocate( 53 | _Out_ PKSOCKET_ASYNC_CONTEXT AsyncContext 54 | ); 55 | 56 | VOID 57 | NTAPI 58 | KspAsyncContextFree( 59 | _In_ PKSOCKET_ASYNC_CONTEXT AsyncContext 60 | ); 61 | 62 | VOID 63 | NTAPI 64 | KspAsyncContextReset( 65 | _In_ PKSOCKET_ASYNC_CONTEXT AsyncContext 66 | ); 67 | 68 | NTSTATUS 69 | NTAPI 70 | KspAsyncContextCompletionRoutine( 71 | _In_ PDEVICE_OBJECT DeviceObject, 72 | _In_ PIRP Irp, 73 | _In_ PKEVENT CompletionEvent 74 | ); 75 | 76 | NTSTATUS 77 | NTAPI 78 | KspAsyncContextWaitForCompletion( 79 | _In_ PKSOCKET_ASYNC_CONTEXT AsyncContext, 80 | _Inout_ PNTSTATUS Status 81 | ); 82 | 83 | ////////////////////////////////////////////////////////////////////////// 84 | // Private functions. 85 | ////////////////////////////////////////////////////////////////////////// 86 | 87 | NTSTATUS 88 | NTAPI 89 | KspAsyncContextAllocate( 90 | _Out_ PKSOCKET_ASYNC_CONTEXT AsyncContext 91 | ) 92 | { 93 | // 94 | // Initialize the completion event. 95 | // 96 | 97 | KeInitializeEvent( 98 | &AsyncContext->CompletionEvent, 99 | SynchronizationEvent, 100 | FALSE 101 | ); 102 | 103 | // 104 | // Initialize the IRP. 105 | // 106 | 107 | AsyncContext->Irp = IoAllocateIrp(1, FALSE); 108 | 109 | if (AsyncContext->Irp == NULL) 110 | { 111 | return STATUS_INSUFFICIENT_RESOURCES; 112 | } 113 | 114 | // 115 | // KspAsyncContextCompletionRoutine will set 116 | // the CompletionEvent. 117 | // 118 | 119 | IoSetCompletionRoutine( 120 | AsyncContext->Irp, 121 | &KspAsyncContextCompletionRoutine, 122 | &AsyncContext->CompletionEvent, 123 | TRUE, 124 | TRUE, 125 | TRUE 126 | ); 127 | 128 | return STATUS_SUCCESS; 129 | } 130 | 131 | VOID 132 | NTAPI 133 | KspAsyncContextFree( 134 | _In_ PKSOCKET_ASYNC_CONTEXT AsyncContext 135 | ) 136 | { 137 | // 138 | // Free the IRP. 139 | // 140 | 141 | IoFreeIrp(AsyncContext->Irp); 142 | } 143 | 144 | VOID 145 | NTAPI 146 | KspAsyncContextReset( 147 | _In_ PKSOCKET_ASYNC_CONTEXT AsyncContext 148 | ) 149 | { 150 | // 151 | // If the WSK application allocated the IRP, or is reusing an IRP 152 | // that it previously allocated, then it must set an IoCompletion 153 | // routine for the IRP before calling a WSK function. In this 154 | // situation, the WSK application must specify TRUE for the 155 | // InvokeOnSuccess, InvokeOnError, and InvokeOnCancel parameters that 156 | // are passed to the IoSetCompletionRoutine function to ensure that 157 | // the IoCompletion routine is always called. Furthermore, the IoCompletion 158 | // routine that is set for the IRP must always return 159 | // STATUS_MORE_PROCESSING_REQUIRED to terminate the completion processing 160 | // of the IRP. If the WSK application is done using the IRP after the 161 | // IoCompletion routine has been called, then it should call the IoFreeIrp 162 | // function to free the IRP before returning from the IoCompletion routine. 163 | // If the WSK application does not free the IRP then it can reuse the IRP 164 | // for a call to another WSK function. 165 | // 166 | // (ref: https://docs.microsoft.com/en-us/windows-hardware/drivers/network/using-irps-with-winsock-kernel-functions) 167 | // 168 | 169 | // 170 | // Reset the completion event. 171 | // 172 | 173 | KeResetEvent(&AsyncContext->CompletionEvent); 174 | 175 | // 176 | // Reuse the IRP. 177 | // 178 | 179 | IoReuseIrp(AsyncContext->Irp, STATUS_UNSUCCESSFUL); 180 | 181 | IoSetCompletionRoutine( 182 | AsyncContext->Irp, 183 | &KspAsyncContextCompletionRoutine, 184 | &AsyncContext->CompletionEvent, 185 | TRUE, 186 | TRUE, 187 | TRUE 188 | ); 189 | } 190 | 191 | NTSTATUS 192 | NTAPI 193 | KspAsyncContextCompletionRoutine( 194 | _In_ PDEVICE_OBJECT DeviceObject, 195 | _In_ PIRP Irp, 196 | _In_ PKEVENT CompletionEvent 197 | ) 198 | { 199 | UNREFERENCED_PARAMETER(DeviceObject); 200 | UNREFERENCED_PARAMETER(Irp); 201 | 202 | KeSetEvent(CompletionEvent, IO_NO_INCREMENT, FALSE); 203 | return STATUS_MORE_PROCESSING_REQUIRED; 204 | } 205 | 206 | NTSTATUS 207 | NTAPI 208 | KspAsyncContextWaitForCompletion( 209 | _In_ PKSOCKET_ASYNC_CONTEXT AsyncContext, 210 | _Inout_ PNTSTATUS Status 211 | ) 212 | { 213 | if (*Status == STATUS_PENDING) 214 | { 215 | KeWaitForSingleObject( 216 | &AsyncContext->CompletionEvent, 217 | Executive, 218 | KernelMode, 219 | FALSE, 220 | NULL 221 | ); 222 | 223 | *Status = AsyncContext->Irp->IoStatus.Status; 224 | } 225 | 226 | return *Status; 227 | } 228 | 229 | ////////////////////////////////////////////////////////////////////////// 230 | // Public functions. 231 | ////////////////////////////////////////////////////////////////////////// 232 | 233 | NTSTATUS 234 | NTAPI 235 | KsInitialize( 236 | VOID 237 | ) 238 | { 239 | NTSTATUS Status; 240 | 241 | // 242 | // Register as a WSK client. 243 | // 244 | 245 | WSK_CLIENT_NPI WskClient; 246 | WskClient.ClientContext = NULL; 247 | WskClient.Dispatch = &WskDispatch; 248 | 249 | Status = WskRegister(&WskClient, &WskRegistration); 250 | 251 | if (!NT_SUCCESS(Status)) 252 | { 253 | return Status; 254 | } 255 | 256 | // 257 | // Capture the provider NPI. 258 | // 259 | 260 | return WskCaptureProviderNPI( 261 | &WskRegistration, 262 | WSK_INFINITE_WAIT, 263 | &WskProvider 264 | ); 265 | } 266 | 267 | VOID 268 | NTAPI 269 | KsDestroy( 270 | VOID 271 | ) 272 | { 273 | // 274 | // Release the provider NPI instance. 275 | // 276 | 277 | WskReleaseProviderNPI(&WskRegistration); 278 | 279 | // 280 | // Deregister as a WSK client. 281 | // 282 | 283 | WskDeregister(&WskRegistration); 284 | } 285 | 286 | NTSTATUS 287 | NTAPI 288 | KsGetAddrInfo( 289 | _In_ PUNICODE_STRING NodeName, 290 | _In_ PUNICODE_STRING ServiceName, 291 | _In_ PADDRINFOEXW Hints, 292 | _Out_ PADDRINFOEXW* Result 293 | ) 294 | { 295 | NTSTATUS Status; 296 | 297 | // 298 | // Allocate async context. 299 | // 300 | 301 | KSOCKET_ASYNC_CONTEXT AsyncContext; 302 | Status = KspAsyncContextAllocate(&AsyncContext); 303 | 304 | if (!NT_SUCCESS(Status)) 305 | { 306 | return Status; 307 | } 308 | 309 | // 310 | // Call the WSK API. 311 | // 312 | 313 | Status = WskProvider.Dispatch->WskGetAddressInfo( 314 | WskProvider.Client, // Client 315 | NodeName, // NodeName 316 | ServiceName, // ServiceName 317 | 0, // NameSpace 318 | NULL, // Provider 319 | Hints, // Hints 320 | Result, // Result 321 | NULL, // OwningProcess 322 | NULL, // OwningThread 323 | AsyncContext.Irp // Irp 324 | ); 325 | 326 | KspAsyncContextWaitForCompletion(&AsyncContext, &Status); 327 | 328 | // 329 | // Free the async context. 330 | // 331 | 332 | KspAsyncContextFree(&AsyncContext); 333 | 334 | return Status; 335 | } 336 | 337 | VOID 338 | NTAPI 339 | KsFreeAddrInfo( 340 | _In_ PADDRINFOEXW AddrInfo 341 | ) 342 | { 343 | WskProvider.Dispatch->WskFreeAddressInfo( 344 | WskProvider.Client, // Client 345 | AddrInfo // AddrInfo 346 | ); 347 | } 348 | 349 | NTSTATUS 350 | NTAPI 351 | KsCreateSocket( 352 | _Out_ PKSOCKET* Socket, 353 | _In_ ADDRESS_FAMILY AddressFamily, 354 | _In_ USHORT SocketType, 355 | _In_ ULONG Protocol, 356 | _In_ ULONG Flags 357 | ) 358 | { 359 | NTSTATUS Status; 360 | 361 | // 362 | // Allocate memory for the socket structure. 363 | // 364 | 365 | PKSOCKET NewSocket = ExAllocatePoolWithTag(PagedPool, sizeof(KSOCKET), MEMORY_TAG); 366 | 367 | if (!NewSocket) 368 | { 369 | return STATUS_INSUFFICIENT_RESOURCES; 370 | } 371 | 372 | // 373 | // Allocate async context for the socket. 374 | // 375 | 376 | Status = KspAsyncContextAllocate(&NewSocket->AsyncContext); 377 | 378 | if (!NT_SUCCESS(Status)) 379 | { 380 | return Status; 381 | } 382 | 383 | // 384 | // Create the WSK socket. 385 | // 386 | 387 | Status = WskProvider.Dispatch->WskSocket( 388 | WskProvider.Client, // Client 389 | AddressFamily, // AddressFamily 390 | SocketType, // SocketType 391 | Protocol, // Protocol 392 | Flags, // Flags 393 | NULL, // SocketContext 394 | NULL, // Dispatch 395 | NULL, // OwningProcess 396 | NULL, // OwningThread 397 | NULL, // SecurityDescriptor 398 | NewSocket->AsyncContext.Irp // Irp 399 | ); 400 | 401 | KspAsyncContextWaitForCompletion(&NewSocket->AsyncContext, &Status); 402 | 403 | // 404 | // Save the socket instance and the socket dispatch table. 405 | // 406 | 407 | if (NT_SUCCESS(Status)) 408 | { 409 | NewSocket->WskSocket = (PWSK_SOCKET)NewSocket->AsyncContext.Irp->IoStatus.Information; 410 | NewSocket->WskDispatch = (PVOID)NewSocket->WskSocket->Dispatch; 411 | 412 | *Socket = NewSocket; 413 | } 414 | 415 | return Status; 416 | } 417 | 418 | NTSTATUS 419 | NTAPI 420 | KsCreateConnectionSocket( 421 | _Out_ PKSOCKET* Socket, 422 | _In_ ADDRESS_FAMILY AddressFamily, 423 | _In_ USHORT SocketType, 424 | _In_ ULONG Protocol 425 | ) 426 | { 427 | return KsCreateSocket(Socket, AddressFamily, SocketType, Protocol, WSK_FLAG_CONNECTION_SOCKET); 428 | } 429 | 430 | NTSTATUS 431 | NTAPI 432 | KsCreateListenSocket( 433 | _Out_ PKSOCKET* Socket, 434 | _In_ ADDRESS_FAMILY AddressFamily, 435 | _In_ USHORT SocketType, 436 | _In_ ULONG Protocol 437 | ) 438 | { 439 | return KsCreateSocket(Socket, AddressFamily, SocketType, Protocol, WSK_FLAG_LISTEN_SOCKET); 440 | } 441 | 442 | NTSTATUS 443 | NTAPI 444 | KsCreateDatagramSocket( 445 | _Out_ PKSOCKET* Socket, 446 | _In_ ADDRESS_FAMILY AddressFamily, 447 | _In_ USHORT SocketType, 448 | _In_ ULONG Protocol 449 | ) 450 | { 451 | return KsCreateSocket(Socket, AddressFamily, SocketType, Protocol, WSK_FLAG_DATAGRAM_SOCKET); 452 | } 453 | 454 | NTSTATUS 455 | NTAPI 456 | KsCloseSocket( 457 | _In_ PKSOCKET Socket 458 | ) 459 | { 460 | NTSTATUS Status; 461 | 462 | // 463 | // Reset the async context. 464 | // 465 | 466 | KspAsyncContextReset(&Socket->AsyncContext); 467 | 468 | // 469 | // Close the WSK socket. 470 | // 471 | 472 | Status = Socket->WskConnectionDispatch->WskCloseSocket( 473 | Socket->WskSocket, 474 | Socket->AsyncContext.Irp 475 | ); 476 | 477 | KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status); 478 | 479 | // 480 | // Free the async context. 481 | // 482 | 483 | KspAsyncContextFree(&Socket->AsyncContext); 484 | 485 | // 486 | // Free memory for the socket structure. 487 | // 488 | 489 | ExFreePoolWithTag(Socket, MEMORY_TAG); 490 | 491 | return Status; 492 | } 493 | 494 | NTSTATUS 495 | NTAPI 496 | KsBind( 497 | _In_ PKSOCKET Socket, 498 | _In_ PSOCKADDR LocalAddress 499 | ) 500 | { 501 | NTSTATUS Status; 502 | 503 | // 504 | // Reset the async context. 505 | // 506 | 507 | KspAsyncContextReset(&Socket->AsyncContext); 508 | 509 | // 510 | // Bind the socket. 511 | // 512 | 513 | Status = Socket->WskListenDispatch->WskBind( 514 | Socket->WskSocket, // Socket 515 | LocalAddress, // LocalAddress 516 | 0, // Flags (reserved) 517 | Socket->AsyncContext.Irp // Irp 518 | ); 519 | 520 | KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status); 521 | 522 | return Status; 523 | } 524 | 525 | NTSTATUS 526 | NTAPI 527 | KsAccept( 528 | _In_ PKSOCKET Socket, 529 | _Out_ PKSOCKET* NewSocket, 530 | _Out_opt_ PSOCKADDR LocalAddress, 531 | _Out_opt_ PSOCKADDR RemoteAddress 532 | ) 533 | { 534 | NTSTATUS Status; 535 | 536 | // 537 | // Reset the async context. 538 | // 539 | 540 | KspAsyncContextReset(&Socket->AsyncContext); 541 | 542 | // 543 | // Accept the connection. 544 | // 545 | 546 | Status = Socket->WskListenDispatch->WskAccept( 547 | Socket->WskSocket, // ListenSocket 548 | 0, // Flags 549 | NULL, // AcceptSocketContext 550 | NULL, // AcceptSocketDispatch 551 | LocalAddress, // LocalAddress 552 | RemoteAddress, // RemoteAddress 553 | Socket->AsyncContext.Irp // Irp 554 | ); 555 | 556 | KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status); 557 | 558 | // 559 | // Save the socket instance and the socket dispatch table. 560 | // 561 | 562 | if (NT_SUCCESS(Status)) 563 | { 564 | PKSOCKET KNewSocket = ExAllocatePoolWithTag(PagedPool, sizeof(KSOCKET), MEMORY_TAG); 565 | 566 | if (!KNewSocket) 567 | { 568 | return STATUS_INSUFFICIENT_RESOURCES; 569 | } 570 | 571 | KNewSocket->WskSocket = (PWSK_SOCKET)Socket->AsyncContext.Irp->IoStatus.Information; 572 | KNewSocket->WskDispatch = (PVOID)KNewSocket->WskSocket->Dispatch; 573 | KspAsyncContextAllocate(&KNewSocket->AsyncContext); 574 | 575 | *NewSocket = KNewSocket; 576 | } 577 | 578 | return Status; 579 | } 580 | 581 | NTSTATUS 582 | NTAPI 583 | KsConnect( 584 | _In_ PKSOCKET Socket, 585 | _In_ PSOCKADDR RemoteAddress 586 | ) 587 | { 588 | NTSTATUS Status; 589 | 590 | // 591 | // Reset the async context. 592 | // 593 | 594 | KspAsyncContextReset(&Socket->AsyncContext); 595 | 596 | // 597 | // Bind the socket to the local address. 598 | // 599 | 600 | SOCKADDR_IN LocalAddress; 601 | LocalAddress.sin_family = AF_INET; 602 | LocalAddress.sin_addr.s_addr = INADDR_ANY; 603 | LocalAddress.sin_port = 0; 604 | 605 | Status = Socket->WskConnectionDispatch->WskBind( 606 | Socket->WskSocket, // Socket 607 | (PSOCKADDR)& LocalAddress, // LocalAddress 608 | 0, // Flags (reserved) 609 | Socket->AsyncContext.Irp // Irp 610 | ); 611 | 612 | KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status); 613 | 614 | if (!NT_SUCCESS(Status)) 615 | { 616 | return Status; 617 | } 618 | 619 | // 620 | // Reset the async context (again). 621 | // 622 | 623 | KspAsyncContextReset(&Socket->AsyncContext); 624 | 625 | // 626 | // Connect to the remote host. 627 | // 628 | // N.B.: Instead of calling WskSocket(), WskBind() and WskConnect(), 629 | // it is possible to just call WskSocketConnect(). 630 | // 631 | 632 | Status = Socket->WskConnectionDispatch->WskConnect( 633 | Socket->WskSocket, // Socket 634 | RemoteAddress, // RemoteAddress 635 | 0, // Flags (reserved) 636 | Socket->AsyncContext.Irp // Irp 637 | ); 638 | 639 | KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status); 640 | 641 | return Status; 642 | } 643 | 644 | NTSTATUS 645 | NTAPI 646 | KsSendRecv( 647 | _In_ PKSOCKET Socket, 648 | _In_ PVOID Buffer, 649 | _Inout_ PULONG Length, 650 | _In_ ULONG Flags, 651 | _In_ BOOLEAN Send 652 | ) 653 | { 654 | NTSTATUS Status; 655 | 656 | // 657 | // Wrap the buffer into the "WSK buffer". 658 | // 659 | 660 | WSK_BUF WskBuffer; 661 | WskBuffer.Offset = 0; 662 | WskBuffer.Length = *Length; 663 | WskBuffer.Mdl = IoAllocateMdl(Buffer, (ULONG)WskBuffer.Length, FALSE, FALSE, NULL); 664 | 665 | __try 666 | { 667 | MmProbeAndLockPages(WskBuffer.Mdl, KernelMode, IoWriteAccess); 668 | } 669 | __except (EXCEPTION_EXECUTE_HANDLER) 670 | { 671 | Status = STATUS_ACCESS_VIOLATION; 672 | goto Error; 673 | } 674 | 675 | // 676 | // Reset the async context. 677 | // 678 | 679 | KspAsyncContextReset(&Socket->AsyncContext); 680 | 681 | // 682 | // Send / receive the data. 683 | // 684 | 685 | if (Send) 686 | { 687 | Status = Socket->WskConnectionDispatch->WskSend( 688 | Socket->WskSocket, // Socket 689 | &WskBuffer, // Buffer 690 | Flags, // Flags 691 | Socket->AsyncContext.Irp // Irp 692 | ); 693 | } 694 | else 695 | { 696 | Status = Socket->WskConnectionDispatch->WskReceive( 697 | Socket->WskSocket, // Socket 698 | &WskBuffer, // Buffer 699 | Flags, // Flags 700 | Socket->AsyncContext.Irp // Irp 701 | ); 702 | } 703 | 704 | KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status); 705 | 706 | // 707 | // Set the number of bytes sent / received. 708 | // 709 | 710 | if (NT_SUCCESS(Status)) 711 | { 712 | *Length = (ULONG)Socket->AsyncContext.Irp->IoStatus.Information; 713 | } 714 | 715 | // 716 | // Free the MDL. 717 | // 718 | 719 | MmUnlockPages(WskBuffer.Mdl); 720 | 721 | Error: 722 | IoFreeMdl(WskBuffer.Mdl); 723 | return Status; 724 | } 725 | 726 | NTSTATUS 727 | NTAPI 728 | KsSendRecvUdp( 729 | _In_ PKSOCKET Socket, 730 | _In_ PVOID Buffer, 731 | _Inout_ PULONG Length, 732 | _In_ ULONG Flags, 733 | _In_ PSOCKADDR RemoteAddress, 734 | _In_ BOOLEAN Send 735 | ) 736 | { 737 | NTSTATUS Status; 738 | 739 | // 740 | // Wrap the buffer into the "WSK buffer". 741 | // 742 | 743 | WSK_BUF WskBuffer; 744 | WskBuffer.Offset = 0; 745 | WskBuffer.Length = *Length; 746 | WskBuffer.Mdl = IoAllocateMdl(Buffer, (ULONG)WskBuffer.Length, FALSE, FALSE, NULL); 747 | 748 | __try 749 | { 750 | MmProbeAndLockPages(WskBuffer.Mdl, KernelMode, IoWriteAccess); 751 | } 752 | __except (EXCEPTION_EXECUTE_HANDLER) 753 | { 754 | Status = STATUS_ACCESS_VIOLATION; 755 | goto Error; 756 | } 757 | 758 | // 759 | // Reset the async context. 760 | // 761 | 762 | KspAsyncContextReset(&Socket->AsyncContext); 763 | 764 | // 765 | // Send / receive the data. 766 | // 767 | 768 | if (Send) 769 | { 770 | Status = Socket->WskDatagramDispatch->WskSendTo( 771 | Socket->WskSocket, // Socket 772 | &WskBuffer, // Buffer 773 | Flags, // Flags (reserved) 774 | RemoteAddress, // RemoteAddress 775 | 0, // ControlInfoLength 776 | NULL, // ControlInfo 777 | Socket->AsyncContext.Irp // Irp 778 | ); 779 | } 780 | else 781 | { 782 | // 783 | // Use #pragma prefast (suppress: ...), because SAL annotation is wrong 784 | // for this function. 785 | // 786 | // From MSDN: 787 | // ControlLength 788 | // ControlInfo 789 | // 790 | // ... This pointer is optional and can be NULL. If the ControlInfoLength 791 | // parameter is NULL, the ControlInfo parameter should be NULL. 792 | // 793 | 794 | #pragma prefast ( \ 795 | suppress:__WARNING_INVALID_PARAM_VALUE_1, \ 796 | "If the ControlInfoLength parameter is NULL, the ControlInfo parameter should be NULL." \ 797 | ) 798 | 799 | Status = Socket->WskDatagramDispatch->WskReceiveFrom( 800 | Socket->WskSocket, // Socket 801 | &WskBuffer, // Buffer 802 | Flags, // Flags (reserved) 803 | RemoteAddress, // RemoteAddress 804 | NULL, // ControlInfoLength 805 | NULL, // ControlInfo 806 | NULL, // ControlFlags 807 | Socket->AsyncContext.Irp // Irp 808 | ); 809 | } 810 | 811 | KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status); 812 | 813 | // 814 | // Set the number of bytes sent / received. 815 | // 816 | 817 | if (NT_SUCCESS(Status)) 818 | { 819 | *Length = (ULONG)Socket->AsyncContext.Irp->IoStatus.Information; 820 | } 821 | 822 | // 823 | // Free the MDL. 824 | // 825 | 826 | MmUnlockPages(WskBuffer.Mdl); 827 | 828 | Error: 829 | IoFreeMdl(WskBuffer.Mdl); 830 | return Status; 831 | } 832 | 833 | NTSTATUS 834 | NTAPI 835 | KsSend( 836 | _In_ PKSOCKET Socket, 837 | _In_ PVOID Buffer, 838 | _Inout_ PULONG Length, 839 | _In_ ULONG Flags 840 | ) 841 | { 842 | return KsSendRecv(Socket, Buffer, Length, Flags, TRUE); 843 | } 844 | 845 | NTSTATUS 846 | NTAPI 847 | KsRecv( 848 | _In_ PKSOCKET Socket, 849 | _In_ PVOID Buffer, 850 | _Inout_ PULONG Length, 851 | _In_ ULONG Flags 852 | ) 853 | { 854 | return KsSendRecv(Socket, Buffer, Length, Flags, FALSE); 855 | } 856 | 857 | NTSTATUS 858 | NTAPI 859 | KsSendTo( 860 | _In_ PKSOCKET Socket, 861 | _In_ PVOID Buffer, 862 | _Inout_ PULONG Length, 863 | _In_ ULONG Flags, 864 | _In_ PSOCKADDR RemoteAddress 865 | ) 866 | { 867 | return KsSendRecvUdp(Socket, Buffer, Length, Flags, RemoteAddress, TRUE); 868 | } 869 | 870 | NTSTATUS 871 | NTAPI 872 | KsRecvFrom( 873 | _In_ PKSOCKET Socket, 874 | _In_ PVOID Buffer, 875 | _Inout_ PULONG Length, 876 | _In_ ULONG Flags, 877 | _In_ PSOCKADDR RemoteAddress 878 | ) 879 | { 880 | return KsSendRecvUdp(Socket, Buffer, Length, Flags, RemoteAddress, FALSE); 881 | } -------------------------------------------------------------------------------- /driver/ksocket.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | typedef struct _KSOCKET KSOCKET, * PKSOCKET; 8 | 9 | NTSTATUS 10 | NTAPI 11 | KsInitialize( 12 | VOID 13 | ); 14 | 15 | VOID 16 | NTAPI 17 | KsDestroy( 18 | VOID 19 | ); 20 | 21 | NTSTATUS 22 | NTAPI 23 | KsGetAddrInfo( 24 | _In_ PUNICODE_STRING NodeName, 25 | _In_ PUNICODE_STRING ServiceName, 26 | _In_ PADDRINFOEXW Hints, 27 | _Out_ PADDRINFOEXW* Result 28 | ); 29 | 30 | VOID 31 | NTAPI 32 | KsFreeAddrInfo( 33 | _In_ PADDRINFOEXW AddrInfo 34 | ); 35 | 36 | NTSTATUS 37 | NTAPI 38 | KsCreateSocket( 39 | _Out_ PKSOCKET* Socket, 40 | _In_ ADDRESS_FAMILY AddressFamily, 41 | _In_ USHORT SocketType, 42 | _In_ ULONG Protocol, 43 | _In_ ULONG Flags 44 | ); 45 | 46 | NTSTATUS 47 | NTAPI 48 | KsCreateConnectionSocket( 49 | _Out_ PKSOCKET* Socket, 50 | _In_ ADDRESS_FAMILY AddressFamily, 51 | _In_ USHORT SocketType, 52 | _In_ ULONG Protocol 53 | ); 54 | 55 | NTSTATUS 56 | NTAPI 57 | KsCreateListenSocket( 58 | _Out_ PKSOCKET* Socket, 59 | _In_ ADDRESS_FAMILY AddressFamily, 60 | _In_ USHORT SocketType, 61 | _In_ ULONG Protocol 62 | ); 63 | 64 | NTSTATUS 65 | NTAPI 66 | KsCreateDatagramSocket( 67 | _Out_ PKSOCKET* Socket, 68 | _In_ ADDRESS_FAMILY AddressFamily, 69 | _In_ USHORT SocketType, 70 | _In_ ULONG Protocol 71 | ); 72 | 73 | NTSTATUS 74 | NTAPI 75 | KsCloseSocket( 76 | _In_ PKSOCKET Socket 77 | ); 78 | 79 | NTSTATUS 80 | NTAPI 81 | KsBind( 82 | _In_ PKSOCKET Socket, 83 | _In_ PSOCKADDR LocalAddress 84 | ); 85 | 86 | NTSTATUS 87 | NTAPI 88 | KsAccept( 89 | _In_ PKSOCKET Socket, 90 | _Out_ PKSOCKET* NewSocket, 91 | _Out_opt_ PSOCKADDR LocalAddress, 92 | _Out_opt_ PSOCKADDR RemoteAddress 93 | ); 94 | 95 | NTSTATUS 96 | NTAPI 97 | KsConnect( 98 | _In_ PKSOCKET Socket, 99 | _In_ PSOCKADDR RemoteAddress 100 | ); 101 | 102 | NTSTATUS 103 | NTAPI 104 | KsSendRecv( 105 | _In_ PKSOCKET Socket, 106 | _In_ PVOID Buffer, 107 | _Inout_ PULONG Length, 108 | _In_ ULONG Flags, 109 | _In_ BOOLEAN Send 110 | ); 111 | 112 | NTSTATUS 113 | NTAPI 114 | KsSendRecvUdp( 115 | _In_ PKSOCKET Socket, 116 | _In_ PVOID Buffer, 117 | _Inout_ PULONG Length, 118 | _In_ ULONG Flags, 119 | _In_ PSOCKADDR RemoteAddress, 120 | _In_ BOOLEAN Send 121 | ); 122 | 123 | NTSTATUS 124 | NTAPI 125 | KsSend( 126 | _In_ PKSOCKET Socket, 127 | _In_ PVOID Buffer, 128 | _Inout_ PULONG Length, 129 | _In_ ULONG Flags 130 | ); 131 | 132 | NTSTATUS 133 | NTAPI 134 | KsRecv( 135 | _In_ PKSOCKET Socket, 136 | _In_ PVOID Buffer, 137 | _Inout_ PULONG Length, 138 | _In_ ULONG Flags 139 | ); 140 | 141 | NTSTATUS 142 | NTAPI 143 | KsSendTo( 144 | _In_ PKSOCKET Socket, 145 | _In_ PVOID Buffer, 146 | _Inout_ PULONG Length, 147 | _In_ ULONG Flags, 148 | _In_ PSOCKADDR RemoteAddress 149 | ); 150 | 151 | NTSTATUS 152 | NTAPI 153 | KsRecvFrom( 154 | _In_ PKSOCKET Socket, 155 | _In_ PVOID Buffer, 156 | _Inout_ PULONG Length, 157 | _In_ ULONG Flags, 158 | _In_ PSOCKADDR RemoteAddress 159 | ); 160 | 161 | #ifdef __cplusplus 162 | } 163 | #endif -------------------------------------------------------------------------------- /driver/main.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | void start(void* context) 4 | { 5 | log("Thread started.\n"); 6 | 7 | initialize_server(55123ui16); 8 | 9 | return; 10 | } 11 | 12 | NTSTATUS DriverEntry(PDRIVER_OBJECT driver_object, PUNICODE_STRING registry_path) 13 | { 14 | HANDLE thread_handle; 15 | auto result = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, 0, 0, 0, start, 0); 16 | 17 | return result; 18 | } -------------------------------------------------------------------------------- /driver/server.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | SOCKET create_server_socket(uint16_t port) 4 | { 5 | SOCKADDR_IN address; 6 | 7 | address.sin_family = AF_INET; 8 | address.sin_addr.s_addr = htonl(server_ip); 9 | address.sin_port = htons(port); 10 | 11 | SOCKET sockfd = socket_listen(AF_INET, SOCK_STREAM, 0); 12 | if (sockfd == INVALID_SOCKET) 13 | { 14 | log("Failed to create a valid server socket.\n"); 15 | 16 | return INVALID_SOCKET; 17 | } 18 | 19 | if (bind(sockfd, (SOCKADDR*)&address, sizeof(address)) == SOCKET_ERROR) 20 | { 21 | log("Failed to bind the server socket.\n"); 22 | 23 | closesocket(sockfd); 24 | return INVALID_SOCKET; 25 | } 26 | 27 | if (listen(sockfd, 10) == SOCKET_ERROR) 28 | { 29 | log("Failed to start listening in on the server socket.\n"); 30 | 31 | closesocket(sockfd); 32 | return INVALID_SOCKET; 33 | } 34 | 35 | return sockfd; 36 | } 37 | 38 | void initialize_server(uint16_t port) 39 | { 40 | NTSTATUS status = KsInitialize(); 41 | 42 | if (!NT_SUCCESS(status)) 43 | { 44 | log("Failed to initialize KSOCKET.\n"); 45 | 46 | return; 47 | } 48 | 49 | SOCKET server_socket = create_server_socket(port); 50 | 51 | if (server_socket == INVALID_SOCKET) 52 | { 53 | log("Failed to initialize the server socket.\n"); 54 | 55 | KsDestroy(); 56 | return; 57 | } 58 | 59 | log("Listening on port %d\n", port); 60 | 61 | while (TRUE) 62 | { 63 | struct sockaddr socket_addr; 64 | socklen_t socket_length; 65 | 66 | SOCKET client_connection = accept(server_socket, &socket_addr, &socket_length); 67 | 68 | if (client_connection == INVALID_SOCKET) 69 | { 70 | log("Failed to accept client connection.\n", port); 71 | } 72 | else 73 | { 74 | HANDLE thread_handle; 75 | PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, 0, 0, 0, server_thread, &client_connection); 76 | } 77 | } 78 | 79 | log("The main thread has terminated...\n"); 80 | 81 | closesocket(server_socket); 82 | } 83 | 84 | uint64_t handle_ping(data_packet_t packet) 85 | { 86 | log("Received ping packet! %d\n", packet.data.ping.ping_magic); 87 | 88 | return packet.data.ping.ping_magic + 1; 89 | } 90 | 91 | uint64_t handle_copy_memory(data_packet_t packet) 92 | { 93 | SIZE_T return_size = 0ull; 94 | PEPROCESS source, target; 95 | 96 | if (NT_SUCCESS(PsLookupProcessByProcessId(packet.data.copy_memory.source_pid, &source)) && 97 | NT_SUCCESS(PsLookupProcessByProcessId(packet.data.copy_memory.target_pid, &target))) 98 | { 99 | bool source_valid = FALSE; 100 | bool target_valid = FALSE; 101 | 102 | KAPC_STATE kapc; 103 | KeStackAttachProcess(source, &kapc); 104 | { 105 | source_valid = MmIsAddressValid(packet.data.copy_memory.source_address); 106 | } 107 | KeUnstackDetachProcess(&kapc); 108 | 109 | KeStackAttachProcess(target, &kapc); 110 | { 111 | target_valid = MmIsAddressValid(packet.data.copy_memory.target_address); 112 | } 113 | KeUnstackDetachProcess(&kapc); 114 | 115 | if (target_valid && source_valid) 116 | { 117 | MmCopyVirtualMemory(source, (PVOID)packet.data.copy_memory.source_address, target, 118 | (PVOID)packet.data.copy_memory.target_address, packet.data.copy_memory.size, KernelMode, &return_size); 119 | } 120 | 121 | ObDereferenceObject(source); 122 | ObDereferenceObject(target); 123 | } 124 | 125 | return return_size; 126 | } 127 | 128 | uint64_t handle_allocate(data_packet_t packet) 129 | { 130 | PVOID base_address = 0; 131 | PEPROCESS target; 132 | 133 | if (NT_SUCCESS(PsLookupProcessByProcessId(packet.data.allocate_memory.target_pid, &target))) 134 | { 135 | KAPC_STATE kapc; 136 | KeStackAttachProcess(target, &kapc); 137 | { 138 | ZwAllocateVirtualMemory(ZwCurrentProcess(), &base_address, 0, &packet.data.allocate_memory.size, 139 | packet.data.allocate_memory.allocation_type, packet.data.allocate_memory.protection); 140 | } 141 | KeUnstackDetachProcess(&kapc); 142 | 143 | ObDereferenceObject(target); 144 | } 145 | 146 | return base_address; 147 | } 148 | 149 | uint64_t handle_free(data_packet_t packet) 150 | { 151 | NTSTATUS result; 152 | PEPROCESS target; 153 | 154 | if (NT_SUCCESS(PsLookupProcessByProcessId(packet.data.free_memory.target_pid, &target))) 155 | { 156 | KAPC_STATE kapc; 157 | KeStackAttachProcess(target, &kapc); 158 | { 159 | result = ZwFreeVirtualMemory(ZwCurrentProcess(), &packet.data.free_memory.target_address, 160 | &packet.data.free_memory.region_size, MEM_RELEASE); 161 | } 162 | KeUnstackDetachProcess(&kapc); 163 | 164 | ObDereferenceObject(target); 165 | } 166 | 167 | return result; 168 | } 169 | 170 | uint64_t handle_protect(data_packet_t packet) 171 | { 172 | uint64_t result = 0ull; 173 | PEPROCESS target; 174 | 175 | if (NT_SUCCESS(PsLookupProcessByProcessId(packet.data.protect_memory.target_pid, &target))) 176 | { 177 | KAPC_STATE kapc; 178 | KeStackAttachProcess(target, &kapc); 179 | { 180 | ZwProtectVirtualMemory(ZwCurrentProcess(), &packet.data.protect_memory.target_address, 181 | &packet.data.protect_memory.size, packet.data.protect_memory.new_protection, &result); 182 | } 183 | KeUnstackDetachProcess(&kapc); 184 | 185 | ObDereferenceObject(target); 186 | } 187 | 188 | return result; 189 | } 190 | 191 | uint64_t handle_get_base(data_packet_t packet) 192 | { 193 | uint64_t result = 0ull; 194 | PEPROCESS target; 195 | 196 | if (NT_SUCCESS(PsLookupProcessByProcessId(packet.data.get_base.target_pid, &target))) 197 | { 198 | KAPC_STATE kapc; 199 | KeStackAttachProcess(target, &kapc); 200 | { 201 | PLDR_DATA_TABLE_ENTRY entry = get_module_by_name_x64(target, packet.data.get_base.module_name); 202 | 203 | if (entry) 204 | { 205 | result = entry->DllBase; 206 | } 207 | } 208 | KeUnstackDetachProcess(&kapc); 209 | 210 | ObDereferenceObject(target); 211 | } 212 | 213 | return result; 214 | } 215 | 216 | uint64_t handle_get_size(data_packet_t packet) 217 | { 218 | uint64_t result = 0ull; 219 | PEPROCESS target; 220 | 221 | if (NT_SUCCESS(PsLookupProcessByProcessId(packet.data.get_size.target_pid, &target))) 222 | { 223 | KAPC_STATE kapc; 224 | KeStackAttachProcess(target, &kapc); 225 | { 226 | PLDR_DATA_TABLE_ENTRY entry = get_module_by_name_x64(target, packet.data.get_size.module_name); 227 | 228 | if (entry) 229 | { 230 | result = entry->SizeOfImage; 231 | } 232 | } 233 | KeUnstackDetachProcess(&kapc); 234 | 235 | ObDereferenceObject(target); 236 | } 237 | 238 | return result; 239 | } 240 | 241 | uint64_t handle_packet(data_packet_t packet) 242 | { 243 | uint64_t result = 0ull; 244 | 245 | switch (packet.header.type) 246 | { 247 | case ping: 248 | result = handle_ping(packet); 249 | break; 250 | 251 | case packet_copy_memory: 252 | result = handle_copy_memory(packet); 253 | break; 254 | 255 | case packet_allocate: 256 | result = handle_allocate(packet); 257 | break; 258 | 259 | case packet_free: 260 | result = handle_free(packet); 261 | break; 262 | 263 | case packet_protect: 264 | result = handle_protect(packet); 265 | break; 266 | 267 | case packet_get_base: 268 | result = handle_get_base(packet); 269 | break; 270 | 271 | case packet_get_size: 272 | result = handle_get_size(packet); 273 | break; 274 | 275 | default: 276 | log("Received unknown packet.\n"); 277 | break; 278 | } 279 | 280 | return result; 281 | } 282 | 283 | bool answer_client(SOCKET sockfd, uint64_t result) 284 | { 285 | data_packet_t packet; 286 | packet.header.magic_header = magic_header_value; 287 | packet.header.type = completed; 288 | packet.data.response.data = result; 289 | 290 | return send(sockfd, &packet, sizeof(packet), 0) != SOCKET_ERROR; 291 | } 292 | 293 | void server_thread(SOCKET* sockfd) 294 | { 295 | log("Connection received, server thread spawned.\n"); 296 | 297 | 298 | SOCKET connection = *sockfd; 299 | 300 | data_packet_t packet; 301 | 302 | while (TRUE) 303 | { 304 | int result = recv(connection, (void*)&packet, sizeof(packet), 0); 305 | 306 | if (result > 0 && result >= sizeof(packet.header) && packet.header.magic_header == magic_header_value) 307 | { 308 | uint64_t packet_result = handle_packet(packet); 309 | 310 | if (!answer_client(connection, packet_result)) 311 | { 312 | break; 313 | } 314 | } 315 | } 316 | 317 | log("A server thread has terminated...\n"); 318 | } 319 | -------------------------------------------------------------------------------- /driver/server.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define magic_header_value 0x59da412859da4128 4 | #define server_ip 0x7F000001 // localhost 5 | 6 | enum e_packet_type 7 | { 8 | packet_get_base, 9 | packet_get_size, 10 | packet_copy_memory, 11 | packet_allocate, 12 | packet_free, 13 | packet_protect, 14 | completed, 15 | ping 16 | }; 17 | 18 | typedef struct _packet_header_t 19 | { 20 | uint64_t magic_header; 21 | int type; 22 | } packet_header_t, *lpacket_header_t; 23 | 24 | typedef struct _packet_response_t 25 | { 26 | uint64_t data; 27 | } packet_response_t, *lpacket_response_t; 28 | 29 | typedef struct _packet_ping_t 30 | { 31 | int32_t ping_magic; 32 | } packet_ping_t, *lpacket_ping_t; 33 | 34 | typedef struct _packet_copy_memory_t 35 | { 36 | uint32_t source_pid; 37 | uint64_t source_address; 38 | uint32_t target_pid; 39 | uint64_t target_address; 40 | size_t size; 41 | } packet_copy_memory_t, *lpacket_copy_memory_t; 42 | 43 | typedef struct _packet_allocate_memory_t 44 | { 45 | uint32_t target_pid; 46 | uint32_t protection; 47 | uint32_t allocation_type; 48 | size_t size; 49 | } packet_allocate_memory_t, *lpacket_allocate_memory_t; 50 | 51 | typedef struct _packet_free_memory_t 52 | { 53 | uint32_t target_pid; 54 | uint64_t target_address; 55 | size_t region_size; 56 | } packet_free_memory_t, *lpacket_free_memory_t; 57 | 58 | typedef struct _packet_protect_memory_t 59 | { 60 | uint32_t target_pid; 61 | uint64_t target_address; 62 | uint32_t new_protection; 63 | size_t size; 64 | } packet_protect_memory_t, *lpacket_protect_memory_t; 65 | 66 | typedef struct _packet_get_base_t 67 | { 68 | uint32_t target_pid; 69 | wchar_t module_name[64]; 70 | } packet_get_base_t, *lpacket_get_base_t; 71 | 72 | typedef struct _packet_get_size_t 73 | { 74 | uint32_t target_pid; 75 | wchar_t module_name[64]; 76 | } packet_get_size_t, *lpacket_get_size_t; 77 | 78 | typedef struct _data_packet_t 79 | { 80 | packet_header_t header; 81 | union 82 | { 83 | packet_response_t response; 84 | packet_ping_t ping; 85 | packet_copy_memory_t copy_memory; 86 | packet_allocate_memory_t allocate_memory; 87 | packet_free_memory_t free_memory; 88 | packet_protect_memory_t protect_memory; 89 | packet_get_base_t get_base; 90 | packet_get_size_t get_size; 91 | } data; 92 | } data_packet_t, *lpdata_packet_t; 93 | 94 | // server initialization 95 | SOCKET create_server_socket(uint16_t port); 96 | void initialize_server(uint16_t port); 97 | 98 | // specific handlers 99 | uint64_t handle_ping(data_packet_t packet); 100 | uint64_t handle_copy_memory(data_packet_t packet); 101 | uint64_t handle_allocate(data_packet_t packet); 102 | uint64_t handle_free(data_packet_t packet); 103 | uint64_t handle_protect(data_packet_t packet); 104 | uint64_t handle_get_base(data_packet_t packet); 105 | uint64_t handle_get_size(data_packet_t packet); 106 | 107 | // master handler(s) 108 | uint64_t handle_packet(data_packet_t packet); 109 | bool answer_client(SOCKET sockfd, uint64_t result); 110 | void server_thread(SOCKET* sockfd); -------------------------------------------------------------------------------- /driver/utils.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | PLDR_DATA_TABLE_ENTRY get_module_by_name_x64(PEPROCESS process, wchar_t* module_name) 4 | { 5 | UNICODE_STRING module_name_unicode = { 0 }; 6 | RtlInitUnicodeString(&module_name_unicode, module_name); 7 | 8 | PLIST_ENTRY list = &(PsGetProcessPeb(process)->Ldr->InLoadOrderModuleList); 9 | 10 | for (PLIST_ENTRY entry = list->Flink; entry != list; ) 11 | { 12 | PLDR_DATA_TABLE_ENTRY module = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); 13 | 14 | if (RtlCompareUnicodeString(&module->BaseDllName, &module_name_unicode, TRUE) == 0) 15 | { 16 | return module; 17 | } 18 | 19 | entry = module->InLoadOrderLinks.Flink; 20 | } 21 | 22 | return NULL; 23 | } -------------------------------------------------------------------------------- /driver/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | PLDR_DATA_TABLE_ENTRY get_module_by_name_x64(PEPROCESS process, wchar_t* module_name); -------------------------------------------------------------------------------- /kersock.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31005.135 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "client", "client\client.vcxproj", "{81699472-E045-4DF8-99A1-72936EE445EE}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "driver", "driver\driver.vcxproj", "{6AA61830-4BA3-4097-B4FF-EA62F47D98D6}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|x64 = Debug|x64 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {81699472-E045-4DF8-99A1-72936EE445EE}.Debug|x64.ActiveCfg = Debug|x64 17 | {81699472-E045-4DF8-99A1-72936EE445EE}.Debug|x64.Build.0 = Debug|x64 18 | {81699472-E045-4DF8-99A1-72936EE445EE}.Release|x64.ActiveCfg = Release|x64 19 | {81699472-E045-4DF8-99A1-72936EE445EE}.Release|x64.Build.0 = Release|x64 20 | {6AA61830-4BA3-4097-B4FF-EA62F47D98D6}.Debug|x64.ActiveCfg = Debug|x64 21 | {6AA61830-4BA3-4097-B4FF-EA62F47D98D6}.Debug|x64.Build.0 = Debug|x64 22 | {6AA61830-4BA3-4097-B4FF-EA62F47D98D6}.Debug|x64.Deploy.0 = Debug|x64 23 | {6AA61830-4BA3-4097-B4FF-EA62F47D98D6}.Release|x64.ActiveCfg = Release|x64 24 | {6AA61830-4BA3-4097-B4FF-EA62F47D98D6}.Release|x64.Build.0 = Release|x64 25 | {6AA61830-4BA3-4097-B4FF-EA62F47D98D6}.Release|x64.Deploy.0 = Release|x64 26 | EndGlobalSection 27 | GlobalSection(SolutionProperties) = preSolution 28 | HideSolutionNode = FALSE 29 | EndGlobalSection 30 | GlobalSection(ExtensibilityGlobals) = postSolution 31 | SolutionGuid = {5440F2C6-E2BF-4D38-9500-0EC8FE4A4105} 32 | EndGlobalSection 33 | EndGlobal 34 | --------------------------------------------------------------------------------