diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c76c071..a53d8e4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,9 +17,14 @@ jobs: - name: Add msbuild to PATH uses: microsoft/setup-msbuild@v1.0.2 + + - uses: nuget/setup-nuget@v1 + with: + nuget-version: '5.x' - name: Build run: | + nuget restore ${{ github.event.repository.name }}.sln msbuild.exe ${{ github.event.repository.name }}.sln /m /verbosity:minimal /t:Rebuild /p:Configuration=Release /p:Platform=x64 - uses: actions/upload-artifact@v2 diff --git a/.gitignore b/.gitignore index d0a8ed1..706d453 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ Release/ Debug/ x64/ *.user +packages/ diff --git a/Injector/App.config b/Injector/App.config new file mode 100644 index 0000000..6265743 --- /dev/null +++ b/Injector/App.config @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/Injector/Injector.cpp b/Injector/Injector.cpp deleted file mode 100644 index 42f641b..0000000 --- a/Injector/Injector.cpp +++ /dev/null @@ -1,156 +0,0 @@ -#include -#include -#include -#include -#include - -static std::vector ReadAllBytes(const char* FileName) -{ - auto hFile = CreateFileA(FileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); - if (hFile == INVALID_HANDLE_VALUE) - { - return {}; - } - std::vector data; - auto FileSize = GetFileSize(hFile, nullptr); - data.resize(FileSize); - DWORD BytesRead = 0; - if (!ReadFile(hFile, data.data(), FileSize, &BytesRead, nullptr)) - { - data.clear(); - } - CloseHandle(hFile); - return data; -} - -static bool WriteAllBytes(const char* FileName, const std::vector& Data) -{ - auto hFile = CreateFileA(FileName, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); - if (hFile == INVALID_HANDLE_VALUE) - { - return false; - } - DWORD BytesWritten = 0; - auto success = !!WriteFile(hFile, Data.data(), (DWORD)Data.size(), &BytesWritten, nullptr); - CloseHandle(hFile); - return success; -} - -static PIMAGE_NT_HEADERS GetNtHeaders(void* ImageData) -{ - auto DosHeader = PIMAGE_DOS_HEADER(ImageData); - if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE) - { - return nullptr; - } - auto NtHeaders = PIMAGE_NT_HEADERS((char*)ImageData + DosHeader->e_lfanew); - if (NtHeaders->Signature != IMAGE_NT_SIGNATURE || NtHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) - { - return nullptr; - } - return NtHeaders; -} - -static DWORD AlignSize(DWORD Size, DWORD Alignment) -{ - // TODO: this is fugly - if (Size % Alignment) - Size = ((Size + Alignment) / Alignment) * Alignment; - return Size; -} - -static bool AppendBootkit(std::vector& BootmgfwData, std::vector& BootkitData) -{ - auto BootmgfwHeaders = GetNtHeaders(BootmgfwData.data()); - if (BootmgfwHeaders == nullptr) - { - puts("[Injector] Invalid PE file (bootmgfw)"); - return false; - } - - auto BootkitHeaders = GetNtHeaders(BootkitData.data()); - if (BootkitHeaders == nullptr) - { - puts("[Injector] Invalid PE file (bootkit)"); - return false; - } - - auto SectionAlignment = BootkitHeaders->OptionalHeader.SectionAlignment; - auto FileAlignment = BootkitHeaders->OptionalHeader.FileAlignment; - if (SectionAlignment != 0x1000 || FileAlignment != 0x1000) - { - puts("[Injector] Bootkit not compiled with /FILEALIGN:0x1000 /ALIGN:0x1000"); - return false; - } - - // Put the original entry point in the bootkit headers - auto BootkitEntryPoint = BootkitHeaders->OptionalHeader.AddressOfEntryPoint; - BootkitHeaders->OptionalHeader.AddressOfEntryPoint = BootmgfwHeaders->OptionalHeader.AddressOfEntryPoint; - - std::vector SectionData; - auto AlignmentSize = 0x1000; - SectionData.resize(AlignmentSize, 0xCC); - BootkitData.resize(AlignSize((DWORD)BootkitData.size(), FileAlignment)); - SectionData.insert(SectionData.end(), BootkitData.begin(), BootkitData.end()); - - // Create the new section - auto Sections = IMAGE_FIRST_SECTION(BootmgfwHeaders); - auto NumberOfSections = BootmgfwHeaders->FileHeader.NumberOfSections; - IMAGE_SECTION_HEADER NewSection = {}; - memcpy(NewSection.Name, ".bootkit", 8); - NewSection.SizeOfRawData = (DWORD)SectionData.size(); - NewSection.PointerToRawData = (DWORD)BootmgfwData.size(); - NewSection.Misc.VirtualSize = AlignSize((DWORD)SectionData.size(), SectionAlignment); - NewSection.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE; - NewSection.VirtualAddress = Sections[NumberOfSections - 1].VirtualAddress + AlignSize(Sections[NumberOfSections - 1].Misc.VirtualSize, BootmgfwHeaders->OptionalHeader.SectionAlignment); - - // Adjust the headers - auto BootkitBase = NewSection.VirtualAddress + AlignmentSize; - BootmgfwHeaders->OptionalHeader.AddressOfEntryPoint = BootkitBase + BootkitEntryPoint; - BootmgfwHeaders->OptionalHeader.SizeOfImage += NewSection.Misc.VirtualSize; - BootmgfwHeaders->FileHeader.NumberOfSections++; - Sections[NumberOfSections] = NewSection; - - // Append the section data to the file - BootmgfwData.insert(BootmgfwData.end(), SectionData.begin(), SectionData.end()); - - // TODO: fix up the checksum? - - return true; -} - -int main(int argc, char** argv) -{ - if (argc < 4) - { - puts("Usage: Injector bootmgfw.original bootkit.efi bootmgfw.injected"); - return EXIT_FAILURE; - } - auto BootmgfwOriginal = argv[1]; - auto Bootkit = argv[2]; - auto BootmgfwInjected = argv[3]; - auto BootmgfwData = ReadAllBytes(BootmgfwOriginal); - if (BootmgfwData.empty()) - { - printf("[Injector] Failed to read '%s'\n", BootmgfwOriginal); - return EXIT_FAILURE; - } - auto BootkitData = ReadAllBytes(Bootkit); - if (BootkitData.empty()) - { - printf("[Injector] Failed to read '%s'\n", Bootkit); - return EXIT_FAILURE; - } - if (!AppendBootkit(BootmgfwData, BootkitData)) - { - puts("[Injector] Failed to inject .bootkit section"); - return EXIT_FAILURE; - } - if (!WriteAllBytes(BootmgfwInjected, BootmgfwData)) - { - printf("[Injector] Failed to write '%s'\n", BootmgfwInjected); - return EXIT_FAILURE; - } - puts("[Injector] Bootkit injected!"); - return EXIT_SUCCESS; -} \ No newline at end of file diff --git a/Injector/Injector.cs b/Injector/Injector.cs new file mode 100644 index 0000000..129849c --- /dev/null +++ b/Injector/Injector.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PeNet; +using PeNet.Header.Pe; + +namespace Injector +{ + internal class Program + { + static uint AlignUp(uint Size, uint Alignment) + { + return (Size + (Alignment - 1)) & ~(Alignment - 1); + } + + static int Main(string[] args) + { + if (args.Length < 3) + { + Console.WriteLine("Usage: Injector bootmgfw.bak bootkit.efi bootmgfw.injected"); + return 1; + } + + try + { + var bootmgfwPe = new PeFile(File.ReadAllBytes(args[0])); + var bootkitData = File.ReadAllBytes(args[1]); + var bootkitPe = new PeFile(bootkitData); + + var fileAlignment = bootkitPe.ImageNtHeaders.OptionalHeader.FileAlignment; + var sectionAlignment = bootkitPe.ImageNtHeaders.OptionalHeader.SectionAlignment; + if (fileAlignment != 0x1000 || sectionAlignment != 0x1000) + throw new Exception($"Bootkit not compiled with /FILEALIGN:0x1000 /ALIGN:0x1000"); + + // Put the original entry point in the bootkit headers + var bootkitEntry = bootkitPe.ImageNtHeaders.OptionalHeader.AddressOfEntryPoint; + bootkitPe.ImageNtHeaders.OptionalHeader.AddressOfEntryPoint = bootmgfwPe.ImageNtHeaders.OptionalHeader.AddressOfEntryPoint; + + var sizeOfImage = bootmgfwPe.ImageNtHeaders.OptionalHeader.SizeOfImage; + var alignmentSize = AlignUp(sizeOfImage, 0x10000) - sizeOfImage; + var sectionSize = (int)(alignmentSize + bootkitData.Length); + + var bootkitBase = sizeOfImage + alignmentSize; + Console.WriteLine(bootkitBase); + + bootmgfwPe.ImageNtHeaders.OptionalHeader.AddressOfEntryPoint = bootkitBase + bootkitEntry; + + bootmgfwPe.AddSection(".bootkit", sectionSize, ScnCharacteristicsType.MemExecute | ScnCharacteristicsType.MemRead | ScnCharacteristicsType.MemWrite); + var newSection = bootmgfwPe.ImageSectionHeaders[bootmgfwPe.ImageSectionHeaders.Length - 1]; + bootmgfwPe.RawFile.WriteBytes(newSection.PointerToRawData + alignmentSize, bootkitData); + Console.WriteLine(newSection.VirtualAddress.ToHexString()); + File.WriteAllBytes(args[2], bootmgfwPe.RawFile.ToArray()); + return 0; + } + catch (Exception x) + { + Console.WriteLine(x); + return 1; + } + } + } +} diff --git a/Injector/Injector.csproj b/Injector/Injector.csproj new file mode 100644 index 0000000..1f303e9 --- /dev/null +++ b/Injector/Injector.csproj @@ -0,0 +1,107 @@ + + + + + Debug + AnyCPU + {1FC97804-FF0D-40F9-A772-213A46DFA1EC} + Exe + Injector + Injector + v4.8 + 512 + true + true + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + ..\x64\Release\Injector\ + TRACE + prompt + 4 + + + + ..\packages\PeNet.2.9.8\lib\net48\PeNet.dll + + + ..\packages\PeNet.Asn1.2.0.0\lib\net48\PeNet.Asn1.dll + + + + ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + + ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll + + + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + + ..\packages\System.Security.Cryptography.Pkcs.6.0.1\lib\net461\System.Security.Cryptography.Pkcs.dll + + + + + + + + + + + + + + + + + + + False + Microsoft .NET Framework 4.8 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + \ No newline at end of file diff --git a/Injector/Injector.vcxproj b/Injector/Injector.vcxproj deleted file mode 100644 index 4f03135..0000000 --- a/Injector/Injector.vcxproj +++ /dev/null @@ -1,56 +0,0 @@ - - - - - Release - x64 - - - - 16.0 - Win32Proj - {7d9f180e-70d2-4b1e-92cd-f462027d8c75} - Injector - 10.0 - - - - Application - false - v142 - true - Unicode - - - - - - - - - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - MultiThreaded - - - Console - true - true - true - - - - - - - - - \ No newline at end of file diff --git a/Injector/Injector.vcxproj.filters b/Injector/Injector.vcxproj.filters deleted file mode 100644 index aa01c21..0000000 --- a/Injector/Injector.vcxproj.filters +++ /dev/null @@ -1,22 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - \ No newline at end of file diff --git a/Injector/Properties/AssemblyInfo.cs b/Injector/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c9543da --- /dev/null +++ b/Injector/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Injector")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Injector")] +[assembly: AssemblyCopyright("Copyright © Secret Club 2022")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("1fc97804-ff0d-40f9-a772-213a46dfa1ec")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Injector/packages.config b/Injector/packages.config new file mode 100644 index 0000000..64f03ff --- /dev/null +++ b/Injector/packages.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Installer/App.config b/Installer/App.config index 00bfd11..5ffd8f8 100644 --- a/Installer/App.config +++ b/Installer/App.config @@ -1,6 +1,6 @@ - + - + - \ No newline at end of file + diff --git a/Installer/Installer.cs b/Installer/Installer.cs index 70cc4e8..9f19f83 100644 --- a/Installer/Installer.cs +++ b/Installer/Installer.cs @@ -191,7 +191,7 @@ static int Main(string[] args) if (!File.Exists(sandboxBootkit)) Error($"Bootkit not found ${sandboxBootkit}, please compile SandboxBootkit"); - var injector = Path.Combine(basePath, "Injector.exe"); + var injector = Path.Combine(basePath, "Injector", "Injector.exe"); if (!File.Exists(injector)) Error($"Injector not found: {injector}"); var bootkitPath = Path.Combine(basePath, "bootmgfw.efi"); diff --git a/Installer/Installer.csproj b/Installer/Installer.csproj index 9c939b7..4f6ab1c 100644 --- a/Installer/Installer.csproj +++ b/Installer/Installer.csproj @@ -8,10 +8,11 @@ Exe Installer Installer - v4.6.1 + v4.8 512 true true + ..\x64\Release\ diff --git a/SandboxBootkit.sln b/SandboxBootkit.sln index 1ba842b..a002013 100644 --- a/SandboxBootkit.sln +++ b/SandboxBootkit.sln @@ -4,28 +4,25 @@ Microsoft Visual Studio Solution File, Format Version 12.00 VisualStudioVersion = 17.2.32616.157 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SandboxBootkit", "SandboxBootkit\SandboxBootkit.vcxproj", "{00F9B865-9986-4D9C-BB53-7BB826522896}" + ProjectSection(ProjectDependencies) = postProject + {1FC97804-FF0D-40F9-A772-213A46DFA1EC} = {1FC97804-FF0D-40F9-A772-213A46DFA1EC} + EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Installer", "Installer\Installer.csproj", "{D3606CE8-4338-40BB-9CFD-20D931339BA0}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Injector", "Injector\Injector.vcxproj", "{7D9F180E-70D2-4B1E-92CD-F462027D8C75}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Injector", "Injector\Injector.csproj", "{1FC97804-FF0D-40F9-A772-213A46DFA1EC}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Release|x64 = Release|x64 - Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {00F9B865-9986-4D9C-BB53-7BB826522896}.Release|x64.ActiveCfg = Release|x64 {00F9B865-9986-4D9C-BB53-7BB826522896}.Release|x64.Build.0 = Release|x64 - {00F9B865-9986-4D9C-BB53-7BB826522896}.Release|x86.ActiveCfg = Release|x64 - {00F9B865-9986-4D9C-BB53-7BB826522896}.Release|x86.Build.0 = Release|x64 {D3606CE8-4338-40BB-9CFD-20D931339BA0}.Release|x64.ActiveCfg = Release|x64 {D3606CE8-4338-40BB-9CFD-20D931339BA0}.Release|x64.Build.0 = Release|x64 - {D3606CE8-4338-40BB-9CFD-20D931339BA0}.Release|x86.ActiveCfg = Release|x64 - {D3606CE8-4338-40BB-9CFD-20D931339BA0}.Release|x86.Build.0 = Release|x64 - {7D9F180E-70D2-4B1E-92CD-F462027D8C75}.Release|x64.ActiveCfg = Release|x64 - {7D9F180E-70D2-4B1E-92CD-F462027D8C75}.Release|x64.Build.0 = Release|x64 - {7D9F180E-70D2-4B1E-92CD-F462027D8C75}.Release|x86.ActiveCfg = Release|x64 + {1FC97804-FF0D-40F9-A772-213A46DFA1EC}.Release|x64.ActiveCfg = Release|Any CPU + {1FC97804-FF0D-40F9-A772-213A46DFA1EC}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SandboxBootkit/SandboxBootkit.vcxproj b/SandboxBootkit/SandboxBootkit.vcxproj index f3cb826..5ed775c 100644 --- a/SandboxBootkit/SandboxBootkit.vcxproj +++ b/SandboxBootkit/SandboxBootkit.vcxproj @@ -62,7 +62,7 @@ if exist "$(OutDir)bootmgfw.bak" ( - "$(OutDir)Injector.exe" "$(OutDir)bootmgfw.bak" "$(TargetPath)" "$(OutDir)bootmgfw.efi" + "$(OutDir)Injector\Injector.exe" "$(OutDir)bootmgfw.bak" "$(TargetPath)" "$(OutDir)bootmgfw.efi" ) else ( echo You need to copy bootmgfw.bak next to SandboxBootkit.efi for automatic injection ) @@ -79,11 +79,6 @@ - - - {7d9f180e-70d2-4b1e-92cd-f462027d8c75} - -