Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
Initial source commit
  • Loading branch information
xi-tauw committed Apr 23, 2019
0 parents commit 53ecca9
Show file tree
Hide file tree
Showing 9 changed files with 569 additions and 0 deletions.
29 changes: 29 additions & 0 deletions README.MD
Original file line number Diff line number Diff line change
@@ -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
Binary file added Screenshots/example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions SymbiontPE.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.9
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SymbiontPE", "SymbiontPE\SymbiontPE.csproj", "{335C42E0-AB15-4EB4-B450-977D94B0741C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{335C42E0-AB15-4EB4-B450-977D94B0741C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{335C42E0-AB15-4EB4-B450-977D94B0741C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{335C42E0-AB15-4EB4-B450-977D94B0741C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{335C42E0-AB15-4EB4-B450-977D94B0741C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
20 changes: 20 additions & 0 deletions SymbiontPE/BWExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.IO;

namespace SymbiontPE
{
public static class BWExtensions
{
public static void WriteZero(this BinaryWriter bw, int count = 1)
{
var zeroes = new byte[count];
bw.Write(zeroes);
}

public static void Write4(this BinaryWriter bw, long qword)
{
// Cast once, instead of everytime
bw.Write((UInt32)qword);
}
}
}
274 changes: 274 additions & 0 deletions SymbiontPE/PEFile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace SymbiontPE
{
public class PEFile
{
// Data
private byte[] _content;
private bool _is64;

// Offsets
private int _PEHeaderOffset;
private int _sectionsOffset;
private int _importDataDirRVAOffset;
private int _importDataDirSizeOffset;

// Sections
private List<string> _sections;
private List<PESectionParameters> _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<string>();
_sectionParameters = new List<PESectionParameters>();
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<string> GetSections()
{
var rv = new List<string>();
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)");
}
}
}
Loading

0 comments on commit 53ecca9

Please sign in to comment.