diff --git a/src/apphost-extract/apphost-extract/AppHostFile.cs b/src/apphost-extract/apphost-extract/AppHostFile.cs index f04ce35..ac3d4df 100644 --- a/src/apphost-extract/apphost-extract/AppHostFile.cs +++ b/src/apphost-extract/apphost-extract/AppHostFile.cs @@ -12,23 +12,28 @@ namespace apphost_extract private FileStream FileStream; public AppHostFileHeader Header { get; set; } + private const int HEADER_OFFSET_PTR = 0x27600; public AppHostFile(FileStream fileStream) { FileStream = fileStream; - Header = new AppHostFileHeader(FileStream); + + var buffer = new byte[sizeof(int)]; + FileStream.Seek(HEADER_OFFSET_PTR, SeekOrigin.Begin); + FileStream.Read(buffer, 0, buffer.Length); + + Header = new AppHostFileHeader(FileStream, BitConverter.ToInt32(buffer, 0)); } public static AppHostFile Open(string path) { - if (!File.Exists(path)) Log.Fatal("File not found."); - try { FileStream fs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite); AppHostFile file = new AppHostFile(fs); + Log.Info("File opened successfully!"); return file; } catch(Exception ex) @@ -37,5 +42,33 @@ namespace apphost_extract return null; } } + + public void ExtractAll(string outputDir) + { + Directory.CreateDirectory(outputDir); + foreach (var fileEntry in Header.Manifest.FileEntries) + { + try + { + var bytes = fileEntry.Read(); + 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 void Close() + { + FileStream.Close(); + } } } diff --git a/src/apphost-extract/apphost-extract/AppHostFileEntry.cs b/src/apphost-extract/apphost-extract/AppHostFileEntry.cs index 13d1a22..d018502 100644 --- a/src/apphost-extract/apphost-extract/AppHostFileEntry.cs +++ b/src/apphost-extract/apphost-extract/AppHostFileEntry.cs @@ -9,23 +9,39 @@ namespace apphost_extract { public class AppHostFileEntry { - public int Offset { get; set; } + public long Offset { get; set; } public int Size { get; set; } - public string RelativePath { get; set; } + public string Name { get; set; } private byte[] Raw; + private FileStream FileStream; private const int FILE_ENTRY_SIZE = 0x12; public AppHostFileEntry(FileStream File) { + 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); - RelativePath = Encoding.UTF8.GetString(stringBuffer); + 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; } } } diff --git a/src/apphost-extract/apphost-extract/AppHostFileHeader.cs b/src/apphost-extract/apphost-extract/AppHostFileHeader.cs index 9047870..b910e33 100644 --- a/src/apphost-extract/apphost-extract/AppHostFileHeader.cs +++ b/src/apphost-extract/apphost-extract/AppHostFileHeader.cs @@ -9,19 +9,17 @@ namespace apphost_extract { public class AppHostFileHeader { - private const int HEADER_OFFSET = 0x1DE7E2; private const int HEADER_SIZE = 0xD; private byte[] Raw; public string Path { get; set; } - public int EmbeddedFilesCount { get; set; } public AppHostManifest Manifest { get; set; } - public AppHostFileHeader(FileStream File) + public AppHostFileHeader(FileStream File, int HeaderOffset) { - File.Seek(HEADER_OFFSET, SeekOrigin.Begin); + File.Seek(HeaderOffset, SeekOrigin.Begin); byte[] headerBuffer = new byte[HEADER_SIZE]; File.Read(headerBuffer, 0, HEADER_SIZE); Raw = headerBuffer; @@ -29,8 +27,11 @@ namespace apphost_extract byte[] stringBuffer = new byte[Raw[0xC]]; File.Read(stringBuffer, 0, stringBuffer.Length); Path = Encoding.UTF8.GetString(stringBuffer); + Log.Info("Header parsed successfully!"); Manifest = new AppHostManifest(File, BitConverter.ToInt32(Raw, 0x8)); + + } diff --git a/src/apphost-extract/apphost-extract/AppHostManifest.cs b/src/apphost-extract/apphost-extract/AppHostManifest.cs index 4b61c29..1c107d8 100644 --- a/src/apphost-extract/apphost-extract/AppHostManifest.cs +++ b/src/apphost-extract/apphost-extract/AppHostManifest.cs @@ -20,6 +20,9 @@ namespace apphost_extract AppHostFileEntry entry = new AppHostFileEntry(File); entries.Add(entry); } + FileEntries = entries.AsReadOnly(); + + Log.Info("Manifest parsed successfully!"); } } } diff --git a/src/apphost-extract/apphost-extract/Program.cs b/src/apphost-extract/apphost-extract/Program.cs index 6266206..b6efb6c 100644 --- a/src/apphost-extract/apphost-extract/Program.cs +++ b/src/apphost-extract/apphost-extract/Program.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Reflection; using System.Text; using System.Threading.Tasks; @@ -10,9 +12,49 @@ namespace apphost_extract { static void Main(string[] args) { - string path = "testapp.exe"; - var file = AppHostFile.Open(path); - + Log.Info("apphost-extract by VollRagm\n", ConsoleColor.Yellow); + var path = GetPath(args); + var file = AppHostFile.Open(path.FullName); + Log.Info($"{file.Header.Manifest.FileEntries.Count} embedded file(s) found."); + + var directory = Path.Combine(path.DirectoryName, path.Name.Remove(path.Name.Length - path.Extension.Length) +"_extracted"); + Console.WriteLine(); + Log.Info("Extracting..."); + + file.ExtractAll(directory); + + Console.WriteLine(); + Log.Info("Done."); + file.Close(); + Console.ReadLine(); + } + + static FileInfo GetPath(string[] args) + { + try + { + var fileName = new FileInfo(Assembly.GetExecutingAssembly().Location).Name; + + if (args.Length > 0) + { + if (File.Exists(args[0])) + { + return new FileInfo(args[0]); + } + else + { + Log.Fatal($"{args[0]} could not be found. Usage: {fileName} "); + } + } + else + { + Log.Fatal($"No File provided. Usage: {fileName} "); + } + }catch(Exception ex) + { + Log.Fatal($"Could not get file: {ex.Message}"); + } + return null; } } }