Skip to content

Commit

Permalink
Added hash resolving, added BO3 to memory loading, fixed crashes for …
Browse files Browse the repository at this point in the history
…havok, ...
  • Loading branch information
JariKCoding committed Aug 18, 2021
1 parent 523e3c7 commit 3b55ab4
Show file tree
Hide file tree
Showing 48 changed files with 21,176 additions and 129 deletions.
39 changes: 30 additions & 9 deletions CoDLuaDecompiler.AssetExporter/AssetExport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,40 @@
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;
using CoDLuaDecompiler.AssetExporter.Games;
using CoDLuaDecompiler.AssetExporter.Util;
using CoDLuaDecompiler.Decompiler;
using CoDLuaDecompiler.Decompiler.IR.Instruction;
using CoDLuaDecompiler.Decompiler.LuaFile;
using CoDLuaDecompiler.HashResolver;

namespace CoDLuaDecompiler.AssetExporter
{
public class AssetExport : IAssetExport
{
private readonly IDecompiler _decompiler;
private readonly Dictionary<ulong, string> _hashEntries;
public static ProcessReader Reader { get; set; }

public AssetExport(IDecompiler decompiler)
public AssetExport(IDecompiler decompiler, IPackageIndex packageIndex)
{
_decompiler = decompiler;
_hashEntries = packageIndex.GetEntries();
}

public static Dictionary<string, Tuple<IGame, bool>> Games = new Dictionary<string, Tuple<IGame, bool>>()
{
{ "BlackOps3", new Tuple<IGame, bool>(new BlackOps3(), true) },
{ "BlackOps4", new Tuple<IGame, bool>(new BlackOps4(), true) },
{ "BlackOpsColdWar", new Tuple<IGame, bool>(new BlackOpsColdWar(), true) },
{ "ModernWarfare", new Tuple<IGame, bool>(new ModernWarfare(), true) },
};

public void ExportAssets()
public void ExportAssets(bool dumpRaw = false)
{
Process[] Processes = Process.GetProcesses();
Process[] processes = Process.GetProcesses();

foreach(var process in Processes)
foreach(var process in processes)
{
// Check process name against game list
if(Games.ContainsKey(process.ProcessName))
Expand All @@ -49,7 +53,7 @@ public void ExportAssets()
if (files == null)
Console.WriteLine("This game is supported, but this update is not.");
else
HandleLuaFiles(files, game.Item1);
HandleLuaFiles(files, game.Item1, dumpRaw);
// Done
return;
}
Expand All @@ -66,13 +70,21 @@ private string GetHash(LuaFileData luaFile)
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
}

private void HandleLuaFiles(List<LuaFileData> luaFiles, IGame game)
private void HandleLuaFiles(List<LuaFileData> luaFiles, IGame game, bool dumpRaw = false)
{
luaFiles.ForEach(file =>
Parallel.ForEach(luaFiles, file =>
{
string filePath = file.Name;
if (String.IsNullOrEmpty(filePath))
filePath = String.Format("Luafile_{0:x}.luac", file.Hash & 0xFFFFFFFFFFFFFFF);
{
ulong hashNumber = (ulong) (file.Hash & 0xFFFFFFFFFFFFFFF);
if (_hashEntries.ContainsKey(hashNumber))
filePath = _hashEntries[hashNumber];
else
filePath = String.Format("Luafile_{0:x}", hashNumber);
}
var directory = Path.GetDirectoryName(game.ExportFolder + filePath);
if (!Directory.Exists(directory))
Expand All @@ -93,6 +105,15 @@ private void HandleLuaFiles(List<LuaFileData> luaFiles, IGame game)
return;
}
}
if (dumpRaw)
{
using (var fileStream = File.Create(Path.ChangeExtension(game.ExportFolder + filePath, ".luac")))
{
file.Reader.BaseStream.Seek(0, SeekOrigin.Begin);
file.Reader.BaseStream.CopyTo(fileStream);
}
}
var luaFile = LuaFileFactory.Create(file.Reader);
try
Expand Down
98 changes: 98 additions & 0 deletions CoDLuaDecompiler.AssetExporter/Games/BlackOps3.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.IO;
using CoDLuaDecompiler.AssetExporter.Util;

namespace CoDLuaDecompiler.AssetExporter.Games
{
public class BlackOps3 : IGame
{
public override string ExportFolder => "BO3/";

public static long[] GameOffsets =
{
0x88788D0,
};

struct AssetPool
{
public long PoolPointer { get; set; }
public int AssetSize { get; set; }
public int PoolSize { get; set; }
public bool IsSingleton { get; set; }
public int ItemAllocCount { get; set; }
public long FreeHead { get; set; }
}

private struct LuaFile
{

public long NamePtr { get; set; }
public Int32 AssetSize { get; set; }
public long RawDataPtr { get; set; }
}
public override unsafe List<LuaFileData> LoadLuaFiles(bool isMP = true)
{
// Get Base Address for ASLR and Scans
long baseAddress = AssetExport.Reader.GetBaseAddress();

foreach (var gameOffset in GameOffsets)
{
var xmodelPoolData = AssetExport.Reader.ReadStruct<AssetPool>(baseAddress + gameOffset + sizeof(AssetPool) * 0x4);

// Check XModel Hash
if (AssetExport.Reader.ReadNullTerminatedString(AssetExport.Reader.ReadInt64(xmodelPoolData.PoolPointer)) == "void")
{
var luaPoolData = AssetExport.Reader.ReadStruct<AssetPool>(baseAddress + gameOffset + sizeof(AssetPool) * 47);

return FetchFiles(luaPoolData);
}
}

var dbAssetsScan = AssetExport.Reader.FindBytes(new byte?[] { 0x63, 0xC1, 0x48, 0x8D, 0x05, null, null, null, null, 0x49, 0xC1, 0xE0, null, 0x4C, 0x03, 0xC0 }, baseAddress, baseAddress + AssetExport.Reader.GetModuleMemorySize(), true);

// Check that we had hits
if (dbAssetsScan.Length > 0)
{
var assetPoolAddress = AssetExport.Reader.ReadUInt32(dbAssetsScan[0] + 0x5) + dbAssetsScan[0] + 0x9;
var xmodelPoolData = AssetExport.Reader.ReadStruct<AssetPool>(assetPoolAddress + sizeof(AssetPool) * 0x4);

// Check XModel Hash
if (AssetExport.Reader.ReadNullTerminatedString(AssetExport.Reader.ReadInt64(xmodelPoolData.PoolPointer)) == "void")
{
var luaPoolData = AssetExport.Reader.ReadStruct<AssetPool>(assetPoolAddress + sizeof(AssetPool) * 47);

return FetchFiles(luaPoolData);
}
}

return null;
}

private List<LuaFileData> FetchFiles(AssetPool luaPoolData)
{
var filesList = new List<LuaFileData>();
for (int i = 0; i < luaPoolData.PoolSize; i++)
{
var luaFile = AssetExport.Reader.ReadStruct<LuaFile>(luaPoolData.PoolPointer + (i * luaPoolData.AssetSize));

if (luaFile.AssetSize == 0 || luaFile.RawDataPtr == 0)
continue;

var name = AssetExport.Reader.ReadNullTerminatedString(luaFile.NamePtr);
if (!name.EndsWith(".lua"))
continue;

var luaFileData = AssetExport.Reader.ReadBytes(luaFile.RawDataPtr, luaFile.AssetSize);

filesList.Add(new LuaFileData()
{
Reader = new BinaryReader(new MemoryStream(luaFileData)),
Name = name,
});
}

return filesList;
}
}
}
2 changes: 1 addition & 1 deletion CoDLuaDecompiler.AssetExporter/Games/BlackOps4.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace CoDLuaDecompiler.AssetExporter.Games
{
public class BlackOps4 : IGame
{
public override string ExportFolder => "BO4_BETA/";
public override string ExportFolder => "BO4/";

public static long[] GameOffsets =
{
Expand Down
2 changes: 1 addition & 1 deletion CoDLuaDecompiler.AssetExporter/IAssetExport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
{
public interface IAssetExport
{
void ExportAssets();
void ExportAssets(bool dumpRaw = false);
}
}
1 change: 1 addition & 0 deletions CoDLuaDecompiler.CLI/CoDLuaDecompiler.CLI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<ItemGroup>
<ProjectReference Include="..\CoDLuaDecompiler.AssetExporter\CoDLuaDecompiler.AssetExporter.csproj" />
<ProjectReference Include="..\CoDLuaDecompiler.Decompiler\CoDLuaDecompiler.Decompiler.csproj" />
<ProjectReference Include="..\CoDLuaDecompiler.HashResolver\CoDLuaDecompiler.HashResolver.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion CoDLuaDecompiler.CLI/GithubUpdateChecker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace CoDLuaDecompiler.CLI
{
public class GithubUpdateChecker
{
private const string Version = "2.0.0";
private const string Version = "2.1.0";
private const string RepositoryOwner = "JariKCoding";
private const string RepositoryName = "CoDLuaDecompiler";

Expand Down
5 changes: 3 additions & 2 deletions CoDLuaDecompiler.CLI/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using CoDLuaDecompiler.AssetExporter;
using CoDLuaDecompiler.Decompiler;
using CoDLuaDecompiler.Decompiler.LuaFile;
Expand Down Expand Up @@ -83,15 +84,15 @@ public void Main(string[] args)
if (args.Contains("--export"))
{
Console.WriteLine("Starting asset export from memory.");
_assetExport.ExportAssets();
_assetExport.ExportAssets(args.Contains("--dump"));
}

// parse files from arguments
var files = ParseFilesFromArgs(args);

Console.WriteLine($"Total of {files.Count} to process.");

files.ForEach(HandleFile);
Parallel.ForEach(files, HandleFile);
}
}
}
2 changes: 2 additions & 0 deletions CoDLuaDecompiler.CLI/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using CoDLuaDecompiler.AssetExporter;
using CoDLuaDecompiler.Decompiler;
using CoDLuaDecompiler.Decompiler.LuaFile;
using CoDLuaDecompiler.HashResolver;

namespace CoDLuaDecompiler.CLI
{
Expand All @@ -31,6 +32,7 @@ private static async Task Main(string[] args)
// CodHavokTool
builder.RegisterType<GithubUpdateChecker>().SingleInstance();
builder.RegisterType<AssetExport>().As<IAssetExport>().SingleInstance();
builder.RegisterType<PackageIndex>().As<IPackageIndex>().SingleInstance();
builder.RegisterType<Program>().SingleInstance();

var container = builder.Build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,9 @@ public void Analyze(Function f)
if (i is Assignment a && a.Right is FunctionCall fc && a.Left.Count == 1)
{
string name;
if (fc.Function.ToString().Contains("LUI.UIElement.new"))
if (fc.Function.ToString().StartsWith("LUI.UI") && fc.Function.ToString().EndsWith(".new") || fc.Function.ToString().Contains("CoD.Menu.NewForUIEditor"))
{
name = "Widget";
}
else if (fc.Function.ToString().Contains("CoD.Menu.NewForUIEditor"))
{
name = "HudRef";
name = "self";
}
else
continue;
Expand All @@ -83,14 +79,14 @@ public void Analyze(Function f)
// Change parameter names for menus and widgets
if (f.Blocks[0] != null && f.Blocks[0].Instructions.Count > 0 && f.Blocks[0].Instructions[0] is Assignment a2 && a2.Right is FunctionCall fc2)
{
if (fc2.Function.ToString().Contains("LUI.UIElement.new") && f.Parameters.Count == 2)
if (fc2.Function.ToString().StartsWith("LUI.UI") && fc2.Function.ToString().EndsWith(".new") && f.Parameters.Count == 2)
{
f.Parameters[0].Name = "HudRef";
f.Parameters[1].Name = "InstanceRef";
f.Parameters[0].Name = "menu";
f.Parameters[1].Name = "controller";
}
else if (fc2.Function.ToString().Contains("CoD.Menu.NewForUIEditor") && f.Parameters.Count == 1)
{
f.Parameters[0].Name = "InstanceRef";
f.Parameters[0].Name = "controller";
}
}

Expand All @@ -105,24 +101,32 @@ public void Analyze(Function f)
{
if (arg is Closure c)
{
c.Function.ArgumentNames = new List<Local>(){new Local(){Name = "ModelRef"}};
c.Function.ArgumentNames = new List<Local>(){new Local(){Name = "modelRef"}};
}
}
}

if (i is Assignment {Right: FunctionCall fc5} && fc5.Function.ToString().Contains("registerEventHandler"))
if (i is Assignment {Right: FunctionCall fc5} && fc5.Function.ToString().EndsWith("registerEventHandler"))
{
if (fc5.Arguments.Count == 3 && fc5.Arguments[2] is Closure c2)
if (fc5.Arguments.Count >= 2 && fc5.Arguments[^1] is Closure c2)
{
c2.Function.ArgumentNames = new List<Local>() {new Local(){Name = "Sender"}, new Local(){Name = "Event"}};
c2.Function.ArgumentNames = new List<Local>() {new Local(){Name = "element"}, new Local(){Name = "event"}};
}
}

if (i is Assignment {Right: FunctionCall fc6} && fc6.Function.ToString().Contains("LUI.OverrideFunction_CallOriginalSecond"))
{
if (fc6.Arguments.Count == 3 && fc6.Arguments[2] is Closure c2)
{
c2.Function.ArgumentNames = new List<Local>() {new Local(){Name = "Sender"}};
c2.Function.ArgumentNames = new List<Local>() {new Local(){Name = "element"}};
}
}

if (i is Assignment {Right: FunctionCall fc7} && fc7.Function.ToString().Contains("LUI.OverrideFunction_CallOriginalFirst"))
{
if (fc7.Arguments.Count == 3 && fc7.Arguments[2] is Closure c2)
{
c2.Function.ArgumentNames = new List<Local>() {new Local(){Name = "element"}, new Local(){Name = "controller"}};
}
}
}
Expand All @@ -134,7 +138,7 @@ public void Analyze(Function f)
{
if (fc3.Function.ToString().Contains("Engine.GetModelValue") && f.Parameters.Count == 1)
{
a4.Left[0].Identifier.Name = "ModelValue";
a4.Left[0].Identifier.Name = "modelValue";
}
}

Expand Down Expand Up @@ -175,7 +179,7 @@ public void Analyze(Function f)
}
} && il2.Expressions[1] is ListAssignment {Left: Constant {Type: ValueType.String, String: "condition"}, Right: Closure cl})
{
cl.Function.ArgumentNames = new List<Local>() {new Local(){Name = "HudRef"}, new Local(){Name = "ItemRef"}, new Local(){Name = "UpdateTable"}};
cl.Function.ArgumentNames = new List<Local>() {new Local(){Name = "menu"}, new Local(){Name = "element"}, new Local(){Name = "event"}};
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ public void Analyze(Function f)
f.Instructions.Insert(f.Instructions.IndexOf(j2.Dest), new Assignment(new IdentifierReference(j.TestsetLocation),
new BinOp(new IdentifierReference(newLeftId), new IdentifierReference(newRightId), j.TestsetType)));
f.Instructions.RemoveAt(i);
f.Instructions.Remove(j.Dest);
if (j.Dest.UsageCount == 1)
f.Instructions.Remove(j.Dest);
else
j.Dest.UsageCount--;
f.Instructions.Remove(j2);
if (j2.Dest.UsageCount > 1)
j2.Dest.UsageCount--;
Expand Down
19 changes: 19 additions & 0 deletions CoDLuaDecompiler.Decompiler/Analyzers/HavokFileAnalyzerList.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.Collections.Generic;
using CoDLuaDecompiler.Decompiler.Analyzers.Havok;
using CoDLuaDecompiler.Decompiler.Analyzers.Shared;

namespace CoDLuaDecompiler.Decompiler.Analyzers
{
public class HavokFileAnalyzerList : IAnalyzerList
{
public List<IAnalyzer> GetAnalyzers()
{
return new List<IAnalyzer>()
{
new PrePostLoadFuncAnalyzer(),
new PostRequireStatementsNewLine(),
new UIModelFunctionValueVarNamesAnalyzer(),
};
}
}
}
Loading

0 comments on commit 3b55ab4

Please sign in to comment.