- Added full .NET 5 Support

- Added logging
master
VollRagm 3 years ago
parent 8732f358b1
commit 7919d230c6

@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Reflection.PortableExecutable;
using System.Text;
using static apphost_extract_v2.Util;
namespace apphost_extract_v2
{
@ -18,31 +19,35 @@ namespace apphost_extract_v2
private readonly byte[] VERSION_SIGNATURE = new byte[] { 0x4C, 0x8D, 0x05, 0x0, 0x0, 0x0, 0x0, 0x48, 0x8D, 0x15, 0x0, 0x0, 0x0, 0x0, 0x48, 0x8D, 0x0D, 0x0, 0x0, 0x0, 0x0 };
private const string VERSION_SIGNATURE_MASK = "xxx???xxxx???xxxx???x";
public Analyzer(FileStream fs)
public Analyzer(FileInfo fi)
{
File = fs;
PEHeader = new PEHeaders(fs);
File = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read);
PEHeader = new PEHeaders(File);
}
public IApphostFile Open()
{
var textSegment = GetSegment(".text");
var textSegment = PEHeader.GetSegment(".text");
var sw = Stopwatch.StartNew();
var sigscanResults = Util.PatternScan(File,
Log.Info("Scanning for version string pointer...");
var sigscanResults = PatternScan(File,
textSegment.PointerToRawData, textSegment.SizeOfRawData,
VERSION_SIGNATURE, VERSION_SIGNATURE_MASK);
sw.Stop();
Log.Info($"Scan took {sw.ElapsedMilliseconds}ms | Version String Instructions -> {sigscanResults[0]:X8}");
if (sigscanResults.Length == 0)
return null;
var versionOffset = (int)BitConverter.ToUInt32(File.ReadBuffer(sigscanResults[0] + 3, 4));
var versionStringPtr = AddVirtualOffset(sigscanResults[0] + 7, versionOffset);
var versionStringPtr = PEHeader.AddVirtualOffset(sigscanResults[0] + 7, versionOffset);
var versionString = Encoding.Unicode.GetString(
File.ReadBuffer(
versionStringPtr, 6));
Log.Info($"Translated virtual offset -> {versionStringPtr:X8}: {versionString}");
Log.Info($"Found version string at 0x{versionStringPtr:X8} in {sw.ElapsedMilliseconds}ms -> {versionString}");
Console.WriteLine();
switch (versionString)
{
@ -58,43 +63,5 @@ namespace apphost_extract_v2
return null;
}
}
private int AddVirtualOffset(int fileAddress, int offset)
{
return VirtualAddressToFileOffset(FileOffsetToVirtualAddress(fileAddress) + offset);
}
private int FileOffsetToVirtualAddress(int offset)
{
var section = FindSection(offset, true);
return offset + (section.VirtualAddress - section.PointerToRawData);
}
private int VirtualAddressToFileOffset(int address)
{
var section = FindSection(address, false);
return address - (section.VirtualAddress - section.PointerToRawData);
}
public SectionHeader GetSegment(string name)
{
var section = PEHeader.SectionHeaders.Where(x => x.Name == name).FirstOrDefault();
return section;
}
public SectionHeader FindSection(int address, bool fileOffset)
{
foreach (var section in PEHeader.SectionHeaders)
{
if (fileOffset)
{
if (section.PointerToRawData < address && section.PointerToRawData + section.SizeOfRawData > address) return section;
}
else
if (section.VirtualAddress < address && section.VirtualAddress + section.VirtualSize > address) return section;
}
return new SectionHeader();
}
}
}

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace apphost_extract_v2
{
public class HashChecker
{
}
}

@ -16,6 +16,7 @@ namespace apphost_extract_v2.Models
public ApphostFile30(FileStream fs, PEHeaders peheader) : base(fs, peheader)
{
Header = new AppHostFileHeader();
Log.Info($"Reading header at 0x{HEADER_OFFSET_PTR:X8}...");
var headerAddress = BitConverter.ToInt32(fs.ReadBuffer(HEADER_OFFSET_PTR, 4));
var headerBuffer = fs.ReadBuffer(headerAddress, HEADER_SIZE);
@ -23,13 +24,13 @@ namespace apphost_extract_v2.Models
Header.Path = Encoding.UTF8.GetString(fs.ReadBuffer(headerAddress + HEADER_SIZE, 0xC));
Header.Manifest = ParseManifest();
}
private AppHostManifest ParseManifest()
{
AppHostManifest manifest = new AppHostManifest();
var embeddedFileCount = BitConverter.ToInt32(Header.Raw, 0x8);
Log.Info($"Found {embeddedFileCount} embedded files.");
for (int i = 0; i < embeddedFileCount; i++)
{

@ -18,7 +18,7 @@ namespace apphost_extract_v2.Models
Header = new AppHostFileHeader();
var headerAddress = BitConverter.ToInt32(fs.ReadBuffer(HEADER_OFFSET_PTR, 4));
var headerBuffer = fs.ReadBuffer(headerAddress, HEADER_SIZE);
Log.Info($"Reading header at 0x{HEADER_OFFSET_PTR:X8}...");
Header.Raw = headerBuffer;
Header.Path = Encoding.UTF8.GetString(fs.ReadBuffer(headerAddress + HEADER_SIZE, 0xC));
@ -30,8 +30,8 @@ namespace apphost_extract_v2.Models
{
AppHostManifest manifest = new AppHostManifest();
var embeddedFileCount = BitConverter.ToInt32(Header.Raw, 0x8);
for(int i = 0; i< embeddedFileCount; i++)
Log.Info($"Found {embeddedFileCount} embedded files.");
for (int i = 0; i< embeddedFileCount; i++)
{
manifest.FileEntries.Add(GetNextEntry());
}

@ -1,40 +1,73 @@
using apphost_extract_v2.General;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection.PortableExecutable;
using System.Text;
using static apphost_extract_v2.Util;
namespace apphost_extract_v2.Models
{
public class ApphostFile5 : IApphostFile
{
private const int HEADER_OFFSET_PTR = 0x20268;
private readonly byte[] HEADER_OFFSET_SIG = { 0xE8, 0x0, 0x0, 0x0, 0x0, 0x48, 0x8B, 0x05, 0x0, 0x0, 0x0, 0x0, 0x48, 0x85, 0xC0 };
private const string HEADER_OFFSET_MASK = "x????xxx????xxx";
private const int HEADER_SIZE = 0xD;
private const int FILE_ENTRY_SIZE = 0x12;
public ApphostFile5(FileStream fs, PEHeaders peheader) : base(fs, peheader)
{
Header = new AppHostFileHeader();
var headerAddress = BitConverter.ToInt32(fs.ReadBuffer(HEADER_OFFSET_PTR, 4));
var headerAddress = FindHeaderOffset();
if(headerAddress == 0)
Log.Fatal("Unable to located bundle header :/");
var headerBuffer = fs.ReadBuffer(headerAddress, HEADER_SIZE);
Header.Raw = headerBuffer;
Header.Path = Encoding.UTF8.GetString(fs.ReadBuffer(headerAddress + HEADER_SIZE, 0xC));
Header.Path = Encoding.UTF8.GetString(
fs.ReadBuffer(headerAddress + HEADER_SIZE, 0xC));
Header.Manifest = ParseManifest();
}
private uint FindHeaderOffset()
{
var textSegment = PEHeader.GetSegment(".text");
Log.Info("Scanning for the .NET 5 Bundle header...");
var sw = Stopwatch.StartNew();
var sigscanResults = PatternScan(FileStream,
textSegment.PointerToRawData, textSegment.SizeOfRawData,
HEADER_OFFSET_SIG, HEADER_OFFSET_MASK);
sw.Stop();
if (sigscanResults.Length == 0) return 0;
var headerOffset = (int)BitConverter.ToUInt32(
FileStream.ReadBuffer(sigscanResults[0] + 8, 4));
var headerPtr = PEHeader.AddVirtualOffset(sigscanResults[0] + 12, headerOffset);
var headerAddress = BitConverter.ToUInt32(FileStream.ReadBuffer(headerPtr, 4));
Log.Info($"Found bundle header offset at 0x{headerPtr:X8} in {sw.ElapsedMilliseconds}ms -> {headerAddress:X8}");
return headerAddress;
}
private AppHostManifest ParseManifest()
{
//Seek over random bullshit that got added in .NET 5
FileStream.Seek(0x28, SeekOrigin.Current);
AppHostManifest manifest = new AppHostManifest();
var embeddedFileCount = BitConverter.ToInt32(Header.Raw, 0x8);
Log.Info($"Found {embeddedFileCount} embedded files.");
for (int i = 0; i < embeddedFileCount; i++)
{
manifest.FileEntries.Add(GetNextEntry());
}
return manifest;
}
@ -59,7 +92,6 @@ namespace apphost_extract_v2.Models
}
public override void Close()
{
FileStream.Close();

@ -14,32 +14,5 @@ namespace apphost_extract_v2.General
public string Name { get; set; }
public byte[] Raw;
//public AppHostFileEntry()
//{
// FileStream = File;
// byte[] entryBuffer = new byte[FILE_ENTRY_SIZE];
// File.Read(entryBuffer, 0, entryBuffer.Length);
// Raw = entryBuffer;
// Offset = BitConverter.ToInt64(Raw, 0);
// //hopefully nobody embeds a file larger than 2GB :D
// Size = (int)BitConverter.ToInt64(Raw, 0x8);
// byte[] stringBuffer = new byte[Raw[0x11]];
// File.Read(stringBuffer, 0, stringBuffer.Length);
// Name = Encoding.UTF8.GetString(stringBuffer);
//}
//public byte[] Read()
//{
// //jumps to the offsets and reads the bytes
// byte[] buffer = new byte[Size];
// FileStream.Seek(Offset, SeekOrigin.Begin);
// FileStream.Read(buffer, 0, Size);
// return buffer;
//}
}
}

@ -14,16 +14,6 @@ namespace apphost_extract_v2.General
public AppHostManifest()
{
FileEntries = new List<AppHostFileEntry>();
//List<AppHostFileEntry> entries = new List<AppHostFileEntry>();
//for (int i = 0; i < embeddedFileCount; i++)
//{
// AppHostFileEntry entry = new AppHostFileEntry(File);
// entries.Add(entry);
//}
//FileEntries = entries.AsReadOnly();
//Log.Info("Manifest parsed successfully!");
}
}
}

@ -10,51 +10,27 @@ namespace apphost_extract_v2
{
static void Main(string[] args)
{
var file = "net5-fd.exe";
var fs = new FileStream(file, FileMode.Open, FileAccess.Read);
var anal = new Analyzer(fs);
var af = anal.Open();
var path = new FileInfo(file);
var directory = Path.Combine(path.DirectoryName, path.Name.Remove(path.Name.Length - path.Extension.Length) + "_extracted");
af.ExtractAll(directory);
Console.ReadLine();
//RunTest("net30-sc.exe");
//RunTest("net5-sc.exe");
//Log.Info("Scanning for pattern...");
//Stopwatch sw = Stopwatch.StartNew();
//var res = Util.PatternScan(fs, 0, (int)fs.Length, pattern, mask);
//sw.Stop();
//Log.Info("Found pattern at " + res[0].ToString("X8") + $" in {sw.ElapsedMilliseconds}ms");
Log.Info("apphost-extract-v2 by VollRagm\n", ConsoleColor.Yellow);
/* Log.Info("apphost-extract by VollRagm\n", ConsoleColor.Yellow);
var path = GetPath(args);
var fileInfo = GetFileInfo(args);
// var file = AppHostFile.Open(path2);//path.FullName);
// Log.Info($"{file.Header.Manifest.FileEntries.Count} embedded file(s) found.");
var apphostAnalyzer = new Analyzer(fileInfo);
var apphost = apphostAnalyzer.Open();
if(apphost == null)
Log.Fatal("Unable to determine apphost version.");
var directory = Path.Combine(path.DirectoryName, path.Name.Remove(path.Name.Length - path.Extension.Length) + "_extracted");
Console.WriteLine();
Log.Info("Extracting...");
Log.Info("File parsed successfully, extracting contents...");
Console.WriteLine();
//file.ExtractAll(directory);
var directory = Path.Combine(fileInfo.DirectoryName, fileInfo.Name.Remove(fileInfo.Name.Length - fileInfo.Extension.Length) + "_extracted");
apphost.ExtractAll(directory);
Console.WriteLine();
Log.Info("Done.");
// file.Close();
Console.ReadLine();*/
Log.Info("Done.");
Console.ReadLine();
}
//static void RunTest(string file)
//{
// Log.Info("Running test on " + file + ", scanning for version sig...");
// var d = new Analyzer(fs).GetVersion();
//}
static FileInfo GetPath(string[] args)
static FileInfo GetFileInfo(string[] args)
{
try
{

@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.PortableExecutable;
using System.Text;
namespace apphost_extract_v2
@ -45,5 +47,43 @@ namespace apphost_extract_v2
fs.Read(buff, 0, length);
return buff;
}
public static int AddVirtualOffset(this PEHeaders header, int fileAddress, int offset)
{
return header.VirtualAddressToFileOffset(header.FileOffsetToVirtualAddress(fileAddress) + offset);
}
public static int FileOffsetToVirtualAddress(this PEHeaders header, int offset)
{
var section = header.FindSection(offset, true);
return offset + (section.VirtualAddress - section.PointerToRawData);
}
public static int VirtualAddressToFileOffset(this PEHeaders header, int address)
{
var section = header.FindSection(address, false);
return address - (section.VirtualAddress - section.PointerToRawData);
}
public static SectionHeader GetSegment(this PEHeaders header, string name)
{
var section = header.SectionHeaders.Where(x => x.Name == name).FirstOrDefault();
return section;
}
public static SectionHeader FindSection(this PEHeaders header, int address, bool fileOffset)
{
foreach (var section in header.SectionHeaders)
{
if (fileOffset)
{
if (section.PointerToRawData < address && section.PointerToRawData + section.SizeOfRawData > address) return section;
}
else
if (section.VirtualAddress < address && section.VirtualAddress + section.VirtualSize > address) return section;
}
return new SectionHeader();
}
}
}

Loading…
Cancel
Save