├── .gitignore ├── .gitmodules ├── LICENSE ├── MemoryPipePlugin.sln ├── PipeServer ├── MemoryHelper.cpp ├── MessageClient.cpp ├── MessageClient.hpp ├── Messages.cpp ├── Messages.hpp ├── PipeServer.vcxproj ├── PipeServer.vcxproj.filters ├── ReClassNET_Plugin.hpp └── dllmain.cpp ├── Plugin ├── Extensions.cs ├── MemoryPipePlugin.csproj ├── MemoryPipePluginExt.CoreProcessFunctions.cs ├── MemoryPipePluginExt.cs ├── MessageClient.cs ├── Messages.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx └── Resources │ └── logo.png └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | *.pubxml 146 | *.publishproj 147 | 148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 149 | # checkin your Azure Web App publish settings, but sensitive information contained 150 | # in these scripts will be unencrypted 151 | PublishScripts/ 152 | 153 | # NuGet Packages 154 | *.nupkg 155 | # The packages folder can be ignored because of Package Restore 156 | **/packages/* 157 | # except build/, which is used as an MSBuild target. 158 | !**/packages/build/ 159 | # Uncomment if necessary however generally it will be regenerated when needed 160 | #!**/packages/repositories.config 161 | # NuGet v3's project.json files produces more ignoreable files 162 | *.nuget.props 163 | *.nuget.targets 164 | 165 | # Microsoft Azure Build Output 166 | csx/ 167 | *.build.csdef 168 | 169 | # Microsoft Azure Emulator 170 | ecf/ 171 | rcf/ 172 | 173 | # Windows Store app package directories and files 174 | AppPackages/ 175 | BundleArtifacts/ 176 | Package.StoreAssociation.xml 177 | _pkginfo.txt 178 | 179 | # Visual Studio cache files 180 | # files ending in .cache can be ignored 181 | *.[Cc]ache 182 | # but keep track of directories ending in .cache 183 | !*.[Cc]ache/ 184 | 185 | # Others 186 | ClientBin/ 187 | ~$* 188 | *~ 189 | *.dbmdl 190 | *.dbproj.schemaview 191 | *.pfx 192 | *.publishsettings 193 | node_modules/ 194 | orleans.codegen.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # JetBrains Rider 251 | .idea/ 252 | *.sln.iml 253 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "PipeServer/PipeStream"] 2 | path = PipeServer/PipeStream 3 | url = https://github.com/KN4CK3R/PipeStream 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 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 | -------------------------------------------------------------------------------- /MemoryPipePlugin.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27004.2002 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MemoryPipePlugin", "Plugin\MemoryPipePlugin.csproj", "{CA79BA0B-0D80-476A-B793-FC7EF6DCEAD8}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReClass.NET", "..\ReClass.NET\ReClass.NET\ReClass.NET.csproj", "{BFB8917D-E9B4-463F-A6E8-612C35728C78}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PipeServer", "PipeServer\PipeServer.vcxproj", "{75CAA2A9-D512-40E0-8918-B7F87806805E}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{01140249-48EF-45C1-B14E-9CC1B835F8AC}" 13 | ProjectSection(SolutionItems) = preProject 14 | README.md = README.md 15 | EndProjectSection 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|x64 = Debug|x64 20 | Debug|x86 = Debug|x86 21 | Release|x64 = Release|x64 22 | Release|x86 = Release|x86 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {CA79BA0B-0D80-476A-B793-FC7EF6DCEAD8}.Debug|x64.ActiveCfg = Debug|x64 26 | {CA79BA0B-0D80-476A-B793-FC7EF6DCEAD8}.Debug|x64.Build.0 = Debug|x64 27 | {CA79BA0B-0D80-476A-B793-FC7EF6DCEAD8}.Debug|x86.ActiveCfg = Debug|x86 28 | {CA79BA0B-0D80-476A-B793-FC7EF6DCEAD8}.Debug|x86.Build.0 = Debug|x86 29 | {CA79BA0B-0D80-476A-B793-FC7EF6DCEAD8}.Release|x64.ActiveCfg = Release|x64 30 | {CA79BA0B-0D80-476A-B793-FC7EF6DCEAD8}.Release|x64.Build.0 = Release|x64 31 | {CA79BA0B-0D80-476A-B793-FC7EF6DCEAD8}.Release|x86.ActiveCfg = Release|x86 32 | {CA79BA0B-0D80-476A-B793-FC7EF6DCEAD8}.Release|x86.Build.0 = Release|x86 33 | {BFB8917D-E9B4-463F-A6E8-612C35728C78}.Debug|x64.ActiveCfg = Debug|x64 34 | {BFB8917D-E9B4-463F-A6E8-612C35728C78}.Debug|x64.Build.0 = Debug|x64 35 | {BFB8917D-E9B4-463F-A6E8-612C35728C78}.Debug|x86.ActiveCfg = Debug|x86 36 | {BFB8917D-E9B4-463F-A6E8-612C35728C78}.Debug|x86.Build.0 = Debug|x86 37 | {BFB8917D-E9B4-463F-A6E8-612C35728C78}.Release|x64.ActiveCfg = Release|x64 38 | {BFB8917D-E9B4-463F-A6E8-612C35728C78}.Release|x64.Build.0 = Release|x64 39 | {BFB8917D-E9B4-463F-A6E8-612C35728C78}.Release|x86.ActiveCfg = Release|x86 40 | {BFB8917D-E9B4-463F-A6E8-612C35728C78}.Release|x86.Build.0 = Release|x86 41 | {75CAA2A9-D512-40E0-8918-B7F87806805E}.Debug|x64.ActiveCfg = Debug|x64 42 | {75CAA2A9-D512-40E0-8918-B7F87806805E}.Debug|x64.Build.0 = Debug|x64 43 | {75CAA2A9-D512-40E0-8918-B7F87806805E}.Debug|x86.ActiveCfg = Debug|Win32 44 | {75CAA2A9-D512-40E0-8918-B7F87806805E}.Debug|x86.Build.0 = Debug|Win32 45 | {75CAA2A9-D512-40E0-8918-B7F87806805E}.Release|x64.ActiveCfg = Release|x64 46 | {75CAA2A9-D512-40E0-8918-B7F87806805E}.Release|x64.Build.0 = Release|x64 47 | {75CAA2A9-D512-40E0-8918-B7F87806805E}.Release|x86.ActiveCfg = Release|Win32 48 | {75CAA2A9-D512-40E0-8918-B7F87806805E}.Release|x86.Build.0 = Release|Win32 49 | EndGlobalSection 50 | GlobalSection(SolutionProperties) = preSolution 51 | HideSolutionNode = FALSE 52 | EndGlobalSection 53 | GlobalSection(ExtensibilityGlobals) = postSolution 54 | SolutionGuid = {002EFECF-F8EE-4634-878A-C0DE1E00EE03} 55 | EndGlobalSection 56 | EndGlobal 57 | -------------------------------------------------------------------------------- /PipeServer/MemoryHelper.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "ReClassNET_Plugin.hpp" 9 | 10 | bool IsValidMemoryRange(LPCVOID address, int length) 11 | { 12 | const auto endAddress = static_cast(address) + length; 13 | 14 | do 15 | { 16 | MEMORY_BASIC_INFORMATION info; 17 | if (!VirtualQuery(address, &info, sizeof(MEMORY_BASIC_INFORMATION))) 18 | { 19 | return false; 20 | } 21 | 22 | if (info.State != MEM_COMMIT) 23 | { 24 | return false; 25 | } 26 | 27 | switch (info.Protect) 28 | { 29 | case PAGE_EXECUTE_READ: 30 | case PAGE_EXECUTE_READWRITE: 31 | case PAGE_EXECUTE_WRITECOPY: 32 | case PAGE_READONLY: 33 | case PAGE_READWRITE: 34 | case PAGE_WRITECOPY: 35 | break; 36 | default: 37 | return false; 38 | } 39 | 40 | address = static_cast(info.BaseAddress) + info.RegionSize; 41 | } while (endAddress > address); 42 | 43 | return true; 44 | } 45 | //--------------------------------------------------------------------------- 46 | bool ReadMemory(LPCVOID address, std::vector& buffer) 47 | { 48 | if (!IsValidMemoryRange(address, static_cast(buffer.size()))) 49 | { 50 | return false; 51 | } 52 | 53 | std::memcpy(buffer.data(), address, buffer.size()); 54 | 55 | return true; 56 | } 57 | //--------------------------------------------------------------------------- 58 | bool WriteMemory(LPVOID address, const std::vector& buffer) 59 | { 60 | if (!IsValidMemoryRange(address, static_cast(buffer.size()))) 61 | { 62 | return false; 63 | } 64 | 65 | DWORD oldProtect; 66 | if (VirtualProtect(address, buffer.size(), PAGE_EXECUTE_READWRITE, &oldProtect)) 67 | { 68 | std::memcpy(address, buffer.data(), buffer.size()); 69 | 70 | VirtualProtect(address, buffer.size(), oldProtect, nullptr); 71 | 72 | return true; 73 | } 74 | 75 | return false; 76 | } 77 | //--------------------------------------------------------------------------- 78 | void EnumerateRemoteSectionsAndModules(const std::function& moduleCallback, const std::function& sectionCallback) 79 | { 80 | std::vector sections; 81 | 82 | // First enumerate all memory sections. 83 | MEMORY_BASIC_INFORMATION memInfo = { }; 84 | memInfo.RegionSize = 0x1000; 85 | size_t address = 0; 86 | while (VirtualQuery(reinterpret_cast(address), &memInfo, sizeof(MEMORY_BASIC_INFORMATION)) != 0 && address + memInfo.RegionSize > address) 87 | { 88 | if (memInfo.State == MEM_COMMIT) 89 | { 90 | EnumerateRemoteSectionData section = {}; 91 | section.BaseAddress = memInfo.BaseAddress; 92 | section.Size = memInfo.RegionSize; 93 | 94 | switch (memInfo.Protect & 0xFF) 95 | { 96 | case PAGE_EXECUTE: 97 | section.Protection = SectionProtection::Execute; 98 | break; 99 | case PAGE_EXECUTE_READ: 100 | section.Protection = SectionProtection::Execute | SectionProtection::Read; 101 | break; 102 | case PAGE_EXECUTE_READWRITE: 103 | case PAGE_EXECUTE_WRITECOPY: 104 | section.Protection = SectionProtection::Execute | SectionProtection::Read | SectionProtection::Write; 105 | break; 106 | case PAGE_NOACCESS: 107 | section.Protection = SectionProtection::NoAccess; 108 | break; 109 | case PAGE_READONLY: 110 | section.Protection = SectionProtection::Read; 111 | break; 112 | case PAGE_READWRITE: 113 | case PAGE_WRITECOPY: 114 | section.Protection = SectionProtection::Read | SectionProtection::Write; 115 | break; 116 | } 117 | if ((memInfo.Protect & PAGE_GUARD) == PAGE_GUARD) 118 | { 119 | section.Protection |= SectionProtection::Guard; 120 | } 121 | 122 | switch (memInfo.Type) 123 | { 124 | case MEM_IMAGE: 125 | section.Type = SectionType::Image; 126 | break; 127 | case MEM_MAPPED: 128 | section.Type = SectionType::Mapped; 129 | break; 130 | case MEM_PRIVATE: 131 | section.Type = SectionType::Private; 132 | break; 133 | } 134 | 135 | section.Category = section.Type == SectionType::Private ? SectionCategory::HEAP : SectionCategory::Unknown; 136 | 137 | sections.push_back(std::move(section)); 138 | } 139 | address = reinterpret_cast(memInfo.BaseAddress) + memInfo.RegionSize; 140 | } 141 | 142 | struct UNICODE_STRING 143 | { 144 | USHORT Length; 145 | USHORT MaximumLength; 146 | PWSTR Buffer; 147 | }; 148 | 149 | struct LDR_MODULE 150 | { 151 | LIST_ENTRY InLoadOrderModuleList; 152 | LIST_ENTRY InMemoryOrderModuleList; 153 | LIST_ENTRY InInitializationOrderModuleList; 154 | PVOID BaseAddress; 155 | PVOID EntryPoint; 156 | ULONG SizeOfImage; 157 | UNICODE_STRING FullDllName; 158 | UNICODE_STRING BaseDllName; 159 | ULONG Flags; 160 | SHORT LoadCount; 161 | SHORT TlsIndex; 162 | LIST_ENTRY HashTableEntry; 163 | ULONG TimeDateStamp; 164 | }; 165 | 166 | struct PEB_LDR_DATA 167 | { 168 | ULONG Length; 169 | BOOLEAN Initialized; 170 | PVOID SsHandle; 171 | LIST_ENTRY InLoadOrderModuleList; 172 | LIST_ENTRY InMemoryOrderModuleList; 173 | LIST_ENTRY InInitializationOrderModuleList; 174 | }; 175 | 176 | struct PEB 177 | { 178 | BOOLEAN InheritedAddressSpace; 179 | BOOLEAN ReadImageFileExecOptions; 180 | BOOLEAN BeingDebugged; 181 | BOOLEAN Spare; 182 | HANDLE Mutant; 183 | PVOID ImageBaseAddress; 184 | PEB_LDR_DATA *LoaderData; 185 | }; 186 | 187 | // Second enumerate all modules. 188 | #ifdef _WIN64 189 | const auto peb = reinterpret_cast(__readgsqword(0x60)); 190 | #else 191 | const auto peb = reinterpret_cast(__readfsdword(0x30)); 192 | #endif 193 | auto ldr = reinterpret_cast(peb->LoaderData->InLoadOrderModuleList.Flink); 194 | while (ldr->BaseAddress != nullptr) 195 | { 196 | moduleCallback(static_cast(ldr->BaseAddress), reinterpret_cast(static_cast(ldr->SizeOfImage)), ldr->FullDllName.Buffer); 197 | 198 | const auto it = std::lower_bound(std::begin(sections), std::end(sections), ldr->BaseAddress, [§ions](const auto& lhs, const LPVOID& rhs) 199 | { 200 | return lhs.BaseAddress < rhs; 201 | }); 202 | 203 | const auto dosHeader = reinterpret_cast(ldr->BaseAddress); 204 | const auto ntHeader = reinterpret_cast(reinterpret_cast(ldr->BaseAddress) + dosHeader->e_lfanew); 205 | 206 | int i = 0; 207 | for (auto sectionHeader = IMAGE_FIRST_SECTION(ntHeader); i < ntHeader->FileHeader.NumberOfSections; i++, sectionHeader++) 208 | { 209 | const auto sectionAddress = reinterpret_cast(ldr->BaseAddress) + static_cast(sectionHeader->VirtualAddress); 210 | for (auto j = it; j != std::end(sections); ++j) 211 | { 212 | if (sectionAddress >= reinterpret_cast(j->BaseAddress) && sectionAddress < reinterpret_cast(j->BaseAddress) + static_cast(j->Size)) 213 | { 214 | // Copy the name because it is not null padded. 215 | char buffer[IMAGE_SIZEOF_SHORT_NAME + 1] = { 0 }; 216 | std::memcpy(buffer, sectionHeader->Name, IMAGE_SIZEOF_SHORT_NAME); 217 | 218 | if (std::strcmp(buffer, ".text") == 0 || std::strcmp(buffer, "code") == 0) 219 | { 220 | j->Category = SectionCategory::CODE; 221 | } 222 | else if (std::strcmp(buffer, ".data") == 0 || std::strcmp(buffer, "data") == 0 || std::strcmp(buffer, ".rdata") == 0 || std::strcmp(buffer, ".idata") == 0) 223 | { 224 | j->Category = SectionCategory::DATA; 225 | } 226 | 227 | size_t convertedChars = 0; 228 | mbstowcs_s(&convertedChars, j->Name, IMAGE_SIZEOF_SHORT_NAME, buffer, _TRUNCATE); 229 | std::memcpy(j->ModulePath, ldr->FullDllName.Buffer, sizeof(EnumerateRemoteSectionData::ModulePath)); 230 | break; 231 | } 232 | } 233 | } 234 | 235 | ldr = reinterpret_cast(ldr->InLoadOrderModuleList.Flink); 236 | } 237 | 238 | for (auto&& section : sections) 239 | { 240 | sectionCallback(section.BaseAddress, reinterpret_cast(section.Size), section.Type, section.Category, section.Protection, section.Name, section.ModulePath); 241 | } 242 | } 243 | //--------------------------------------------------------------------------- 244 | -------------------------------------------------------------------------------- /PipeServer/MessageClient.cpp: -------------------------------------------------------------------------------- 1 | #include "MessageClient.hpp" 2 | #include "PipeStream/MemoryStream.hpp" 3 | 4 | MessageClient::MessageClient(PipeStream& _pipe) 5 | : pipe(_pipe) 6 | { 7 | 8 | } 9 | //--------------------------------------------------------------------------- 10 | std::unique_ptr MessageClient::Receive() 11 | { 12 | MemoryStream ms; 13 | std::vector buffer(256); 14 | do 15 | { 16 | const auto length = pipe.Read(buffer.data(), 0, static_cast(buffer.size())); 17 | ms.Write(buffer.data(), 0, length); 18 | } while (!pipe.IsMessageComplete()); 19 | 20 | ms.SetPosition(0); 21 | 22 | BinaryReader br(ms); 23 | const auto type = static_cast(br.ReadInt32()); 24 | 25 | const auto it = registeredMessages.find(type); 26 | if (it != std::end(registeredMessages)) 27 | { 28 | auto message = it->second(); 29 | message->ReadFrom(br); 30 | 31 | return message; 32 | } 33 | 34 | return nullptr; 35 | } 36 | //--------------------------------------------------------------------------- 37 | void MessageClient::Send(const IMessage& message) const 38 | { 39 | MemoryStream ms; 40 | BinaryWriter bw(ms); 41 | 42 | bw.Write(static_cast(message.GetMessageType())); 43 | message.WriteTo(bw); 44 | 45 | auto data = ms.ToArray(); 46 | pipe.Write(data.data(), 0, static_cast(data.size())); 47 | } 48 | //--------------------------------------------------------------------------- 49 | -------------------------------------------------------------------------------- /PipeServer/MessageClient.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "PipeStream/PipeStream.hpp" 8 | #include "Messages.hpp" 9 | 10 | class MessageClient 11 | { 12 | public: 13 | explicit MessageClient(PipeStream& pipe); 14 | 15 | template 16 | void RegisterMessage() 17 | { 18 | const auto messageCreator = []() { return std::make_unique(); }; 19 | 20 | registeredMessages[messageCreator()->GetMessageType()] = messageCreator; 21 | } 22 | 23 | std::unique_ptr Receive(); 24 | 25 | void Send(const IMessage& message) const; 26 | 27 | private: 28 | PipeStream& pipe; 29 | 30 | std::unordered_map()>> registeredMessages; 31 | }; 32 | -------------------------------------------------------------------------------- /PipeServer/Messages.cpp: -------------------------------------------------------------------------------- 1 | #include "Messages.hpp" 2 | #include "MessageClient.hpp" 3 | 4 | extern bool ReadMemory(LPCVOID, std::vector&); 5 | extern bool WriteMemory(LPVOID, const std::vector&); 6 | extern void EnumerateRemoteSectionsAndModules(const std::function&, const std::function&); 7 | 8 | bool OpenProcessRequest::Handle(MessageClient& client) 9 | { 10 | client.Send(StatusResponse(true)); 11 | 12 | return true; 13 | } 14 | //--------------------------------------------------------------------------- 15 | bool CloseProcessRequest::Handle(MessageClient& client) 16 | { 17 | client.Send(StatusResponse(true)); 18 | 19 | return false; 20 | } 21 | //--------------------------------------------------------------------------- 22 | bool IsValidRequest::Handle(MessageClient& client) 23 | { 24 | client.Send(StatusResponse(true)); 25 | 26 | return true; 27 | } 28 | //--------------------------------------------------------------------------- 29 | bool ReadMemoryRequest::Handle(MessageClient& client) 30 | { 31 | std::vector buffer(GetSize()); 32 | buffer.resize(GetSize()); 33 | 34 | if (ReadMemory(GetAddress(), buffer)) 35 | { 36 | client.Send(ReadMemoryResponse(std::move(buffer))); 37 | } 38 | else 39 | { 40 | client.Send(StatusResponse(false)); 41 | } 42 | 43 | return true; 44 | } 45 | //--------------------------------------------------------------------------- 46 | bool WriteMemoryRequest::Handle(MessageClient& client) 47 | { 48 | const auto success = WriteMemory(const_cast(GetAddress()), GetData()); 49 | 50 | client.Send(StatusResponse(success)); 51 | 52 | return true; 53 | } 54 | //--------------------------------------------------------------------------- 55 | bool EnumerateRemoteSectionsAndModulesRequest::Handle(MessageClient& client) 56 | { 57 | EnumerateRemoteSectionsAndModules( 58 | [&](auto p1, auto p2, auto p3) { client.Send(EnumerateRemoteModuleResponse(p1, p2, std::move(p3))); }, 59 | [&](auto p1, auto p2, auto p3, auto p4, auto p5, auto p6, auto p7) { client.Send(EnumerateRemoteSectionResponse(p1, p2, p3, p4, p5, std::move(p6), std::move(p7))); } 60 | ); 61 | 62 | // Report enumeration complete to client. 63 | client.Send(StatusResponse(true)); 64 | 65 | return true; 66 | } 67 | //--------------------------------------------------------------------------- 68 | -------------------------------------------------------------------------------- /PipeServer/Messages.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "ReClassNET_Plugin.hpp" 6 | 7 | #include "PipeStream/BinaryReader.hpp" 8 | #include "PipeStream/BinaryWriter.hpp" 9 | 10 | class MessageClient; 11 | 12 | enum class MessageType 13 | { 14 | StatusResponse = 1, 15 | OpenProcessRequest = 2, 16 | CloseProcessRequest = 3, 17 | IsValidRequest = 4, 18 | ReadMemoryRequest = 5, 19 | ReadMemoryResponse = 6, 20 | WriteMemoryRequest = 7, 21 | EnumerateRemoteSectionsAndModulesRequest = 8, 22 | EnumerateRemoteSectionResponse = 9, 23 | EnumerateRemoteModuleResponse = 10, 24 | EnumerateProcessHandlesRequest = 11, 25 | EnumerateProcessHandlesResponse = 12, 26 | ClosePipeRequest = 13 27 | }; 28 | //--------------------------------------------------------------------------- 29 | class IMessage 30 | { 31 | public: 32 | virtual ~IMessage() = default; 33 | 34 | virtual MessageType GetMessageType() const = 0; 35 | 36 | virtual void ReadFrom(BinaryReader& br) = 0; 37 | virtual void WriteTo(BinaryWriter& bw) const = 0; 38 | 39 | virtual bool Handle(MessageClient& client) 40 | { 41 | return true; 42 | } 43 | }; 44 | //--------------------------------------------------------------------------- 45 | class StatusResponse : public IMessage 46 | { 47 | public: 48 | MessageType GetMessageType() const override { return MessageType::StatusResponse; } 49 | 50 | bool GetSuccess() const { return success; } 51 | 52 | StatusResponse() 53 | : success(false) 54 | { 55 | 56 | } 57 | 58 | StatusResponse(bool _success) 59 | : success(_success) 60 | { 61 | 62 | } 63 | 64 | void ReadFrom(BinaryReader& reader) override 65 | { 66 | success = reader.ReadBoolean(); 67 | } 68 | 69 | void WriteTo(BinaryWriter& writer) const override 70 | { 71 | writer.Write(success); 72 | } 73 | 74 | private: 75 | bool success; 76 | }; 77 | //--------------------------------------------------------------------------- 78 | class OpenProcessRequest : public IMessage 79 | { 80 | public: 81 | MessageType GetMessageType() const override { return MessageType::OpenProcessRequest; } 82 | 83 | void ReadFrom(BinaryReader& reader) override 84 | { 85 | 86 | } 87 | 88 | void WriteTo(BinaryWriter& writer) const override 89 | { 90 | 91 | } 92 | 93 | bool Handle(MessageClient& client) override; 94 | }; 95 | //--------------------------------------------------------------------------- 96 | class CloseProcessRequest : public IMessage 97 | { 98 | public: 99 | MessageType GetMessageType() const override { return MessageType::CloseProcessRequest; } 100 | 101 | void ReadFrom(BinaryReader& reader) override 102 | { 103 | 104 | } 105 | 106 | void WriteTo(BinaryWriter& writer) const override 107 | { 108 | 109 | } 110 | 111 | bool Handle(MessageClient& client) override; 112 | }; 113 | //--------------------------------------------------------------------------- 114 | class IsValidRequest : public IMessage 115 | { 116 | public: 117 | MessageType GetMessageType() const override { return MessageType::IsValidRequest; } 118 | 119 | void ReadFrom(BinaryReader& reader) override 120 | { 121 | 122 | } 123 | 124 | void WriteTo(BinaryWriter& writer) const override 125 | { 126 | 127 | } 128 | 129 | bool Handle(MessageClient& client) override; 130 | }; 131 | //--------------------------------------------------------------------------- 132 | class ReadMemoryRequest : public IMessage 133 | { 134 | public: 135 | MessageType GetMessageType() const override { return MessageType::ReadMemoryRequest; } 136 | 137 | const void* GetAddress() const { return address; } 138 | int GetSize() const { return size; } 139 | 140 | ReadMemoryRequest() 141 | : address(nullptr), 142 | size(0) 143 | { 144 | 145 | } 146 | 147 | ReadMemoryRequest(const void* _address, int _size) 148 | : address(_address), 149 | size(_size) 150 | { 151 | 152 | } 153 | 154 | void ReadFrom(BinaryReader& reader) override 155 | { 156 | address = reader.ReadIntPtr(); 157 | size = reader.ReadInt32(); 158 | } 159 | 160 | void WriteTo(BinaryWriter& writer) const override 161 | { 162 | writer.Write(address); 163 | writer.Write(size); 164 | } 165 | 166 | bool Handle(MessageClient& client) override; 167 | 168 | private: 169 | const void* address; 170 | int size; 171 | }; 172 | //--------------------------------------------------------------------------- 173 | class ReadMemoryResponse : public IMessage 174 | { 175 | public: 176 | MessageType GetMessageType() const override { return MessageType::ReadMemoryResponse; } 177 | 178 | const std::vector& GetData() const { return data; } 179 | 180 | ReadMemoryResponse() 181 | { 182 | 183 | } 184 | 185 | ReadMemoryResponse(std::vector&& _data) 186 | : data(std::move(_data)) 187 | { 188 | 189 | } 190 | 191 | void ReadFrom(BinaryReader& reader) override 192 | { 193 | const auto size = reader.ReadInt32(); 194 | data = reader.ReadBytes(size); 195 | } 196 | 197 | void WriteTo(BinaryWriter& writer) const override 198 | { 199 | writer.Write(static_cast(data.size())); 200 | writer.Write(data.data(), 0, static_cast(data.size())); 201 | } 202 | 203 | private: 204 | std::vector data; 205 | }; 206 | //--------------------------------------------------------------------------- 207 | class WriteMemoryRequest : public IMessage 208 | { 209 | public: 210 | MessageType GetMessageType() const override { return MessageType::WriteMemoryRequest; } 211 | 212 | const void* GetAddress() const { return address; } 213 | const std::vector& GetData() const { return data; } 214 | 215 | WriteMemoryRequest() 216 | : address(nullptr) 217 | { 218 | 219 | } 220 | 221 | WriteMemoryRequest(const void* _address, std::vector&& _data) 222 | : address(_address), 223 | data(std::move(_data)) 224 | { 225 | 226 | } 227 | 228 | void ReadFrom(BinaryReader& reader) override 229 | { 230 | address = reader.ReadIntPtr(); 231 | const auto size = reader.ReadInt32(); 232 | data = reader.ReadBytes(size); 233 | } 234 | 235 | void WriteTo(BinaryWriter& writer) const override 236 | { 237 | writer.Write(address); 238 | writer.Write(static_cast(data.size())); 239 | writer.Write(data.data(), 0, static_cast(data.size())); 240 | } 241 | 242 | bool Handle(MessageClient& client) override; 243 | 244 | private: 245 | const void* address; 246 | std::vector data; 247 | }; 248 | //--------------------------------------------------------------------------- 249 | class EnumerateRemoteSectionsAndModulesRequest : public IMessage 250 | { 251 | public: 252 | MessageType GetMessageType() const override { return MessageType::EnumerateRemoteSectionsAndModulesRequest; } 253 | 254 | void ReadFrom(BinaryReader& reader) override 255 | { 256 | 257 | } 258 | 259 | void WriteTo(BinaryWriter& writer) const override 260 | { 261 | 262 | } 263 | 264 | bool Handle(MessageClient& client) override; 265 | }; 266 | //--------------------------------------------------------------------------- 267 | class EnumerateRemoteSectionResponse : public IMessage 268 | { 269 | public: 270 | MessageType GetMessageType() const override { return MessageType::EnumerateRemoteSectionResponse; } 271 | 272 | RC_Pointer GetBaseAddress() const { return baseAddress; } 273 | RC_Pointer GetRegionSize() const { return size; } 274 | SectionType GetType() const { return type; } 275 | SectionCategory GetCategory() const { return category; } 276 | SectionProtection GetProtection() const { return protection; } 277 | const std::wstring& GetName() const { return name; } 278 | const std::wstring& GetModulePath() const { return modulePath; } 279 | 280 | EnumerateRemoteSectionResponse() 281 | : baseAddress(nullptr), 282 | size(nullptr), 283 | type(SectionType::Unknown), 284 | category(SectionCategory::Unknown), 285 | protection(SectionProtection::NoAccess) 286 | { 287 | 288 | } 289 | 290 | EnumerateRemoteSectionResponse(RC_Pointer _baseAddress, RC_Pointer _size, SectionType _type, SectionCategory _category, SectionProtection _protection, std::wstring&& _name, std::wstring&& _modulePath) 291 | : baseAddress(_baseAddress), 292 | size(_size), 293 | type(_type), 294 | category(_category), 295 | protection(_protection), 296 | name(std::move(_name)), 297 | modulePath(std::move(_modulePath)) 298 | { 299 | 300 | } 301 | 302 | void ReadFrom(BinaryReader& reader) override 303 | { 304 | baseAddress = reader.ReadIntPtr(); 305 | size = reader.ReadIntPtr(); 306 | type = static_cast(reader.ReadInt32()); 307 | category = static_cast(reader.ReadInt32()); 308 | protection = static_cast(reader.ReadInt32()); 309 | name = reader.ReadString(); 310 | modulePath = reader.ReadString(); 311 | } 312 | 313 | void WriteTo(BinaryWriter& writer) const override 314 | { 315 | writer.Write(baseAddress); 316 | writer.Write(size); 317 | writer.Write(static_cast(type)); 318 | writer.Write(static_cast(category)); 319 | writer.Write(static_cast(protection)); 320 | writer.Write(name); 321 | writer.Write(modulePath); 322 | } 323 | 324 | private: 325 | RC_Pointer baseAddress; 326 | RC_Pointer size; 327 | SectionType type; 328 | SectionCategory category; 329 | SectionProtection protection; 330 | std::wstring name; 331 | std::wstring modulePath; 332 | }; 333 | //--------------------------------------------------------------------------- 334 | class EnumerateRemoteModuleResponse : public IMessage 335 | { 336 | public: 337 | MessageType GetMessageType() const override { return MessageType::EnumerateRemoteModuleResponse; } 338 | 339 | const void* GetBaseAddress() const { return baseAddress; } 340 | const void* GetRegionSize() const { return size; } 341 | const std::wstring& GetModulePath() const { return modulePath; } 342 | 343 | EnumerateRemoteModuleResponse() 344 | : baseAddress(nullptr), 345 | size(nullptr) 346 | { 347 | 348 | } 349 | 350 | EnumerateRemoteModuleResponse(const void* _baseAddress, const void* _regionSize, std::wstring&& _modulePath) 351 | : baseAddress(_baseAddress), 352 | size(_regionSize), 353 | modulePath(std::move(_modulePath)) 354 | { 355 | 356 | } 357 | 358 | void ReadFrom(BinaryReader& reader) override 359 | { 360 | baseAddress = reader.ReadIntPtr(); 361 | size = reader.ReadIntPtr(); 362 | modulePath = reader.ReadString(); 363 | } 364 | 365 | void WriteTo(BinaryWriter& writer) const override 366 | { 367 | writer.Write(baseAddress); 368 | writer.Write(size); 369 | writer.Write(modulePath); 370 | } 371 | 372 | private: 373 | const void* baseAddress; 374 | const void* size; 375 | std::wstring modulePath; 376 | }; 377 | //--------------------------------------------------------------------------- 378 | -------------------------------------------------------------------------------- /PipeServer/PipeServer.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {75CAA2A9-D512-40E0-8918-B7F87806805E} 23 | Win32Proj 24 | PipeServer 25 | 10.0 26 | 27 | 28 | 29 | DynamicLibrary 30 | true 31 | v142 32 | Unicode 33 | 34 | 35 | DynamicLibrary 36 | false 37 | v142 38 | true 39 | Unicode 40 | 41 | 42 | DynamicLibrary 43 | true 44 | v142 45 | Unicode 46 | 47 | 48 | DynamicLibrary 49 | false 50 | v142 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | $(SolutionDir)\bin\$(Configuration)\x86\ 75 | 76 | 77 | true 78 | $(SolutionDir)\bin\$(Configuration)\x64\ 79 | 80 | 81 | false 82 | $(SolutionDir)\bin\$(Configuration)\x86\ 83 | 84 | 85 | false 86 | $(SolutionDir)\bin\$(Configuration)\x64\ 87 | 88 | 89 | 90 | 91 | 92 | Level3 93 | Disabled 94 | WIN32;_DEBUG;_WINDOWS;_USRDLL;PIPESERVER_EXPORTS;%(PreprocessorDefinitions) 95 | 96 | 97 | Windows 98 | true 99 | 100 | 101 | 102 | 103 | 104 | 105 | Level3 106 | Disabled 107 | _DEBUG;_WINDOWS;_USRDLL;PIPESERVER_EXPORTS;%(PreprocessorDefinitions) 108 | 109 | 110 | Windows 111 | true 112 | 113 | 114 | 115 | 116 | Level3 117 | 118 | 119 | MaxSpeed 120 | true 121 | true 122 | WIN32;NDEBUG;_WINDOWS;_USRDLL;PIPESERVER_EXPORTS;%(PreprocessorDefinitions) 123 | 124 | 125 | Windows 126 | true 127 | true 128 | true 129 | 130 | 131 | 132 | 133 | Level3 134 | 135 | 136 | MaxSpeed 137 | true 138 | true 139 | NDEBUG;_WINDOWS;_USRDLL;PIPESERVER_EXPORTS;%(PreprocessorDefinitions) 140 | 141 | 142 | Windows 143 | true 144 | true 145 | true 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /PipeServer/PipeServer.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | PipeStream 10 | 11 | 12 | PipeStream 13 | 14 | 15 | PipeStream 16 | 17 | 18 | PipeStream 19 | 20 | 21 | PipeStream 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | PipeStream 30 | 31 | 32 | PipeStream 33 | 34 | 35 | PipeStream 36 | 37 | 38 | PipeStream 39 | 40 | 41 | PipeStream 42 | 43 | 44 | PipeStream 45 | 46 | 47 | PipeStream 48 | 49 | 50 | PipeStream 51 | 52 | 53 | 54 | 55 | {1e4c323a-61da-425f-b676-5d1d35f0a94e} 56 | 57 | 58 | -------------------------------------------------------------------------------- /PipeServer/ReClassNET_Plugin.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | // Types 7 | 8 | using RC_Pointer = void*; 9 | using RC_Size = size_t; 10 | using RC_UnicodeChar = wchar_t; 11 | 12 | // Constants 13 | 14 | const int PATH_MAXIMUM_LENGTH = 260; 15 | 16 | // Enumerations 17 | 18 | enum class ProcessAccess 19 | { 20 | Read, 21 | Write, 22 | Full 23 | }; 24 | 25 | enum class SectionProtection 26 | { 27 | NoAccess = 0, 28 | 29 | Read = 1, 30 | Write = 2, 31 | Execute = 4, 32 | 33 | Guard = 8 34 | }; 35 | 36 | inline SectionProtection operator|(SectionProtection lhs, SectionProtection rhs) 37 | { 38 | using T = std::underlying_type_t; 39 | 40 | return static_cast(static_cast(lhs) | static_cast(rhs)); 41 | } 42 | 43 | inline SectionProtection& operator|=(SectionProtection& lhs, SectionProtection rhs) 44 | { 45 | using T = std::underlying_type_t; 46 | 47 | lhs = static_cast(static_cast(lhs) | static_cast(rhs)); 48 | 49 | return lhs; 50 | } 51 | 52 | enum class SectionType 53 | { 54 | Unknown, 55 | 56 | Private, 57 | Mapped, 58 | Image 59 | }; 60 | 61 | enum class SectionCategory 62 | { 63 | Unknown, 64 | CODE, 65 | DATA, 66 | HEAP 67 | }; 68 | 69 | enum class ControlRemoteProcessAction 70 | { 71 | Suspend, 72 | Resume, 73 | Terminate 74 | }; 75 | 76 | enum class DebugContinueStatus 77 | { 78 | Handled, 79 | NotHandled 80 | }; 81 | 82 | enum class HardwareBreakpointRegister 83 | { 84 | InvalidRegister, 85 | 86 | Dr0, 87 | Dr1, 88 | Dr2, 89 | Dr3 90 | }; 91 | 92 | enum class HardwareBreakpointTrigger 93 | { 94 | Execute, 95 | Access, 96 | Write, 97 | }; 98 | 99 | enum class HardwareBreakpointSize 100 | { 101 | Size1 = 1, 102 | Size2 = 2, 103 | Size4 = 4, 104 | Size8 = 8 105 | }; 106 | 107 | enum class DebugEventType 108 | { 109 | CreateProcess, 110 | ExitProcess, 111 | CreateThread, 112 | ExitThread, 113 | LoadDll, 114 | UnloadDll, 115 | Exception 116 | }; 117 | 118 | // Structures 119 | 120 | #pragma pack(push, 1) 121 | 122 | struct EnumerateProcessData 123 | { 124 | RC_Size Id; 125 | RC_UnicodeChar ModulePath[PATH_MAXIMUM_LENGTH]; 126 | }; 127 | 128 | struct InstructionData 129 | { 130 | int Length; 131 | uint8_t Data[15]; 132 | RC_UnicodeChar Instruction[64]; 133 | }; 134 | 135 | struct EnumerateRemoteSectionData 136 | { 137 | RC_Pointer BaseAddress; 138 | RC_Size Size; 139 | SectionType Type; 140 | SectionCategory Category; 141 | SectionProtection Protection; 142 | RC_UnicodeChar Name[16]; 143 | RC_UnicodeChar ModulePath[PATH_MAXIMUM_LENGTH]; 144 | }; 145 | 146 | struct EnumerateRemoteModuleData 147 | { 148 | RC_Pointer BaseAddress; 149 | RC_Size Size; 150 | RC_UnicodeChar Path[PATH_MAXIMUM_LENGTH]; 151 | }; 152 | 153 | struct CreateProcessDebugInfo 154 | { 155 | RC_Pointer FileHandle; 156 | RC_Pointer ProcessHandle; 157 | }; 158 | 159 | struct ExitProcessDebugInfo 160 | { 161 | RC_Size ExitCode; 162 | }; 163 | 164 | struct CreateThreadDebugInfo 165 | { 166 | RC_Pointer ThreadHandle; 167 | }; 168 | 169 | struct ExitThreadDebugInfo 170 | { 171 | RC_Size ExitCode; 172 | }; 173 | 174 | struct LoadDllDebugInfo 175 | { 176 | RC_Pointer FileHandle; 177 | RC_Pointer BaseOfDll; 178 | }; 179 | 180 | struct UnloadDllDebugInfo 181 | { 182 | RC_Pointer BaseOfDll; 183 | }; 184 | 185 | struct ExceptionDebugInfo 186 | { 187 | RC_Size ExceptionCode; 188 | RC_Size ExceptionFlags; 189 | RC_Pointer ExceptionAddress; 190 | 191 | HardwareBreakpointRegister CausedBy; 192 | 193 | bool IsFirstChance; 194 | 195 | struct RegisterInfo 196 | { 197 | #ifdef _WIN64 198 | RC_Pointer Rax; 199 | RC_Pointer Rbx; 200 | RC_Pointer Rcx; 201 | RC_Pointer Rdx; 202 | RC_Pointer Rdi; 203 | RC_Pointer Rsi; 204 | RC_Pointer Rsp; 205 | RC_Pointer Rbp; 206 | RC_Pointer Rip; 207 | 208 | RC_Pointer R8; 209 | RC_Pointer R9; 210 | RC_Pointer R10; 211 | RC_Pointer R11; 212 | RC_Pointer R12; 213 | RC_Pointer R13; 214 | RC_Pointer R14; 215 | RC_Pointer R15; 216 | #else 217 | RC_Pointer Eax; 218 | RC_Pointer Ebx; 219 | RC_Pointer Ecx; 220 | RC_Pointer Edx; 221 | RC_Pointer Edi; 222 | RC_Pointer Esi; 223 | RC_Pointer Esp; 224 | RC_Pointer Ebp; 225 | RC_Pointer Eip; 226 | #endif 227 | }; 228 | RegisterInfo Registers; 229 | }; 230 | 231 | struct DebugEvent 232 | { 233 | DebugContinueStatus ContinueStatus; 234 | 235 | RC_Pointer ProcessId; 236 | RC_Pointer ThreadId; 237 | 238 | DebugEventType Type; 239 | 240 | union 241 | { 242 | CreateProcessDebugInfo CreateProcessInfo; 243 | ExitProcessDebugInfo ExitProcessInfo; 244 | CreateThreadDebugInfo CreateThreadInfo; 245 | ExitThreadDebugInfo ExitThreadInfo; 246 | LoadDllDebugInfo LoadDllInfo; 247 | UnloadDllDebugInfo UnloadDllInfo; 248 | ExceptionDebugInfo ExceptionInfo; 249 | }; 250 | }; 251 | 252 | #pragma pack(pop) 253 | 254 | // Callbacks 255 | 256 | typedef void(__stdcall *EnumerateProcessCallback)(EnumerateProcessData* data); 257 | 258 | typedef void(__stdcall EnumerateRemoteSectionsCallback)(EnumerateRemoteSectionData* data); 259 | typedef void(__stdcall EnumerateRemoteModulesCallback)(EnumerateRemoteModuleData* data); 260 | -------------------------------------------------------------------------------- /PipeServer/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | namespace fs = std::experimental::filesystem; 3 | #include 4 | 5 | #include "PipeStream/NamedPipeServerStream.hpp" 6 | #include "MessageClient.hpp" 7 | #include "PipeStream/Exceptions.hpp" 8 | 9 | std::wstring CreatePipeName() 10 | { 11 | fs::path name(L"ReClass.NET"); 12 | #ifdef _WIN64 13 | name.append(L"x64"); 14 | #else 15 | name.append(L"x86"); 16 | #endif 17 | 18 | wchar_t szFileName[MAX_PATH]; 19 | GetModuleFileNameW(nullptr, szFileName, MAX_PATH); 20 | name.append(fs::path(szFileName).filename()); 21 | 22 | return name.wstring(); 23 | } 24 | //--------------------------------------------------------------------------- 25 | MessageClient CreateClient(NamedPipeServerStream& pipe) 26 | { 27 | MessageClient client(pipe); 28 | 29 | client.RegisterMessage(); 30 | client.RegisterMessage(); 31 | client.RegisterMessage(); 32 | client.RegisterMessage(); 33 | client.RegisterMessage(); 34 | client.RegisterMessage(); 35 | 36 | return client; 37 | } 38 | //--------------------------------------------------------------------------- 39 | void PipeThread(void*) 40 | { 41 | const auto name = CreatePipeName(); 42 | 43 | while (true) 44 | { 45 | try 46 | { 47 | NamedPipeServerStream pipe(name, PipeDirection::InOut, 1, PipeTransmissionMode::Message); 48 | pipe.WaitForConnection(); 49 | 50 | auto server = CreateClient(pipe); 51 | while (true) 52 | { 53 | auto message = server.Receive(); 54 | if (message != nullptr) 55 | { 56 | if (!message->Handle(server)) 57 | { 58 | break; 59 | } 60 | } 61 | } 62 | 63 | pipe.Disconnect(); 64 | } 65 | catch (InvalidOperationException*) 66 | { 67 | 68 | } 69 | catch (IOException*) 70 | { 71 | 72 | } 73 | catch (...) 74 | { 75 | 76 | } 77 | } 78 | } 79 | //--------------------------------------------------------------------------- 80 | BOOL WINAPI DllMain(HMODULE handle, DWORD reason, PVOID reversed) 81 | { 82 | if (reason == DLL_PROCESS_ATTACH) 83 | { 84 | _beginthread(PipeThread, 0, nullptr); 85 | 86 | return TRUE; 87 | } 88 | 89 | return FALSE; 90 | } 91 | //--------------------------------------------------------------------------- 92 | -------------------------------------------------------------------------------- /Plugin/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.Contracts; 3 | using System.IO; 4 | 5 | namespace MemoryPipePlugin 6 | { 7 | static class Extensions 8 | { 9 | public static IntPtr ReadIntPtr(this BinaryReader br) 10 | { 11 | Contract.Requires(br != null); 12 | 13 | #if RECLASSNET64 14 | return (IntPtr)br.ReadInt64(); 15 | #else 16 | return (IntPtr)br.ReadInt32(); 17 | #endif 18 | } 19 | 20 | public static void Write(this BinaryWriter bw, IntPtr value) 21 | { 22 | Contract.Requires(bw != null); 23 | 24 | #if RECLASSNET64 25 | bw.Write(value.ToInt64()); 26 | #else 27 | bw.Write(value.ToInt32()); 28 | #endif 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Plugin/MemoryPipePlugin.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x86 7 | {CA79BA0B-0D80-476A-B793-FC7EF6DCEAD8} 8 | Library 9 | Properties 10 | MemoryPipePlugin 11 | MemoryPipePlugin 12 | v4.7.2 13 | 512 14 | 15 | 16 | 17 | x86 18 | true 19 | full 20 | false 21 | ..\bin\Debug\x86\ 22 | TRACE;DEBUG;RECLASSNET32 23 | prompt 24 | 4 25 | false 26 | 27 | 28 | x86 29 | pdbonly 30 | true 31 | ..\bin\Release\x86\ 32 | TRACE;RECLASSNET32;RELEASE 33 | prompt 34 | 4 35 | 36 | 37 | x64 38 | true 39 | full 40 | false 41 | ..\bin\Debug\x64\ 42 | TRACE;DEBUG;RECLASSNET64 43 | prompt 44 | 4 45 | false 46 | 47 | 48 | x64 49 | pdbonly 50 | true 51 | ..\bin\Release\x64\ 52 | TRACE;RECLASSNET64;RELEASE 53 | prompt 54 | 4 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | True 79 | True 80 | Resources.resx 81 | 82 | 83 | 84 | 85 | ResXFileCodeGenerator 86 | Resources.Designer.cs 87 | Designer 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | {bfb8917d-e9b4-463f-a6e8-612c35728c78} 96 | ReClass.NET 97 | 98 | 99 | 100 | 107 | -------------------------------------------------------------------------------- /Plugin/MemoryPipePluginExt.CoreProcessFunctions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using ReClassNET.Core; 5 | using ReClassNET.Debugger; 6 | 7 | namespace MemoryPipePlugin 8 | { 9 | partial class MemoryPipePluginExt 10 | { 11 | /// Queries if the process is valid. If the pipe isn't broken we can assume the process is valid. 12 | /// IsValidRequest 15 | /// <- StatusResponse 16 | /// ]]> 17 | /// The process to check. 18 | /// True if the process is valid, false if not. 19 | public bool IsProcessValid(IntPtr process) 20 | { 21 | lock (sync) 22 | { 23 | if (openPipes.TryGetValue(process, out var client)) 24 | { 25 | try 26 | { 27 | client.Send(new IsValidRequest()); 28 | var message = client.Receive() as StatusResponse; 29 | 30 | return message.Success; 31 | } 32 | catch (Exception ex) 33 | { 34 | LogErrorAndRemoveClient(process, ex); 35 | } 36 | } 37 | 38 | return false; 39 | } 40 | } 41 | 42 | /// Opens the pipe to the target process. 43 | /// OpenProcessRequest 46 | /// <- StatusResponse 47 | /// ]]> 48 | /// The process id. 49 | /// The desired access. (ignored) 50 | /// A plugin internal handle to the process. 51 | public IntPtr OpenRemoteProcess(IntPtr pid, ProcessAccess desiredAccess) 52 | { 53 | lock (sync) 54 | { 55 | try 56 | { 57 | var pipePath = GetPipes().FirstOrDefault(p => p.GetHashCode() == pid.ToInt32()); 58 | if (pipePath == null) 59 | { 60 | return IntPtr.Zero; 61 | } 62 | 63 | var client = CreateClientForPipe(pipePath); 64 | 65 | try 66 | { 67 | client.Send(new OpenProcessRequest()); 68 | client.Receive(); // swallow the StatusResponse 69 | 70 | return client.Id; 71 | } 72 | catch (Exception ex) 73 | { 74 | LogErrorAndRemoveClient(client.Id, ex); 75 | } 76 | } 77 | catch (Exception ex) 78 | { 79 | host.Logger.Log(ex); 80 | } 81 | } 82 | 83 | return IntPtr.Zero; 84 | } 85 | 86 | /// Closes the pipe to the remote process. 87 | /// CloseProcessRequest 90 | /// <- StatusResponse 91 | /// ]]> 92 | /// The process to close. 93 | public void CloseRemoteProcess(IntPtr process) 94 | { 95 | lock (sync) 96 | { 97 | if (openPipes.TryGetValue(process, out var client)) 98 | { 99 | try 100 | { 101 | client.Send(new CloseProcessRequest()); 102 | client.Receive(); // swallow the StatusResponse 103 | } 104 | catch 105 | { 106 | 107 | } 108 | 109 | openPipes.Remove(process); 110 | client.Dispose(); 111 | } 112 | } 113 | } 114 | 115 | /// Reads memory of the remote process through the pipe. 116 | /// ReadMemoryRequest 119 | /// <- StatusResponse, if an error occured 120 | /// <- ReadMemoryResponse, if no error occured 121 | /// ]]> 122 | /// The process to read from. 123 | /// The address to read from. 124 | /// The buffer to read into. 125 | /// The offset into the buffer. 126 | /// The size of the memory to read. 127 | /// True if it succeeds, false if it fails. 128 | public bool ReadRemoteMemory(IntPtr process, IntPtr address, ref byte[] buffer, int offset, int size) 129 | { 130 | lock (sync) 131 | { 132 | var client = GetClientById(process); 133 | if (client != null) 134 | { 135 | try 136 | { 137 | client.Send(new ReadMemoryRequest(address, size)); 138 | var response = client.Receive(); 139 | if (response is StatusResponse statusMessage) 140 | { 141 | return statusMessage.Success; 142 | } 143 | if (response is ReadMemoryResponse memoryResponse) 144 | { 145 | if (memoryResponse.Data.Length == size) 146 | { 147 | Array.Copy(memoryResponse.Data, 0, buffer, offset, size); 148 | 149 | return true; 150 | } 151 | } 152 | } 153 | catch (Exception ex) 154 | { 155 | LogErrorAndRemoveClient(process, ex); 156 | } 157 | } 158 | 159 | return false; 160 | } 161 | } 162 | 163 | /// Writes memory to the remote process. 164 | /// WriteMemoryRequest 167 | /// <- StatusResponse 168 | /// ]]> 169 | /// The process to write to. 170 | /// The address to write to. 171 | /// The memory to write. 172 | /// The offset into the buffer. 173 | /// The size of the memory to write. 174 | /// True if it succeeds, false if it fails. 175 | public bool WriteRemoteMemory(IntPtr process, IntPtr address, ref byte[] buffer, int offset, int size) 176 | { 177 | lock (sync) 178 | { 179 | var client = GetClientById(process); 180 | if (client != null) 181 | { 182 | try 183 | { 184 | var data = new byte[size]; 185 | Array.Copy(buffer, offset, data, 0, size); 186 | 187 | client.Send(new WriteMemoryRequest(address, data)); 188 | var message = client.Receive() as StatusResponse; 189 | return message.Success; 190 | } 191 | catch (Exception ex) 192 | { 193 | LogErrorAndRemoveClient(process, ex); 194 | } 195 | } 196 | 197 | return false; 198 | } 199 | } 200 | 201 | /// Enumerates all pipes started by the ReClass.NET PipeServer. 202 | /// The callback which gets called for every process. 203 | public void EnumerateProcesses(EnumerateProcessCallback callbackProcess) 204 | { 205 | if (callbackProcess == null) 206 | { 207 | return; 208 | } 209 | 210 | foreach (var pipe in GetPipes()) 211 | { 212 | var platform = new DirectoryInfo(pipe).Parent?.Name ?? string.Empty; 213 | #if RECLASSNET64 214 | if (platform.ToLower() == "x64") 215 | #else 216 | if (platform.ToLower() == "x86") 217 | #endif 218 | { 219 | var data = new EnumerateProcessData 220 | { 221 | Id = (IntPtr)pipe.GetHashCode(), 222 | Name = Path.GetFileName(pipe), 223 | Path = pipe 224 | }; 225 | 226 | callbackProcess(ref data); 227 | } 228 | } 229 | } 230 | 231 | /// Enumerate all sections and modules of the remote process. 232 | /// EnumerateRemoteSectionsAndModulesRequest 235 | /// <- EnumerateRemoteSectionResponse [*] 236 | /// <- EnumerateRemoteModuleResponse [*] 237 | /// <- StatusResponse 238 | /// 239 | /// Both callback messages can arrive in random order and count. The enumeration is finished if the StatusResponse was received. 240 | /// ]]> 241 | /// The process. 242 | /// The callback which gets called for every section. 243 | /// The callback which gets called for every module. 244 | public void EnumerateRemoteSectionsAndModules(IntPtr process, EnumerateRemoteSectionCallback callbackSection, EnumerateRemoteModuleCallback callbackModule) 245 | { 246 | if (callbackSection == null && callbackModule == null) 247 | { 248 | return; 249 | } 250 | 251 | lock (sync) 252 | { 253 | var client = GetClientById(process); 254 | if (client != null) 255 | { 256 | try 257 | { 258 | client.Send(new EnumerateRemoteSectionsAndModulesRequest()); 259 | 260 | while (true) 261 | { 262 | var message = client.Receive(); 263 | if (message is StatusResponse) 264 | { 265 | break; 266 | } 267 | 268 | switch (message) 269 | { 270 | case EnumerateRemoteSectionResponse callbackSectionMessage: 271 | { 272 | var data = new EnumerateRemoteSectionData 273 | { 274 | BaseAddress = callbackSectionMessage.BaseAddress, 275 | Size = callbackSectionMessage.Size, 276 | Type = callbackSectionMessage.Type, 277 | Category = callbackSectionMessage.Category, 278 | Protection = callbackSectionMessage.Protection, 279 | Name = callbackSectionMessage.Name, 280 | ModulePath = callbackSectionMessage.ModulePath 281 | }; 282 | 283 | callbackSection?.Invoke(ref data); 284 | break; 285 | } 286 | case EnumerateRemoteModuleResponse callbackModuleMessage: 287 | { 288 | var data = new EnumerateRemoteModuleData 289 | { 290 | BaseAddress = callbackModuleMessage.BaseAddress, 291 | Size = callbackModuleMessage.Size, 292 | Path = callbackModuleMessage.Path 293 | }; 294 | 295 | callbackModule?.Invoke(ref data); 296 | break; 297 | } 298 | } 299 | } 300 | } 301 | catch (Exception ex) 302 | { 303 | LogErrorAndRemoveClient(process, ex); 304 | } 305 | } 306 | } 307 | } 308 | 309 | public void ControlRemoteProcess(IntPtr process, ControlRemoteProcessAction action) 310 | { 311 | // Not supported. 312 | } 313 | 314 | public bool AttachDebuggerToProcess(IntPtr id) 315 | { 316 | // Not supported. 317 | 318 | return false; 319 | } 320 | 321 | public void DetachDebuggerFromProcess(IntPtr id) 322 | { 323 | // Not supported. 324 | } 325 | 326 | public bool AwaitDebugEvent(ref DebugEvent evt, int timeoutInMilliseconds) 327 | { 328 | // Not supported. 329 | 330 | return false; 331 | } 332 | 333 | public void HandleDebugEvent(ref DebugEvent evt) 334 | { 335 | // Not supported. 336 | } 337 | 338 | public bool SetHardwareBreakpoint(IntPtr id, IntPtr address, HardwareBreakpointRegister register, HardwareBreakpointTrigger trigger, HardwareBreakpointSize size, bool set) 339 | { 340 | // Not supported. 341 | 342 | return false; 343 | } 344 | } 345 | } 346 | -------------------------------------------------------------------------------- /Plugin/MemoryPipePluginExt.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.Contracts; 4 | using System.Drawing; 5 | using System.IO; 6 | using System.IO.Pipes; 7 | using System.Linq; 8 | using ReClassNET.Core; 9 | using ReClassNET.Plugins; 10 | 11 | namespace MemoryPipePlugin 12 | { 13 | public partial class MemoryPipePluginExt : Plugin, ICoreProcessFunctions 14 | { 15 | private const string PipePrefix = @"\\.\pipe\"; 16 | 17 | private readonly object sync = new object(); 18 | 19 | private IPluginHost host; 20 | 21 | private Dictionary openPipes; 22 | 23 | public override Image Icon => Properties.Resources.logo; 24 | 25 | public override bool Initialize(IPluginHost host) 26 | { 27 | Contract.Requires(host != null); 28 | 29 | //System.Diagnostics.Debugger.Launch(); 30 | 31 | if (this.host != null) 32 | { 33 | Terminate(); 34 | } 35 | 36 | this.host = host ?? throw new ArgumentNullException(nameof(host)); 37 | 38 | host.Process.CoreFunctions.RegisterFunctions("Memory Pipe", this); 39 | 40 | openPipes = new Dictionary(); 41 | 42 | return true; 43 | } 44 | 45 | public override void Terminate() 46 | { 47 | foreach (var client in openPipes.Values) 48 | { 49 | client.Dispose(); 50 | } 51 | openPipes.Clear(); 52 | 53 | host = null; 54 | } 55 | 56 | /// Gets a by its plugin internal identifier. 57 | /// The identifier. 58 | /// The client or null if the identifier doesn't exist. 59 | private MessageClient GetClientById(IntPtr id) 60 | { 61 | openPipes.TryGetValue(id, out var client); 62 | return client; 63 | } 64 | 65 | /// Logs the exception and removes client. 66 | /// The identifier. 67 | /// The exception. 68 | private void LogErrorAndRemoveClient(IntPtr id, Exception ex) 69 | { 70 | Contract.Requires(ex != null); 71 | 72 | GetClientById(id)?.Dispose(); 73 | 74 | openPipes.Remove(id); 75 | 76 | host.Logger.Log(ex); 77 | } 78 | 79 | /// Enumerates all pipes created by the ReClass.NET PipeServer. 80 | /// An enumerator to all pipes. 81 | private static IEnumerable GetPipes() 82 | { 83 | return Directory.GetFiles(PipePrefix).Where(p => p.Contains("ReClass.NET")); 84 | } 85 | 86 | /// Creates a for the given pipe. 87 | /// Full pathname of the pipe. 88 | /// The for the pipe. 89 | private MessageClient CreateClientForPipe(string pipePath) 90 | { 91 | var pipeName = pipePath.Substring(PipePrefix.Length); 92 | 93 | var pipe = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut); 94 | pipe.Connect(); 95 | pipe.ReadMode = PipeTransmissionMode.Message; 96 | 97 | var client = new MessageClient(pipe); 98 | 99 | client.RegisterMessage(); 100 | client.RegisterMessage(); 101 | client.RegisterMessage(); 102 | client.RegisterMessage(); 103 | 104 | openPipes.Add(client.Id, client); 105 | 106 | return client; 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /Plugin/MessageClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.Contracts; 4 | using System.IO; 5 | using System.IO.Pipes; 6 | using System.Text; 7 | 8 | namespace MemoryPipePlugin 9 | { 10 | internal class MessageClient : IDisposable 11 | { 12 | private readonly PipeStream pipe; 13 | 14 | private readonly Dictionary> registeredMessages = new Dictionary>(); 15 | 16 | public IntPtr Id => pipe.SafePipeHandle.DangerousGetHandle(); 17 | 18 | public MessageClient(PipeStream pipe) 19 | { 20 | Contract.Requires(pipe != null); 21 | 22 | this.pipe = pipe; 23 | } 24 | 25 | public void Dispose() 26 | { 27 | pipe?.Dispose(); 28 | } 29 | 30 | public void RegisterMessage() where T : IMessage, new() 31 | { 32 | IMessage MessageCreator() => new T(); 33 | 34 | registeredMessages.Add(MessageCreator().MessageType, MessageCreator); 35 | } 36 | 37 | public IMessage Receive() 38 | { 39 | using (var ms = new MemoryStream()) 40 | { 41 | var buffer = new byte[256]; 42 | do 43 | { 44 | var length = pipe.Read(buffer, 0, buffer.Length); 45 | ms.Write(buffer, 0, length); 46 | } 47 | while (!pipe.IsMessageComplete); 48 | 49 | ms.Position = 0; 50 | 51 | using (var br = new BinaryReader(ms, Encoding.Unicode, true)) 52 | { 53 | var type = (MessageType)br.ReadInt32(); 54 | 55 | if (registeredMessages.TryGetValue(type, out var createFn)) 56 | { 57 | var message = createFn(); 58 | message.ReadFrom(br); 59 | return message; 60 | } 61 | } 62 | } 63 | 64 | return null; 65 | } 66 | 67 | public void Send(IMessage message) 68 | { 69 | Contract.Requires(message != null); 70 | 71 | using (var ms = new MemoryStream()) 72 | { 73 | using (var bw = new BinaryWriter(ms, Encoding.Unicode, true)) 74 | { 75 | bw.Write((int)message.MessageType); 76 | message.WriteTo(bw); 77 | } 78 | 79 | var buffer = ms.ToArray(); 80 | pipe.Write(buffer, 0, buffer.Length); 81 | } 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Plugin/Messages.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.Contracts; 3 | using System.IO; 4 | using ReClassNET.Memory; 5 | 6 | namespace MemoryPipePlugin 7 | { 8 | internal enum MessageType 9 | { 10 | StatusResponse = 1, 11 | OpenProcessRequest = 2, 12 | CloseProcessRequest = 3, 13 | IsValidRequest = 4, 14 | ReadMemoryRequest = 5, 15 | ReadMemoryResponse = 6, 16 | WriteMemoryRequest = 7, 17 | EnumerateRemoteSectionsAndModulesRequest = 8, 18 | EnumerateRemoteSectionResponse = 9, 19 | EnumerateRemoteModuleResponse = 10, 20 | EnumerateProcessHandlesRequest = 11, 21 | EnumerateProcessHandlesResponse = 12, 22 | ClosePipeRequest = 13 23 | } 24 | 25 | internal interface IMessage 26 | { 27 | MessageType MessageType { get; } 28 | 29 | void ReadFrom(BinaryReader reader); 30 | void WriteTo(BinaryWriter writer); 31 | } 32 | 33 | [ContractClassFor(typeof(IMessage))] 34 | internal class MessageContract : IMessage 35 | { 36 | public MessageType MessageType => throw new NotImplementedException(); 37 | 38 | public void ReadFrom(BinaryReader reader) 39 | { 40 | Contract.Requires(reader != null); 41 | 42 | throw new NotImplementedException(); 43 | } 44 | 45 | public void WriteTo(BinaryWriter writer) 46 | { 47 | Contract.Requires(writer != null); 48 | 49 | throw new NotImplementedException(); 50 | } 51 | } 52 | 53 | internal class StatusResponse : IMessage 54 | { 55 | public MessageType MessageType => MessageType.StatusResponse; 56 | 57 | public bool Success { get; private set; } 58 | 59 | public StatusResponse() 60 | { 61 | 62 | } 63 | 64 | public StatusResponse(bool success) 65 | { 66 | Success = success; 67 | } 68 | 69 | public void ReadFrom(BinaryReader reader) 70 | { 71 | Success = reader.ReadBoolean(); 72 | } 73 | 74 | public void WriteTo(BinaryWriter writer) 75 | { 76 | writer.Write(Success); 77 | } 78 | } 79 | 80 | internal class OpenProcessRequest : IMessage 81 | { 82 | public MessageType MessageType => MessageType.OpenProcessRequest; 83 | 84 | public void ReadFrom(BinaryReader reader) 85 | { 86 | 87 | } 88 | 89 | public void WriteTo(BinaryWriter writer) 90 | { 91 | 92 | } 93 | } 94 | 95 | internal class CloseProcessRequest : IMessage 96 | { 97 | public MessageType MessageType => MessageType.CloseProcessRequest; 98 | 99 | public void ReadFrom(BinaryReader reader) 100 | { 101 | 102 | } 103 | 104 | public void WriteTo(BinaryWriter writer) 105 | { 106 | 107 | } 108 | } 109 | 110 | internal class IsValidRequest : IMessage 111 | { 112 | public MessageType MessageType => MessageType.IsValidRequest; 113 | 114 | public void ReadFrom(BinaryReader reader) 115 | { 116 | 117 | } 118 | 119 | public void WriteTo(BinaryWriter writer) 120 | { 121 | 122 | } 123 | } 124 | 125 | internal class ReadMemoryRequest : IMessage 126 | { 127 | public MessageType MessageType => MessageType.ReadMemoryRequest; 128 | 129 | public IntPtr Address { get; private set; } 130 | public int Size { get; private set; } 131 | 132 | public ReadMemoryRequest() 133 | { 134 | 135 | } 136 | 137 | public ReadMemoryRequest(IntPtr address, int size) 138 | { 139 | Address = address; 140 | Size = size; 141 | } 142 | 143 | public void ReadFrom(BinaryReader reader) 144 | { 145 | Address = reader.ReadIntPtr(); 146 | Size = reader.ReadInt32(); 147 | } 148 | 149 | public void WriteTo(BinaryWriter writer) 150 | { 151 | writer.Write(Address); 152 | writer.Write(Size); 153 | } 154 | } 155 | 156 | internal class ReadMemoryResponse : IMessage 157 | { 158 | public MessageType MessageType => MessageType.ReadMemoryResponse; 159 | 160 | public byte[] Data { get; private set; } 161 | 162 | public ReadMemoryResponse() 163 | { 164 | 165 | } 166 | 167 | public ReadMemoryResponse(byte[] data) 168 | { 169 | Data = data; 170 | } 171 | 172 | public void ReadFrom(BinaryReader reader) 173 | { 174 | var size = reader.ReadInt32(); 175 | Data = reader.ReadBytes(size); 176 | } 177 | 178 | public void WriteTo(BinaryWriter writer) 179 | { 180 | writer.Write(Data.Length); 181 | writer.Write(Data); 182 | } 183 | } 184 | 185 | internal class WriteMemoryRequest : IMessage 186 | { 187 | public MessageType MessageType => MessageType.WriteMemoryRequest; 188 | 189 | public IntPtr Address { get; private set; } 190 | public byte[] Data { get; private set; } 191 | 192 | public WriteMemoryRequest() 193 | { 194 | 195 | } 196 | 197 | public WriteMemoryRequest(IntPtr address, byte[] data) 198 | { 199 | Address = address; 200 | Data = data; 201 | } 202 | 203 | public void ReadFrom(BinaryReader reader) 204 | { 205 | Address = reader.ReadIntPtr(); 206 | var size = reader.ReadInt32(); 207 | Data = reader.ReadBytes(size); 208 | } 209 | 210 | public void WriteTo(BinaryWriter writer) 211 | { 212 | writer.Write(Address); 213 | writer.Write(Data.Length); 214 | writer.Write(Data); 215 | } 216 | } 217 | 218 | internal class EnumerateRemoteSectionsAndModulesRequest : IMessage 219 | { 220 | public MessageType MessageType => MessageType.EnumerateRemoteSectionsAndModulesRequest; 221 | 222 | public void ReadFrom(BinaryReader reader) 223 | { 224 | 225 | } 226 | 227 | public void WriteTo(BinaryWriter writer) 228 | { 229 | 230 | } 231 | } 232 | 233 | internal class EnumerateRemoteSectionResponse : IMessage 234 | { 235 | public MessageType MessageType => MessageType.EnumerateRemoteSectionResponse; 236 | 237 | public IntPtr BaseAddress { get; private set; } 238 | public IntPtr Size { get; private set; } 239 | public SectionType Type { get; private set; } 240 | public SectionCategory Category { get; private set; } 241 | public SectionProtection Protection { get; private set; } 242 | public string Name { get; private set; } 243 | public string ModulePath { get; private set; } 244 | 245 | public EnumerateRemoteSectionResponse() 246 | { 247 | 248 | } 249 | 250 | public EnumerateRemoteSectionResponse(IntPtr baseAddress, IntPtr regionSize, SectionType type, SectionCategory category, SectionProtection protection, string name, string modulePath) 251 | { 252 | BaseAddress = baseAddress; 253 | Size = regionSize; 254 | Type = type; 255 | Category = category; 256 | Protection = protection; 257 | Name = name; 258 | ModulePath = modulePath; 259 | } 260 | 261 | public void ReadFrom(BinaryReader reader) 262 | { 263 | BaseAddress = reader.ReadIntPtr(); 264 | Size = reader.ReadIntPtr(); 265 | Type = (SectionType)reader.ReadInt32(); 266 | Category = (SectionCategory)reader.ReadInt32(); 267 | Protection = (SectionProtection)reader.ReadInt32(); 268 | Name = reader.ReadString(); 269 | ModulePath = reader.ReadString(); 270 | } 271 | 272 | public void WriteTo(BinaryWriter writer) 273 | { 274 | writer.Write(BaseAddress); 275 | writer.Write(Size); 276 | writer.Write((int)Type); 277 | writer.Write((int)Category); 278 | writer.Write((int)Protection); 279 | writer.Write(Name); 280 | writer.Write(ModulePath); 281 | } 282 | } 283 | 284 | internal class EnumerateRemoteModuleResponse : IMessage 285 | { 286 | public MessageType MessageType => MessageType.EnumerateRemoteModuleResponse; 287 | 288 | public IntPtr BaseAddress { get; private set; } 289 | public IntPtr Size { get; private set; } 290 | public string Path { get; private set; } 291 | 292 | public EnumerateRemoteModuleResponse() 293 | { 294 | 295 | } 296 | 297 | public EnumerateRemoteModuleResponse(IntPtr baseAddress, IntPtr regionSize, string path) 298 | { 299 | BaseAddress = baseAddress; 300 | Size = regionSize; 301 | Path = path; 302 | } 303 | 304 | public void ReadFrom(BinaryReader reader) 305 | { 306 | BaseAddress = reader.ReadIntPtr(); 307 | Size = reader.ReadIntPtr(); 308 | Path = reader.ReadString(); 309 | } 310 | 311 | public void WriteTo(BinaryWriter writer) 312 | { 313 | writer.Write(BaseAddress); 314 | writer.Write(Size); 315 | writer.Write(Path); 316 | } 317 | } 318 | } 319 | -------------------------------------------------------------------------------- /Plugin/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // Allgemeine Informationen über eine Assembly werden über die folgenden 6 | // Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, 7 | // die einer Assembly zugeordnet sind. 8 | [assembly: AssemblyTitle("Memory Pipe")] 9 | [assembly: AssemblyDescription("A plugin which transfers memory from a target process through a pipe. This can be used if the target process doesn't allow remote access but can be attacked by dll injection.")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("KN4CK3R")] 12 | [assembly: AssemblyProduct("ReClass.NET Plugin")] 13 | [assembly: AssemblyCopyright("")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar 18 | // für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von 19 | // COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen. 20 | [assembly: ComVisible(false)] 21 | 22 | // Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird 23 | [assembly: Guid("ca79ba0b-0d80-476a-b793-fc7ef6dcead7")] 24 | 25 | // Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: 26 | // 27 | // Hauptversion 28 | // Nebenversion 29 | // Buildnummer 30 | // Revision 31 | // 32 | // Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern 33 | // übernehmen, indem Sie "*" eingeben: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Plugin/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 MemoryPipePlugin.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", "16.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("MemoryPipePlugin.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 | /// Looks up a localized resource of type System.Drawing.Bitmap. 65 | /// 66 | internal static System.Drawing.Bitmap logo { 67 | get { 68 | object obj = ResourceManager.GetObject("logo", resourceCulture); 69 | return ((System.Drawing.Bitmap)(obj)); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Plugin/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 | 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 | 122 | ..\Resources\logo.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 123 | 124 | -------------------------------------------------------------------------------- /Plugin/Resources/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReClassNET/ReClass.NET-MemoryPipePlugin/0a82081309bf42a3867ce168906881ae5ed569a5/Plugin/Resources/logo.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ReClass.NET MemoryPipe Plugin 2 | A ReClass.NET plugin which allows direct memory access via dll injection. 3 | The injected dll works like a server which reads requests from a pipe. Results are transfered back to ReClass.NET through the pipe. 4 | 5 | ## Installation 6 | - Download from https://github.com/KN4CK3R/ReClass.NET-MemoryPipePlugin 7 | - Copy the dll files in the appropriate Plugin folder (ReClass.NET/x86/Plugins or ReClass.NET/x64/Plugins) 8 | - Start ReClass.NET and check the plugins form if the MemoryPipe plugin is listed. Open the "Native" tab and switch all available methods to the MemoryPipe plugin. 9 | - Inject the PipeServer.dll into the target. 10 | - Attach to the process via its pipe and use ReClass.NET as normal. (Note: Controlling the remote process (start, stop, pause) is not supported.) 11 | 12 | ![](https://abload.de/img/pipe0mj0z.jpg) 13 | 14 | ## Compiling 15 | If you want to compile the ReClass.NET MemoryPipe Plugin just fork the repository and create the following folder structure. If you don't use this structure you need to fix the project references. 16 | 17 | ``` 18 | ..\ReClass.NET\ 19 | ..\ReClass.NET\ReClass.NET\ReClass.NET.csproj 20 | ..\ReClass.NET-MemoryPipePlugin 21 | ..\ReClass.NET-MemoryPipePlugin\Plugin 22 | ..\ReClass.NET-MemoryPipePlugin\Plugin\MemoryPipePlugin.csproj 23 | ``` --------------------------------------------------------------------------------