- Added .NET Core 3.1 support

master
VollRagm 4 years ago
parent 08905b1747
commit a8bb52ed2d

@ -1,5 +1,8 @@
using System; using apphost_extract_v2.General;
using apphost_extract_v2.Models;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection.PortableExecutable; using System.Reflection.PortableExecutable;
@ -12,8 +15,8 @@ namespace apphost_extract_v2
private FileStream File; private FileStream File;
public PEHeaders PEHeader; public PEHeaders PEHeader;
private readonly byte[] VERSION_SIGNATURE = new byte[] { }; 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 = ""; private const string VERSION_SIGNATURE_MASK = "xxx???xxxx???xxxx???x";
public Analyzer(FileStream fs) public Analyzer(FileStream fs)
{ {
@ -21,23 +24,77 @@ namespace apphost_extract_v2
PEHeader = new PEHeaders(fs); PEHeader = new PEHeaders(fs);
} }
public IApphostFile Open()
{
var textSegment = GetSegment(".text");
var sw = Stopwatch.StartNew();
var sigscanResults = Util.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 versionString = Encoding.Unicode.GetString(
File.ReadBuffer(
versionStringPtr, 6));
Log.Info($"Translated virtual offset -> {versionStringPtr:X8}: {versionString}");
switch (versionString)
{
case "3.0":
return new ApphostFile30(File, PEHeader);
case "3.1":
return new ApphostFile31(File, PEHeader);
case "5.0":
return new ApphostFile5(File, PEHeader);
default:
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) public SectionHeader GetSegment(string name)
{ {
var section = PEHeader.SectionHeaders.Where(x => x.Name == name).FirstOrDefault(); var section = PEHeader.SectionHeaders.Where(x => x.Name == name).FirstOrDefault();
return section; return section;
} }
public ApphostVersion GetVersion() 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();
} }
}
public enum ApphostVersion
{
NET30,
NET31,
NET5
} }
} }

@ -0,0 +1,21 @@
using apphost_extract_v2.General;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection.PortableExecutable;
using System.Text;
namespace apphost_extract_v2.Models
{
public class ApphostFile30 : IApphostFile
{
public ApphostFile30(FileStream fs, PEHeaders peheader) : base(fs, peheader) { }
public override void Close()
{
throw new NotImplementedException();
}
}
}

@ -0,0 +1,69 @@
using apphost_extract_v2.General;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection.PortableExecutable;
using System.Text;
namespace apphost_extract_v2.Models
{
public class ApphostFile31 : IApphostFile
{
private const int HEADER_OFFSET_PTR = 0x27600;
private const int HEADER_SIZE = 0xD;
private const int FILE_ENTRY_SIZE = 0x12;
public ApphostFile31(FileStream fs, PEHeaders peheader) : base(fs, peheader)
{
Header = new AppHostFileHeader();
var headerAddress = BitConverter.ToInt32(fs.ReadBuffer(HEADER_OFFSET_PTR, 4));
var headerBuffer = fs.ReadBuffer(headerAddress, HEADER_SIZE);
Header.Raw = headerBuffer;
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);
for(int i = 0; i< embeddedFileCount; i++)
{
manifest.FileEntries.Add(GetNextEntry());
}
return manifest;
}
private AppHostFileEntry GetNextEntry()
{
AppHostFileEntry entry = new AppHostFileEntry();
byte[] entryBuffer = new byte[FILE_ENTRY_SIZE];
FileStream.Read(entryBuffer, 0, entryBuffer.Length);
entry.Raw = entryBuffer;
entry.Offset = BitConverter.ToInt64(entry.Raw, 0);
//hopefully nobody embeds a file larger than 2GB :D
entry.Size = (int)BitConverter.ToInt64(entry.Raw, 0x8);
byte[] stringBuffer = new byte[entry.Raw[0x11]];
FileStream.Read(stringBuffer, 0, stringBuffer.Length);
entry.Name = Encoding.UTF8.GetString(stringBuffer);
return entry;
}
public override void Close()
{
FileStream.Close();
}
}
}

@ -0,0 +1,20 @@
using apphost_extract_v2.General;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection.PortableExecutable;
using System.Text;
namespace apphost_extract_v2.Models
{
public class ApphostFile5 : IApphostFile
{
public ApphostFile5(FileStream fs, PEHeaders peheader) : base(fs, peheader) { }
public override void Close()
{
throw new NotImplementedException();
}
}
}

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace apphost_extract_v2.General
{
public class AppHostFileEntry
{
public long Offset { get; set; }
public int Size { get; set; }
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;
//}
}
}

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace apphost_extract_v2.General
{
public class AppHostFileHeader
{
public byte[] Raw;
public string Path { get; set; }
public AppHostManifest Manifest { get; set; }
}
}

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace apphost_extract_v2.General
{
public class AppHostManifest
{
public List<AppHostFileEntry> FileEntries { get; set; }
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!");
}
}
}

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection.PortableExecutable;
using System.Text;
namespace apphost_extract_v2.General
{
public abstract class IApphostFile
{
internal FileStream FileStream;
public PEHeaders PEHeader;
public AppHostFileHeader Header;
public IApphostFile(FileStream fs, PEHeaders peheader)
{
FileStream = fs;
PEHeader = peheader;
}
public void ExtractAll(string outputDir)
{
Directory.CreateDirectory(outputDir);
foreach (var fileEntry in Header.Manifest.FileEntries)
{
try
{
var bytes = FileStream.ReadBuffer(fileEntry.Offset, fileEntry.Size);
var name = fileEntry.Name;
var filePath = Path.Combine(outputDir, name);
File.WriteAllBytes(filePath, bytes);
Log.Critical($"Extracted {name}");
}
catch (Exception ex)
{
Log.Error($"Could not extract {fileEntry.Name}: {ex.Message}");
}
}
}
public abstract void Close();
}
}

@ -1,11 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace apphost_extract_v2.Models
{
public interface IApphostFile
{
}
}

@ -10,18 +10,21 @@ namespace apphost_extract_v2
{ {
static void Main(string[] args) static void Main(string[] args)
{ {
var file = "net31-fd.exe"; var file = args[0];
var fs = new FileStream(file, FileMode.Open, FileAccess.Read); var fs = new FileStream(file, FileMode.Open, FileAccess.Read);
var anal = new Analyzer(fs);
var d = new Analyzer(fs).GetTextSectionVA(); var af = anal.Open();
var pattern = new byte[] { 0x4c, 0x8D, 0x5, 0xE2, 0x8A, 0x00, 0x00 }; var path = new FileInfo(file);
string mask = "xxxxxxx"; var directory = Path.Combine(path.DirectoryName, path.Name.Remove(path.Name.Length - path.Extension.Length) + "_extracted");
af.ExtractAll(directory);
Log.Info("Scanning for pattern..."); Console.ReadLine();
Stopwatch sw = Stopwatch.StartNew(); //RunTest("net30-sc.exe");
var res = Util.PatternScan(fs, 0, (int)fs.Length, pattern, mask); //RunTest("net5-sc.exe");
sw.Stop(); //Log.Info("Scanning for pattern...");
Log.Info("Found pattern at " + res[0].ToString("X8") + $" in {sw.ElapsedMilliseconds}ms"); //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");
@ -43,6 +46,14 @@ namespace apphost_extract_v2
Console.ReadLine();*/ 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 GetPath(string[] args)
{ {
try try

@ -9,9 +9,7 @@ namespace apphost_extract_v2
{ {
public static int[] PatternScan(FileStream fs, int start, int length, byte[] pattern, string mask) public static int[] PatternScan(FileStream fs, int start, int length, byte[] pattern, string mask)
{ {
byte[] scanBuffer = new byte[length]; byte[] scanBuffer = fs.ReadBuffer(start, length);
fs.Seek(start, SeekOrigin.Begin);
fs.Read(scanBuffer, 0, length);
List<int> scanResults = new List<int>(); List<int> scanResults = new List<int>();
@ -39,5 +37,13 @@ namespace apphost_extract_v2
return true; return true;
} }
public static byte[] ReadBuffer(this FileStream fs, long start, int length)
{
byte[] buff = new byte[length];
fs.Seek(start, SeekOrigin.Begin);
fs.Read(buff, 0, length);
return buff;
}
} }
} }

Loading…
Cancel
Save