From 53ecca991e4c87e9fd703c3a5d6a4627f309f3c1 Mon Sep 17 00:00:00 2001 From: "Vasiliy [Xi-Tauw] Kravets" Date: Tue, 23 Apr 2019 12:01:24 +0300 Subject: [PATCH] Initial commit Initial source commit --- README.MD | 29 +++ Screenshots/example.png | Bin 0 -> 15658 bytes SymbiontPE.sln | 22 +++ SymbiontPE/BWExtensions.cs | 20 ++ SymbiontPE/PEFile.cs | 274 ++++++++++++++++++++++++++ SymbiontPE/PESectionParameters.cs | 67 +++++++ SymbiontPE/Program.cs | 71 +++++++ SymbiontPE/Properties/AssemblyInfo.cs | 36 ++++ SymbiontPE/SymbiontPE.csproj | 50 +++++ 9 files changed, 569 insertions(+) create mode 100644 README.MD create mode 100644 Screenshots/example.png create mode 100644 SymbiontPE.sln create mode 100644 SymbiontPE/BWExtensions.cs create mode 100644 SymbiontPE/PEFile.cs create mode 100644 SymbiontPE/PESectionParameters.cs create mode 100644 SymbiontPE/Program.cs create mode 100644 SymbiontPE/Properties/AssemblyInfo.cs create mode 100644 SymbiontPE/SymbiontPE.csproj diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..8066c2d --- /dev/null +++ b/README.MD @@ -0,0 +1,29 @@ +# SymbiontPE + +## Description + +Simple tool that allows add custom function (with custom dll) to PE-file import section. After that the dll will be force to loaded by executed app. This allows to easily write proxy dll for the app. + +For examle some app has version.dll in import (this is almost every app). We want to hijack version.dll through placing custom version.dll with payload near app. One solution is write code of payload dll. For correct loading, payload dll must be same bitness and has same import as original version.dll. If we want app to contine workin after dll hijack, than we need add correct code for all functions in our payload dll (e.g. redirect calls to original library). There are some ways of writing those code (link_github). + +But there is another way - we could copy version.dll and add custom function from custom dll. When app started, it loads modified version.dll and OS force app to load custom dll. So, with this approach dll still needed, but this payload dll coulde easily coded, since it has inly two simple requirements - corresponded bittness and export only one function with any prototype (void dummy() {}, will work). + +## Sreenshot + +![Example of using](Screenshots/example.png) + +## Using + +SymbiontPE PathToDll ImportDllName ImportFunctionName OutputPath + +* PathToDll - path to original dll + +* ImportDllName - dll name to be added to import section + +* ImportFunctionName - function name to be added to import section + +* OutputPath - output path for saveing result + +Example of using: + +SymbiontPE C:\Windows\version.dll dummy.dll dummy C:\1\version.dll diff --git a/Screenshots/example.png b/Screenshots/example.png new file mode 100644 index 0000000000000000000000000000000000000000..be3b06380fe408b4adabb370793d4677f5588247 GIT binary patch literal 15658 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 _sections; + private List _sectionParameters; + + // Import Data + private byte[] _importData; + + // Consts + //private const int SECTION_DESCRIPTOR_SIZE = 40; + + public PEFile(string path) + { + _content = File.ReadAllBytes(path); + // DOS header + if (((_content[0] == 0x4d) && (_content[1] == 0x5a)) || (((_content[0] == 0x5a) && (_content[1] == 0x4d)))) + // MZ + { + _PEHeaderOffset = (Int32) BitConverter.ToUInt32(_content, 0x3c); + // PE header + if ((_content[_PEHeaderOffset] == 0x50) && (_content[_PEHeaderOffset + 1] == 0x45)) // PE + { + const int MACHINE_OFFSET = 4; + var machine = BitConverter.ToUInt16(_content, _PEHeaderOffset + MACHINE_OFFSET); + if (machine == 0x014c) + { + Console.WriteLine(" [.] Machine: pe32"); + _is64 = false; + } + else if (machine == 0x8664) + { + Console.WriteLine(" [.] Machine: pe64"); + _is64 = true; + } + else + throw new Exception("Unsupported machine value"); + + const int SECTION_COUNT_OFFSET = MACHINE_OFFSET + 2; + var countOfSections = BitConverter.ToUInt16(_content, _PEHeaderOffset + SECTION_COUNT_OFFSET); + Console.WriteLine($" [.] Sections count: {countOfSections}"); + + const int OPTIONAL_HEADER_SIZE_OFFSET = SECTION_COUNT_OFFSET + 14; + var optionalHeaderSize = BitConverter.ToUInt16(_content, + _PEHeaderOffset + OPTIONAL_HEADER_SIZE_OFFSET); + Console.WriteLine($" [.] Optional header size: {optionalHeaderSize}"); + + // Optional Header + const int OPTIONAL_HEADER_OFFSET = OPTIONAL_HEADER_SIZE_OFFSET + 4; + var optionalHeaderMagic = BitConverter.ToUInt16(_content, _PEHeaderOffset + OPTIONAL_HEADER_OFFSET); + bool isMagic64; + if (optionalHeaderMagic == 0x010b) + { + Console.WriteLine(" [.] OptHeader Magic: 32bit"); + isMagic64 = false; + } + else if (optionalHeaderMagic == 0x020b) + { + Console.WriteLine(" [.] OptHeader Magic: 64bit"); + isMagic64 = true; + } + else + throw new Exception("Unsupported OptHeader magic value"); + if (_is64 != isMagic64) + throw new Exception("OptHeader magic does not match machine"); + + // Data Directories + const int DATADIR_COUNT = 16; + const int DATADIR_SIZE = 8; + int dataDirsOffset = OPTIONAL_HEADER_OFFSET + optionalHeaderSize - DATADIR_COUNT * DATADIR_SIZE; + _importDataDirRVAOffset = dataDirsOffset + 8; + var importDataDirRVA = BitConverter.ToUInt32(_content, _PEHeaderOffset + _importDataDirRVAOffset); + + _importDataDirSizeOffset = _importDataDirRVAOffset + 4; + var importDataDirSize = BitConverter.ToUInt32(_content, _PEHeaderOffset + _importDataDirSizeOffset); + + // Sections Table + _sectionsOffset = OPTIONAL_HEADER_OFFSET + optionalHeaderSize; + var index = _sectionsOffset; + _sections = new List(); + _sectionParameters = new List(); + for (var i = 0; i < countOfSections; i++) + { + var sectionBytes = new byte[PESectionParameters.SECTION_DESCRIPTOR_SIZE]; + Array.Copy(_content, _PEHeaderOffset + index, sectionBytes, 0, + PESectionParameters.SECTION_DESCRIPTOR_SIZE); + index += PESectionParameters.SECTION_DESCRIPTOR_SIZE; + var p = new PESectionParameters(sectionBytes); + _sectionParameters.Add(p); + _sections.Add(p.Name); + Console.WriteLine($" [.] Find section: '{p.Name}'"); + } + + // Find section with import + var sectionWithImport = -1; + for (var i = 0; i < _sectionParameters.Count; i++) + { + var p = _sectionParameters[i]; + if ((p.VirtualAddress <= importDataDirRVA) && + (p.VirtualAddress + p.SizeOfRawData >= importDataDirRVA + importDataDirSize)) + sectionWithImport = i; + } + if (sectionWithImport == -1) + throw new Exception("Unable to find section with Import Directory"); + Console.WriteLine($" [.] Import found at section '{_sectionParameters[sectionWithImport].Name}'"); + + var importDataDirOffset = importDataDirRVA - _sectionParameters[sectionWithImport].VirtualAddress + _sectionParameters[sectionWithImport].PointerToRawData; + _importData = new byte[importDataDirSize]; + Array.Copy(_content, importDataDirOffset, _importData, 0, importDataDirSize); + return; + } + } + throw new Exception("Bad PE"); + } + + public void FixSizeOfImage() + { + var size = _sectionParameters[_sectionParameters.Count - 1].VirtualSize + _sectionParameters[_sectionParameters.Count - 1].VirtualAddress; + if (size % 0x1000 != 0) + size = ((size / 0x1000) + 1) * 0x1000; + Array.Copy(BitConverter.GetBytes(size), 0, _content, _PEHeaderOffset + 80, 4); + Console.WriteLine(" [.] SizeOfImage fixed"); + } + + public List GetSections() + { + var rv = new List(); + rv.AddRange(_sections); + return rv; + } + + public PESectionParameters GetSectionParams(string sectionName) + { + foreach (var p in _sectionParameters) + { + if (p.Name == sectionName) + return p; + } + throw new Exception($"Section '{sectionName}' not found (GetSectionParams)"); + } + + public void SetSectionParams(string sectionName, PESectionParameters sectParams) + { + for (var i = 0; i < _sectionParameters.Count; i++) + { + if (_sectionParameters[i].Name == sectionName) + { + _sectionParameters[i] = sectParams; + Array.Copy(sectParams.ToBytes(), 0, _content, + _PEHeaderOffset + _sectionsOffset + PESectionParameters.SECTION_DESCRIPTOR_SIZE * i, + PESectionParameters.SECTION_DESCRIPTOR_SIZE); + return; + } + } + throw new Exception($"Section '{sectionName}' not found (SetSectionParams)"); + } + + public void WriteDataAndTrim(string sectionName, UInt32 offset, byte[] bytes) + { + for (var i = 0; i < _sectionParameters.Count; i++) + { + if (_sectionParameters[i].Name == sectionName) + { + var beginSize = _sectionParameters[i].PointerToRawData + offset; + var beginAlign = _sectionParameters[i].PointerToRawData + Align(offset, 0x1000); + var endAlign = Align((UInt32) bytes.Length, 0x200); + var newContent = new byte[beginAlign + endAlign]; + Array.Copy(_content, 0, newContent, 0, beginSize); + Array.Copy(bytes, 0, newContent, beginAlign, bytes.Length); + _content = newContent; + Console.WriteLine($" [.] File new size: {_content.Length}"); + return; + } + } + throw new Exception($"Section '{sectionName}' not found (WriteDataAndTrim)"); + } + + public void Save(string outputPath) + { + File.WriteAllBytes(outputPath, _content); + } + + public UInt32 Align(UInt32 length, UInt32 align) + { + UInt32 rv = 0; + while (rv < length) + rv += align; + return rv; + } + + public UInt32 CalcNewImportSize(string dllName, string dllFunc) + { + return (UInt32)(_importData.Length + 20 + dllName.Length + 1 + 2 + dllFunc.Length + 1 + 0x10 + 0x10); + } + + public byte[] CreateNewImport(string sectionName, UInt32 offset, string dllName, string dllFunc) + { + for (var i = 0; i < _sectionParameters.Count; i++) + { + if (_sectionParameters[i].Name == sectionName) + { + var rv = new byte[CalcNewImportSize(dllName, dllFunc)]; + UInt32 BaseAddr = _sectionParameters[i].VirtualAddress + offset; + using (var mem = new MemoryStream(rv)) + using (var bw = new BinaryWriter(mem)) + { + // Write original without last line (originalImport.Length - 20) + bw.Write(_importData, 0, _importData.Length - 20); + // Write IMPORT ENTRY (20) + bw.Write4(BaseAddr + (_importData.Length + 20 + dllName.Length + 1 + 2 + dllFunc.Length + 1 + 0x10)); + bw.WriteZero(4); + bw.WriteZero(4); + bw.Write4(BaseAddr + (_importData.Length + 20)); + bw.Write4(BaseAddr + (_importData.Length + 20 + dllName.Length + 1 + 2 + dllFunc.Length + 1)); + // Write last line (20) + bw.WriteZero(20); + // Write dll (dllName.Length + 1) + bw.Write(Encoding.ASCII.GetBytes(dllName)); + bw.WriteZero(); + // Write zero-struct (2) + bw.WriteZero(2); + // Write func (dllFunc.Length + 1) + bw.Write(Encoding.ASCII.GetBytes(dllFunc)); + bw.WriteZero(); + // Write Thunks (0x20) + bw.Write4(BaseAddr + (_importData.Length + 20 + dllName.Length + 1)); + bw.WriteZero(12); + bw.Write4(BaseAddr + (_importData.Length + 20 + dllName.Length + 1)); + bw.WriteZero(12); + } + // Copy + return rv; + } + } + throw new Exception($"Section '{sectionName}' not found (CreateNewImport)"); + } + + public void RedirectImportDataDir(string sectionName, UInt32 offset) + { + for (var i = 0; i < _sectionParameters.Count; i++) + { + if (_sectionParameters[i].Name == sectionName) + { + var newImportOff = _sectionParameters[i].VirtualAddress + offset; + Array.Copy(BitConverter.GetBytes(newImportOff), 0, _content, + _PEHeaderOffset + _importDataDirRVAOffset, 4); + var newImportSize = BitConverter.ToUInt32(_content, _PEHeaderOffset + _importDataDirSizeOffset); + newImportSize += 0x14; // FIXME + Array.Copy(BitConverter.GetBytes(newImportSize), 0, _content, + _PEHeaderOffset + _importDataDirSizeOffset, 4); + return; + } + } + throw new Exception($"Section '{sectionName}' not found (RedirectImportDataDir)"); + } + } +} \ No newline at end of file diff --git a/SymbiontPE/PESectionParameters.cs b/SymbiontPE/PESectionParameters.cs new file mode 100644 index 0000000..0f295a9 --- /dev/null +++ b/SymbiontPE/PESectionParameters.cs @@ -0,0 +1,67 @@ +using System; +using System.IO; +using System.Text; + +namespace SymbiontPE +{ + public class PESectionParameters + { + public const int SECTION_DESCRIPTOR_SIZE = 40; + + public readonly string Name; + public UInt32 VirtualSize; + public readonly UInt32 VirtualAddress; + public UInt32 SizeOfRawData; + public readonly UInt32 PointerToRawData; + /* + public readonly UInt32 PointerToRelocations; + public readonly UInt32 PointerToLinenumbers; + public readonly UInt16 NumberOfRelocations; + public readonly UInt16 NumberOfLinenumbers; + */ + public UInt32 Characteristics; + + public PESectionParameters(byte[] sectionBytes) + { + if (sectionBytes.Length != SECTION_DESCRIPTOR_SIZE) + throw new Exception("Bad section"); + using (var mem = new MemoryStream(sectionBytes)) + using (var br = new BinaryReader(mem)) + { + var nameBts = br.ReadBytes(8); + Name = Encoding.ASCII.GetString(nameBts).TrimEnd('\0'); + VirtualSize = br.ReadUInt32(); + VirtualAddress = br.ReadUInt32(); + SizeOfRawData = br.ReadUInt32(); + PointerToRawData = br.ReadUInt32(); + br.ReadUInt32(); // PointerToRelocations + br.ReadUInt32(); // PointerToLinenumbers + br.ReadUInt16(); // NumberOfRelocations + br.ReadUInt16(); // NumberOfLinenumbers + Characteristics = br.ReadUInt32(); + } + } + + public byte[] ToBytes() + { + var rv = new byte[SECTION_DESCRIPTOR_SIZE]; + using (var mem = new MemoryStream(rv)) + using (var bw = new BinaryWriter(mem)) + { + var nameBts = new byte[8]; + Array.Copy(Encoding.ASCII.GetBytes(Name), nameBts, Name.Length); + bw.Write(nameBts); + bw.Write(VirtualSize); + bw.Write(VirtualAddress); + bw.Write(SizeOfRawData); + bw.Write(PointerToRawData); + bw.WriteZero(4); // PointerToRelocations + bw.WriteZero(4); // PointerToLinenumbers + bw.WriteZero(2); // NumberOfRelocations + bw.WriteZero(2); // NumberOfLinenumbers + bw.Write(Characteristics); + } + return rv; + } + } +} \ No newline at end of file diff --git a/SymbiontPE/Program.cs b/SymbiontPE/Program.cs new file mode 100644 index 0000000..532e448 --- /dev/null +++ b/SymbiontPE/Program.cs @@ -0,0 +1,71 @@ +using System; +using System.IO; +using System.Linq; +using System.Text; + +namespace SymbiontPE +{ + class Program + { + static void Banner() + { + Console.WriteLine(" ____ _ _ _ ____ _____\n / ___| _ _ _ __ ___ | |__ (_) ___ _ __ | |_|####\\|#####|\n \\___ \\| | | | '_ ` _ \\| '_ \\| |/ _ \\| '_ \\| __|#|_)#|###|\n ___) | |_| | | | | | | |_) | | (_) | | | | |_|####/|#|___\n |____/ \\__, |_| |_| |_|_.__/|_|\\___/|_| |_|\\__|#| |#####|\n |___/\n\n (c) 2019, Xi-Tauw, https://amonitoring.ru\n"); + } + + static void Usage() + { + Console.WriteLine(" Usage:\n SymbiontPE pathToInputDll importDllName importFunction pathToOutputDll\n Parameters:\n - path to existing dll (target of proxy)\n - name of dll to be added to import\n - name of function to be added to import\n - path to save output proxy dll\n Notes:\n Any overlay (e.g. embedded signature) from input dll will be removed.\n importFunction must be present in importDllName for correct loading of library, but it will not be invoked. Payload must be executed from DllEntry.\n Example:\n SymbiontPE C:\\windows\\system32\\version.dll my.dll func C:\\data\\version.dll\n The command create proxy library, that acts like version.dll, but load my.dll at start."); + } + + static void Main(string[] args) + { + Banner(); + if (args.Length != 4) + { + Usage(); + return; + } + AddImportTableFunction(args[0], args[1], args[2], args[3]); + } + + private static void AddImportTableFunction(string path, string dllName, string dllFunc, string outputPath) + { + try + { + Console.WriteLine(" [!] Parse PE file"); + var pe = new PEFile(path); + + var newImportSize = pe.CalcNewImportSize(dllName, dllFunc); + + Console.WriteLine(" [!] Parse sections"); + var sections = pe.GetSections(); + var lastSection = sections[sections.Count - 1]; + var sectParams = pe.GetSectionParams(lastSection); + + Console.WriteLine(" [!] Change last section parameters"); + var originalSize = sectParams.SizeOfRawData; + sectParams.Characteristics |= 0xC0000000; + var addSize = pe.Align(originalSize, 0x1000) + pe.Align(newImportSize, 0x200) - originalSize; + sectParams.VirtualSize += addSize; + sectParams.SizeOfRawData += addSize; + pe.SetSectionParams(lastSection, sectParams); + + Console.WriteLine(" [!] Create new import"); + var newImport = pe.CreateNewImport(lastSection, pe.Align(originalSize, 0x1000), dllName, dllFunc); + + Console.WriteLine(" [!] Write new import"); + pe.WriteDataAndTrim(lastSection, originalSize, newImport); + pe.RedirectImportDataDir(lastSection, pe.Align(originalSize, 0x1000)); + pe.FixSizeOfImage(); + + Console.WriteLine(" [!] Save result"); + pe.Save(outputPath); + Console.WriteLine(" [!] Done"); + } + catch (Exception e) + { + Console.WriteLine($"[-] Crash. Message: {e.Message}"); + } + } + } +} diff --git a/SymbiontPE/Properties/AssemblyInfo.cs b/SymbiontPE/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..7111fa0 --- /dev/null +++ b/SymbiontPE/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("SymbiontPE")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SymbiontPE")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[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("335c42e0-ab15-4eb4-b450-977d94b0741c")] + +// 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/SymbiontPE/SymbiontPE.csproj b/SymbiontPE/SymbiontPE.csproj new file mode 100644 index 0000000..adf3f12 --- /dev/null +++ b/SymbiontPE/SymbiontPE.csproj @@ -0,0 +1,50 @@ + + + + + Debug + AnyCPU + {335C42E0-AB15-4EB4-B450-977D94B0741C} + Exe + SymbiontPE + SymbiontPE + v4.0 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + \ No newline at end of file