do not pull - broken

This commit is contained in:
nullifiedcat 2017-07-23 17:07:21 +03:00
parent 825865ca0c
commit 381ff27659
11 changed files with 461 additions and 15 deletions

View File

@ -1,11 +1,14 @@
# Cathook Multihack
# Cathook Training Software
![banner](https://raw.githubusercontent.com/nullifiedcat/cathook/master/banner.png)
cathook is a multihack for Team Fortress 2 for Linux. cathook includes some joke features like
## Discord Server
[Official Discord Server](https://discord.gg/kvNVNSX)
cathook is a training software designed for Team Fortress 2 for Linux. cathook includes some joke features like
* Always/Never spycrab
* Ignore Hoovy
* 100% Casual/Comp coin flip hack
* 100% Casual/Comp coin flip
* Encrypted chat
* Emoji ESP
* Fidget Spinner crosshair
@ -13,29 +16,50 @@ cathook is a multihack for Team Fortress 2 for Linux. cathook includes some joke
and a lot of useful features, including
* Anti Backstab with option to say "No" voice command when spy tries to backstab you
* Heal Arrows hack (overheal an enemy for 1200 health with single huntsman arrow, you can also do it with buildings!)
* Heal Arrows exploit (overheal an enemy for 1200 health with single huntsman arrow, you can also do it with buildings!)
* Extremely customizable spam (you can make spam lines that'll include name of random dead enemy pyro or sniper)
* Follow Bots
* Working crit hack
[FULL LIST OF FEATURES HERE](https://github.com/nullifiedcat/cathook/wiki/List-of-features)
# Discord Server
[Official Discord Server](https://discord.gg/kvNVNSX)
# INSTALLATION
Ubuntu dependencies installation:
You **have** to use gcc6, not 7 or 5!
You also have to have g++-6-multilib package.
Ubuntu gcc6 installation: (check if you have gcc-6 installed already by typing `gcc-6 -v`
```bash
sudo apt update && sudo apt install build-essential software-properties-common -y && sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y && sudo apt update && sudo apt install gcc-snapshot -y && sudo apt update && sudo apt install git libc6-dev gcc-6 g++-6 libc6-dev:i386 g++-6-multilib gdb libsdl2-dev libglew-dev libfreetype6-dev libfreetype6-dev:i386 -y
sudo apt update && sudo apt install build-essential software-properties-common -y && sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y && sudo apt update && sudo apt install gcc-snapshot g++-6-multilib gcc-6 g++-6 -y
```
Ubuntu other dependencies installation:
```bash
sudo apt update && sudo apt install git libssl-dev:i386 libc6-dev:i386 gdb libsdl2-dev libglew-dev:i386 libfreetype6-dev:i386 -y
```
Arch dependencies installation::
Arch gcc6 & dependencies installation:
```bash
sudo pacman -Syu && sudo pacman -S gdb gdb-common glew1.10 lib32-glew1.10 rsync --noconfirm && yes | sudo pacman -U https://archive.archlinux.org/packages/g/gcc-multilib/gcc-multilib-6.3.1-2-x86_64.pkg.tar.xz https://archive.archlinux.org/packages/g/gcc-libs-multilib/gcc-libs-multilib-6.3.1-2-x86_64.pkg.tar.xz https://archive.archlinux.org/packages/l/lib32-gcc-libs/lib32-gcc-libs-6.3.1-2-x86_64.pkg.tar.xz
```
If you don't use Ubuntu or Arch (or if Arch script gets outdated), here's the list of what cathook requires:
* `gcc-6`
* `g++-6`
* `gcc-6-multilib`
* `g++-6-multilib`
* `gdb` (for the injection script, you can use different injector if you want)
* `libssl-dev:i386`
* `libc6-dev:i386`
* `libsdl2-dev`
* `libglew-dev:i386`
* `libfreetype6-dev:i386`
* `rsync` (only for copying shaders/fonts to tf2 data directory, `update-data` script)
Cathook installation script:
```bash

Binary file not shown.

Before

Width:  |  Height:  |  Size: 219 KiB

After

Width:  |  Height:  |  Size: 222 KiB

View File

@ -52,7 +52,7 @@ ifndef CLANG
LDFLAGS+=-flto
endif
endif
LDLIBS=-l:libSDL2-2.0.so.0 -static -l:libc.so.6 -static -l:libstdc++.so.6 -l:libtier0.so -l:libvstdlib.so -static -l:libGLEW.so -l:libfreetype.so
LDLIBS=-lssl -l:libSDL2-2.0.so.0 -static -l:libc.so.6 -static -l:libstdc++.so.6 -l:libtier0.so -l:libvstdlib.so -static -l:libGLEW.so -l:libfreetype.so
SRC_DIR = src
RES_DIR = res
OUT_NAME = libcathook.so

181
src/backpacktf.cpp Normal file
View File

@ -0,0 +1,181 @@
/*
* backpacktf.cpp
*
* Created on: Jul 23, 2017
* Author: nullifiedcat
*/
#include "backpacktf.hpp"
#include "json.hpp"
#include "https_request.hpp"
#include "common.h"
#include "cvwrapper.h"
#include <thread>
#include <queue>
namespace backpacktf {
std::unordered_map<unsigned, backpack_data_s> cache {};
std::queue<backpack_data_s*> pending_queue {};
std::mutex queue_mutex {};
std::mutex cache_mutex {};
std::string api_key_s = "";
bool valid_api_key = false;
CatVar enable_bptf(CV_SWITCH, "bptf_enable", "0", "Enable backpack.tf", "Enable backpack.tf integration\nYou have to set your API key in cat_bptf_key");
CatCommand api_key("bptf_key", "Set API Key", [](const CCommand& args) {
api_key_s = args.ArgS();
logging::Info("API key changed!");
valid_api_key = false;
if (api_key_s.length() != 24) {
logging::Info("API key must be exactly 24 characters long");
valid_api_key = false;
} else {
valid_api_key = true;
}
});
void store_data(unsigned id, unsigned value, bool no_value, bool outdated_value);
void processing_thread() {
logging::Info("[bp.tf] Starting the thread");
while (true) {
if (enabled()) {
try {
std::vector<backpack_data_s*> batch {};
int count = 0;
{
std::lock_guard<std::mutex> lock(queue_mutex);
while (not pending_queue.empty() && ++count < 100) {
batch.push_back(pending_queue.front());
pending_queue.pop();
}
}
logging::Info("[bp.tf] Requesting data for %d users", count);
if (count) {
std::string id_list = "";
logging::Info("Constructing list");
for (const auto& x : batch) {
x->pending = false;
logging::Info("Adding %u to the list", x->id);
id_list += format("[U:1:", x->id, "],");
}
logging::Info("List constructed");
// Remove trailing ','
id_list = id_list.substr(0, id_list.length() - 1);
std::string query = format("steamids=", id_list, "&key=", api_key_s);
logging::Info("Query constructed");
try {
auto sock = https::RAII_HTTPS_Socket("backpack.tf");
logging::Info("Socket created");
sock.ssl_connect();
logging::Info("Socket connected (%d)", sock.sock_);
std::string response = sock.get("/api/users/info/v1?" + query);
logging::Info("Request sent");
if (response.find("HTTP/1.1 200 OK\r\n") != 0) {
size_t status = response.find("\r\n");
throw std::runtime_error("Response isn't 200 OK! It's " + response.substr(0, status));
}
std::string body = response.substr(response.find("\r\n\r\n") + 4);
logging::Info("[bp.tf] Response: %s", body.c_str());
try {
nlohmann::json data(body);
nlohmann::json users = data["users"];
std::lock_guard<std::mutex> lock(cache_mutex);
for (auto it = users.begin(); it != users.end(); ++it) {
try {
unsigned userid = strtoul(it.key().substr(5).c_str(), nullptr, 10);
const auto& v = it.value();
if (not v.is_object()) {
logging::Info("Data for %u (%s) is not an object!", userid, it.key());
continue;
}
logging::Info("Parsing data for user %u (%s)", userid, v["name"]);
const auto& inv = v["inventory"]["440"];
if (inv.find("value") == inv.end()) {
logging::Info("Private backpack");
store_data(userid, 0, true, false);
} else {
float value = float(inv["value"]);
unsigned updated = unsigned(inv["updated"]);
store_data(userid, value * REFINED_METAL_PRICE, false, (unsigned(time(0)) - updated > OUTDATED_AGE));
}
} catch (std::exception& ex) {
logging::Info("Error while parsing user %s", it.key().c_str());
}
}
} catch (std::exception& e) {
logging::Info("[bp.tf] Exception while parsing response: %s", e.what());
}
} catch (std::exception& e) {
logging::Info("[bp.tf] HTTPS exception: %s", e.what());
}
}
} catch (std::exception& e) {
logging::Info("[bp.tf] Thread exception: %s", e.what());
}
}
sleep(REQUEST_INTERVAL);
}
}
void request_data(unsigned id) {
if (cache[id].pending) return;
cache[id].pending = true;
{
std::lock_guard<std::mutex> lock(queue_mutex);
pending_queue.push(&cache[id]);
}
}
bool enabled() {
return enable_bptf && valid_api_key;
}
backpack_data_s& access_data(unsigned id) {
try {
return cache.at(id);
} catch (std::out_of_range& oor) {
cache.emplace(id, backpack_data_s {});
cache.at(id).id = id;
return cache.at(id);
}
}
void store_data(unsigned id, unsigned value, bool none, bool outdated) {
auto& d = access_data(id);
d.last_request = unsigned(time(0));
d.bad = false;
d.value = value;
d.no_value = none;
d.outdated_value = outdated;
d.pending = false;
}
const backpack_data_s& get_data(unsigned id) {
auto& d = access_data(id);
if (d.bad || ((unsigned)time(0) - MAX_CACHE_AGE > cache[id].last_request)) {
request_data(id);
}
return d;
}
std::thread& GetBackpackTFThread() {
static std::thread thread(processing_thread);
return thread;
}
void init() {
GetBackpackTFThread();
}
}

35
src/backpacktf.hpp Normal file
View File

@ -0,0 +1,35 @@
/*
* backpacktf.hpp
*
* Created on: Jul 23, 2017
* Author: nullifiedcat
*/
#pragma once
class CatVar;
namespace backpacktf {
constexpr float REFINED_METAL_PRICE = 0.075f; // $
constexpr unsigned REQUEST_INTERVAL = 10; // Make a backpack.tf request every 30 seconds
constexpr unsigned MAX_CACHE_AGE = 60 * 30;
constexpr unsigned OUTDATED_AGE = 60 * 60 * 24 * 3; // After how many seconds backpack is marked "outdated" (possibly private)
extern CatVar enable_bptf;
struct backpack_data_s {
bool pending { false };
bool bad { true };
bool no_value { false }; // No recorded value
bool outdated_value { false }; // Outdated value. Private inventory?
unsigned last_request { 0 };
unsigned value { 0 };
unsigned id { 0 };
};
const backpack_data_s& get_data(unsigned id);
void init();
bool enabled();
}

View File

@ -83,6 +83,7 @@ extern "C" {
#include "hooks/hookedmethods.h"
#include "classinfo/classinfo.hpp"
#include "crits.h"
#include "backpacktf.hpp"
#if ENABLE_GUI
#include "gui/GUI.h"

View File

@ -83,7 +83,31 @@ void RenderPlayer(int eid) {
if (bgcolor.a) {
ImGui::PopStyleColor();
}
ImGui::SameLine();
if (backpacktf::enabled()) {
ImGui::SameLine();
if (!info.friendsID) {
ImGui::Text("[BOT]");
}
const auto& d = backpacktf::get_data(info.friendsID);
if (d.bad && not d.pending) {
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.0f, 0.0f, 1.0f));
ImGui::Text("Error");
} else if (d.pending) {
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.6f, 0.6f, 0.6f, 1.0f));
ImGui::Text("Fetching");
} else if (d.no_value) {
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 0.0f, 1.0f));
ImGui::Text("No value");
} else if (d.outdated_value) {
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.6f, 0.6f, 0.6f, 1.0f));
ImGui::Text("$%u", d.value);
} else {
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 0.8f, 0.0f, 1.0f));
ImGui::Text("$%u", d.value);
}
ImGui::PopStyleColor();
}
ImGui::SameLine(610);
ImGui::PushItemWidth(200.0f);
if (ImGui::ColorEdit3("", data.color)) {
if (!data.color.r && !data.color.b && !data.color.g) {
@ -104,7 +128,7 @@ void RenderPlayerlist() {
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 1));
std::vector<int> teammates {};
for (int i = 1; i < 32; i++) {
if (g_pPlayerResource->GetTeam(i) == LOCAL_E->m_iTeam) {
if (!g_Settings.bInvalid && (g_pPlayerResource->GetTeam(i) == LOCAL_E->m_iTeam)) {
teammates.push_back(i);
continue;
}

View File

@ -272,8 +272,10 @@ void hack::Initialize() {
hacks::shared::anticheat::Init();
hacks::tf2::healarrow::Init();
InitSpinner();
hacks::shared::spam::Init();
logging::Info("Initialized Fidget Spinner");
hacks::shared::spam::Init();
backpacktf::init();
logging::Info("Initialized Backpack.TF integration");
}

127
src/https_request.cpp Normal file
View File

@ -0,0 +1,127 @@
/*
* https_request.cpp
*
* Created on: Jul 23, 2017
* Author: nullifiedcat
*/
#include "https_request.hpp"
#include "logging.h"
#include <string.h>
#include <netdb.h>
#include <unistd.h>
#include <openssl/err.h>
#include <stdexcept>
#include <memory>
namespace https {
SSL_CTX *ssl_context;
bool initialized = false;
RAII_HTTPS_Socket::RAII_HTTPS_Socket(const std::string& host) : hostname_(host) {
if (!initialized) {
logging::Info("Initializing SSL");
initialize();
}
sock_ = socket(AF_INET, SOCK_STREAM, 0);
if (sock_ < 0) {
throw std::runtime_error("Socket creation error");
}
host_ = gethostbyname(hostname_.c_str());
if (not host_) {
throw std::runtime_error("Could not resolve hostname: " + host);
}
memset(&addr_, 0, sizeof(addr_));
addr_.sin_family = AF_INET;
addr_.sin_port = htons(443);
memcpy(&addr_.sin_addr.s_addr, host_->h_addr, host_->h_length);
if (connect(sock_, (sockaddr *)&addr_, sizeof(addr_)) < 0) {
close(sock_);
sock_ = -1;
throw std::runtime_error("Couldn't connect to host");
}
ssl_connect();
}
RAII_HTTPS_Socket::~RAII_HTTPS_Socket() {
logging::Info("Cleaning up HTTPS socket");
ssl_die();
if (sock_ >= 0)
close(sock_);
}
bool RAII_HTTPS_Socket::ssl_connect() {
connection_ = SSL_new(ssl_context);
SSL_set_fd(connection_, sock_);
if (SSL_connect(connection_) != 1) {
printf("SSL connection error\n");
return false;
}
return true;
}
void RAII_HTTPS_Socket::ssl_die() {
if (connection_) {
SSL_free(connection_);
connection_ = nullptr;
}
}
std::string RAII_HTTPS_Socket::get(const std::string& path) {
constexpr size_t rq_size = 1024 * 8;
constexpr size_t rs_size = 1024 * 1024;
std::unique_ptr<char>
buffer_rq(new char[rq_size]),
buffer_rs(new char[rs_size]);
memset(buffer_rq.get(), 0, rq_size);
int rq_length = snprintf(buffer_rq.get(), rq_size, "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", path.c_str(), hostname_.c_str());
int sent = 0;
int chunk = 0;
logging::Info("Writing %d bytes to socket %d", rq_length, sock_);
do {
chunk = SSL_write(connection_, buffer_rq.get() + sent, rq_length - sent);
logging::Info("Written %d bytes", chunk);
if (chunk < 0) {
throw std::runtime_error("Error writing to Secure Socket: " + std::to_string(ERR_get_error()));
} else if (chunk == 0) {
break;
}
sent += chunk;
} while (sent < rq_length);
memset(buffer_rs.get(), 0, rs_size);
int total = rs_size - 1;
int received = 0;
do {
chunk = SSL_read(connection_, buffer_rs.get() + received, total - received);
if (chunk < 0)
throw std::runtime_error("Error reading from socket");
if (chunk == 0)
break;
received += chunk;
} while (received < total);
if (received == total)
throw std::runtime_error("Response too large");
return std::string(buffer_rs.get());
}
void initialize() {
SSL_load_error_strings();
SSL_library_init();
ssl_context = SSL_CTX_new(SSLv23_client_method());
initialized = true;
}
}

44
src/https_request.hpp Normal file
View File

@ -0,0 +1,44 @@
/*
* https_request.hpp
*
* Created on: Jul 23, 2017
* Author: nullifiedcat
*/
#pragma once
#include <openssl/ssl.h>
#include <netinet/in.h>
#include "beforecheaders.h"
#include <string>
#include "aftercheaders.h"
namespace https {
extern SSL_CTX *ssl_context;
class RAII_HTTPS_Socket {
public:
RAII_HTTPS_Socket(const std::string& host);
~RAII_HTTPS_Socket();
bool ssl_connect();
void ssl_die();
std::string get(const std::string& path);
const std::string hostname_;
hostent *host_ { nullptr };
sockaddr_in addr_ {};
int sock_ { -1 };
SSL *connection_ { nullptr };
};
void initialize();
}

View File

@ -222,10 +222,17 @@ Vector ProjectilePrediction_Engine(CachedEntity* ent, int hb, float speed, float
return result;
}
CatVar debug_pp_extrapolate(CV_SWITCH, "debug_pp_extrapolate", "0", "Extrapolate entity position when predicting projectiles");
CatVar debug_pp_rockettimeping(CV_SWITCH, "debug_pp_rocket_time_ping", "0", "Compensate for ping in pp");
Vector ProjectilePrediction(CachedEntity* ent, int hb, float speed, float gravitymod, float entgmod) {
if (!ent) return Vector();
Vector result;
GetHitbox(ent, hb, result);
if (not debug_pp_extrapolate) {
GetHitbox(ent, hb, result);
} else {
result = SimpleLatencyPrediction(ent, hb);
}
if (speed == 0.0f) return Vector();
float dtg = DistanceToGround(ent);
Vector vel;
@ -250,6 +257,7 @@ Vector ProjectilePrediction(CachedEntity* ent, int hb, float speed, float gravit
if (curpos.z < result.z - dtg) curpos.z = result.z - dtg;
}
float rockettime = g_pLocalPlayer->v_Eye.DistTo(curpos) / speed;
if (debug_pp_rockettimeping) rockettime += g_IEngine->GetNetChannelInfo()->GetLatency(FLOW_OUTGOING);
if (fabs(rockettime - currenttime) < mindelta) {
besttime = currenttime;
bestpos = curpos;