Fixed "meta unload" segfault.
Added fake responces to server queries. Added dynamic link ents. (except android).
This commit is contained in:
parent
4f664f0162
commit
535f298621
16 changed files with 763 additions and 246 deletions
|
|
@ -205,7 +205,7 @@ public:
|
|||
if (index + count > m_capacity) {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = m_length; i < m_length + count; i++) {
|
||||
for (size_t i = index; i < index + count; i++) {
|
||||
alloc.destruct (&m_data[i]);
|
||||
}
|
||||
m_length -= count;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <crlib/cr-random.h>
|
||||
#include <crlib/cr-ulz.h>
|
||||
#include <crlib/cr-color.h>
|
||||
#include <crlib/cr-hook.h>
|
||||
|
||||
CR_NAMESPACE_BEGIN
|
||||
|
||||
|
|
|
|||
132
include/crlib/cr-hook.h
Normal file
132
include/crlib/cr-hook.h
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
//
|
||||
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
||||
// Copyright (c) YaPB Development Team.
|
||||
//
|
||||
// This software is licensed under the BSD-style license.
|
||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||
// https://yapb.ru/license
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <crlib/cr-basic.h>
|
||||
|
||||
#if !defined (CR_WINDOWS)
|
||||
# include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
CR_NAMESPACE_BEGIN
|
||||
|
||||
class SimpleHook : DenyCopying {
|
||||
private:
|
||||
enum : uint32 {
|
||||
CodeLength = 12
|
||||
};
|
||||
|
||||
private:
|
||||
bool m_patched;
|
||||
|
||||
uint32 m_pageSize;
|
||||
uint32 m_origFunc;
|
||||
uint32 m_hookFunc;
|
||||
|
||||
uint8 m_origBytes[CodeLength];
|
||||
uint8 m_hookBytes[CodeLength];
|
||||
|
||||
private:
|
||||
void setPageSize () {
|
||||
#if defined (CR_WINDOWS)
|
||||
SYSTEM_INFO sysinfo;
|
||||
GetSystemInfo (&sysinfo);
|
||||
|
||||
m_pageSize = sysinfo.dwPageSize;
|
||||
#else
|
||||
m_pageSize = sysconf (_SC_PAGESIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void *align (void *address) {
|
||||
return reinterpret_cast <void *> ((reinterpret_cast <long> (address) & ~(m_pageSize - 1)));
|
||||
}
|
||||
|
||||
bool unprotect () {
|
||||
auto orig = reinterpret_cast <void *> (m_origFunc);
|
||||
|
||||
#if defined (CR_WINDOWS)
|
||||
DWORD oldProt;
|
||||
|
||||
FlushInstructionCache (GetCurrentProcess (), orig, m_pageSize);
|
||||
return VirtualProtect (orig, m_pageSize, PAGE_EXECUTE_READWRITE, &oldProt);
|
||||
#else
|
||||
auto aligned = align (orig);
|
||||
return !mprotect (aligned, m_pageSize, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
SimpleHook () : m_patched (false), m_origFunc (0), m_hookFunc (0), m_pageSize (0) {
|
||||
setPageSize ();
|
||||
}
|
||||
|
||||
~SimpleHook () {
|
||||
disable ();
|
||||
}
|
||||
|
||||
public:
|
||||
bool patch (void *address, void *replacement) {
|
||||
uint8 *ptr = reinterpret_cast <uint8 *> (address);
|
||||
|
||||
while (*reinterpret_cast <uint16 *> (ptr) == 0x25ff) {
|
||||
ptr = **reinterpret_cast <uint8 * **> ((ptr + 2));
|
||||
}
|
||||
m_origFunc = reinterpret_cast <uint32> (ptr);
|
||||
|
||||
if (!m_origFunc) {
|
||||
return false;
|
||||
}
|
||||
m_hookFunc = reinterpret_cast <uint32> (replacement);
|
||||
|
||||
m_hookBytes[0] = 0x68;
|
||||
m_hookBytes[5] = 0xc3;
|
||||
|
||||
*reinterpret_cast <uint32 *> (&m_hookBytes[1]) = m_hookFunc;
|
||||
|
||||
if (unprotect ()) {
|
||||
memcpy (m_origBytes, reinterpret_cast <void *> (m_origFunc), CodeLength);
|
||||
return enable ();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool enable () {
|
||||
if (m_patched) {
|
||||
return false;
|
||||
}
|
||||
m_patched = true;
|
||||
|
||||
if (unprotect ()) {
|
||||
memcpy (reinterpret_cast <void *> (m_origFunc), m_hookBytes, CodeLength);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool disable () {
|
||||
if (!m_patched) {
|
||||
return false;
|
||||
}
|
||||
m_patched = false;
|
||||
|
||||
if (unprotect ()) {
|
||||
memcpy (reinterpret_cast <void *> (m_origFunc), m_origBytes, CodeLength);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool enabled () const {
|
||||
return m_patched;
|
||||
}
|
||||
};
|
||||
|
||||
CR_NAMESPACE_END
|
||||
|
|
@ -20,14 +20,13 @@
|
|||
# include <netinet/in.h>
|
||||
# include <sys/socket.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/uio.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <unistd.h>
|
||||
# include <errno.h>
|
||||
# include <netdb.h>
|
||||
# include <fcntl.h>
|
||||
#elif defined (CR_WINDOWS)
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
|
||||
|
|
@ -138,6 +137,30 @@ public:
|
|||
template <typename U> int32 recv (U *buffer, int32 length) {
|
||||
return ::recv (m_socket, reinterpret_cast <char *> (buffer), length, 0);
|
||||
}
|
||||
|
||||
public:
|
||||
static int32 CR_STDCALL sendto (int socket, const void *message, size_t length, int flags, const struct sockaddr *dest, int32 destLength) {
|
||||
#if defined (CR_WINDOWS)
|
||||
WSABUF buffer = { length, const_cast <char *> (reinterpret_cast <const char *> (message)) };
|
||||
DWORD sendLength = 0;
|
||||
|
||||
if (WSASendTo (socket, &buffer, 1, &sendLength, flags, dest, destLength, NULL, NULL) == SOCKET_ERROR) {
|
||||
errno = WSAGetLastError ();
|
||||
return -1;
|
||||
}
|
||||
return static_cast <int32> (sendLength);
|
||||
#else
|
||||
iovec iov = { const_cast <void *> (message), length };
|
||||
msghdr msg = { 0, };
|
||||
|
||||
msg.msg_name = reinterpret_cast <void *> (const_cast <struct sockaddr *> (dest));
|
||||
msg.msg_namelen = destLength;
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
return sendmsg (socket, &msg, flags);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
|
|
|||
|
|
@ -169,5 +169,4 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
CR_NAMESPACE_END
|
||||
|
|
@ -46,8 +46,8 @@ public:
|
|||
}
|
||||
|
||||
public:
|
||||
inline bool load (const String &file) noexcept {
|
||||
#ifdef CR_WINDOWS
|
||||
bool load (const String &file) noexcept {
|
||||
#if defined (CR_WINDOWS)
|
||||
m_handle = LoadLibraryA (file.chars ());
|
||||
#else
|
||||
m_handle = dlopen (file.chars (), RTLD_NOW);
|
||||
|
|
@ -55,15 +55,39 @@ public:
|
|||
return m_handle != nullptr;
|
||||
}
|
||||
|
||||
bool locate (void *address) {
|
||||
#if defined (CR_WINDOWS)
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
|
||||
if (!VirtualQuery (address, &mbi, sizeof (mbi))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mbi.State != MEM_COMMIT) {
|
||||
return false;
|
||||
}
|
||||
m_handle = reinterpret_cast <void *> (mbi.AllocationBase);
|
||||
#else
|
||||
Dl_info dli;
|
||||
memset (&dli, 0, sizeof (dli));
|
||||
|
||||
if (dladdr (address, &dli)) {
|
||||
return load (dli.dli_fname);
|
||||
}
|
||||
#endif
|
||||
return m_handle != nullptr;
|
||||
}
|
||||
|
||||
void unload () noexcept {
|
||||
if (!*this) {
|
||||
return;
|
||||
}
|
||||
#ifdef CR_WINDOWS
|
||||
#if defined (CR_WINDOWS)
|
||||
FreeLibrary (static_cast <HMODULE> (m_handle));
|
||||
#else
|
||||
dlclose (m_handle);
|
||||
#endif
|
||||
m_handle = nullptr;
|
||||
}
|
||||
|
||||
template <typename R> R resolve (const char *function) const {
|
||||
|
|
@ -72,7 +96,7 @@ public:
|
|||
}
|
||||
|
||||
return reinterpret_cast <R> (
|
||||
#ifdef CR_WINDOWS
|
||||
#if defined (CR_WINDOWS)
|
||||
GetProcAddress (static_cast <HMODULE> (m_handle), function)
|
||||
#else
|
||||
dlsym (m_handle, function)
|
||||
|
|
@ -80,6 +104,10 @@ public:
|
|||
);
|
||||
}
|
||||
|
||||
void *handle () const {
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit operator bool () const {
|
||||
return m_handle != nullptr;
|
||||
|
|
|
|||
|
|
@ -34,11 +34,13 @@ CR_NAMESPACE_BEGIN
|
|||
# define CR_CXX_CLANG
|
||||
#endif
|
||||
|
||||
// configure export macros
|
||||
// configure macroses
|
||||
#if defined(CR_WINDOWS)
|
||||
# define CR_EXPORT extern "C" __declspec (dllexport)
|
||||
# define CR_STDCALL __stdcall
|
||||
#elif defined(CR_LINUX) || defined(CR_OSX)
|
||||
# define CR_EXPORT extern "C" __attribute__((visibility("default")))
|
||||
# define CR_STDCALL
|
||||
#else
|
||||
# error "Can't configure export macros. Compiler unrecognized."
|
||||
#endif
|
||||
|
|
@ -56,11 +58,14 @@ CR_NAMESPACE_BEGIN
|
|||
CR_NAMESPACE_END
|
||||
|
||||
#if defined(CR_WINDOWS)
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# include <direct.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
# include <strings.h>
|
||||
# include <sys/stat.h>
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
|
@ -154,6 +159,25 @@ struct Platform : public Singleton <Platform> {
|
|||
#endif
|
||||
}
|
||||
|
||||
float seconds () {
|
||||
#if defined(CR_WINDOWS)
|
||||
LARGE_INTEGER count, freq;
|
||||
|
||||
count.QuadPart = 0;
|
||||
freq.QuadPart = 0;
|
||||
|
||||
QueryPerformanceFrequency (&freq);
|
||||
QueryPerformanceCounter (&count);
|
||||
|
||||
return static_cast <float> (count.QuadPart) / static_cast <float> (freq.QuadPart);
|
||||
#else
|
||||
timeval tv;
|
||||
gettimeofday (&tv, NULL);
|
||||
|
||||
return static_cast <float> (tv.tv_sec) + (static_cast <float> (tv.tv_usec)) / 1000000.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void abort (const char *msg = "OUT OF MEMORY!") noexcept {
|
||||
fprintf (stderr, "%s\n", msg);
|
||||
|
||||
|
|
|
|||
134
include/engine.h
134
include/engine.h
|
|
@ -165,7 +165,7 @@ public:
|
|||
void precache ();
|
||||
|
||||
// initialize levels
|
||||
void levelInitialize (edict_t *ents, int max);
|
||||
void levelInitialize (edict_t *entities, int max);
|
||||
|
||||
// display world line
|
||||
void drawLine (edict_t *ent, const Vector &start, const Vector &end, int width, int noise, const Color &color, int brightness, int speed, int life, DrawLine type = DrawLine::Simple);
|
||||
|
|
@ -304,8 +304,8 @@ public:
|
|||
int getTeam (edict_t *ent);
|
||||
|
||||
// adds translation pair from config
|
||||
void addTranslation (const String &original, const String &translated) {
|
||||
m_language.push (original, translated);
|
||||
void addTranslation (const String &m_origBytes, const String &translated) {
|
||||
m_language.push (m_origBytes, translated);
|
||||
}
|
||||
|
||||
// clear the translation table
|
||||
|
|
@ -572,4 +572,132 @@ public:
|
|||
void enableAnimation (bool enable) {
|
||||
m_doAnimation = enable;
|
||||
}
|
||||
};
|
||||
|
||||
// simple handler for parsing and rewriting queries (fake queries)
|
||||
class QueryBuffer {
|
||||
SmallArray <uint8> m_buffer;
|
||||
size_t m_cursor;
|
||||
|
||||
public:
|
||||
QueryBuffer (const uint8 *msg, size_t length, size_t shift) : m_cursor (0) {
|
||||
m_buffer.insert (0, msg, length);
|
||||
m_cursor += shift;
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename T> T read () {
|
||||
T result;
|
||||
auto size = sizeof (T);
|
||||
|
||||
if (m_cursor + size > m_buffer.length ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy (&result, m_buffer.data () + m_cursor, size);
|
||||
m_cursor += size;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// must be called right after read
|
||||
template <typename T> void write (T value) {
|
||||
auto size = sizeof (value);
|
||||
memcpy (m_buffer.data () + m_cursor - size, &value, size);
|
||||
}
|
||||
|
||||
template <typename T> void skip () {
|
||||
auto size = sizeof (T);
|
||||
|
||||
if (m_cursor + size > m_buffer.length ()) {
|
||||
return;
|
||||
}
|
||||
m_cursor += size;
|
||||
}
|
||||
|
||||
void skipString () {
|
||||
if (m_buffer.length () < m_cursor) {
|
||||
return;
|
||||
}
|
||||
for (; m_cursor < m_buffer.length () && m_buffer[m_cursor] != '\0'; ++m_cursor) { }
|
||||
++m_cursor;
|
||||
}
|
||||
|
||||
void shiftToEnd () {
|
||||
m_cursor = m_buffer.length ();
|
||||
}
|
||||
|
||||
public:
|
||||
Twin <const uint8 *, size_t> data () {
|
||||
return { m_buffer.data (), m_buffer.length () };
|
||||
}
|
||||
};
|
||||
|
||||
// for android
|
||||
#if defined (CR_ANDROID)
|
||||
extern "C" void player (entvars_t *pev);
|
||||
#endif
|
||||
|
||||
class DynamicEntityLink : public Singleton <DynamicEntityLink> {
|
||||
private:
|
||||
#if defined (CR_WINDOWS)
|
||||
# define CastType HMODULE
|
||||
# define LookupSymbol GetProcAddress
|
||||
#else
|
||||
# define CastType void *
|
||||
# define LookupSymbol dlsym
|
||||
#endif
|
||||
|
||||
private:
|
||||
using Handle = void *;
|
||||
using Name = const char *;
|
||||
|
||||
private:
|
||||
template <typename K> struct FunctionHash {
|
||||
uint32 operator () (Name key) const {
|
||||
char *str = const_cast <char *> (key);
|
||||
uint32 hash = 0;
|
||||
|
||||
while (*str++) {
|
||||
hash = ((hash << 5) + hash) + *str;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
SharedLibrary m_self;
|
||||
SimpleHook m_dlsym;
|
||||
Dictionary <Name, Handle, FunctionHash <Name>> m_exports;
|
||||
|
||||
public:
|
||||
DynamicEntityLink () = default;
|
||||
|
||||
~DynamicEntityLink () {
|
||||
m_dlsym.disable ();
|
||||
}
|
||||
public:
|
||||
Handle search (Handle module, Name function);
|
||||
|
||||
public:
|
||||
void initialize () {
|
||||
if (plat.isAndroid) {
|
||||
return;
|
||||
}
|
||||
m_dlsym.patch (reinterpret_cast <void *> (&LookupSymbol), reinterpret_cast <void *> (&DynamicEntityLink::replacement));
|
||||
m_self.locate (&engfuncs);
|
||||
}
|
||||
|
||||
EntityFunction getPlayerFunction () {
|
||||
#if defined (CR_ANDROID)
|
||||
return player;
|
||||
#else
|
||||
return reinterpret_cast <EntityFunction> (search (Game::get ().lib ().handle (), "player"));
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
static Handle CR_STDCALL replacement (Handle module, Name function) {
|
||||
return DynamicEntityLink::get ().search (module, function);
|
||||
}
|
||||
};
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#include <engine/extdll.h>
|
||||
#include <engine/meta_api.h>
|
||||
|
||||
|
|
@ -846,6 +846,8 @@ private:
|
|||
float m_oldCombatDesire; // holds old desire for filtering
|
||||
float m_avoidTime; // time to avoid players around
|
||||
float m_itemCheckTime; // time next search for items needs to be done
|
||||
float m_joinServerTime; // time when bot joined the game
|
||||
float m_playServerTime; // time bot spent in the game
|
||||
|
||||
bool m_moveToGoal; // bot currently moving to goal??
|
||||
bool m_isStuck; // bot is stuck
|
||||
|
|
@ -1322,6 +1324,7 @@ public:
|
|||
int getHumansCount (bool ignoreSpectators = false);
|
||||
int getAliveHumansCount ();
|
||||
int getBotCount ();
|
||||
float getConnectionTime (int botId);
|
||||
|
||||
void setBombPlanted (bool isPlanted);
|
||||
void slowFrame ();
|
||||
|
|
@ -1894,6 +1897,8 @@ private:
|
|||
SmallArray <Client> m_clients;
|
||||
SmallArray <Twin <String, String>> m_tags;
|
||||
|
||||
SimpleHook m_sendToHook;
|
||||
|
||||
public:
|
||||
BotUtils ();
|
||||
~BotUtils () = default;
|
||||
|
|
@ -1968,6 +1973,9 @@ public:
|
|||
// send modified pings to all the clients
|
||||
void sendPings (edict_t *to);
|
||||
|
||||
// installs the sendto function intreception
|
||||
void installSendTo ();
|
||||
|
||||
public:
|
||||
|
||||
// re-show welcome after changelevel ?
|
||||
|
|
@ -1990,6 +1998,16 @@ public:
|
|||
return m_clients[index];
|
||||
}
|
||||
|
||||
// disables send hook
|
||||
bool disableSendTo () {
|
||||
return m_sendToHook.disable ();
|
||||
}
|
||||
|
||||
// enables send hook
|
||||
bool enableSendTo () {
|
||||
return m_sendToHook.enable ();
|
||||
}
|
||||
|
||||
// checks if string is not empty
|
||||
bool isEmptyStr (const char *input) const {
|
||||
if (input == nullptr) {
|
||||
|
|
@ -1997,6 +2015,9 @@ public:
|
|||
}
|
||||
return *input == '\0';
|
||||
}
|
||||
|
||||
public:
|
||||
static int32 CR_STDCALL sendTo (int socket, const void *message, size_t length, int flags, const struct sockaddr *dest, int destLength);
|
||||
};
|
||||
|
||||
// bot command manager
|
||||
|
|
@ -2185,6 +2206,7 @@ static auto &util = BotUtils::get ();
|
|||
static auto &ctrl = BotControl::get ();
|
||||
static auto &game = Game::get ();
|
||||
static auto &illum = LightMeasure::get ();
|
||||
static auto &ents = DynamicEntityLink::get ();
|
||||
|
||||
// very global convars
|
||||
extern ConVar yb_jasonmode;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue