Skip to content

Commit

Permalink
t7 injector
Browse files Browse the repository at this point in the history
  • Loading branch information
ate47 committed Jul 29, 2024
1 parent 4e8ef94 commit 4b416fe
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 19 deletions.
128 changes: 128 additions & 0 deletions src/acts/tools/bo3/bo3.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#include <includes.hpp>
#include "pools.hpp"
#include "bo3.hpp"
#include "tools/gsc.hpp"

namespace bo3 {
int InjectScriptBO3(Process& proc, const char* script, const char* replaced, std::string& notify) {
using namespace bo3::pool;
LOG_DEBUG("script: {}", script);
LOG_DEBUG("replaced: {}", replaced);

std::filesystem::path scriptPath = script;
std::string scriptBuffStr{};

if (!utils::ReadFile(scriptPath, scriptBuffStr)) {
notify = std::format("Can't read '{}'", scriptPath.string());
return tool::BASIC_ERROR;
}

void* scriptBuffer = scriptBuffStr.data();
size_t scriptSize = scriptBuffStr.size();

if (scriptSize < 8 || *reinterpret_cast<uint64_t*>(scriptBuffer) != bo3::GSC_MAGIC) {
notify = "Not a valid compiled Black Ops Cold War script (BAD MAGIC)";
return tool::BASIC_ERROR;
}

pool::T7XAssetPool sptPool{};

uintptr_t poolLoc = proc[bo3::pool::xassetpools];

proc.WriteLocation(std::cout << "pool: ", poolLoc) << "\n";

if (!proc.ReadMemory(&sptPool, poolLoc + sizeof(sptPool) * bo3::pool::T7_ASSET_TYPE_SCRIPTPARSETREE, sizeof(sptPool))) {
notify = "Can't read SPT pool";
return tool::BASIC_ERROR;
}

auto entries = std::make_unique<T7ScriptParseTree[]>(sptPool.itemAllocCount);

if (!proc.ReadMemory(&entries[0], sptPool.pool, sptPool.itemAllocCount * sizeof(entries[0]))) {
notify = "Can't read SPT pool entries";
return tool::BASIC_ERROR;
}

T7ScriptParseTree* scriptEntry = reinterpret_cast<bo3::pool::T7ScriptParseTree*>(&entries[0]);

T7ScriptParseTree* end = scriptEntry + sptPool.itemAllocCount;

uintptr_t replacedEntry = 0;
bo3::pool::T7ScriptParseTree* replacedEntryH = NULL;

for (size_t i = 0; i < sptPool.itemAllocCount; i++) {
if (!_strcmpi(proc.ReadStringTmp(scriptEntry[i].name, ""), replaced)) {
replacedEntryH = scriptEntry + i;
replacedEntry = sptPool.pool + sizeof(*scriptEntry) * i;
break;
}
}

if (!replacedEntry) {
notify = std::format("Can't find replaced script '{}'", replaced);
return tool::BASIC_ERROR;
}
tool::gsc::T7GSCOBJ replacerScriptHeader{};
if (!proc.ReadMemory(&replacerScriptHeader, replacedEntryH->script, sizeof(tool::gsc::T7GSCOBJ))) {
notify = "Can't read replacer header";
return tool::BASIC_ERROR;
}

LOG_DEBUG("{} -> {:x} ({})", replaced, replacedEntryH->script, proc.ReadStringTmp(replacedEntryH->name, "<err>"));

// fixup crc & name
reinterpret_cast<tool::gsc::T7GSCOBJ*>(scriptBuffer)->source_crc = replacerScriptHeader.source_crc;
// reinterpret_cast<tool::gsc::T7GSCOBJ*>(scriptBuffer)->name = replacerScriptHeader.name; // assume that we have the right name??

auto loc = proc.AllocateMemory(scriptSize + 0xF, PAGE_READWRITE);

if (!loc) {
notify = "Can't allocate memory";
return tool::BASIC_ERROR;
}

auto locAligned = (loc + 0xF) & ~0xF;
LOG_DEBUG("Allocating script at 0x{:x} (0x{:x})", locAligned, loc);

if (!proc.WriteMemory(locAligned, scriptBuffer, scriptSize)) {
auto err = GetLastError();
notify = std::format("Error when writing script: 0x{:x}", err);
proc.FreeMemory(loc, scriptSize + 0xF);
return tool::BASIC_ERROR;
}

if (!proc.WriteMemory(replacedEntry + offsetof(T7ScriptParseTree, script), &locAligned, sizeof(locAligned))) {
notify = std::format("Error when patching SPT entry to 0x{:x}", locAligned);
proc.FreeMemory(loc, scriptSize + 0xF);
return tool::BASIC_ERROR;
}

notify = std::format("{} injected at {:x}", script, locAligned);
return tool::OK;
}
}
namespace {
int injectbo3(Process& proc, int argc, const char* argv[]) {
if (argc < 4) {
return tool::BAD_USAGE;
}

const char* script = argv[2];
const char* replaced = argv[3];

std::string notify{};
int ret = bo3::InjectScriptBO3(proc, script, replaced, notify);

if (!notify.empty()) {
if (ret) {
LOG_ERROR("{}", notify);
}
else {
LOG_INFO("{}", notify);
}
}

return ret;
}
}
ADD_TOOL("injectbo3", "bo3", " (script) (replace)", "inject script (bo3)", L"BlackOps3.exe", injectbo3);
8 changes: 8 additions & 0 deletions src/acts/tools/bo3/bo3.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once

namespace bo3 {
constexpr uint64_t GSC_MAGIC = 0x1C000a0d43534780;
constexpr uint64_t GSC_MAGIC_1B = 0x1B000a0d43534780;

int InjectScriptBO3(Process& proc, const char* script, const char* replace, std::string& notify);
}
4 changes: 1 addition & 3 deletions src/acts/tools/bo3/dumpt7.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <includes.hpp>
#include "pools.hpp"
#include "bo3.hpp"
#include "tools/gsc.hpp"

static const char* t7names[]{
Expand Down Expand Up @@ -125,9 +126,6 @@ const char* bo3::pool::T7XAssetName(T7XAssetType type) {
return type >= T7_ASSET_TYPE_COUNT || type < 0 ? "unknown" : t7names[type];
}
namespace {
constexpr size_t xassetpools = 0x94073F0;
constexpr size_t gscobjinfo = 0x50DC2E0;
constexpr size_t gscobjinfocount = 0x50EFB60;

struct objFileInfo_t {
uintptr_t activeVersion; // GSC_OBJ*
Expand Down
3 changes: 3 additions & 0 deletions src/acts/tools/bo3/pools.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#pragma once

namespace bo3::pool {
constexpr size_t xassetpools = 0x94073F0;
constexpr size_t gscobjinfo = 0x50DC2E0;
constexpr size_t gscobjinfocount = 0x50EFB60;

struct T7XAssetPool {
uintptr_t pool; // void*
Expand Down
30 changes: 20 additions & 10 deletions src/acts/tools/dump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1793,8 +1793,8 @@ namespace {
uint64_t unk17e0;
uint64_t unk17e8;
uint64_t unk17f0;
uint64_t unk17f8;
uint64_t unk1800;
uintptr_t lighting; // GfxLighting*
uintptr_t streamerworld; // StreamerWorld*
uint64_t unk1808;
uint64_t unk1810;
uint64_t unk1818;
Expand Down Expand Up @@ -1892,14 +1892,15 @@ namespace {

struct static_model_info
{
uint64_t unk0;
uintptr_t model; // XModel*
uint64_t unk8;
uint64_t unk10;
uint64_t unk18;
uintptr_t unk18;
uint32_t unk20;
uint32_t name;
uint64_t unk28;
uint64_t unk30;
uint32_t unk30;
uint32_t unk34;
};

auto [info, ok] = proc.ReadMemoryObject<GfxWorld>(data); // s_world
Expand All @@ -1924,6 +1925,13 @@ namespace {
utils::Padding(out << "\n", 1) << "\"checksum\": " << std::dec << info->checksum << ",";
//utils::Padding(out << "\n", 1) << "\"surfaceCount\": " << std::dec << info->surfaceCount << ",";

if (info->lighting) {
utils::Padding(out << "\n", 1) << "\"lighting\": \"#" << hashutils::ExtractTmp("hash", proc.ReadMemory<uint64_t>(info->lighting)) << "\",";
}

if (info->streamerworld) {
utils::Padding(out << "\n", 1) << "\"streamerworld\": \"#" << hashutils::ExtractTmp("hash", proc.ReadMemory<uint64_t>(info->streamerworld)) << "\",";
}

for (size_t i = 0; i < ARRAYSIZE(info->unk550); i++) {
if (info->unk550[i]) {
Expand Down Expand Up @@ -2011,7 +2019,7 @@ namespace {
}
utils::Padding(out << ",\n", 1) << "\"static_models\": ";

if (info->static_model_count && 0) {
if (info->static_model_count) {
out << "[";


Expand All @@ -2025,13 +2033,15 @@ namespace {
for (size_t i = 0; i < info->static_model_count; i++) {
static_model_info& model = static_models[i];

if (!model.model) continue;

if (i) {
out << ",";
}
utils::Padding(out << "\n", 2) << "{";
utils::Padding(out << "\n", 3) << "\"name\": \"" << tool::pool::ReadMTString(proc, model.name, utils::va("<invalid:%d>", model.name)) << "\"";
tool::pool::WriteHex(out << "\n", info->static_model + sizeof(model) * i, &model, sizeof(model), proc);
utils::Padding(out << "\n", 2) << "}";
//utils::Padding(out << "\n", 2) << "{";
utils::Padding(out << "\n", 2) << "\"#" << hashutils::ExtractTmp("hash", proc.ReadMemory<uint64_t>(model.model)) << "\"";
//tool::pool::WriteHex(out << "\n", info->static_model + sizeof(model) * i, &model, sizeof(model), proc);
//utils::Padding(out << "\n", 2) << "}";
}

utils::Padding(out << "\n", 1) << "]";
Expand Down
15 changes: 15 additions & 0 deletions src/acts/tools/gsc_injector_ui.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <includes.hpp>
#include "tools/tools_ui.hpp"
#include "tools/cw/cw.hpp"
#include "tools/bo3/bo3.hpp"
#include "tools/gsc.hpp"
#include "mods/custom_ees.hpp"
#include <core/config.hpp>
Expand Down Expand Up @@ -295,6 +296,20 @@ namespace {
SetNotif(notif);

}
else if (magic == bo3::GSC_MAGIC) {
// bo3 gsc

Process proc{ L"BlackOps3.exe" };

if (!proc || !proc.Open()) {
SetNotif("Can't find Black Ops 3");
return TRUE;
}
utils::CloseEnd ce{ [&proc] { proc.Close(); } };

bo3::InjectScriptBO3(proc, filePath.c_str(), "scripts/shared/duplicaterender_mgr.gsc", notif);
SetNotif(notif);
}
else {
tool::gsc::opcode::VmInfo* nfo{};
if (tool::gsc::opcode::IsValidVmMagic(magic, nfo)) {
Expand Down
2 changes: 1 addition & 1 deletion src/acts/tools/gsc_opcodes_load.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1227,7 +1227,7 @@ namespace tool::gsc::opcode {
RegisterOpCode(VM_T71B, PLATFORM_PC, OPCODE_Jump, 0x45);


RegisterVM(VM_T831, "Call of Duty: Black ops 4 (35)", "t8", "bo4_35", VmFlags::VMF_OPCODE_U16 | VmFlags::VMF_ALIGN | VmFlags::VMF_INV_ADD_TO_OBJECT | VmFlags::VMF_CLIENT_VM);
RegisterVM(VM_T831, "Call of Duty: Black ops 4 (31)", "t8", "bo4_31", VmFlags::VMF_OPCODE_U16 | VmFlags::VMF_ALIGN | VmFlags::VMF_INV_ADD_TO_OBJECT | VmFlags::VMF_CLIENT_VM);
RegisterVMPlatform(VM_T831, PLATFORM_PLAYSTATION);
SetMaxOpCode(VM_T831, 0xFFF);
RegisterDevCall(VM_T831, "assert", "assertmsg", "errormsg", "throw", "println");
Expand Down
4 changes: 2 additions & 2 deletions src/acts/tools/gsc_vm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1976,7 +1976,7 @@ class T7GSCOBJHandler : public GSCOBJHandler {
return Ptr<T7GSCOBJ>()->source_crc;
}
const char* GetDefaultName(bool client) override {
return "";
return client ? "" : "scripts/shared/duplicaterender_mgr.gsc";
}

byte RemapFlagsExport(byte flags) override {
Expand Down Expand Up @@ -2262,7 +2262,7 @@ class T71BGSCOBJHandler : public GSCOBJHandler {
return Ptr<T7GSCOBJ>()->source_crc;
}
const char* GetDefaultName(bool client) override {
return "";
return client ? "" : "scripts/shared/duplicaterender_mgr.gsc";
}

byte RemapFlagsExport(byte flags) override {
Expand Down
7 changes: 4 additions & 3 deletions src/acts/tools/pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1298,13 +1298,14 @@ int pooltoolnames(Process& proc, int argc, const char* argv[]) {
}


defout << "id,name,type";
defout << "id,name,type,offset";
auto off = xoffsets[id];

for (size_t asset = 0; asset < entry.itemAllocCount; asset++) {
auto xhash = proc.ReadMemory<uint64_t>(entry.pool + entry.itemSize * asset + off);
uintptr_t offset = entry.pool + entry.itemSize * asset;
uint64_t xhash = proc.ReadMemory<uint64_t>(offset + off);

defout << "\n" << std::dec << asset << "," << hashutils::ExtractTmp("hash", xhash) << "," << name;
defout << "\n" << std::dec << asset << "," << hashutils::ExtractTmp("hash", xhash) << "," << name << "," << std::hex << offset;
}

defout.close();
Expand Down

0 comments on commit 4b416fe

Please sign in to comment.