diff --git a/README.md b/README.md index afe8c78e..726375b6 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Reverse engineering and analysis of Call of Duty: Black Ops 3. Very experimental - [x] RE Tool Detection Bypass (IDA Pro, HxD, ...) - [x] Disable Hardware Breakpoint Detection - [x] Disable Integrity Checks -- [ ] Demonware Emulation +- [x] Demonware Emulation - [ ] Disable Anti-Debugging Mechanisms ## Download diff --git a/src/client/component/demonware.cpp b/src/client/component/demonware.cpp index 2466ff83..9de9bc3d 100644 --- a/src/client/component/demonware.cpp +++ b/src/client/component/demonware.cpp @@ -481,6 +481,10 @@ namespace demonware utils::hook::copy_string(0x1430B93C8_g, "http://%s:%d/auth/"); utils::hook::set(0x141EC4B50_g, 0xC3D08948); // Skip publisher file signature stuff + + utils::hook::set(0x141EC4B40_g, 0xC301B0); // FFOTD is valid + utils::hook::set(0x141EBDF30_g, 0xC301B0); // DDLs available + utils::hook::set(0x141E968F0_g, 0xC301B0); // QOL finished } void pre_destroy() override diff --git a/src/client/game/demonware/data_types.hpp b/src/client/game/demonware/data_types.hpp index 579e2248..83c188c3 100644 --- a/src/client/game/demonware/data_types.hpp +++ b/src/client/game/demonware/data_types.hpp @@ -72,6 +72,33 @@ namespace demonware } }; + struct bdFileQueryResult final : public bdTaskResult + { + std::uint64_t user_id; + std::string platform; + std::string filename; + std::uint32_t errorcode; + std::string filedata; + + void serialize(byte_buffer* data) override + { + data->write_uint64(user_id); + data->write_string(platform); + data->write_string(filename); + data->write_uint32(errorcode); + data->write_blob(filedata); + } + + void deserialize(byte_buffer* data) override + { + data->read_uint64(&user_id); + data->read_string(&platform); + data->read_string(&filename); + data->read_uint32(&errorcode); + data->read_blob(&filedata); + } + }; + class bdTimeStamp final : public bdTaskResult { public: diff --git a/src/client/game/demonware/services/bdStorage.cpp b/src/client/game/demonware/services/bdStorage.cpp index fe9fbaf7..ebb3c329 100644 --- a/src/client/game/demonware/services/bdStorage.cpp +++ b/src/client/game/demonware/services/bdStorage.cpp @@ -222,52 +222,66 @@ namespace demonware void bdStorage::get_files(service_server* server, byte_buffer* buffer) const { - uint32_t unk32_0; - uint32_t numfiles, count = 0; - uint64_t owner; - std::string game, platform; + std::string context; + buffer->read_string(&context); - buffer->read_string(&game); - buffer->read_uint32(&unk32_0); - buffer->read_uint64(&owner); - buffer->read_string(&platform); - buffer->read_uint64(&owner); - buffer->read_string(&platform); - buffer->read_uint32(&numfiles); + printf("demonware: ctx '%s'\n", context.data()); - auto reply = server->create_reply(this->task_id()); + uint32_t count; + buffer->read_uint32(&count); - for (uint32_t i = 0; i < numfiles; i++) + std::vector> user_ctxs; + + for (auto i = 0u; i < count; i++) { - std::string filename, data; - buffer->read_string(&filename); + uint64_t user_id; + std::string acc_type; + buffer->read_uint64(&user_id); + buffer->read_string(&acc_type); - const auto path = get_user_file_path(filename); - if (!utils::io::read_file(path, &data)) - { -#ifndef NDEBUG - printf("[DW]: [bdStorage]: get user file: missing file: %s, %s, %s\n", game.data(), filename.data(), - platform.data()); -#endif - continue; - } - - auto response = new bdFile; - response->owner_id = owner; - response->unk = 0; - response->platform = platform; - response->filename = filename; - response->data = data; - - reply->add(response); - ++count; - -#ifndef NDEBUG - printf("[DW]: [bdStorage]: get user file: %s, %s, %s\n", game.data(), filename.data(), platform.data()); -#endif + printf("demonware: user 0x%llX '%s'\n", user_id, acc_type.data()); + user_ctxs.emplace_back(user_id, acc_type); } - if (count == numfiles) + buffer->read_uint32(&count); + + std::vector filenames; + + for (auto i = 0u; i < count; i++) + { + std::string filename; + buffer->read_string(&filename); + printf("demonware: file '%s'\n", filename.data()); + + filenames.push_back(std::move(filename)); + } + + auto reply = server->create_reply(this->task_id()); + uint32_t available = 0; + + for (size_t i = 0u; i < filenames.size(); i++) + { + auto& name = filenames.at(i); + std::string filedata; + if (utils::io::read_file(get_user_file_path(name), &filedata)) + { + auto* entry = new bdFileQueryResult; + entry->user_id = user_ctxs.at(i).first; + entry->platform = user_ctxs.at(i).second; + entry->filename = filenames.at(i); + entry->errorcode = 0; + entry->filedata = filedata; + reply->add(entry); + available++; + std::cout << "demonware: user file '" << name << "' dispatched.\n"; + } + else + { + std::cout << "demonware: user file '" << name << "' not found.\n"; + } + } + + if (available == count) { reply->send(); }