Skip to content

Commit

Permalink
add bgcache/cluifunc dump with gsc requires_implements decompile
Browse files Browse the repository at this point in the history
  • Loading branch information
ate47 committed Dec 20, 2023
1 parent 04fe962 commit d4a2c43
Show file tree
Hide file tree
Showing 9 changed files with 567 additions and 12 deletions.
19 changes: 11 additions & 8 deletions src/cli/tools/gsc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,17 @@ int GscInfoHandleData(tool::gsc::T8GSCOBJ* data, size_t size, const char* path,
}
}

// no clue what this thing is doing
UINT64* requires_implements_table = reinterpret_cast<UINT64*>(&data->magic[data->requires_implements_offset]);

for (size_t i = 0; i < data->requires_implements_count; i++) {
asmout << "#precache(\"requires_implements\" #\"" << hashutils::ExtractTmp("hash", requires_implements_table[i]) << "\");\n";
}

if (data->requires_implements_count) {
asmout << "\n";
}

if (opt.m_exptests) {
auto* fixups = reinterpret_cast<T8GSCFixup*>(&data->magic[data->fixup_offset]);

Expand Down Expand Up @@ -692,14 +703,6 @@ int GscInfoHandleData(tool::gsc::T8GSCOBJ* data, size_t size, const char* path,
}
}

if (opt.m_exptests) {
auto* ukn4c = reinterpret_cast<UINT64*>(&data->magic[data->ukn4c_offset]);

for (size_t i = 0; i < data->ukn4c_count; i++) {
asmout << "ukn4c: " << hashutils::ExtractTmp("hash", ukn4c[i]) << "\n";
}
}

asmout.close();

return 0;
Expand Down
4 changes: 2 additions & 2 deletions src/cli/tools/gsc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -570,12 +570,12 @@ namespace tool::gsc {
INT32 fixup_offset;
INT32 globalvar_offset;
INT32 script_size;
INT32 ukn4c_offset;
INT32 requires_implements_offset;
INT32 ukn50;
INT32 ukn54;
UINT16 include_count;
BYTE ukn5a;
BYTE ukn4c_count;
BYTE requires_implements_count;

/*
* Path the code to remove linking
Expand Down
4 changes: 4 additions & 0 deletions src/cli/tools/gsc_opcodes_load.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,10 @@ void tool::gsc::opcode::RegisterOpCodesMap() {
// T8-Compiler opcodes
RegisterOpCode(0x36, PLATFORM_PC, OPCODE_T8C_GetLazyFunction, 0x16);

RegisterVM(0x37, "Call of Duty 2020");

RegisterVM(0x38, "Call of Duty: Black Ops Cold War");

#ifdef PS4_INCLUDES
ps4::RegisterPS4OpCodes();
#endif
Expand Down
230 changes: 230 additions & 0 deletions src/cli/tools/hks_bytecode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
#include <includes.hpp>

namespace {
enum LuaType {
LT_NIL = 0,
LT_BOOLEAN,
LT_LIGHTUSERDATA,
LT_NUMBER,
LT_STRING,
LT_TABLE,
LT_FUNCTION,
LT_USERDATA,
LT_THREAD,
LT_IFUNCTION,
LT_CFUNCTION,
LT_UI64,
LT_STRUCT,
LT_XHASH,

LT_BADTYPE = 0xFFFF
};

LuaType ReadLuaType(LPCCH type) {
static std::unordered_map<std::string, LuaType> luaTypeMap{
{ "TNIL", LT_NIL },
{ "TBOOLEAN", LT_BOOLEAN },
{ "TLIGHTUSERDATA", LT_LIGHTUSERDATA },
{ "TNUMBER", LT_NUMBER },
{ "TSTRING", LT_STRING },
{ "TTABLE", LT_TABLE },
{ "TFUNCTION", LT_FUNCTION },
{ "TUSERDATA", LT_USERDATA },
{ "TTHREAD", LT_THREAD },
{ "TIFUNCTION", LT_IFUNCTION },
{ "TCFUNCTION", LT_CFUNCTION },
{ "TUI64", LT_UI64 },
{ "TSTRUCT", LT_STRUCT },
{ "TXHASH", LT_XHASH },
};

auto it = luaTypeMap.find(type);

return it == luaTypeMap.end() ? LT_BADTYPE : it->second;
}


struct CLIOption {
bool m_help = false;
bool m_verbose = true;
bool m_header = false;

LPCCH m_outputDir{};
std::vector<LPCCH> m_inputFiles{};

bool Compute(LPCCH* args, INT startIndex, INT endIndex) {
// default values
for (size_t i = startIndex; i < endIndex; i++) {
LPCCH arg = args[i];

if (!strcmp("-?", arg) || !_strcmpi("--help", arg) || !strcmp("-h", arg)) {
m_help = true;
}
else if (!strcmp("-s", arg) || !_strcmpi("--silent", arg)) {
m_verbose = false;
}
else if (!strcmp("-H", arg) || !_strcmpi("--header", arg)) {
m_header = true;
}
else if (!strcmp("-o", arg) || !_strcmpi("--output", arg)) {
if (i + 1 == endIndex) {
std::cerr << "Missing value for param: " << arg << "!\n";
return false;
}
m_outputDir = args[++i];
}

else if (*arg == '-') {
std::cerr << "Unknown option: " << arg << "!\n";
return false;
}
else {
m_inputFiles.push_back(arg);
}
}
if (!m_inputFiles.size()) {
m_inputFiles.push_back("scriptparsetree");
}
return true;
}

void PrintHelp(std::ostream& out) {
out << "-h --help : Print help\n"
<< "-o --output [d] : Output dir\n";
}
};

bool HandleByteCode(BYTE* buffer, size_t size, const std::filesystem::path& origin, CLIOption& opt) {
constexpr auto minimumSize = 14 // header
+ 4 // numTypeObjects
+ 4 // typeId
+ 4 // nameSize
;
if (size < minimumSize || *reinterpret_cast<UINT32*>(buffer) != 0x61754C1B) {
std::cerr << "Bad magic : 0x" << std::hex << *reinterpret_cast<UINT32*>(buffer) << "\n";
return false;
}

if (buffer[4] != 0x51) {
std::cerr << "Bad version : 0x" << std::hex << (int)buffer[4] << "\n";
return false;
}

// header is 14 bytes
size_t loc = 14;

std::filesystem::path outputFile;
const auto fn = origin.filename().string();
if (opt.m_outputDir) {
outputFile = std::filesystem::path{ opt.m_outputDir } / std::format("{}.dec.lua", fn);
}
else {
outputFile = origin.parent_path() / std::format("{}.dec.lua", fn);
}

std::filesystem::create_directories(outputFile.parent_path());

std::ofstream out{ outputFile };

if (!out) {
std::cerr << "Can't create output file " << outputFile.string() << "\n";
return false;
}

out << "-- file: " << origin.string() << "\n";

UINT32 numTypeObjects = *reinterpret_cast<UINT32*>(buffer + loc);
loc += 4;

out << "-- types (" << std::dec << numTypeObjects << "):\n";

std::unordered_map<UINT32, LuaType> typeIds{};

for (size_t i = 0; i < numTypeObjects; i++) {
if (loc + 8 >= size) {
std::cerr << "Bad type declaration (not enough bytes)\n";
out.close();
return false;
}

UINT32 typeId = *reinterpret_cast<UINT32*>(buffer + loc);
loc += 4;

UINT32 typeSize = *reinterpret_cast<UINT32*>(buffer + loc);
loc += 4;

if (typeSize > 32 || loc + typeSize >= size || buffer[loc + typeSize - 1]) {
std::cerr << "Bad text buffer\n";
out.close();
return false;
}

auto* name = reinterpret_cast<LPCCH>(buffer + loc);
auto luaType = ReadLuaType(name);

if (luaType == LT_BADTYPE) {
std::cerr << "Unknown Lua type: " << name << "\n";
out.close();
return false;
}

typeIds[typeId] = luaType;

out << "-- " << std::dec << std::setw(2) << std::setfill(' ') << typeId << " : " << name << "\n";
loc += typeSize;
}



out.close();

return true;
}

int hks_bytecode(const Process& proc, int argc, const char* argv[]) {
CLIOption opt{};

if (!opt.Compute(argv, 2, argc) || opt.m_help || !opt.m_inputFiles.size()) {
opt.PrintHelp(std::cout);
return tool::OK;
}

std::vector<std::filesystem::path> paths{};

for (const auto* file : opt.m_inputFiles) {
utils::GetFileRecurse(file, paths, [](const std::filesystem::path& f) {
const auto str = f.string();
return str.ends_with(".luac") || str.ends_with(".lua");
});
}

if (!paths.size()) {
std::cerr << "No input file\n";
return tool::BASIC_ERROR;
}

LPVOID buffer{};
SIZE_T size{};

for (const auto& path : paths) {
std::cout << "Reading " << path.string() << "\n";

if (!utils::ReadFileNotAlign(path, buffer, size)) {
std::cerr << "Can't read file\n";
continue;
}

if (!HandleByteCode(reinterpret_cast<BYTE*>(buffer), size, path, opt)) {
std::cerr << "Error when reading\n";
}

std::free(buffer);
buffer = NULL;
}
std::cout << "Done\n";

return tool::OK;
}
}

ADD_TOOL("hks", " [file]", "Lua Havok Script tests", false, hks_bytecode);
59 changes: 59 additions & 0 deletions src/cli/tools/lui.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#include <includes.hpp>

namespace {

struct LUIElementFunction
{
uintptr_t name;
uintptr_t func;
uintptr_t next;
};


int dump_luifuncs(const Process& proc, int argc, const char* argv[]) {

LUIElementFunction func{0, 0, 0};

func.next = proc.ReadMemory<uintptr_t>(proc[0x12D263F0]);

std::ofstream out{"luifuncs.csv"};

if (!out) {
std::cerr << "Can't open output\n";
return tool::BASIC_ERROR;
}

out << "id,name,func";

CHAR outBuffer[0x300];

int count{};

while (func.next) {
if (!proc.ReadMemory(&func, func.next, sizeof(func))) {
out.close();
std::cerr << "Error when reading next function\n";
return tool::BASIC_ERROR;
}

if (proc.ReadString(outBuffer, func.name, sizeof(outBuffer)) < 0) {
out.close();
std::cerr << "Error when reading function name\n";
return tool::BASIC_ERROR;
}

out << "\n" << std::dec << (int)count << "," << outBuffer << ",";

proc.WriteLocation(out, func.func);
count++;
}
std::cout << "Dumped " << std::dec << (int)count << " func(s)\n";
out.close();

return tool::OK;
}


}

ADD_TOOL("dluif", "", "dump lui cfunc", true, dump_luifuncs);
Loading

0 comments on commit d4a2c43

Please sign in to comment.