├── .gitignore ├── KsDumper.sln ├── KsDumperClient ├── App.config ├── Driver │ ├── DriverInterface.cs │ └── Operations.cs ├── Dumper.Designer.cs ├── Dumper.cs ├── Dumper.resx ├── KsDumperClient.csproj ├── PE │ ├── 32 │ │ ├── PE32File.cs │ │ └── PE32Header.cs │ ├── 64 │ │ ├── PE64File.cs │ │ └── PE64Header.cs │ ├── DOSHeader.cs │ ├── NativePEStructs.cs │ ├── PEFile.cs │ └── PESection.cs ├── ProcessDumper.cs ├── ProcessSummary.cs ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── Utility │ ├── Logger.cs │ ├── MarshalUtility.cs │ ├── ProcessListView.cs │ └── WinApi.cs └── app.manifest ├── KsDumperDriver ├── Driver.c ├── KsDumperDriver.vcxproj ├── KsDumperDriver.vcxproj.filters ├── NTUndocumented.h ├── ProcessLister.c ├── ProcessLister.h ├── UserModeBridge.h ├── Utility.c └── Utility.h ├── LICENSE └── README.md /.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 | # ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true 235 | **/wwwroot/lib/ 236 | 237 | # RIA/Silverlight projects 238 | Generated_Code/ 239 | 240 | # Backup & report files from converting an old project file 241 | # to a newer Visual Studio version. Backup files are not needed, 242 | # because we have git ;-) 243 | _UpgradeReport_Files/ 244 | Backup*/ 245 | UpgradeLog*.XML 246 | UpgradeLog*.htm 247 | ServiceFabricBackup/ 248 | *.rptproj.bak 249 | 250 | # SQL Server files 251 | *.mdf 252 | *.ldf 253 | *.ndf 254 | 255 | # Business Intelligence projects 256 | *.rdl.data 257 | *.bim.layout 258 | *.bim_*.settings 259 | *.rptproj.rsuser 260 | *- Backup*.rdl 261 | 262 | # Microsoft Fakes 263 | FakesAssemblies/ 264 | 265 | # GhostDoc plugin setting file 266 | *.GhostDoc.xml 267 | 268 | # Node.js Tools for Visual Studio 269 | .ntvs_analysis.dat 270 | node_modules/ 271 | 272 | # Visual Studio 6 build log 273 | *.plg 274 | 275 | # Visual Studio 6 workspace options file 276 | *.opt 277 | 278 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 279 | *.vbw 280 | 281 | # Visual Studio LightSwitch build output 282 | **/*.HTMLClient/GeneratedArtifacts 283 | **/*.DesktopClient/GeneratedArtifacts 284 | **/*.DesktopClient/ModelManifest.xml 285 | **/*.Server/GeneratedArtifacts 286 | **/*.Server/ModelManifest.xml 287 | _Pvt_Extensions 288 | 289 | # Paket dependency manager 290 | .paket/paket.exe 291 | paket-files/ 292 | 293 | # FAKE - F# Make 294 | .fake/ 295 | 296 | # JetBrains Rider 297 | .idea/ 298 | *.sln.iml 299 | 300 | # CodeRush personal settings 301 | .cr/personal 302 | 303 | # Python Tools for Visual Studio (PTVS) 304 | __pycache__/ 305 | *.pyc 306 | 307 | # Cake - Uncomment if you are using it 308 | # tools/** 309 | # !tools/packages.config 310 | 311 | # Tabs Studio 312 | *.tss 313 | 314 | # Telerik's JustMock configuration file 315 | *.jmconfig 316 | 317 | # BizTalk build output 318 | *.btp.cs 319 | *.btm.cs 320 | *.odx.cs 321 | *.xsd.cs 322 | 323 | # OpenCover UI analysis results 324 | OpenCover/ 325 | 326 | # Azure Stream Analytics local run output 327 | ASALocalRun/ 328 | 329 | # MSBuild Binary and Structured Log 330 | *.binlog 331 | 332 | # NVidia Nsight GPU debugger configuration file 333 | *.nvuser 334 | 335 | # MFractors (Xamarin productivity tool) working folder 336 | .mfractor/ 337 | 338 | # Local History for Visual Studio 339 | .localhistory/ 340 | 341 | # BeatPulse healthcheck temp database 342 | healthchecksdb -------------------------------------------------------------------------------- /KsDumper.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.329 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KsDumperDriver", "KsDumperDriver\KsDumperDriver.vcxproj", "{8EADAB93-F111-43AF-9E10-2376AE515491}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KsDumperClient", "KsDumperClient\KsDumperClient.csproj", "{7881B99D-0B5A-44E7-AF34-80A0ECFFD5DB}" 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 | {8EADAB93-F111-43AF-9E10-2376AE515491}.Debug|x64.ActiveCfg = Release|x64 17 | {8EADAB93-F111-43AF-9E10-2376AE515491}.Debug|x64.Build.0 = Release|x64 18 | {8EADAB93-F111-43AF-9E10-2376AE515491}.Release|x64.ActiveCfg = Release|x64 19 | {8EADAB93-F111-43AF-9E10-2376AE515491}.Release|x64.Build.0 = Release|x64 20 | {7881B99D-0B5A-44E7-AF34-80A0ECFFD5DB}.Debug|x64.ActiveCfg = Debug|x64 21 | {7881B99D-0B5A-44E7-AF34-80A0ECFFD5DB}.Debug|x64.Build.0 = Debug|x64 22 | {7881B99D-0B5A-44E7-AF34-80A0ECFFD5DB}.Release|x64.ActiveCfg = Release|x64 23 | {7881B99D-0B5A-44E7-AF34-80A0ECFFD5DB}.Release|x64.Build.0 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {B97C5D1A-00B8-411D-9716-A3805DA64FD6} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /KsDumperClient/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /KsDumperClient/Driver/DriverInterface.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Runtime.InteropServices; 4 | using KsDumperClient.Utility; 5 | 6 | using static KsDumperClient.Driver.Operations; 7 | 8 | namespace KsDumperClient.Driver 9 | { 10 | public class DriverInterface 11 | { 12 | private readonly IntPtr driverHandle; 13 | 14 | public DriverInterface(string registryPath) 15 | { 16 | driverHandle = WinApi.CreateFileA(registryPath, FileAccess.ReadWrite, 17 | FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero); 18 | } 19 | 20 | public bool HasValidHandle() 21 | { 22 | return driverHandle != WinApi.INVALID_HANDLE_VALUE; 23 | } 24 | 25 | public bool GetProcessSummaryList(out ProcessSummary[] result) 26 | { 27 | result = new ProcessSummary[0]; 28 | 29 | if (driverHandle != WinApi.INVALID_HANDLE_VALUE) 30 | { 31 | int requiredBufferSize = GetProcessListRequiredBufferSize(); 32 | 33 | if (requiredBufferSize > 0) 34 | { 35 | IntPtr bufferPointer = MarshalUtility.AllocZeroFilled(requiredBufferSize); 36 | KERNEL_PROCESS_LIST_OPERATION operation = new KERNEL_PROCESS_LIST_OPERATION 37 | { 38 | bufferAddress = (ulong)bufferPointer.ToInt64(), 39 | bufferSize = requiredBufferSize 40 | }; 41 | IntPtr operationPointer = MarshalUtility.CopyStructToMemory(operation); 42 | int operationSize = Marshal.SizeOf(); 43 | 44 | if (WinApi.DeviceIoControl(driverHandle, IO_GET_PROCESS_LIST, operationPointer, operationSize, operationPointer, operationSize, IntPtr.Zero, IntPtr.Zero)) 45 | { 46 | operation = MarshalUtility.GetStructFromMemory(operationPointer); 47 | 48 | if (operation.processCount > 0) 49 | { 50 | byte[] managedBuffer = new byte[requiredBufferSize]; 51 | Marshal.Copy(bufferPointer, managedBuffer, 0, requiredBufferSize); 52 | Marshal.FreeHGlobal(bufferPointer); 53 | 54 | result = new ProcessSummary[operation.processCount]; 55 | 56 | using (BinaryReader reader = new BinaryReader(new MemoryStream(managedBuffer))) 57 | { 58 | for (int i = 0; i < result.Length; i++) 59 | { 60 | result[i] = ProcessSummary.FromStream(reader); 61 | } 62 | } 63 | return true; 64 | } 65 | } 66 | } 67 | } 68 | return false; 69 | } 70 | 71 | private int GetProcessListRequiredBufferSize() 72 | { 73 | IntPtr operationPointer = MarshalUtility.AllocEmptyStruct(); 74 | int operationSize = Marshal.SizeOf(); 75 | 76 | if (WinApi.DeviceIoControl(driverHandle, IO_GET_PROCESS_LIST, operationPointer, operationSize, operationPointer, operationSize, IntPtr.Zero, IntPtr.Zero)) 77 | { 78 | KERNEL_PROCESS_LIST_OPERATION operation = MarshalUtility.GetStructFromMemory(operationPointer); 79 | 80 | if (operation.processCount == 0 && operation.bufferSize > 0) 81 | { 82 | return operation.bufferSize; 83 | } 84 | } 85 | return 0; 86 | } 87 | 88 | public bool CopyVirtualMemory(int targetProcessId, IntPtr targetAddress, IntPtr bufferAddress, int bufferSize) 89 | { 90 | if (driverHandle != WinApi.INVALID_HANDLE_VALUE) 91 | { 92 | KERNEL_COPY_MEMORY_OPERATION operation = new KERNEL_COPY_MEMORY_OPERATION 93 | { 94 | targetProcessId = targetProcessId, 95 | targetAddress = (ulong)targetAddress.ToInt64(), 96 | bufferAddress = (ulong)bufferAddress.ToInt64(), 97 | bufferSize = bufferSize 98 | }; 99 | 100 | IntPtr operationPointer = MarshalUtility.CopyStructToMemory(operation); 101 | 102 | bool result = WinApi.DeviceIoControl(driverHandle, IO_COPY_MEMORY, operationPointer, Marshal.SizeOf(), IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero); 103 | Marshal.FreeHGlobal(operationPointer); 104 | 105 | return result; 106 | } 107 | return false; 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /KsDumperClient/Driver/Operations.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | using static KsDumperClient.Utility.WinApi; 4 | 5 | namespace KsDumperClient.Driver 6 | { 7 | public static class Operations 8 | { 9 | public static readonly uint IO_GET_PROCESS_LIST = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x1724, METHOD_BUFFERED, FILE_ANY_ACCESS); 10 | 11 | public static readonly uint IO_COPY_MEMORY = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x1725, METHOD_BUFFERED, FILE_ANY_ACCESS); 12 | 13 | [StructLayout(LayoutKind.Sequential)] 14 | public struct KERNEL_PROCESS_LIST_OPERATION 15 | { 16 | public ulong bufferAddress; 17 | public int bufferSize; 18 | public int processCount; 19 | } 20 | 21 | [StructLayout(LayoutKind.Sequential)] 22 | public struct KERNEL_COPY_MEMORY_OPERATION 23 | { 24 | public int targetProcessId; 25 | public ulong targetAddress; 26 | public ulong bufferAddress; 27 | public int bufferSize; 28 | } 29 | 30 | private static uint CTL_CODE(int deviceType, int function, int method, int access) 31 | { 32 | return (uint)(((deviceType) << 16) | ((access) << 14) | ((function) << 2) | (method)); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /KsDumperClient/Dumper.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace KsDumperClient 2 | { 3 | partial class Dumper 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.components = new System.ComponentModel.Container(); 32 | this.toolStrip1 = new System.Windows.Forms.ToolStrip(); 33 | this.refreshMenuBtn = new System.Windows.Forms.ToolStripButton(); 34 | this.hideSystemProcessMenuBtn = new System.Windows.Forms.ToolStripButton(); 35 | this.groupBox1 = new System.Windows.Forms.GroupBox(); 36 | this.logsTextBox = new System.Windows.Forms.RichTextBox(); 37 | this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); 38 | this.dumpMainModuleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 39 | this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); 40 | this.openInExplorerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 41 | this.processList = new KsDumperClient.Utility.ProcessListView(); 42 | this.PIDHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); 43 | this.NameHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); 44 | this.PathHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); 45 | this.BaseAddressHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); 46 | this.EntryPointHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); 47 | this.ImageSizeHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); 48 | this.ImageTypeHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); 49 | this.toolStrip1.SuspendLayout(); 50 | this.groupBox1.SuspendLayout(); 51 | this.contextMenuStrip1.SuspendLayout(); 52 | this.SuspendLayout(); 53 | // 54 | // toolStrip1 55 | // 56 | this.toolStrip1.AllowMerge = false; 57 | this.toolStrip1.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; 58 | this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 59 | this.refreshMenuBtn, 60 | this.hideSystemProcessMenuBtn}); 61 | this.toolStrip1.Location = new System.Drawing.Point(0, 0); 62 | this.toolStrip1.Margin = new System.Windows.Forms.Padding(2); 63 | this.toolStrip1.Name = "toolStrip1"; 64 | this.toolStrip1.Padding = new System.Windows.Forms.Padding(2, 3, 2, 2); 65 | this.toolStrip1.ShowItemToolTips = false; 66 | this.toolStrip1.Size = new System.Drawing.Size(1004, 27); 67 | this.toolStrip1.TabIndex = 4; 68 | this.toolStrip1.Text = "toolStrip1"; 69 | // 70 | // refreshMenuBtn 71 | // 72 | this.refreshMenuBtn.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; 73 | this.refreshMenuBtn.ImageTransparentColor = System.Drawing.Color.Magenta; 74 | this.refreshMenuBtn.Name = "refreshMenuBtn"; 75 | this.refreshMenuBtn.Size = new System.Drawing.Size(50, 19); 76 | this.refreshMenuBtn.Text = "Refresh"; 77 | this.refreshMenuBtn.Click += new System.EventHandler(this.refreshMenuBtn_Click); 78 | // 79 | // hideSystemProcessMenuBtn 80 | // 81 | this.hideSystemProcessMenuBtn.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right; 82 | this.hideSystemProcessMenuBtn.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; 83 | this.hideSystemProcessMenuBtn.ImageTransparentColor = System.Drawing.Color.Magenta; 84 | this.hideSystemProcessMenuBtn.Name = "hideSystemProcessMenuBtn"; 85 | this.hideSystemProcessMenuBtn.Size = new System.Drawing.Size(135, 19); 86 | this.hideSystemProcessMenuBtn.Text = "Show System Processes"; 87 | this.hideSystemProcessMenuBtn.Click += new System.EventHandler(this.hideSystemProcessMenuBtn_Click); 88 | // 89 | // groupBox1 90 | // 91 | this.groupBox1.Controls.Add(this.logsTextBox); 92 | this.groupBox1.Location = new System.Drawing.Point(5, 525); 93 | this.groupBox1.Name = "groupBox1"; 94 | this.groupBox1.Size = new System.Drawing.Size(992, 222); 95 | this.groupBox1.TabIndex = 5; 96 | this.groupBox1.TabStop = false; 97 | this.groupBox1.Text = "Logs"; 98 | // 99 | // logsTextBox 100 | // 101 | this.logsTextBox.BackColor = System.Drawing.SystemColors.Control; 102 | this.logsTextBox.BorderStyle = System.Windows.Forms.BorderStyle.None; 103 | this.logsTextBox.Location = new System.Drawing.Point(12, 19); 104 | this.logsTextBox.Name = "logsTextBox"; 105 | this.logsTextBox.ReadOnly = true; 106 | this.logsTextBox.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.Vertical; 107 | this.logsTextBox.Size = new System.Drawing.Size(968, 197); 108 | this.logsTextBox.TabIndex = 0; 109 | this.logsTextBox.Text = ""; 110 | this.logsTextBox.TextChanged += new System.EventHandler(this.logsTextBox_TextChanged); 111 | // 112 | // contextMenuStrip1 113 | // 114 | this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 115 | this.dumpMainModuleToolStripMenuItem, 116 | this.toolStripSeparator1, 117 | this.openInExplorerToolStripMenuItem}); 118 | this.contextMenuStrip1.Name = "contextMenuStrip1"; 119 | this.contextMenuStrip1.Size = new System.Drawing.Size(182, 76); 120 | this.contextMenuStrip1.Opening += new System.ComponentModel.CancelEventHandler(this.contextMenuStrip1_Opening); 121 | // 122 | // dumpMainModuleToolStripMenuItem 123 | // 124 | this.dumpMainModuleToolStripMenuItem.Name = "dumpMainModuleToolStripMenuItem"; 125 | this.dumpMainModuleToolStripMenuItem.Size = new System.Drawing.Size(181, 22); 126 | this.dumpMainModuleToolStripMenuItem.Text = "Dump Main Module"; 127 | this.dumpMainModuleToolStripMenuItem.Click += new System.EventHandler(this.dumpMainModuleToolStripMenuItem_Click); 128 | // 129 | // toolStripSeparator1 130 | // 131 | this.toolStripSeparator1.Name = "toolStripSeparator1"; 132 | this.toolStripSeparator1.Size = new System.Drawing.Size(178, 6); 133 | // 134 | // openInExplorerToolStripMenuItem 135 | // 136 | this.openInExplorerToolStripMenuItem.Name = "openInExplorerToolStripMenuItem"; 137 | this.openInExplorerToolStripMenuItem.Size = new System.Drawing.Size(181, 22); 138 | this.openInExplorerToolStripMenuItem.Text = "Open In Explorer"; 139 | this.openInExplorerToolStripMenuItem.Click += new System.EventHandler(this.openInExplorerToolStripMenuItem_Click); 140 | // 141 | // processList 142 | // 143 | this.processList.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { 144 | this.PIDHeader, 145 | this.NameHeader, 146 | this.PathHeader, 147 | this.BaseAddressHeader, 148 | this.EntryPointHeader, 149 | this.ImageSizeHeader, 150 | this.ImageTypeHeader}); 151 | this.processList.ContextMenuStrip = this.contextMenuStrip1; 152 | this.processList.FullRowSelect = true; 153 | this.processList.Location = new System.Drawing.Point(5, 28); 154 | this.processList.MultiSelect = false; 155 | this.processList.Name = "processList"; 156 | this.processList.Size = new System.Drawing.Size(992, 491); 157 | this.processList.TabIndex = 2; 158 | this.processList.UseCompatibleStateImageBehavior = false; 159 | this.processList.View = System.Windows.Forms.View.Details; 160 | // 161 | // PIDHeader 162 | // 163 | this.PIDHeader.Text = "PID"; 164 | this.PIDHeader.Width = 76; 165 | // 166 | // NameHeader 167 | // 168 | this.NameHeader.Text = "Name"; 169 | this.NameHeader.Width = 143; 170 | // 171 | // PathHeader 172 | // 173 | this.PathHeader.Text = "Path"; 174 | this.PathHeader.Width = 375; 175 | // 176 | // BaseAddressHeader 177 | // 178 | this.BaseAddressHeader.Text = "Base Address"; 179 | this.BaseAddressHeader.Width = 106; 180 | // 181 | // EntryPointHeader 182 | // 183 | this.EntryPointHeader.Text = "Entry Point"; 184 | this.EntryPointHeader.Width = 106; 185 | // 186 | // ImageSizeHeader 187 | // 188 | this.ImageSizeHeader.Text = "Image Size"; 189 | this.ImageSizeHeader.Width = 88; 190 | // 191 | // ImageTypeHeader 192 | // 193 | this.ImageTypeHeader.Text = "Image Type"; 194 | this.ImageTypeHeader.Width = 72; 195 | // 196 | // Dumper 197 | // 198 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 199 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 200 | this.ClientSize = new System.Drawing.Size(1004, 756); 201 | this.Controls.Add(this.groupBox1); 202 | this.Controls.Add(this.toolStrip1); 203 | this.Controls.Add(this.processList); 204 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; 205 | this.MaximizeBox = false; 206 | this.Name = "Dumper"; 207 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; 208 | this.Text = "KsDumper"; 209 | this.Load += new System.EventHandler(this.Dumper_Load); 210 | this.toolStrip1.ResumeLayout(false); 211 | this.toolStrip1.PerformLayout(); 212 | this.groupBox1.ResumeLayout(false); 213 | this.contextMenuStrip1.ResumeLayout(false); 214 | this.ResumeLayout(false); 215 | this.PerformLayout(); 216 | 217 | } 218 | 219 | #endregion 220 | private KsDumperClient.Utility.ProcessListView processList; 221 | private System.Windows.Forms.ColumnHeader PIDHeader; 222 | private System.Windows.Forms.ColumnHeader NameHeader; 223 | private System.Windows.Forms.ColumnHeader PathHeader; 224 | private System.Windows.Forms.ColumnHeader BaseAddressHeader; 225 | private System.Windows.Forms.ColumnHeader EntryPointHeader; 226 | private System.Windows.Forms.ColumnHeader ImageSizeHeader; 227 | private System.Windows.Forms.ColumnHeader ImageTypeHeader; 228 | private System.Windows.Forms.ToolStrip toolStrip1; 229 | private System.Windows.Forms.ToolStripButton refreshMenuBtn; 230 | private System.Windows.Forms.ToolStripButton hideSystemProcessMenuBtn; 231 | private System.Windows.Forms.GroupBox groupBox1; 232 | private System.Windows.Forms.RichTextBox logsTextBox; 233 | private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; 234 | private System.Windows.Forms.ToolStripMenuItem dumpMainModuleToolStripMenuItem; 235 | private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; 236 | private System.Windows.Forms.ToolStripMenuItem openInExplorerToolStripMenuItem; 237 | } 238 | } 239 | 240 | -------------------------------------------------------------------------------- /KsDumperClient/Dumper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Threading.Tasks; 6 | using System.Windows.Forms; 7 | using KsDumperClient.Driver; 8 | using KsDumperClient.PE; 9 | using KsDumperClient.Utility; 10 | 11 | namespace KsDumperClient 12 | { 13 | public partial class Dumper : Form 14 | { 15 | private readonly DriverInterface driver; 16 | private readonly ProcessDumper dumper; 17 | 18 | public Dumper() 19 | { 20 | InitializeComponent(); 21 | 22 | driver = new DriverInterface("\\\\.\\KsDumper"); 23 | dumper = new ProcessDumper(driver); 24 | LoadProcessList(); 25 | } 26 | 27 | private void Dumper_Load(object sender, EventArgs e) 28 | { 29 | Logger.OnLog += Logger_OnLog; 30 | Logger.Log("KsDumper v1.1 - By EquiFox"); 31 | } 32 | 33 | private void LoadProcessList() 34 | { 35 | if (driver.HasValidHandle()) 36 | { 37 | if (driver.GetProcessSummaryList(out ProcessSummary[] result)) 38 | { 39 | processList.LoadProcesses(result); 40 | } 41 | else 42 | { 43 | MessageBox.Show("Unable to retrieve process list !", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 44 | } 45 | } 46 | } 47 | 48 | private void dumpMainModuleToolStripMenuItem_Click(object sender, EventArgs e) 49 | { 50 | if (driver.HasValidHandle()) 51 | { 52 | ProcessSummary targetProcess = processList.SelectedItems[0].Tag as ProcessSummary; 53 | 54 | Task.Run(() => 55 | { 56 | 57 | if (dumper.DumpProcess(targetProcess, out PEFile peFile)) 58 | { 59 | Invoke(new Action(() => 60 | { 61 | using (SaveFileDialog sfd = new SaveFileDialog()) 62 | { 63 | sfd.FileName = targetProcess.ProcessName.Replace(".exe", "_dump.exe"); 64 | sfd.Filter = "Executable File (.exe)|*.exe"; 65 | 66 | if (sfd.ShowDialog() == DialogResult.OK) 67 | { 68 | peFile.SaveToDisk(sfd.FileName); 69 | Logger.Log("Saved at '{0}' !", sfd.FileName); 70 | } 71 | } 72 | })); 73 | } 74 | else 75 | { 76 | Invoke(new Action(() => 77 | { 78 | MessageBox.Show("Unable to dump target process !", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 79 | })); 80 | } 81 | }); 82 | } 83 | else 84 | { 85 | MessageBox.Show("Unable to communicate with driver ! Make sure it is loaded.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 86 | } 87 | } 88 | 89 | private void Logger_OnLog(string message) 90 | { 91 | logsTextBox.Invoke(new Action(() => logsTextBox.AppendText(message))); 92 | } 93 | 94 | private void refreshMenuBtn_Click(object sender, EventArgs e) 95 | { 96 | LoadProcessList(); 97 | } 98 | 99 | private void hideSystemProcessMenuBtn_Click(object sender, EventArgs e) 100 | { 101 | if (!processList.SystemProcessesHidden) 102 | { 103 | processList.HideSystemProcesses(); 104 | hideSystemProcessMenuBtn.Text = "Show System Processes"; 105 | } 106 | else 107 | { 108 | processList.ShowSystemProcesses(); 109 | hideSystemProcessMenuBtn.Text = "Hide System Processes"; 110 | } 111 | } 112 | 113 | private void contextMenuStrip1_Opening(object sender, CancelEventArgs e) 114 | { 115 | e.Cancel = processList.SelectedItems.Count == 0; 116 | } 117 | 118 | private void logsTextBox_TextChanged(object sender, EventArgs e) 119 | { 120 | logsTextBox.SelectionStart = logsTextBox.Text.Length; 121 | logsTextBox.ScrollToCaret(); 122 | } 123 | 124 | private void openInExplorerToolStripMenuItem_Click(object sender, EventArgs e) 125 | { 126 | ProcessSummary targetProcess = processList.SelectedItems[0].Tag as ProcessSummary; 127 | Process.Start("explorer.exe", Path.GetDirectoryName(targetProcess.MainModuleFileName)); 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /KsDumperClient/Dumper.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 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 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 132, 17 122 | 123 | 124 | 237, 17 125 | 126 | -------------------------------------------------------------------------------- /KsDumperClient/KsDumperClient.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {7881B99D-0B5A-44E7-AF34-80A0ECFFD5DB} 8 | WinExe 9 | KsDumperClient 10 | KsDumperClient 11 | v4.6.1 12 | 512 13 | true 14 | true 15 | 16 | 17 | true 18 | bin\x64\Debug\ 19 | TRACE;DEBUG;WIN64 20 | full 21 | x64 22 | prompt 23 | MinimumRecommendedRules.ruleset 24 | true 25 | 26 | 27 | bin\x64\Release\ 28 | TRACE;WIN64 29 | true 30 | pdbonly 31 | x64 32 | prompt 33 | MinimumRecommendedRules.ruleset 34 | true 35 | 36 | 37 | app.manifest 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | Form 57 | 58 | 59 | Dumper.cs 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | Component 78 | 79 | 80 | Dumper.cs 81 | 82 | 83 | ResXFileCodeGenerator 84 | Resources.Designer.cs 85 | Designer 86 | 87 | 88 | True 89 | Resources.resx 90 | True 91 | 92 | 93 | 94 | SettingsSingleFileGenerator 95 | Settings.Designer.cs 96 | 97 | 98 | True 99 | Settings.settings 100 | True 101 | 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /KsDumperClient/PE/32/PE32File.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Runtime.InteropServices; 3 | 4 | using static KsDumperClient.PE.NativePEStructs; 5 | 6 | namespace KsDumperClient.PE 7 | { 8 | public class PE32File : PEFile 9 | { 10 | public DOSHeader DOSHeader { get; private set; } 11 | 12 | public byte[] DOS_Stub { get; private set; } 13 | 14 | public PE32Header PEHeader { get; private set; } 15 | 16 | public PE32File(IMAGE_DOS_HEADER dosHeader, IMAGE_NT_HEADERS32 peHeader, byte[] dosStub) 17 | { 18 | Type = PEType.PE32; 19 | DOSHeader = DOSHeader.FromNativeStruct(dosHeader); 20 | PEHeader = PE32Header.FromNativeStruct(peHeader); 21 | Sections = new PESection[peHeader.FileHeader.NumberOfSections]; 22 | DOS_Stub = dosStub; 23 | } 24 | 25 | public override void SaveToDisk(string fileName) 26 | { 27 | try 28 | { 29 | using (BinaryWriter writer = new BinaryWriter(new FileStream(fileName, FileMode.Create, FileAccess.Write))) 30 | { 31 | DOSHeader.AppendToStream(writer); 32 | writer.Write(DOS_Stub); 33 | PEHeader.AppendToStream(writer); 34 | AppendSections(writer); 35 | } 36 | } 37 | catch { } 38 | } 39 | 40 | public override int GetFirstSectionHeaderOffset() 41 | { 42 | return Marshal.OffsetOf("OptionalHeader").ToInt32() + 43 | PEHeader.FileHeader.SizeOfOptionalHeader; 44 | } 45 | 46 | public override void AlignSectionHeaders() 47 | { 48 | int newFileSize = DOSHeader.e_lfanew + 0x4 + 49 | Marshal.SizeOf() + 50 | PEHeader.FileHeader.SizeOfOptionalHeader + 51 | (PEHeader.FileHeader.NumberOfSections * Marshal.SizeOf()); 52 | 53 | OrderSectionsBy(s => s.Header.PointerToRawData); 54 | 55 | for (int i = 0; i < Sections.Length; i++) 56 | { 57 | Sections[i].Header.VirtualAddress = AlignValue(Sections[i].Header.VirtualAddress, PEHeader.OptionalHeader.SectionAlignment); 58 | Sections[i].Header.VirtualSize = AlignValue(Sections[i].Header.VirtualSize, PEHeader.OptionalHeader.SectionAlignment); 59 | Sections[i].Header.PointerToRawData = AlignValue((uint)newFileSize, PEHeader.OptionalHeader.FileAlignment); 60 | Sections[i].Header.SizeOfRawData = AlignValue((uint)Sections[i].DataSize, PEHeader.OptionalHeader.FileAlignment); 61 | 62 | newFileSize = (int)(Sections[i].Header.PointerToRawData + Sections[i].Header.SizeOfRawData); 63 | } 64 | 65 | OrderSectionsBy(s => s.Header.VirtualAddress); 66 | } 67 | 68 | public override void FixPEHeader() 69 | { 70 | PEHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0; 71 | PEHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0; 72 | 73 | for (uint i = PEHeader.OptionalHeader.NumberOfRvaAndSizes; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++) 74 | { 75 | PEHeader.OptionalHeader.DataDirectory[i].VirtualAddress = 0; 76 | PEHeader.OptionalHeader.DataDirectory[i].Size = 0; 77 | } 78 | 79 | PEHeader.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; 80 | PEHeader.FileHeader.SizeOfOptionalHeader = (ushort)Marshal.SizeOf(); 81 | FixSizeOfImage(); 82 | 83 | int size = DOSHeader.e_lfanew + 0x4 + Marshal.SizeOf(); 84 | PEHeader.OptionalHeader.SizeOfHeaders = AlignValue((uint)(size + PEHeader.FileHeader.SizeOfOptionalHeader + (PEHeader.FileHeader.NumberOfSections * Marshal.SizeOf())), PEHeader.OptionalHeader.FileAlignment); 85 | 86 | RemoveIatDirectory(); 87 | } 88 | 89 | private uint AlignValue(uint value, uint alignment) 90 | { 91 | return ((value + alignment - 1) / alignment) * alignment; 92 | } 93 | 94 | private void FixSizeOfImage() 95 | { 96 | uint lastSize = 0; 97 | 98 | for (int i = 0; i < PEHeader.FileHeader.NumberOfSections; i++) 99 | { 100 | if (Sections[i].Header.VirtualAddress + Sections[i].Header.VirtualSize > lastSize) 101 | { 102 | lastSize = Sections[i].Header.VirtualAddress + Sections[i].Header.VirtualSize; 103 | } 104 | } 105 | PEHeader.OptionalHeader.SizeOfImage = lastSize; 106 | } 107 | 108 | private void RemoveIatDirectory() 109 | { 110 | uint iatDataAddress = PEHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress; 111 | 112 | PEHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0; 113 | PEHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0; 114 | 115 | if (iatDataAddress != 0) 116 | { 117 | for (int i = 0; i < PEHeader.FileHeader.NumberOfSections; i++) 118 | { 119 | if (Sections[i].Header.VirtualAddress <= iatDataAddress && 120 | Sections[i].Header.VirtualAddress + Sections[i].Header.VirtualSize > iatDataAddress) 121 | { 122 | Sections[i].Header.Characteristics |= DataSectionFlags.MemoryRead | DataSectionFlags.MemoryWrite; 123 | } 124 | } 125 | } 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /KsDumperClient/PE/32/PE32Header.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | 4 | using static KsDumperClient.PE.NativePEStructs; 5 | 6 | namespace KsDumperClient.PE 7 | { 8 | public class PE32Header 9 | { 10 | public string Signature { get; private set; } 11 | 12 | public PE32FileHeader FileHeader { get; private set; } 13 | 14 | public PE32OptionalHeader OptionalHeader { get; private set; } 15 | 16 | 17 | public void AppendToStream(BinaryWriter writer) 18 | { 19 | writer.Write(Signature.ToCharArray()); 20 | FileHeader.AppendToStream(writer); 21 | OptionalHeader.AppendToStream(writer); 22 | } 23 | 24 | public static PE32Header FromNativeStruct(IMAGE_NT_HEADERS32 nativeStruct) 25 | { 26 | return new PE32Header 27 | { 28 | Signature = new string(nativeStruct.Signature), 29 | FileHeader = PE32FileHeader.FromNativeStruct(nativeStruct.FileHeader), 30 | OptionalHeader = PE32OptionalHeader.FromNativeStruct(nativeStruct.OptionalHeader) 31 | }; 32 | } 33 | 34 | 35 | public class PE32FileHeader 36 | { 37 | public ushort Machine { get; set; } 38 | public ushort NumberOfSections { get; set; } 39 | public uint TimeDateStamp { get; set; } 40 | public uint PointerToSymbolTable { get; set; } 41 | public uint NumberOfSymbols { get; set; } 42 | public ushort SizeOfOptionalHeader { get; set; } 43 | public ushort Characteristics { get; set; } 44 | 45 | public void AppendToStream(BinaryWriter writer) 46 | { 47 | writer.Write(Machine); 48 | writer.Write(NumberOfSections); 49 | writer.Write(TimeDateStamp); 50 | writer.Write(PointerToSymbolTable); 51 | writer.Write(NumberOfSymbols); 52 | writer.Write(SizeOfOptionalHeader); 53 | writer.Write(Characteristics); 54 | } 55 | 56 | public static PE32FileHeader FromNativeStruct(IMAGE_FILE_HEADER nativeStruct) 57 | { 58 | return new PE32FileHeader 59 | { 60 | Machine = nativeStruct.Machine, 61 | NumberOfSections = nativeStruct.NumberOfSections, 62 | TimeDateStamp = nativeStruct.TimeDateStamp, 63 | PointerToSymbolTable = nativeStruct.PointerToSymbolTable, 64 | NumberOfSymbols = nativeStruct.NumberOfSymbols, 65 | SizeOfOptionalHeader = nativeStruct.SizeOfOptionalHeader, 66 | Characteristics = nativeStruct.Characteristics 67 | }; 68 | } 69 | } 70 | 71 | public class PE32OptionalHeader 72 | { 73 | public ushort Magic { get; set; } 74 | public byte MajorLinkerVersion { get; set; } 75 | public byte MinorLinkerVersion { get; set; } 76 | public uint SizeOfCode { get; set; } 77 | public uint SizeOfInitializedData { get; set; } 78 | public uint SizeOfUninitializedData { get; set; } 79 | public uint AddressOfEntryPoint { get; set; } 80 | public uint BaseOfCode { get; set; } 81 | public uint BaseOfData { get; set; } 82 | public uint ImageBase { get; set; } 83 | public uint SectionAlignment { get; set; } 84 | public uint FileAlignment { get; set; } 85 | public ushort MajorOperatingSystemVersion { get; set; } 86 | public ushort MinorOperatingSystemVersion { get; set; } 87 | public ushort MajorImageVersion { get; set; } 88 | public ushort MinorImageVersion { get; set; } 89 | public ushort MajorSubsystemVersion { get; set; } 90 | public ushort MinorSubsystemVersion { get; set; } 91 | public uint Win32VersionValue { get; set; } 92 | public uint SizeOfImage { get; set; } 93 | public uint SizeOfHeaders { get; set; } 94 | public uint CheckSum { get; set; } 95 | public ushort Subsystem { get; set; } 96 | public ushort DllCharacteristics { get; set; } 97 | public uint SizeOfStackReserve { get; set; } 98 | public uint SizeOfStackCommit { get; set; } 99 | public uint SizeOfHeapReserve { get; set; } 100 | public uint SizeOfHeapCommit { get; set; } 101 | public uint LoaderFlags { get; set; } 102 | public uint NumberOfRvaAndSizes { get; set; } 103 | public PE32DataDirectory[] DataDirectory { get; private set; } 104 | 105 | 106 | public void AppendToStream(BinaryWriter writer) 107 | { 108 | writer.Write(Magic); 109 | writer.Write(MajorLinkerVersion); 110 | writer.Write(MinorLinkerVersion); 111 | writer.Write(SizeOfCode); 112 | writer.Write(SizeOfInitializedData); 113 | writer.Write(SizeOfUninitializedData); 114 | writer.Write(AddressOfEntryPoint); 115 | writer.Write(BaseOfCode); 116 | writer.Write(BaseOfData); 117 | writer.Write(ImageBase); 118 | writer.Write(SectionAlignment); 119 | writer.Write(FileAlignment); 120 | writer.Write(MajorOperatingSystemVersion); 121 | writer.Write(MinorOperatingSystemVersion); 122 | writer.Write(MajorImageVersion); 123 | writer.Write(MinorImageVersion); 124 | writer.Write(MajorSubsystemVersion); 125 | writer.Write(MinorSubsystemVersion); 126 | writer.Write(Win32VersionValue); 127 | writer.Write(SizeOfImage); 128 | writer.Write(SizeOfHeaders); 129 | writer.Write(CheckSum); 130 | writer.Write(Subsystem); 131 | writer.Write(DllCharacteristics); 132 | writer.Write(SizeOfStackReserve); 133 | writer.Write(SizeOfStackCommit); 134 | writer.Write(SizeOfHeapReserve); 135 | writer.Write(SizeOfHeapCommit); 136 | writer.Write(LoaderFlags); 137 | writer.Write(NumberOfRvaAndSizes); 138 | 139 | foreach (PE32DataDirectory dataDirectory in DataDirectory) 140 | { 141 | dataDirectory.AppendToStream(writer); 142 | } 143 | } 144 | 145 | public static PE32OptionalHeader FromNativeStruct(IMAGE_OPTIONAL_HEADER32 nativeStruct) 146 | { 147 | PE32DataDirectory[] directories = nativeStruct.DataDirectory.Select(d => PE32DataDirectory.FromNativeStruct(d)).ToArray(); 148 | 149 | return new PE32OptionalHeader 150 | { 151 | Magic = nativeStruct.Magic, 152 | MajorLinkerVersion = nativeStruct.MajorLinkerVersion, 153 | MinorLinkerVersion = nativeStruct.MinorLinkerVersion, 154 | SizeOfCode = nativeStruct.SizeOfCode, 155 | SizeOfInitializedData = nativeStruct.SizeOfInitializedData, 156 | SizeOfUninitializedData = nativeStruct.SizeOfUninitializedData, 157 | AddressOfEntryPoint = nativeStruct.AddressOfEntryPoint, 158 | BaseOfCode = nativeStruct.BaseOfCode, 159 | BaseOfData = nativeStruct.BaseOfData, 160 | ImageBase = nativeStruct.ImageBase, 161 | SectionAlignment = nativeStruct.SectionAlignment, 162 | FileAlignment = nativeStruct.FileAlignment, 163 | MajorOperatingSystemVersion = nativeStruct.MajorOperatingSystemVersion, 164 | MinorOperatingSystemVersion = nativeStruct.MinorOperatingSystemVersion, 165 | MajorImageVersion = nativeStruct.MajorImageVersion, 166 | MinorImageVersion = nativeStruct.MinorImageVersion, 167 | MajorSubsystemVersion = nativeStruct.MajorSubsystemVersion, 168 | MinorSubsystemVersion = nativeStruct.MinorSubsystemVersion, 169 | Win32VersionValue = nativeStruct.Win32VersionValue, 170 | SizeOfImage = nativeStruct.SizeOfImage, 171 | SizeOfHeaders = nativeStruct.SizeOfHeaders, 172 | CheckSum = nativeStruct.CheckSum, 173 | Subsystem = nativeStruct.Subsystem, 174 | DllCharacteristics = nativeStruct.DllCharacteristics, 175 | SizeOfStackReserve = nativeStruct.SizeOfStackReserve, 176 | SizeOfStackCommit = nativeStruct.SizeOfStackCommit, 177 | SizeOfHeapReserve = nativeStruct.SizeOfHeapReserve, 178 | SizeOfHeapCommit = nativeStruct.SizeOfHeapCommit, 179 | LoaderFlags = nativeStruct.LoaderFlags, 180 | NumberOfRvaAndSizes = nativeStruct.NumberOfRvaAndSizes, 181 | DataDirectory = directories 182 | }; 183 | } 184 | 185 | public class PE32DataDirectory 186 | { 187 | public uint VirtualAddress { get; set; } 188 | public uint Size { get; set; } 189 | 190 | 191 | public void AppendToStream(BinaryWriter writer) 192 | { 193 | writer.Write(VirtualAddress); 194 | writer.Write(Size); 195 | } 196 | 197 | public static PE32DataDirectory FromNativeStruct(IMAGE_DATA_DIRECTORY nativeStruct) 198 | { 199 | return new PE32DataDirectory 200 | { 201 | VirtualAddress = nativeStruct.VirtualAddress, 202 | Size = nativeStruct.Size 203 | }; 204 | } 205 | } 206 | } 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /KsDumperClient/PE/64/PE64File.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Runtime.InteropServices; 3 | 4 | using static KsDumperClient.PE.NativePEStructs; 5 | 6 | namespace KsDumperClient.PE 7 | { 8 | public class PE64File : PEFile 9 | { 10 | public DOSHeader DOSHeader { get; private set; } 11 | 12 | public byte[] DOS_Stub { get; private set; } 13 | 14 | public PE64Header PEHeader { get; private set; } 15 | 16 | public PE64File(IMAGE_DOS_HEADER dosHeader, IMAGE_NT_HEADERS64 peHeader, byte[] dosStub) 17 | { 18 | Type = PEType.PE64; 19 | DOSHeader = DOSHeader.FromNativeStruct(dosHeader); 20 | PEHeader = PE64Header.FromNativeStruct(peHeader); 21 | Sections = new PESection[peHeader.FileHeader.NumberOfSections]; 22 | DOS_Stub = dosStub; 23 | } 24 | 25 | public override void SaveToDisk(string fileName) 26 | { 27 | try 28 | { 29 | using (BinaryWriter writer = new BinaryWriter(new FileStream(fileName, FileMode.Create, FileAccess.Write))) 30 | { 31 | DOSHeader.AppendToStream(writer); 32 | writer.Write(DOS_Stub); 33 | PEHeader.AppendToStream(writer); 34 | AppendSections(writer); 35 | } 36 | } 37 | catch { } 38 | } 39 | 40 | public override int GetFirstSectionHeaderOffset() 41 | { 42 | return Marshal.OffsetOf("OptionalHeader").ToInt32() + 43 | PEHeader.FileHeader.SizeOfOptionalHeader; 44 | } 45 | 46 | public override void AlignSectionHeaders() 47 | { 48 | int newFileSize = DOSHeader.e_lfanew + 0x4 + 49 | Marshal.SizeOf() + 50 | PEHeader.FileHeader.SizeOfOptionalHeader + 51 | (PEHeader.FileHeader.NumberOfSections * Marshal.SizeOf()); 52 | 53 | OrderSectionsBy(s => s.Header.PointerToRawData); 54 | 55 | for (int i = 0; i < Sections.Length; i++) 56 | { 57 | Sections[i].Header.VirtualAddress = AlignValue(Sections[i].Header.VirtualAddress, PEHeader.OptionalHeader.SectionAlignment); 58 | Sections[i].Header.VirtualSize = AlignValue(Sections[i].Header.VirtualSize, PEHeader.OptionalHeader.SectionAlignment); 59 | Sections[i].Header.PointerToRawData = AlignValue((uint)newFileSize, PEHeader.OptionalHeader.FileAlignment); 60 | Sections[i].Header.SizeOfRawData = AlignValue((uint)Sections[i].DataSize, PEHeader.OptionalHeader.FileAlignment); 61 | 62 | newFileSize = (int)(Sections[i].Header.PointerToRawData + Sections[i].Header.SizeOfRawData); 63 | } 64 | 65 | OrderSectionsBy(s => s.Header.VirtualAddress); 66 | } 67 | 68 | public override void FixPEHeader() 69 | { 70 | PEHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0; 71 | PEHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0; 72 | 73 | for (uint i = PEHeader.OptionalHeader.NumberOfRvaAndSizes; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++) 74 | { 75 | PEHeader.OptionalHeader.DataDirectory[i].VirtualAddress = 0; 76 | PEHeader.OptionalHeader.DataDirectory[i].Size = 0; 77 | } 78 | 79 | PEHeader.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; 80 | PEHeader.FileHeader.SizeOfOptionalHeader = (ushort)Marshal.SizeOf(); 81 | FixSizeOfImage(); 82 | 83 | int size = DOSHeader.e_lfanew + 0x4 + Marshal.SizeOf(); 84 | PEHeader.OptionalHeader.SizeOfHeaders = AlignValue((uint)(size + PEHeader.FileHeader.SizeOfOptionalHeader + (PEHeader.FileHeader.NumberOfSections * Marshal.SizeOf())), PEHeader.OptionalHeader.FileAlignment); 85 | 86 | RemoveIatDirectory(); 87 | } 88 | 89 | private uint AlignValue(uint value, uint alignment) 90 | { 91 | return ((value + alignment - 1) / alignment) * alignment; 92 | } 93 | 94 | private void FixSizeOfImage() 95 | { 96 | uint lastSize = 0; 97 | 98 | for (int i = 0; i < PEHeader.FileHeader.NumberOfSections; i++) 99 | { 100 | if (Sections[i].Header.VirtualAddress + Sections[i].Header.VirtualSize > lastSize) 101 | { 102 | lastSize = Sections[i].Header.VirtualAddress + Sections[i].Header.VirtualSize; 103 | } 104 | } 105 | PEHeader.OptionalHeader.SizeOfImage = lastSize; 106 | } 107 | 108 | private void RemoveIatDirectory() 109 | { 110 | uint iatDataAddress = PEHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress; 111 | 112 | PEHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0; 113 | PEHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0; 114 | 115 | if (iatDataAddress != 0) 116 | { 117 | for (int i = 0; i < PEHeader.FileHeader.NumberOfSections; i++) 118 | { 119 | if (Sections[i].Header.VirtualAddress <= iatDataAddress && 120 | Sections[i].Header.VirtualAddress + Sections[i].Header.VirtualSize > iatDataAddress) 121 | { 122 | Sections[i].Header.Characteristics |= DataSectionFlags.MemoryRead | DataSectionFlags.MemoryWrite; 123 | } 124 | } 125 | } 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /KsDumperClient/PE/64/PE64Header.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | 4 | using static KsDumperClient.PE.NativePEStructs; 5 | 6 | namespace KsDumperClient.PE 7 | { 8 | public class PE64Header 9 | { 10 | public string Signature { get; private set; } 11 | 12 | public PE64FileHeader FileHeader { get; private set; } 13 | 14 | public PE64OptionalHeader OptionalHeader { get; private set; } 15 | 16 | 17 | public void AppendToStream(BinaryWriter writer) 18 | { 19 | writer.Write(Signature.ToCharArray()); 20 | FileHeader.AppendToStream(writer); 21 | OptionalHeader.AppendToStream(writer); 22 | } 23 | 24 | public static PE64Header FromNativeStruct(IMAGE_NT_HEADERS64 nativeStruct) 25 | { 26 | return new PE64Header 27 | { 28 | Signature = new string(nativeStruct.Signature), 29 | FileHeader = PE64FileHeader.FromNativeStruct(nativeStruct.FileHeader), 30 | OptionalHeader = PE64OptionalHeader.FromNativeStruct(nativeStruct.OptionalHeader) 31 | }; 32 | } 33 | 34 | 35 | public class PE64FileHeader 36 | { 37 | public ushort Machine { get; set; } 38 | public ushort NumberOfSections { get; set; } 39 | public uint TimeDateStamp { get; set; } 40 | public uint PointerToSymbolTable { get; set; } 41 | public uint NumberOfSymbols { get; set; } 42 | public ushort SizeOfOptionalHeader { get; set; } 43 | public ushort Characteristics { get; set; } 44 | 45 | public void AppendToStream(BinaryWriter writer) 46 | { 47 | writer.Write(Machine); 48 | writer.Write(NumberOfSections); 49 | writer.Write(TimeDateStamp); 50 | writer.Write(PointerToSymbolTable); 51 | writer.Write(NumberOfSymbols); 52 | writer.Write(SizeOfOptionalHeader); 53 | writer.Write(Characteristics); 54 | } 55 | 56 | public static PE64FileHeader FromNativeStruct(IMAGE_FILE_HEADER nativeStruct) 57 | { 58 | return new PE64FileHeader 59 | { 60 | Machine = nativeStruct.Machine, 61 | NumberOfSections = nativeStruct.NumberOfSections, 62 | TimeDateStamp = nativeStruct.TimeDateStamp, 63 | PointerToSymbolTable = nativeStruct.PointerToSymbolTable, 64 | NumberOfSymbols = nativeStruct.NumberOfSymbols, 65 | SizeOfOptionalHeader = nativeStruct.SizeOfOptionalHeader, 66 | Characteristics = nativeStruct.Characteristics 67 | }; 68 | } 69 | } 70 | 71 | public class PE64OptionalHeader 72 | { 73 | public ushort Magic { get; set; } 74 | public byte MajorLinkerVersion { get; set; } 75 | public byte MinorLinkerVersion { get; set; } 76 | public uint SizeOfCode { get; set; } 77 | public uint SizeOfInitializedData { get; set; } 78 | public uint SizeOfUninitializedData { get; set; } 79 | public uint AddressOfEntryPoint { get; set; } 80 | public uint BaseOfCode { get; set; } 81 | #if WIN32 82 | public uint BaseOfData { get; set; } 83 | public uint ImageBase { get; set; } 84 | #else 85 | public ulong ImageBase { get; set; } 86 | #endif 87 | public uint SectionAlignment { get; set; } 88 | public uint FileAlignment { get; set; } 89 | public ushort MajorOperatingSystemVersion { get; set; } 90 | public ushort MinorOperatingSystemVersion { get; set; } 91 | public ushort MajorImageVersion { get; set; } 92 | public ushort MinorImageVersion { get; set; } 93 | public ushort MajorSubsystemVersion { get; set; } 94 | public ushort MinorSubsystemVersion { get; set; } 95 | public uint Win32VersionValue { get; set; } 96 | public uint SizeOfImage { get; set; } 97 | public uint SizeOfHeaders { get; set; } 98 | public uint CheckSum { get; set; } 99 | public ushort Subsystem { get; set; } 100 | public ushort DllCharacteristics { get; set; } 101 | #if WIN32 102 | public uint SizeOfStackReserve { get; set; } 103 | public uint SizeOfStackCommit { get; set; } 104 | public uint SizeOfHeapReserve { get; set; } 105 | public uint SizeOfHeapCommit { get; set; } 106 | #else 107 | public ulong SizeOfStackReserve { get; set; } 108 | public ulong SizeOfStackCommit { get; set; } 109 | public ulong SizeOfHeapReserve { get; set; } 110 | public ulong SizeOfHeapCommit { get; set; } 111 | #endif 112 | public uint LoaderFlags { get; set; } 113 | public uint NumberOfRvaAndSizes { get; set; } 114 | public PE64DataDirectory[] DataDirectory { get; private set; } 115 | 116 | 117 | public void AppendToStream(BinaryWriter writer) 118 | { 119 | writer.Write(Magic); 120 | writer.Write(MajorLinkerVersion); 121 | writer.Write(MinorLinkerVersion); 122 | writer.Write(SizeOfCode); 123 | writer.Write(SizeOfInitializedData); 124 | writer.Write(SizeOfUninitializedData); 125 | writer.Write(AddressOfEntryPoint); 126 | writer.Write(BaseOfCode); 127 | #if WIN32 128 | writer.Write(BaseOfData); 129 | #endif 130 | writer.Write(ImageBase); 131 | writer.Write(SectionAlignment); 132 | writer.Write(FileAlignment); 133 | writer.Write(MajorOperatingSystemVersion); 134 | writer.Write(MinorOperatingSystemVersion); 135 | writer.Write(MajorImageVersion); 136 | writer.Write(MinorImageVersion); 137 | writer.Write(MajorSubsystemVersion); 138 | writer.Write(MinorSubsystemVersion); 139 | writer.Write(Win32VersionValue); 140 | writer.Write(SizeOfImage); 141 | writer.Write(SizeOfHeaders); 142 | writer.Write(CheckSum); 143 | writer.Write(Subsystem); 144 | writer.Write(DllCharacteristics); 145 | writer.Write(SizeOfStackReserve); 146 | writer.Write(SizeOfStackCommit); 147 | writer.Write(SizeOfHeapReserve); 148 | writer.Write(SizeOfHeapCommit); 149 | writer.Write(LoaderFlags); 150 | writer.Write(NumberOfRvaAndSizes); 151 | 152 | foreach (PE64DataDirectory dataDirectory in DataDirectory) 153 | { 154 | dataDirectory.AppendToStream(writer); 155 | } 156 | } 157 | 158 | public static PE64OptionalHeader FromNativeStruct(IMAGE_OPTIONAL_HEADER64 nativeStruct) 159 | { 160 | PE64DataDirectory[] directories = nativeStruct.DataDirectory.Select(d => PE64DataDirectory.FromNativeStruct(d)).ToArray(); 161 | 162 | return new PE64OptionalHeader 163 | { 164 | Magic = nativeStruct.Magic, 165 | MajorLinkerVersion = nativeStruct.MajorLinkerVersion, 166 | MinorLinkerVersion = nativeStruct.MinorLinkerVersion, 167 | SizeOfCode = nativeStruct.SizeOfCode, 168 | SizeOfInitializedData = nativeStruct.SizeOfInitializedData, 169 | SizeOfUninitializedData = nativeStruct.SizeOfUninitializedData, 170 | AddressOfEntryPoint = nativeStruct.AddressOfEntryPoint, 171 | BaseOfCode = nativeStruct.BaseOfCode, 172 | #if WIN32 173 | BaseOfData = nativeStruct.BaseOfData, 174 | #endif 175 | ImageBase = nativeStruct.ImageBase, 176 | SectionAlignment = nativeStruct.SectionAlignment, 177 | FileAlignment = nativeStruct.FileAlignment, 178 | MajorOperatingSystemVersion = nativeStruct.MajorOperatingSystemVersion, 179 | MinorOperatingSystemVersion = nativeStruct.MinorOperatingSystemVersion, 180 | MajorImageVersion = nativeStruct.MajorImageVersion, 181 | MinorImageVersion = nativeStruct.MinorImageVersion, 182 | MajorSubsystemVersion = nativeStruct.MajorSubsystemVersion, 183 | MinorSubsystemVersion = nativeStruct.MinorSubsystemVersion, 184 | Win32VersionValue = nativeStruct.Win32VersionValue, 185 | SizeOfImage = nativeStruct.SizeOfImage, 186 | SizeOfHeaders = nativeStruct.SizeOfHeaders, 187 | CheckSum = nativeStruct.CheckSum, 188 | Subsystem = nativeStruct.Subsystem, 189 | DllCharacteristics = nativeStruct.DllCharacteristics, 190 | SizeOfStackReserve = nativeStruct.SizeOfStackReserve, 191 | SizeOfStackCommit = nativeStruct.SizeOfStackCommit, 192 | SizeOfHeapReserve = nativeStruct.SizeOfHeapReserve, 193 | SizeOfHeapCommit = nativeStruct.SizeOfHeapCommit, 194 | LoaderFlags = nativeStruct.LoaderFlags, 195 | NumberOfRvaAndSizes = nativeStruct.NumberOfRvaAndSizes, 196 | DataDirectory = directories 197 | }; 198 | } 199 | 200 | public class PE64DataDirectory 201 | { 202 | public uint VirtualAddress { get; set; } 203 | public uint Size { get; set; } 204 | 205 | 206 | public void AppendToStream(BinaryWriter writer) 207 | { 208 | writer.Write(VirtualAddress); 209 | writer.Write(Size); 210 | } 211 | 212 | public static PE64DataDirectory FromNativeStruct(IMAGE_DATA_DIRECTORY nativeStruct) 213 | { 214 | return new PE64DataDirectory 215 | { 216 | VirtualAddress = nativeStruct.VirtualAddress, 217 | Size = nativeStruct.Size 218 | }; 219 | } 220 | } 221 | } 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /KsDumperClient/PE/DOSHeader.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | using static KsDumperClient.PE.NativePEStructs; 4 | 5 | namespace KsDumperClient.PE 6 | { 7 | public class DOSHeader 8 | { 9 | public string e_magic { get; set; } 10 | public ushort e_cblp { get; set; } 11 | public ushort e_cp { get; set; } 12 | public ushort e_crlc { get; set; } 13 | public ushort e_cparhdr { get; set; } 14 | public ushort e_minalloc { get; set; } 15 | public ushort e_maxalloc { get; set; } 16 | public ushort e_ss { get; set; } 17 | public ushort e_sp { get; set; } 18 | public ushort e_csum { get; set; } 19 | public ushort e_ip { get; set; } 20 | public ushort e_cs { get; set; } 21 | public ushort e_lfarlc { get; set; } 22 | public ushort e_ovno { get; set; } 23 | public ushort[] e_res1 { get; set; } 24 | public ushort e_oemid { get; set; } 25 | public ushort e_oeminfo { get; set; } 26 | public ushort[] e_res2 { get; set; } 27 | public int e_lfanew { get; set; } 28 | 29 | public void AppendToStream(BinaryWriter writer) 30 | { 31 | writer.Write(e_magic.ToCharArray()); 32 | writer.Write(e_cblp); 33 | writer.Write(e_cp); 34 | writer.Write(e_crlc); 35 | writer.Write(e_cparhdr); 36 | writer.Write(e_minalloc); 37 | writer.Write(e_maxalloc); 38 | writer.Write(e_ss); 39 | writer.Write(e_sp); 40 | writer.Write(e_csum); 41 | writer.Write(e_ip); 42 | writer.Write(e_cs); 43 | writer.Write(e_lfarlc); 44 | writer.Write(e_ovno); 45 | 46 | for (int i = 0; i < e_res1.Length; i++) 47 | { 48 | writer.Write(e_res1[i]); 49 | } 50 | writer.Write(e_oemid); 51 | writer.Write(e_oeminfo); 52 | 53 | for (int i = 0; i < e_res2.Length; i++) 54 | { 55 | writer.Write(e_res2[i]); 56 | } 57 | writer.Write(e_lfanew); 58 | } 59 | 60 | public static DOSHeader FromNativeStruct(IMAGE_DOS_HEADER nativeStruct) 61 | { 62 | return new DOSHeader 63 | { 64 | e_magic = new string(nativeStruct.e_magic), 65 | e_cblp = nativeStruct.e_cblp, 66 | e_cp = nativeStruct.e_cp, 67 | e_crlc = nativeStruct.e_crlc, 68 | e_cparhdr = nativeStruct.e_cparhdr, 69 | e_minalloc = nativeStruct.e_minalloc, 70 | e_maxalloc = nativeStruct.e_maxalloc, 71 | e_ss = nativeStruct.e_ss, 72 | e_sp = nativeStruct.e_sp, 73 | e_csum = nativeStruct.e_csum, 74 | e_ip = nativeStruct.e_ip, 75 | e_cs = nativeStruct.e_cs, 76 | e_lfarlc = nativeStruct.e_lfarlc, 77 | e_ovno = nativeStruct.e_ovno, 78 | e_res1 = nativeStruct.e_res1, 79 | e_oemid = nativeStruct.e_oemid, 80 | e_oeminfo = nativeStruct.e_oeminfo, 81 | e_res2 = nativeStruct.e_res2, 82 | e_lfanew = nativeStruct.e_lfanew 83 | }; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /KsDumperClient/PE/NativePEStructs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace KsDumperClient.PE 5 | { 6 | public static class NativePEStructs 7 | { 8 | public const uint IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b; 9 | public const uint IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b; 10 | 11 | public const uint IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; 12 | 13 | public const uint IMAGE_DIRECTORY_ENTRY_EXPORT = 0; 14 | public const uint IMAGE_DIRECTORY_ENTRY_IMPORT = 1; 15 | public const uint IMAGE_DIRECTORY_ENTRY_RESOURCE = 2; 16 | public const uint IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3; 17 | public const uint IMAGE_DIRECTORY_ENTRY_SECURITY = 4; 18 | public const uint IMAGE_DIRECTORY_ENTRY_BASERELOC = 5; 19 | public const uint IMAGE_DIRECTORY_ENTRY_DEBUG = 6; 20 | public const uint IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7; 21 | public const uint IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8; 22 | public const uint IMAGE_DIRECTORY_ENTRY_TLS = 9; 23 | public const uint IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10; 24 | public const uint IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11; 25 | public const uint IMAGE_DIRECTORY_ENTRY_IAT = 12; 26 | public const uint IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13; 27 | public const uint IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14; 28 | 29 | [StructLayout(LayoutKind.Sequential)] 30 | public struct IMAGE_DOS_HEADER 31 | { 32 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] 33 | public char[] e_magic; 34 | public ushort e_cblp; 35 | public ushort e_cp; 36 | public ushort e_crlc; 37 | public ushort e_cparhdr; 38 | public ushort e_minalloc; 39 | public ushort e_maxalloc; 40 | public ushort e_ss; 41 | public ushort e_sp; 42 | public ushort e_csum; 43 | public ushort e_ip; 44 | public ushort e_cs; 45 | public ushort e_lfarlc; 46 | public ushort e_ovno; 47 | 48 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] 49 | public ushort[] e_res1; 50 | public ushort e_oemid; 51 | public ushort e_oeminfo; 52 | 53 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] 54 | public ushort[] e_res2; 55 | public int e_lfanew; 56 | 57 | private string _e_magic 58 | { 59 | get { return new string(e_magic); } 60 | } 61 | 62 | public bool IsValid 63 | { 64 | get { return _e_magic == "MZ"; } 65 | } 66 | } 67 | 68 | [StructLayout(LayoutKind.Sequential)] 69 | public struct IMAGE_NT_HEADERS32 70 | { 71 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] 72 | public char[] Signature; 73 | 74 | public IMAGE_FILE_HEADER FileHeader; 75 | 76 | public IMAGE_OPTIONAL_HEADER32 OptionalHeader; 77 | 78 | private string _Signature 79 | { 80 | get { return new string(Signature); } 81 | } 82 | 83 | public bool IsValid 84 | { 85 | get { return _Signature == "PE\0\0" && OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC; } 86 | } 87 | } 88 | 89 | [StructLayout(LayoutKind.Sequential)] 90 | public struct IMAGE_NT_HEADERS64 91 | { 92 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] 93 | public char[] Signature; 94 | 95 | public IMAGE_FILE_HEADER FileHeader; 96 | 97 | public IMAGE_OPTIONAL_HEADER64 OptionalHeader; 98 | 99 | private string _Signature 100 | { 101 | get { return new string(Signature); } 102 | } 103 | 104 | public bool IsValid 105 | { 106 | get { return _Signature == "PE\0\0" && OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC; } 107 | } 108 | } 109 | 110 | [StructLayout(LayoutKind.Sequential)] 111 | public struct IMAGE_FILE_HEADER 112 | { 113 | internal ushort Machine; 114 | internal ushort NumberOfSections; 115 | internal uint TimeDateStamp; 116 | internal uint PointerToSymbolTable; 117 | internal uint NumberOfSymbols; 118 | internal ushort SizeOfOptionalHeader; 119 | internal ushort Characteristics; 120 | } 121 | 122 | [StructLayout(LayoutKind.Sequential)] 123 | public struct IMAGE_OPTIONAL_HEADER32 124 | { 125 | internal ushort Magic; 126 | internal byte MajorLinkerVersion; 127 | internal byte MinorLinkerVersion; 128 | internal uint SizeOfCode; 129 | internal uint SizeOfInitializedData; 130 | internal uint SizeOfUninitializedData; 131 | internal uint AddressOfEntryPoint; 132 | internal uint BaseOfCode; 133 | internal uint BaseOfData; 134 | internal uint ImageBase; 135 | internal uint SectionAlignment; 136 | internal uint FileAlignment; 137 | internal ushort MajorOperatingSystemVersion; 138 | internal ushort MinorOperatingSystemVersion; 139 | internal ushort MajorImageVersion; 140 | internal ushort MinorImageVersion; 141 | internal ushort MajorSubsystemVersion; 142 | internal ushort MinorSubsystemVersion; 143 | internal uint Win32VersionValue; 144 | internal uint SizeOfImage; 145 | internal uint SizeOfHeaders; 146 | internal uint CheckSum; 147 | internal ushort Subsystem; 148 | internal ushort DllCharacteristics; 149 | internal uint SizeOfStackReserve; 150 | internal uint SizeOfStackCommit; 151 | internal uint SizeOfHeapReserve; 152 | internal uint SizeOfHeapCommit; 153 | internal uint LoaderFlags; 154 | internal uint NumberOfRvaAndSizes; 155 | 156 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 157 | internal IMAGE_DATA_DIRECTORY[] DataDirectory; 158 | } 159 | 160 | [StructLayout(LayoutKind.Sequential)] 161 | public struct IMAGE_OPTIONAL_HEADER64 162 | { 163 | internal ushort Magic; 164 | internal byte MajorLinkerVersion; 165 | internal byte MinorLinkerVersion; 166 | internal uint SizeOfCode; 167 | internal uint SizeOfInitializedData; 168 | internal uint SizeOfUninitializedData; 169 | internal uint AddressOfEntryPoint; 170 | internal uint BaseOfCode; 171 | internal ulong ImageBase; 172 | internal uint SectionAlignment; 173 | internal uint FileAlignment; 174 | internal ushort MajorOperatingSystemVersion; 175 | internal ushort MinorOperatingSystemVersion; 176 | internal ushort MajorImageVersion; 177 | internal ushort MinorImageVersion; 178 | internal ushort MajorSubsystemVersion; 179 | internal ushort MinorSubsystemVersion; 180 | internal uint Win32VersionValue; 181 | internal uint SizeOfImage; 182 | internal uint SizeOfHeaders; 183 | internal uint CheckSum; 184 | internal ushort Subsystem; 185 | internal ushort DllCharacteristics; 186 | internal ulong SizeOfStackReserve; 187 | internal ulong SizeOfStackCommit; 188 | internal ulong SizeOfHeapReserve; 189 | internal ulong SizeOfHeapCommit; 190 | internal uint LoaderFlags; 191 | internal uint NumberOfRvaAndSizes; 192 | 193 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 194 | internal IMAGE_DATA_DIRECTORY[] DataDirectory; 195 | } 196 | 197 | [StructLayout(LayoutKind.Sequential)] 198 | public struct IMAGE_DATA_DIRECTORY 199 | { 200 | internal uint VirtualAddress; 201 | internal uint Size; 202 | } 203 | 204 | [StructLayout(LayoutKind.Sequential)] 205 | public struct IMAGE_SECTION_HEADER 206 | { 207 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] 208 | public char[] Name; 209 | 210 | public uint VirtualSize; 211 | 212 | public uint VirtualAddress; 213 | 214 | public uint SizeOfRawData; 215 | 216 | public uint PointerToRawData; 217 | 218 | public uint PointerToRelocations; 219 | 220 | public uint PointerToLinenumbers; 221 | 222 | public ushort NumberOfRelocations; 223 | 224 | public ushort NumberOfLinenumbers; 225 | 226 | public DataSectionFlags Characteristics; 227 | 228 | public string SectionName 229 | { 230 | get { return new string(Name); } 231 | } 232 | } 233 | 234 | [Flags] 235 | public enum DataSectionFlags : uint 236 | { 237 | TypeReg = 0x00000000, 238 | TypeDsect = 0x00000001, 239 | TypeNoLoad = 0x00000002, 240 | TypeGroup = 0x00000004, 241 | TypeNoPadded = 0x00000008, 242 | TypeCopy = 0x00000010, 243 | ContentCode = 0x00000020, 244 | ContentInitializedData = 0x00000040, 245 | ContentUninitializedData = 0x00000080, 246 | LinkOther = 0x00000100, 247 | LinkInfo = 0x00000200, 248 | TypeOver = 0x00000400, 249 | LinkRemove = 0x00000800, 250 | LinkComDat = 0x00001000, 251 | NoDeferSpecExceptions = 0x00004000, 252 | RelativeGP = 0x00008000, 253 | MemPurgeable = 0x00020000, 254 | Memory16Bit = 0x00020000, 255 | MemoryLocked = 0x00040000, 256 | MemoryPreload = 0x00080000, 257 | Align1Bytes = 0x00100000, 258 | Align2Bytes = 0x00200000, 259 | Align4Bytes = 0x00300000, 260 | Align8Bytes = 0x00400000, 261 | Align16Bytes = 0x00500000, 262 | Align32Bytes = 0x00600000, 263 | Align64Bytes = 0x00700000, 264 | Align128Bytes = 0x00800000, 265 | Align256Bytes = 0x00900000, 266 | Align512Bytes = 0x00A00000, 267 | Align1024Bytes = 0x00B00000, 268 | Align2048Bytes = 0x00C00000, 269 | Align4096Bytes = 0x00D00000, 270 | Align8192Bytes = 0x00E00000, 271 | LinkExtendedRelocationOverflow = 0x01000000, 272 | MemoryDiscardable = 0x02000000, 273 | MemoryNotCached = 0x04000000, 274 | MemoryNotPaged = 0x08000000, 275 | MemoryShared = 0x10000000, 276 | MemoryExecute = 0x20000000, 277 | MemoryRead = 0x40000000, 278 | MemoryWrite = 0x80000000 279 | } 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /KsDumperClient/PE/PEFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | 5 | namespace KsDumperClient.PE 6 | { 7 | public abstract class PEFile 8 | { 9 | public PEType Type { get; protected set; } 10 | 11 | public PESection[] Sections { get; protected set; } 12 | 13 | 14 | public abstract int GetFirstSectionHeaderOffset(); 15 | 16 | public abstract void AlignSectionHeaders(); 17 | 18 | public abstract void FixPEHeader(); 19 | 20 | public abstract void SaveToDisk(string fileName); 21 | 22 | protected void AppendSections(BinaryWriter writer) 23 | { 24 | foreach (var sectionHeader in Sections.Select(s => s.Header)) 25 | { 26 | sectionHeader.AppendToStream(writer); 27 | } 28 | 29 | foreach (var section in Sections) 30 | { 31 | if (section.Header.PointerToRawData > 0) 32 | { 33 | if (section.Header.PointerToRawData > writer.BaseStream.Position) 34 | { 35 | long prePaddingSize = section.Header.PointerToRawData - writer.BaseStream.Position; 36 | writer.Write(new byte[prePaddingSize]); 37 | } 38 | 39 | if (section.DataSize > 0) 40 | { 41 | writer.Write(section.Content); 42 | 43 | if (section.DataSize < section.Header.SizeOfRawData) 44 | { 45 | long postPaddingSize = section.Header.SizeOfRawData - section.DataSize; 46 | writer.Write(new byte[postPaddingSize]); 47 | } 48 | } 49 | } 50 | } 51 | } 52 | 53 | protected void OrderSectionsBy(Func orderFunction) 54 | { 55 | Sections = Sections.OrderBy(orderFunction).ToArray(); 56 | } 57 | 58 | public enum PEType 59 | { 60 | PE32, 61 | PE64 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /KsDumperClient/PE/PESection.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | using static KsDumperClient.PE.NativePEStructs; 4 | 5 | namespace KsDumperClient.PE 6 | { 7 | public class PESection 8 | { 9 | public PESectionHeader Header { get; set; } 10 | 11 | public byte[] Content { get; set; } 12 | 13 | public int InitialSize { get; set; } 14 | 15 | public int DataSize { get; set; } 16 | 17 | public class PESectionHeader 18 | { 19 | public string Name { get; set; } 20 | 21 | public uint VirtualSize { get; set; } 22 | 23 | public uint VirtualAddress { get; set; } 24 | 25 | public uint SizeOfRawData { get; set; } 26 | 27 | public uint PointerToRawData { get; set; } 28 | 29 | public uint PointerToRelocations { get; set; } 30 | 31 | public uint PointerToLinenumbers { get; set; } 32 | 33 | public ushort NumberOfRelocations { get; set; } 34 | 35 | public ushort NumberOfLinenumbers { get; set; } 36 | 37 | public DataSectionFlags Characteristics { get; set; } 38 | 39 | 40 | public void AppendToStream(BinaryWriter writer) 41 | { 42 | writer.Write(Name.ToCharArray()); 43 | writer.Write(VirtualSize); 44 | writer.Write(VirtualAddress); 45 | writer.Write(SizeOfRawData); 46 | writer.Write(PointerToRawData); 47 | writer.Write(PointerToRelocations); 48 | writer.Write(PointerToLinenumbers); 49 | writer.Write(NumberOfRelocations); 50 | writer.Write(NumberOfLinenumbers); 51 | writer.Write((uint)Characteristics); 52 | } 53 | 54 | public static PESectionHeader FromNativeStruct(IMAGE_SECTION_HEADER nativeStruct) 55 | { 56 | return new PESectionHeader 57 | { 58 | Name = nativeStruct.SectionName, 59 | VirtualSize = nativeStruct.VirtualSize, 60 | VirtualAddress = nativeStruct.VirtualAddress, 61 | SizeOfRawData = nativeStruct.SizeOfRawData, 62 | PointerToRawData = nativeStruct.PointerToRawData, 63 | PointerToRelocations = nativeStruct.PointerToRelocations, 64 | PointerToLinenumbers = nativeStruct.PointerToLinenumbers, 65 | NumberOfRelocations = nativeStruct.NumberOfRelocations, 66 | NumberOfLinenumbers = nativeStruct.NumberOfLinenumbers, 67 | Characteristics = nativeStruct.Characteristics 68 | }; 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /KsDumperClient/ProcessDumper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using KsDumperClient.Driver; 4 | using KsDumperClient.PE; 5 | using KsDumperClient.Utility; 6 | 7 | using static KsDumperClient.PE.NativePEStructs; 8 | 9 | namespace KsDumperClient 10 | { 11 | public class ProcessDumper 12 | { 13 | private DriverInterface kernelDriver; 14 | 15 | public ProcessDumper(DriverInterface kernelDriver) 16 | { 17 | this.kernelDriver = kernelDriver; 18 | } 19 | 20 | public bool DumpProcess(ProcessSummary processSummary, out PEFile outputFile) 21 | { 22 | IntPtr basePointer = (IntPtr)processSummary.MainModuleBase; 23 | IMAGE_DOS_HEADER dosHeader = ReadProcessStruct(processSummary.ProcessId, basePointer); 24 | outputFile = default(PEFile); 25 | 26 | Logger.SkipLine(); 27 | Logger.Log("Targeting Process: {0} ({1})", processSummary.ProcessName, processSummary.ProcessId); 28 | 29 | if (dosHeader.IsValid) 30 | { 31 | IntPtr peHeaderPointer = basePointer + dosHeader.e_lfanew; 32 | Logger.Log("PE Header Found: 0x{0:x8}", peHeaderPointer.ToInt64()); 33 | 34 | IntPtr dosStubPointer = basePointer + Marshal.SizeOf(); 35 | byte[] dosStub = ReadProcessBytes(processSummary.ProcessId, dosStubPointer, dosHeader.e_lfanew - Marshal.SizeOf()); 36 | 37 | PEFile peFile; 38 | 39 | if (!processSummary.IsWOW64) 40 | { 41 | peFile = Dump64BitPE(processSummary.ProcessId, dosHeader, dosStub, peHeaderPointer); 42 | } 43 | else 44 | { 45 | peFile = Dump32BitPE(processSummary.ProcessId, dosHeader, dosStub, peHeaderPointer); 46 | } 47 | 48 | if (peFile != default(PEFile)) 49 | { 50 | IntPtr sectionHeaderPointer = peHeaderPointer + peFile.GetFirstSectionHeaderOffset(); 51 | 52 | Logger.Log("Header is valid ({0}) !", peFile.Type); 53 | Logger.Log("Parsing {0} Sections...", peFile.Sections.Length); 54 | 55 | for (int i = 0; i < peFile.Sections.Length; i++) 56 | { 57 | IMAGE_SECTION_HEADER sectionHeader = ReadProcessStruct(processSummary.ProcessId, sectionHeaderPointer); 58 | peFile.Sections[i] = new PESection 59 | { 60 | Header = PESection.PESectionHeader.FromNativeStruct(sectionHeader), 61 | InitialSize = (int)sectionHeader.VirtualSize 62 | }; 63 | 64 | ReadSectionContent(processSummary.ProcessId, new IntPtr(basePointer.ToInt64() + sectionHeader.VirtualAddress), peFile.Sections[i]); 65 | sectionHeaderPointer += Marshal.SizeOf(); 66 | } 67 | 68 | Logger.Log("Aligning Sections..."); 69 | peFile.AlignSectionHeaders(); 70 | 71 | Logger.Log("Fixing PE Header..."); 72 | peFile.FixPEHeader(); 73 | 74 | Logger.Log("Dump Completed !"); 75 | outputFile = peFile; 76 | return true; 77 | } 78 | else 79 | { 80 | Logger.Log("Bad PE Header !"); 81 | } 82 | } 83 | return false; 84 | } 85 | 86 | private PEFile Dump64BitPE(int processId, IMAGE_DOS_HEADER dosHeader, byte[] dosStub, IntPtr peHeaderPointer) 87 | { 88 | IMAGE_NT_HEADERS64 peHeader = ReadProcessStruct(processId, peHeaderPointer); 89 | 90 | if (peHeader.IsValid) 91 | { 92 | return new PE64File(dosHeader, peHeader, dosStub); 93 | } 94 | return default(PEFile); 95 | } 96 | 97 | private PEFile Dump32BitPE(int processId, IMAGE_DOS_HEADER dosHeader, byte[] dosStub, IntPtr peHeaderPointer) 98 | { 99 | IMAGE_NT_HEADERS32 peHeader = ReadProcessStruct(processId, peHeaderPointer); 100 | 101 | if (peHeader.IsValid) 102 | { 103 | return new PE32File(dosHeader, peHeader, dosStub); 104 | } 105 | return default(PEFile); 106 | } 107 | 108 | private T ReadProcessStruct(int processId, IntPtr address) where T : struct 109 | { 110 | IntPtr buffer = MarshalUtility.AllocEmptyStruct(); 111 | 112 | if (kernelDriver.CopyVirtualMemory(processId, address, buffer, Marshal.SizeOf())) 113 | { 114 | return MarshalUtility.GetStructFromMemory(buffer); 115 | } 116 | return default(T); 117 | } 118 | 119 | private bool ReadSectionContent(int processId, IntPtr sectionPointer, PESection section) 120 | { 121 | const int maxReadSize = 100; 122 | int readSize = section.InitialSize; 123 | 124 | if (sectionPointer == IntPtr.Zero || readSize == 0) 125 | { 126 | return true; 127 | } 128 | 129 | if (readSize <= maxReadSize) 130 | { 131 | section.DataSize = readSize; 132 | section.Content = ReadProcessBytes(processId, sectionPointer, readSize); 133 | 134 | return true; 135 | } 136 | else 137 | { 138 | CalculateRealSectionSize(processId, sectionPointer, section); 139 | 140 | if (section.DataSize != 0) 141 | { 142 | section.Content = ReadProcessBytes(processId, sectionPointer, section.DataSize); 143 | return true; 144 | } 145 | } 146 | return false; 147 | } 148 | 149 | private byte[] ReadProcessBytes(int processId, IntPtr address, int size) 150 | { 151 | IntPtr unmanagedBytePointer = MarshalUtility.AllocZeroFilled(size); 152 | kernelDriver.CopyVirtualMemory(processId, address, unmanagedBytePointer, size); 153 | 154 | byte[] buffer = new byte[size]; 155 | Marshal.Copy(unmanagedBytePointer, buffer, 0, size); 156 | Marshal.FreeHGlobal(unmanagedBytePointer); 157 | 158 | return buffer; 159 | } 160 | 161 | private void CalculateRealSectionSize(int processId, IntPtr sectionPointer, PESection section) 162 | { 163 | const int maxReadSize = 100; 164 | int readSize = section.InitialSize; 165 | int currentReadSize = readSize % maxReadSize; 166 | 167 | if (currentReadSize == 0) 168 | { 169 | currentReadSize = maxReadSize; 170 | } 171 | IntPtr currentOffset = sectionPointer + readSize - currentReadSize; 172 | 173 | while (currentOffset.ToInt64() >= sectionPointer.ToInt64()) 174 | { 175 | byte[] buffer = ReadProcessBytes(processId, currentOffset, currentReadSize); 176 | int codeByteCount = GetInstructionByteCount(buffer); 177 | 178 | if (codeByteCount != 0) 179 | { 180 | currentOffset += codeByteCount; 181 | 182 | if (sectionPointer.ToInt64() < currentOffset.ToInt64()) 183 | { 184 | section.DataSize = (int)(currentOffset.ToInt64() - sectionPointer.ToInt64()); 185 | section.DataSize += 4; 186 | 187 | if (section.InitialSize < section.DataSize) 188 | { 189 | section.DataSize = section.InitialSize; 190 | } 191 | } 192 | break; 193 | } 194 | 195 | currentReadSize = maxReadSize; 196 | currentOffset -= currentReadSize; 197 | } 198 | } 199 | 200 | private int GetInstructionByteCount(byte[] dataBlock) 201 | { 202 | for (int i = (dataBlock.Length - 1); i >= 0; i--) 203 | { 204 | if (dataBlock[i] != 0) 205 | { 206 | return i + 1; 207 | } 208 | } 209 | return 0; 210 | } 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /KsDumperClient/ProcessSummary.cs: -------------------------------------------------------------------------------- 1 | using KsDumperClient.Utility; 2 | using System; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using System.Text; 7 | 8 | namespace KsDumperClient 9 | { 10 | public class ProcessSummary 11 | { 12 | public int ProcessId { get; private set; } 13 | public string ProcessName { get; private set; } 14 | public ulong MainModuleBase { get; private set; } 15 | public string MainModuleFileName { get; private set; } 16 | public uint MainModuleImageSize { get; private set; } 17 | public ulong MainModuleEntryPoint { get; private set; } 18 | public bool IsWOW64 { get; private set; } 19 | 20 | private ProcessSummary(int processId, ulong mainModuleBase, string mainModuleFileName, uint mainModuleImageSize, ulong mainModuleEntryPoint, bool isWOW64) 21 | { 22 | ProcessId = processId; 23 | MainModuleBase = mainModuleBase; 24 | MainModuleFileName = FixFileName(mainModuleFileName); 25 | MainModuleImageSize = mainModuleImageSize; 26 | MainModuleEntryPoint = mainModuleEntryPoint; 27 | ProcessName = Path.GetFileName(MainModuleFileName); 28 | IsWOW64 = isWOW64; 29 | } 30 | 31 | private string FixFileName(string fileName) 32 | { 33 | if (fileName.StartsWith(@"\")) 34 | { 35 | return fileName; 36 | } 37 | 38 | StringBuilder sb = new StringBuilder(256); 39 | int length = WinApi.GetLongPathName(fileName, sb, sb.Capacity); 40 | 41 | if (length > sb.Capacity) 42 | { 43 | sb.Capacity = length; 44 | length = WinApi.GetLongPathName(fileName, sb, sb.Capacity); 45 | } 46 | return sb.ToString(); 47 | } 48 | 49 | public static ProcessSummary FromStream(BinaryReader reader) 50 | { 51 | return new ProcessSummary 52 | ( 53 | reader.ReadInt32(), 54 | reader.ReadUInt64(), 55 | Encoding.Unicode.GetString(reader.ReadBytes(512)).Split('\0')[0], 56 | reader.ReadUInt32(), 57 | reader.ReadUInt64(), 58 | reader.ReadBoolean() 59 | ); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /KsDumperClient/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace KsDumperClient 5 | { 6 | static class Program 7 | { 8 | /// 9 | /// The main entry point for the application. 10 | /// 11 | [STAThread] 12 | static void Main() 13 | { 14 | Application.EnableVisualStyles(); 15 | Application.SetCompatibleTextRenderingDefault(false); 16 | Application.Run(new Dumper()); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /KsDumperClient/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("KsDumper")] 9 | [assembly: AssemblyDescription("Dump processes from kernel space !")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("KsDumper")] 13 | [assembly: AssemblyCopyright("")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("7881b99d-0b5a-44e7-af34-80a0ecffd5db")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /KsDumperClient/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace KsDumperClient.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("KsDumperClient.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /KsDumperClient/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 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 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /KsDumperClient/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace KsDumperClient.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /KsDumperClient/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /KsDumperClient/Utility/Logger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KsDumperClient.Utility 4 | { 5 | public static class Logger 6 | { 7 | public static event Action OnLog; 8 | 9 | public static void SkipLine() 10 | { 11 | if (OnLog != null) 12 | { 13 | OnLog("\n"); 14 | } 15 | else 16 | { 17 | Console.WriteLine(); 18 | } 19 | } 20 | 21 | public static void Log(string message, params object[] args) 22 | { 23 | message = string.Format("[{0}] {1}\n", DateTime.Now.ToLongTimeString(), string.Format(message, args)); 24 | 25 | if (OnLog != null) 26 | { 27 | OnLog(message); 28 | } 29 | else 30 | { 31 | Console.WriteLine(message); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /KsDumperClient/Utility/MarshalUtility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace KsDumperClient.Utility 5 | { 6 | public static class MarshalUtility 7 | { 8 | public static IntPtr CopyStructToMemory(T obj) where T : struct 9 | { 10 | IntPtr unmanagedAddress = AllocEmptyStruct(); 11 | Marshal.StructureToPtr(obj, unmanagedAddress, true); 12 | 13 | return unmanagedAddress; 14 | } 15 | 16 | public static IntPtr AllocEmptyStruct() where T : struct 17 | { 18 | int structSize = Marshal.SizeOf(); 19 | IntPtr structPointer = AllocZeroFilled(Marshal.SizeOf()); 20 | 21 | return structPointer; 22 | } 23 | 24 | public static IntPtr AllocZeroFilled(int size) 25 | { 26 | IntPtr allocatedPointer = Marshal.AllocHGlobal(size); 27 | ZeroMemory(allocatedPointer, size); 28 | 29 | return allocatedPointer; 30 | } 31 | 32 | public static void ZeroMemory(IntPtr pointer, int size) 33 | { 34 | for (int i = 0; i < size; i++) 35 | { 36 | Marshal.WriteByte(pointer + i, 0x0); 37 | } 38 | } 39 | 40 | public static T GetStructFromMemory(IntPtr unmanagedAddress, bool freeMemory = true) where T : struct 41 | { 42 | T structObj = Marshal.PtrToStructure(unmanagedAddress); 43 | 44 | if (freeMemory) 45 | { 46 | Marshal.FreeHGlobal(unmanagedAddress); 47 | } 48 | return structObj; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /KsDumperClient/Utility/ProcessListView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | using System.Windows.Forms; 6 | 7 | namespace KsDumperClient.Utility 8 | { 9 | public class ProcessListView : ListView 10 | { 11 | public bool SystemProcessesHidden { get; private set; } = true; 12 | 13 | private int sortColumnIndex = 1; 14 | private ProcessSummary[] processCache; 15 | 16 | public ProcessListView() 17 | { 18 | DoubleBuffered = true; 19 | Sorting = SortOrder.Ascending; 20 | } 21 | 22 | public void LoadProcesses(ProcessSummary[] processSummaries) 23 | { 24 | processCache = processSummaries; 25 | ReloadItems(); 26 | } 27 | 28 | public void ShowSystemProcesses() 29 | { 30 | SystemProcessesHidden = false; 31 | ReloadItems(); 32 | } 33 | 34 | public void HideSystemProcesses() 35 | { 36 | SystemProcessesHidden = true; 37 | ReloadItems(); 38 | } 39 | 40 | private void ReloadItems() 41 | { 42 | Items.Clear(); 43 | 44 | string systemRootFolder = Environment.GetFolderPath(Environment.SpecialFolder.Windows).ToLower(); 45 | 46 | foreach (ProcessSummary processSummary in processCache) 47 | { 48 | if (SystemProcessesHidden && 49 | (processSummary.MainModuleFileName.ToLower().StartsWith(systemRootFolder) || 50 | processSummary.MainModuleFileName.StartsWith(@"\"))) 51 | { 52 | continue; 53 | } 54 | 55 | ListViewItem lvi = new ListViewItem(processSummary.ProcessId.ToString()); 56 | lvi.SubItems.Add(Path.GetFileName(processSummary.MainModuleFileName)); 57 | lvi.SubItems.Add(processSummary.MainModuleFileName); 58 | lvi.SubItems.Add(string.Format("0x{0:x8}", processSummary.MainModuleBase)); 59 | lvi.SubItems.Add(string.Format("0x{0:x8}", processSummary.MainModuleEntryPoint)); 60 | lvi.SubItems.Add(string.Format("0x{0:x4}", processSummary.MainModuleImageSize)); 61 | lvi.SubItems.Add(processSummary.IsWOW64 ? "x86" : "x64"); 62 | lvi.Tag = processSummary; 63 | 64 | Items.Add(lvi); 65 | } 66 | 67 | ListViewItemSorter = new ProcessListViewItemComparer(sortColumnIndex, Sorting); 68 | Sort(); 69 | } 70 | 71 | protected override void OnColumnClick(ColumnClickEventArgs e) 72 | { 73 | if (e.Column != sortColumnIndex) 74 | { 75 | sortColumnIndex = e.Column; 76 | Sorting = SortOrder.Ascending; 77 | } 78 | else 79 | { 80 | if (Sorting == SortOrder.Ascending) 81 | { 82 | Sorting = SortOrder.Descending; 83 | } 84 | else 85 | { 86 | Sorting = SortOrder.Ascending; 87 | } 88 | } 89 | 90 | ListViewItemSorter = new ProcessListViewItemComparer(e.Column, Sorting); 91 | Sort(); 92 | } 93 | 94 | private class ProcessListViewItemComparer : IComparer 95 | { 96 | private readonly int columnIndex; 97 | private readonly SortOrder sortOrder; 98 | 99 | public ProcessListViewItemComparer(int columnIndex, SortOrder sortOrder) 100 | { 101 | this.columnIndex = columnIndex; 102 | this.sortOrder = sortOrder; 103 | } 104 | 105 | public int Compare(object x, object y) 106 | { 107 | if ((x is ListViewItem) && (y is ListViewItem)) 108 | { 109 | ProcessSummary p1 = ((ListViewItem)x).Tag as ProcessSummary; 110 | ProcessSummary p2 = ((ListViewItem)y).Tag as ProcessSummary; 111 | 112 | if (!(p1 == null || p2 == null)) 113 | { 114 | int result = 0; 115 | 116 | switch (columnIndex) 117 | { 118 | case 0: 119 | result = p1.ProcessId.CompareTo(p2.ProcessId); 120 | break; 121 | case 1: 122 | result = p1.ProcessName.CompareTo(p2.ProcessName); 123 | break; 124 | case 2: 125 | result = p1.MainModuleFileName.CompareTo(p2.MainModuleFileName); 126 | break; 127 | case 3: 128 | result = p1.MainModuleBase.CompareTo(p2.MainModuleBase); 129 | break; 130 | case 4: 131 | result = p1.MainModuleEntryPoint.CompareTo(p2.MainModuleEntryPoint); 132 | break; 133 | case 5: 134 | result = p1.MainModuleImageSize.CompareTo(p2.MainModuleImageSize); 135 | break; 136 | case 6: 137 | result = p1.IsWOW64.CompareTo(p2.IsWOW64); 138 | break; 139 | } 140 | 141 | if (sortOrder == SortOrder.Descending) 142 | { 143 | result = -result; 144 | } 145 | return result; 146 | } 147 | } 148 | return 0; 149 | } 150 | } 151 | 152 | protected override void WndProc(ref Message m) 153 | { 154 | if (m.Msg == 0x1) 155 | { 156 | SetWindowTheme(Handle, "Explorer", null); 157 | } 158 | base.WndProc(ref m); 159 | } 160 | 161 | [DllImport("uxtheme.dll", CharSet = CharSet.Unicode)] 162 | private extern static int SetWindowTheme(IntPtr hWnd, string pszSubAppName, string pszSubIdList); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /KsDumperClient/Utility/WinApi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Runtime.InteropServices; 4 | using System.Text; 5 | 6 | namespace KsDumperClient.Utility 7 | { 8 | public static class WinApi 9 | { 10 | public static readonly int FILE_DEVICE_UNKNOWN = 0x22; 11 | public static readonly int METHOD_BUFFERED = 0x0; 12 | public static readonly int FILE_ANY_ACCESS = 0x0; 13 | 14 | public static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); 15 | 16 | [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)] 17 | public static extern IntPtr CreateFileA( 18 | [MarshalAs(UnmanagedType.LPStr)] string filename, 19 | [MarshalAs(UnmanagedType.U4)] FileAccess access, 20 | [MarshalAs(UnmanagedType.U4)] FileShare share, 21 | IntPtr securityAttributes, 22 | [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, 23 | [MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes, 24 | IntPtr templateFile); 25 | 26 | [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)] 27 | public static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode, 28 | IntPtr lpInBuffer, int nInBufferSize, 29 | IntPtr lpOutBuffer, int nOutBufferSize, 30 | IntPtr lpBytesReturned, IntPtr lpOverlapped); 31 | 32 | [DllImport("kernel32.dll")] 33 | public static extern int GetLongPathName(string path, StringBuilder pszPath, int cchPath); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /KsDumperClient/app.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /KsDumperDriver/Driver.c: -------------------------------------------------------------------------------- 1 | #include "NTUndocumented.h" 2 | #include "ProcessLister.h" 3 | #include "UserModeBridge.h" 4 | #include 5 | 6 | DRIVER_INITIALIZE DriverEntry; 7 | #pragma alloc_text(INIT, DriverEntry) 8 | 9 | UNICODE_STRING deviceName, symLink; 10 | 11 | NTSTATUS CopyVirtualMemory(PEPROCESS targetProcess, PVOID sourceAddress, PVOID targetAddress, SIZE_T size) 12 | { 13 | PSIZE_T readBytes; 14 | return MmCopyVirtualMemory(targetProcess, sourceAddress, PsGetCurrentProcess(), targetAddress, size, UserMode, &readBytes); 15 | } 16 | 17 | NTSTATUS IoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) 18 | { 19 | NTSTATUS status; 20 | ULONG bytesIO = 0; 21 | PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); 22 | ULONG controlCode = stack->Parameters.DeviceIoControl.IoControlCode; 23 | 24 | if (controlCode == IO_COPY_MEMORY) 25 | { 26 | if (stack->Parameters.DeviceIoControl.InputBufferLength == sizeof(KERNEL_COPY_MEMORY_OPERATION)) 27 | { 28 | PKERNEL_COPY_MEMORY_OPERATION request = (PKERNEL_COPY_MEMORY_OPERATION)Irp->AssociatedIrp.SystemBuffer; 29 | PEPROCESS targetProcess; 30 | 31 | if (NT_SUCCESS(PsLookupProcessByProcessId(request->targetProcessId, &targetProcess))) 32 | { 33 | CopyVirtualMemory(targetProcess, request->targetAddress, request->bufferAddress, request->bufferSize); 34 | ObDereferenceObject(targetProcess); 35 | } 36 | 37 | status = STATUS_SUCCESS; 38 | bytesIO = sizeof(KERNEL_COPY_MEMORY_OPERATION); 39 | } 40 | else 41 | { 42 | status = STATUS_INFO_LENGTH_MISMATCH; 43 | bytesIO = 0; 44 | } 45 | } 46 | else if (controlCode == IO_GET_PROCESS_LIST) 47 | { 48 | if (stack->Parameters.DeviceIoControl.InputBufferLength == sizeof(KERNEL_PROCESS_LIST_OPERATION) && 49 | stack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(KERNEL_PROCESS_LIST_OPERATION)) 50 | { 51 | PKERNEL_PROCESS_LIST_OPERATION request = (PKERNEL_PROCESS_LIST_OPERATION)Irp->AssociatedIrp.SystemBuffer; 52 | 53 | GetProcessList(request->bufferAddress, request->bufferSize, &request->bufferSize, &request->processCount); 54 | 55 | status = STATUS_SUCCESS; 56 | bytesIO = sizeof(KERNEL_PROCESS_LIST_OPERATION); 57 | } 58 | else 59 | { 60 | status = STATUS_INFO_LENGTH_MISMATCH; 61 | bytesIO = 0; 62 | } 63 | } 64 | else 65 | { 66 | status = STATUS_INVALID_PARAMETER; 67 | bytesIO = 0; 68 | } 69 | 70 | Irp->IoStatus.Status = status; 71 | Irp->IoStatus.Information = bytesIO; 72 | IoCompleteRequest(Irp, IO_NO_INCREMENT); 73 | 74 | return status; 75 | } 76 | 77 | NTSTATUS UnsupportedDispatch(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp) 78 | { 79 | UNREFERENCED_PARAMETER(DeviceObject); 80 | 81 | Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 82 | IoCompleteRequest(Irp, IO_NO_INCREMENT); 83 | return Irp->IoStatus.Status; 84 | } 85 | 86 | NTSTATUS CreateDispatch(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp) 87 | { 88 | UNREFERENCED_PARAMETER(DeviceObject); 89 | 90 | IoCompleteRequest(Irp, IO_NO_INCREMENT); 91 | return Irp->IoStatus.Status; 92 | } 93 | 94 | NTSTATUS CloseDispatch(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp) 95 | { 96 | UNREFERENCED_PARAMETER(DeviceObject); 97 | 98 | IoCompleteRequest(Irp, IO_NO_INCREMENT); 99 | return Irp->IoStatus.Status; 100 | } 101 | 102 | NTSTATUS Unload(IN PDRIVER_OBJECT DriverObject) 103 | { 104 | IoDeleteSymbolicLink(&symLink); 105 | IoDeleteDevice(DriverObject->DeviceObject); 106 | } 107 | 108 | NTSTATUS DriverInitialize(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) 109 | { 110 | NTSTATUS status; 111 | PDEVICE_OBJECT deviceObject; 112 | 113 | UNREFERENCED_PARAMETER(RegistryPath); 114 | 115 | RtlInitUnicodeString(&deviceName, L"\\Device\\KsDumper"); 116 | RtlInitUnicodeString(&symLink, L"\\DosDevices\\KsDumper"); 117 | 118 | status = IoCreateDevice(DriverObject, 0, &deviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &deviceObject); 119 | 120 | if (!NT_SUCCESS(status)) 121 | { 122 | return status; 123 | } 124 | status = IoCreateSymbolicLink(&symLink, &deviceName); 125 | 126 | if (!NT_SUCCESS(status)) 127 | { 128 | IoDeleteDevice(deviceObject); 129 | return status; 130 | } 131 | deviceObject->Flags |= DO_BUFFERED_IO; 132 | 133 | for (ULONG t = 0; t <= IRP_MJ_MAXIMUM_FUNCTION; t++) 134 | DriverObject->MajorFunction[t] = &UnsupportedDispatch; 135 | 136 | DriverObject->MajorFunction[IRP_MJ_CREATE] = &CreateDispatch; 137 | DriverObject->MajorFunction[IRP_MJ_CLOSE] = &CloseDispatch; 138 | DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = &IoControl; 139 | DriverObject->DriverUnload = &Unload; 140 | deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 141 | 142 | return status; 143 | } 144 | 145 | NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) 146 | { 147 | UNREFERENCED_PARAMETER(DriverObject); 148 | UNREFERENCED_PARAMETER(RegistryPath); 149 | 150 | return IoCreateDriver(NULL, &DriverInitialize); 151 | } 152 | -------------------------------------------------------------------------------- /KsDumperDriver/KsDumperDriver.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | {8EADAB93-F111-43AF-9E10-2376AE515491} 15 | {1bc93793-694f-48fe-9372-81e2b05556fd} 16 | v4.5 17 | 12.0 18 | Debug 19 | Win32 20 | TestDriver 21 | KsDumperDriver 22 | 23 | 24 | 25 | Windows10 26 | true 27 | WindowsKernelModeDriver10.0 28 | Driver 29 | KMDF 30 | Universal 31 | 32 | 33 | Windows10 34 | false 35 | WindowsKernelModeDriver10.0 36 | Driver 37 | KMDF 38 | Universal 39 | false 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | DbgengKernelDebugger 51 | 52 | 53 | DbgengKernelDebugger 54 | 55 | 56 | 57 | 58 | false 59 | true 60 | Speed 61 | false 62 | true 63 | All 64 | true 65 | CompileAsC 66 | false 67 | false 68 | 69 | 70 | false 71 | true 72 | DriverEntry 73 | true 74 | true 75 | false 76 | 77 | 78 | 79 | 80 | false 81 | true 82 | Speed 83 | false 84 | true 85 | All 86 | true 87 | CompileAsC 88 | false 89 | false 90 | 91 | 92 | false 93 | true 94 | DriverEntry 95 | true 96 | true 97 | false 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /KsDumperDriver/KsDumperDriver.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 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | 29 | 30 | Header Files 31 | 32 | 33 | Header Files 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | -------------------------------------------------------------------------------- /KsDumperDriver/NTUndocumented.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | typedef struct _KAPC_STATE { 5 | LIST_ENTRY ApcListHead[MaximumMode]; 6 | struct _KPROCESS *Process; 7 | BOOLEAN KernelApcInProgress; 8 | BOOLEAN KernelApcPending; 9 | BOOLEAN UserApcPending; 10 | } KAPC_STATE, *PKAPC_STATE, *PRKAPC_STATE; 11 | 12 | typedef enum _SYSTEM_INFORMATION_CLASS 13 | { 14 | SystemProcessInformation = 5 15 | } SYSTEM_INFORMATION_CLASS; 16 | 17 | typedef enum _MEMORY_INFORMATION_CLASS 18 | { 19 | MemoryBasicInformation, 20 | MemoryWorkingSetInformation, 21 | MemoryMappedFilenameInformation, 22 | MemoryRegionInformation, 23 | MemoryWorkingSetExInformation 24 | 25 | } MEMORY_INFORMATION_CLASS; 26 | 27 | 28 | typedef struct _MEMORY_BASIC_INFORMATION { 29 | PVOID BaseAddress; 30 | PVOID AllocationBase; 31 | INT32 AllocationProtect; 32 | SIZE_T RegionSize; 33 | INT32 State; 34 | INT32 Protect; 35 | INT32 Type; 36 | } MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION; 37 | 38 | NTKERNELAPI NTSTATUS IoCreateDriver(IN PUNICODE_STRING DriverName, OPTIONAL IN PDRIVER_INITIALIZE InitializationFunction); 39 | 40 | NTKERNELAPI VOID KeStackAttachProcess(__inout struct _KPROCESS * PROCESS, __out PRKAPC_STATE ApcState); 41 | NTKERNELAPI VOID KeUnstackDetachProcess(__in PRKAPC_STATE ApcState); 42 | 43 | NTKERNELAPI NTSTATUS NTAPI MmCopyVirtualMemory(IN PEPROCESS FromProcess, IN PVOID FromAddress, IN PEPROCESS ToProcess, OUT PVOID ToAddress, IN SIZE_T BufferSize, IN KPROCESSOR_MODE PreviousMode, OUT PSIZE_T NumberOfBytesCopied); 44 | 45 | NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation(IN SYSTEM_INFORMATION_CLASS SystemInformationClass, OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength OPTIONAL); 46 | NTSYSAPI NTSTATUS NTAPI ZwQueryVirtualMemory(IN HANDLE ProcessHandle, IN PVOID BaseAddress, IN MEMORY_INFORMATION_CLASS MemoryInformationClass, OUT PVOID MemoryInformation, IN SIZE_T MemoryInformationLength, OUT PSIZE_T ReturnLength OPTIONAL); 47 | 48 | NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(IN HANDLE ProcessId, OUT PEPROCESS *Process); 49 | NTKERNELAPI PVOID PsGetProcessSectionBaseAddress(__in PEPROCESS Process); 50 | NTKERNELAPI PPEB NTAPI PsGetProcessPeb(IN PEPROCESS Process); -------------------------------------------------------------------------------- /KsDumperDriver/ProcessLister.c: -------------------------------------------------------------------------------- 1 | #include "NTUndocumented.h" 2 | #include "ProcessLister.h" 3 | #include "Utility.h" 4 | 5 | static PSYSTEM_PROCESS_INFORMATION GetRawProcessList() 6 | { 7 | ULONG bufferSize = 0; 8 | PVOID bufferPtr = NULL; 9 | 10 | if (ZwQuerySystemInformation(SystemProcessInformation, 0, bufferSize, &bufferSize) == STATUS_INFO_LENGTH_MISMATCH) 11 | { 12 | bufferPtr = ExAllocatePool(NonPagedPool, bufferSize); 13 | 14 | if (bufferPtr != NULL) 15 | { 16 | ZwQuerySystemInformation(SystemProcessInformation, bufferPtr, bufferSize, &bufferSize); 17 | } 18 | } 19 | return (PSYSTEM_PROCESS_INFORMATION)bufferPtr; 20 | } 21 | 22 | static ULONG CalculateProcessListOutputSize(PSYSTEM_PROCESS_INFORMATION rawProcessList) 23 | { 24 | int size = 0; 25 | 26 | while (rawProcessList->NextEntryOffset) 27 | { 28 | size += sizeof(PROCESS_SUMMARY); 29 | rawProcessList = (PSYSTEM_PROCESS_INFORMATION)(((CHAR*)rawProcessList) + rawProcessList->NextEntryOffset); 30 | } 31 | return size; 32 | } 33 | 34 | static PLDR_DATA_TABLE_ENTRY GetMainModuleDataTableEntry(PPEB64 peb) 35 | { 36 | if (SanitizeUserPointer(peb, sizeof(PEB64))) 37 | { 38 | if (peb->Ldr) 39 | { 40 | if (SanitizeUserPointer(peb->Ldr, sizeof(PEB_LDR_DATA))) 41 | { 42 | if (!peb->Ldr->Initialized) 43 | { 44 | int initLoadCount = 0; 45 | 46 | while (!peb->Ldr->Initialized && initLoadCount++ < 4) 47 | { 48 | DriverSleep(250); 49 | } 50 | } 51 | 52 | if (peb->Ldr->Initialized) 53 | { 54 | return CONTAINING_RECORD(peb->Ldr->InLoadOrderModuleList.Flink, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); 55 | } 56 | } 57 | } 58 | } 59 | return NULL; 60 | } 61 | 62 | NTSTATUS GetProcessList(PVOID listedProcessBuffer, INT32 bufferSize, PINT32 requiredBufferSize, PINT32 processCount) 63 | { 64 | PPROCESS_SUMMARY processSummary = (PPROCESS_SUMMARY)listedProcessBuffer; 65 | PSYSTEM_PROCESS_INFORMATION rawProcessList = GetRawProcessList(); 66 | PVOID listHeadPointer = rawProcessList; 67 | *processCount = 0; 68 | 69 | if (rawProcessList) 70 | { 71 | int expectedBufferSize = CalculateProcessListOutputSize(rawProcessList); 72 | 73 | if (!listedProcessBuffer || bufferSize < expectedBufferSize) 74 | { 75 | *requiredBufferSize = expectedBufferSize; 76 | return STATUS_INFO_LENGTH_MISMATCH; 77 | } 78 | 79 | while (rawProcessList->NextEntryOffset) 80 | { 81 | PEPROCESS targetProcess; 82 | PKAPC_STATE state = NULL; 83 | 84 | if (NT_SUCCESS(PsLookupProcessByProcessId(rawProcessList->UniqueProcessId, &targetProcess))) 85 | { 86 | PVOID mainModuleBase = NULL; 87 | PVOID mainModuleEntryPoint = NULL; 88 | UINT32 mainModuleImageSize = 0; 89 | PWCHAR mainModuleFileName = NULL; 90 | BOOLEAN isWow64 = 0; 91 | 92 | __try 93 | { 94 | KeStackAttachProcess(targetProcess, &state); 95 | 96 | __try 97 | { 98 | mainModuleBase = PsGetProcessSectionBaseAddress(targetProcess); 99 | 100 | if (mainModuleBase) 101 | { 102 | PPEB64 peb = (PPEB64)PsGetProcessPeb(targetProcess); 103 | 104 | if (peb) 105 | { 106 | PLDR_DATA_TABLE_ENTRY mainModuleEntry = GetMainModuleDataTableEntry(peb); 107 | mainModuleEntry = SanitizeUserPointer(mainModuleEntry, sizeof(LDR_DATA_TABLE_ENTRY)); 108 | 109 | if (mainModuleEntry) 110 | { 111 | mainModuleEntryPoint = mainModuleEntry->EntryPoint; 112 | mainModuleImageSize = mainModuleEntry->SizeOfImage; 113 | isWow64 = IS_WOW64_PE(mainModuleBase); 114 | 115 | mainModuleFileName = ExAllocatePool(NonPagedPool, 256 * sizeof(WCHAR)); 116 | RtlZeroMemory(mainModuleFileName, 256 * sizeof(WCHAR)); 117 | RtlCopyMemory(mainModuleFileName, mainModuleEntry->FullDllName.Buffer, 256 * sizeof(WCHAR)); 118 | } 119 | } 120 | } 121 | } 122 | __except (GetExceptionCode()) 123 | { 124 | DbgPrintEx(0, 0, "Peb Interaction Failed.\n"); 125 | } 126 | } 127 | __finally 128 | { 129 | KeUnstackDetachProcess(&state); 130 | } 131 | 132 | if (mainModuleFileName) 133 | { 134 | RtlCopyMemory(processSummary->MainModuleFileName, mainModuleFileName, 256 * sizeof(WCHAR)); 135 | ExFreePool(mainModuleFileName); 136 | 137 | processSummary->ProcessId = rawProcessList->UniqueProcessId; 138 | processSummary->MainModuleBase = mainModuleBase; 139 | processSummary->MainModuleEntryPoint = mainModuleEntryPoint; 140 | processSummary->MainModuleImageSize = mainModuleImageSize; 141 | processSummary->WOW64 = isWow64; 142 | 143 | processSummary++; 144 | (*processCount)++; 145 | } 146 | 147 | ObDereferenceObject(targetProcess); 148 | } 149 | 150 | rawProcessList = (PSYSTEM_PROCESS_INFORMATION)(((CHAR*)rawProcessList) + rawProcessList->NextEntryOffset); 151 | } 152 | 153 | ExFreePool(listHeadPointer); 154 | return STATUS_SUCCESS; 155 | } 156 | } -------------------------------------------------------------------------------- /KsDumperDriver/ProcessLister.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #pragma pack(push, 1) 5 | typedef struct _PROCESS_SUMMARY 6 | { 7 | INT32 ProcessId; 8 | PVOID MainModuleBase; 9 | WCHAR MainModuleFileName[256]; 10 | UINT32 MainModuleImageSize; 11 | PVOID MainModuleEntryPoint; 12 | BOOLEAN WOW64; 13 | } PROCESS_SUMMARY, *PPROCESS_SUMMARY; 14 | #pragma pack(pop) 15 | 16 | typedef struct _SYSTEM_PROCESS_INFORMATION 17 | { 18 | ULONG NextEntryOffset; 19 | ULONG NumberOfThreads; 20 | LARGE_INTEGER SpareLi1; 21 | LARGE_INTEGER SpareLi2; 22 | LARGE_INTEGER SpareLi3; 23 | LARGE_INTEGER CreateTime; 24 | LARGE_INTEGER UserTime; 25 | LARGE_INTEGER KernelTime; 26 | UNICODE_STRING ImageName; 27 | KPRIORITY BasePriority; 28 | HANDLE UniqueProcessId; 29 | HANDLE InheritedFromUniqueProcessId; 30 | ULONG HandleCount; 31 | ULONG SessionId; 32 | ULONG_PTR PageDirectoryBase; 33 | SIZE_T PeakVirtualSize; 34 | SIZE_T VirtualSize; 35 | ULONG PageFaultCount; 36 | SIZE_T PeakWorkingSetSize; 37 | SIZE_T WorkingSetSize; 38 | SIZE_T QuotaPeakPagedPoolUsage; 39 | SIZE_T QuotaPagedPoolUsage; 40 | SIZE_T QuotaPeakNonPagedPoolUsage; 41 | SIZE_T QuotaNonPagedPoolUsage; 42 | SIZE_T PagefileUsage; 43 | SIZE_T PeakPagefileUsage; 44 | SIZE_T PrivatePageCount; 45 | LARGE_INTEGER ReadOperationCount; 46 | LARGE_INTEGER WriteOperationCount; 47 | LARGE_INTEGER OtherOperationCount; 48 | LARGE_INTEGER ReadTransferCount; 49 | LARGE_INTEGER WriteTransferCount; 50 | LARGE_INTEGER OtherTransferCount; 51 | } SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION; 52 | 53 | typedef struct _LDR_DATA_TABLE_ENTRY 54 | { 55 | LIST_ENTRY InLoadOrderLinks; 56 | LIST_ENTRY InMemoryOrderLinks; 57 | CHAR Reserved0[0x10]; 58 | PVOID DllBase; 59 | PVOID EntryPoint; 60 | ULONG SizeOfImage; 61 | UNICODE_STRING FullDllName; 62 | UNICODE_STRING BaseDllName; 63 | } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; 64 | 65 | typedef struct _PEB_LDR_DATA 66 | { 67 | ULONG Length; 68 | BOOLEAN Initialized; 69 | PVOID SsHandler; 70 | LIST_ENTRY InLoadOrderModuleList; 71 | LIST_ENTRY InMemoryOrderModuleList; 72 | LIST_ENTRY InInitializationOrderModuleList; 73 | PVOID EntryInProgress; 74 | } PEB_LDR_DATA, *PPEB_LDR_DATA; 75 | 76 | typedef struct _PEB64 { 77 | CHAR Reserved[0x10]; 78 | PVOID ImageBaseAddress; 79 | PPEB_LDR_DATA Ldr; 80 | } PEB64, *PPEB64; 81 | 82 | typedef struct _IMAGE_DOS_HEADER { 83 | USHORT e_magic; 84 | USHORT e_cblp; 85 | USHORT e_cp; 86 | USHORT e_crlc; 87 | USHORT e_cparhdr; 88 | USHORT e_minalloc; 89 | USHORT e_maxalloc; 90 | USHORT e_ss; 91 | USHORT e_sp; 92 | USHORT e_csum; 93 | USHORT e_ip; 94 | USHORT e_cs; 95 | USHORT e_lfarlc; 96 | USHORT e_ovno; 97 | USHORT e_res[4]; 98 | USHORT e_oemid; 99 | USHORT e_oeminfo; 100 | USHORT e_res2[10]; 101 | LONG e_lfanew; 102 | } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; 103 | 104 | typedef struct _PE_HEADER { 105 | CHAR Signature[4]; 106 | USHORT Machine; 107 | USHORT NumberOfSections; 108 | UINT32 TimeDateStamp; 109 | UINT32 PointerToSymbolTable; 110 | UINT32 NumberOfSymbols; 111 | USHORT SizeOfOptionalHeader; 112 | USHORT Characteristics; 113 | USHORT Magic; 114 | } PE_HEADER, *PPE_HEADER; 115 | 116 | #define PE_HEADER_MAGIC_OFFSET 0x18 117 | #define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b 118 | 119 | #define IS_WOW64_PE( baseAddress ) (*((USHORT*)((CHAR *)baseAddress + \ 120 | ((PIMAGE_DOS_HEADER)baseAddress)->e_lfanew + PE_HEADER_MAGIC_OFFSET)) \ 121 | == IMAGE_NT_OPTIONAL_HDR32_MAGIC) 122 | 123 | NTSTATUS GetProcessList(PVOID listedProcessBuffer, INT32 bufferSize, PINT32 requiredBufferSize, PINT32 processCount); -------------------------------------------------------------------------------- /KsDumperDriver/UserModeBridge.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #define IO_GET_PROCESS_LIST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x1724, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) 5 | 6 | #define IO_COPY_MEMORY CTL_CODE(FILE_DEVICE_UNKNOWN, 0x1725, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) 7 | 8 | typedef struct _KERNEL_PROCESS_LIST_OPERATION 9 | { 10 | PVOID bufferAddress; 11 | INT32 bufferSize; 12 | INT32 processCount; 13 | } KERNEL_PROCESS_LIST_OPERATION, *PKERNEL_PROCESS_LIST_OPERATION; 14 | 15 | typedef struct _KERNEL_COPY_MEMORY_OPERATION 16 | { 17 | INT32 targetProcessId; 18 | PVOID targetAddress; 19 | PVOID bufferAddress; 20 | INT32 bufferSize; 21 | } KERNEL_COPY_MEMORY_OPERATION, *PKERNEL_COPY_MEMORY_OPERATION; -------------------------------------------------------------------------------- /KsDumperDriver/Utility.c: -------------------------------------------------------------------------------- 1 | #include "NTUndocumented.h" 2 | #include "Utility.h" 3 | 4 | NTSTATUS DriverSleep(int ms) 5 | { 6 | LARGE_INTEGER li; 7 | li.QuadPart = -10000; 8 | 9 | for (int i = 0; i < ms; i++) 10 | { 11 | KeDelayExecutionThread(KernelMode, FALSE, &li); 12 | return STATUS_SUCCESS; 13 | } 14 | return STATUS_UNSUCCESSFUL; 15 | } 16 | 17 | PVOID SanitizeUserPointer(PVOID pointer, SIZE_T size) 18 | { 19 | MEMORY_BASIC_INFORMATION memInfo; 20 | 21 | if (NT_SUCCESS(ZwQueryVirtualMemory(ZwCurrentProcess(), pointer, MemoryBasicInformation, &memInfo, sizeof(MEMORY_BASIC_INFORMATION), NULL))) 22 | { 23 | if (!(((uintptr_t)memInfo.BaseAddress + memInfo.RegionSize) < (((uintptr_t)pointer + size)))) 24 | { 25 | if (memInfo.State & MEM_COMMIT || !(memInfo.Protect & (PAGE_GUARD | PAGE_NOACCESS))) 26 | { 27 | if (memInfo.Protect & PAGE_EXECUTE_READWRITE || memInfo.Protect & PAGE_EXECUTE_WRITECOPY || memInfo.Protect & PAGE_READWRITE || memInfo.Protect & PAGE_WRITECOPY) 28 | { 29 | return pointer; 30 | } 31 | } 32 | } 33 | } 34 | return NULL; 35 | } 36 | -------------------------------------------------------------------------------- /KsDumperDriver/Utility.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | NTSTATUS DriverSleep(int ms); 5 | 6 | PVOID SanitizeUserPointer(PVOID pointer, SIZE_T size); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Nicolas Tremblay 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 | ## 🔴 This repo is outdated due to the Capcom driver being patched 🔴 2 | Thanks to **mastercodeon314** there's now a port working on Windows 11. Enjoy ! 3 | https://github.com/mastercodeon314/KsDumper-11 4 | 5 | # KsDumper 6 | ![Demo](https://i.imgur.com/6XyMDxa.gif) 7 | 8 | I always had an interest in reverse engineering. A few days ago I wanted to look at some game internals for fun, but it was packed & protected by EAC (EasyAntiCheat). 9 | This means its handle were stripped and I was unable to dump the process from Ring3. I decided to try to make a custom driver that would allow me to copy the process memory without using OpenProcess. 10 | I knew nothing about Windows kernel, PE file structure, so I spent a lot of time reading articles and forums to make this project. 11 | 12 | ## Features 13 | - Dump any process main module using a kernel driver (both x86 and x64) 14 | - Rebuild PE32/PE64 header and sections 15 | - Works on protected system processes & processes with stripped handles (anti-cheats) 16 | 17 | **Note**: Import table isn't rebuilt. 18 | 19 | ## Usage 20 | Before using KsDumperClient, the KsDumper driver needs to be loaded. 21 | 22 | It is unsigned so you need to load it however you want. I'm using drvmap for Win10. 23 | Everything is provided in this release if you want to use it aswell. 24 | 25 | - Run `Driver/LoadCapcom.bat` as Admin. Don't press any key or close the window yet ! 26 | - Run `Driver/LoadUnsignedDriver.bat` as Admin. 27 | - Press enter in the `LoadCapcom` cmd to unload the driver. 28 | - Run `KsDumperClient.exe`. 29 | - Profit ! 30 | 31 | **Note**: The driver stays loaded until you reboot, so if you close KsDumperClient.exe, you can just reopen it ! 32 | **Note2**: Even though it can dump both x86 & x64 processes, this has to run on x64 Windows. 33 | 34 | ## Disclaimer 35 | This project was a way for me to learn about Windows kernel, PE file structure and kernel-user space interactions. It has been made available for informational and educational purposes only. 36 | 37 | Considering the nature of this project, it is highly recommended to run it in a `Virtual Environment`. I am not responsible for any crash or damage that could happen to your system. 38 | 39 | **Important**: This tool makes no attempt at hiding itself. If you target protected games, the anti-cheat might flag this as a cheat and ban you after a while. Use a `Virtual Environment` ! 40 | 41 | ## References 42 | - https://github.com/not-wlan/drvmap 43 | - https://github.com/Zer0Mem0ry/KernelBhop 44 | - https://github.com/NtQuery/Scylla/ 45 | - http://terminus.rewolf.pl/terminus/ 46 | - https://www.unknowncheats.me/ 47 | 48 | ## Compile Yourself 49 | - Requires Visual Studio 2017 50 | - Requires Windows Driver Kit (WDK) 51 | - Requires .NET 4.6.1 52 | --------------------------------------------------------------------------------