Skip to content

Commit

Permalink
No longer hook GetHostName(), just store servers
Browse files Browse the repository at this point in the history
  • Loading branch information
tobii-dev committed Jan 19, 2022
1 parent 4624e8a commit ac6d976
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 43 deletions.
Binary file added amax-redirect.asi
Binary file not shown.
6 changes: 3 additions & 3 deletions amax-redirect.cfg
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
lsg.demonware.net amax-emu.com
blur-pc-live.auth.mmp3.demonware.net amax-emu.com
blur-pc-live.lsg.mmp3.demonware.net amax-emu.com
#0x0 lsg.demonware.net amax-emu.com
0xAC5B3C blur-pc-live.auth.mmp3.demonware.net amax-emu.com
0xAC5B64 blur-pc-live.lsg.mmp3.demonware.net amax-emu.com
105 changes: 65 additions & 40 deletions source/dllmain.cpp
Original file line number Diff line number Diff line change
@@ -1,61 +1,86 @@
#include <windows.h>
#include <winsock.h>
#include <libloaderapi.h>
#include <stdint.h>

//#include <iostream>
#include <fstream> // used for std::ifstream input file reading
#include <string> // std::string magic
#include <map> // saving string key-value pairs in the input file
#include <fstream> // used for reading std::ifstream input file
#include <string>
#include <vector>

#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "user32.lib")


#define HOOK_NET_FUNC_ADDY 0x92213B
#define OP_CALL_LEN 6

//TODO consider to give that file a better home / name?
#define DNS_FILE_NAME "amax-redirect.cfg" // input file, must sit next to the amax-redirect.asi


// global map for orignal->redirect domains
std::map<std::string, std::string> dns_redirects;


// parse input file and return domain pairs as map
std::map<std::string, std::string> get_dns_redirects() {
std::map<std::string, std::string> r = {};
std::string key, value;
std::ifstream f(DNS_FILE_NAME);
while (f >> key >> value) {
r[key] = value;
typedef struct {
uintptr_t addy; // offset from start Blur.exe where the entry is located
std::string org_host; // original hostname, in case we would want to restore it. TODO implement restore on unload?
std::string new_host; // new hostname
} Redirect;


// loads and parses entries from text file
std::vector<Redirect> load_redirects(const char* filename) {
std::vector<Redirect> vec_redirects;
std::string str_addy;
uintptr_t addy;
std::string org_host;
std::string new_host;
std::ifstream f(filename);
while (f >> str_addy >> org_host >> new_host) { // this just eats every 3 string (anything), doesnt go line by line
if (str_addy[0] != '#') { // idk something with comments
if ((addy = std::strtol(str_addy.c_str(), NULL, 0)) > 0x0) {
// https://man7.org/linux/man-pages/man3/strtol.3.html
// (EXAMPLE: strtol("0xF") = 15 ) // converts string repr of number into actual number (accepts hex repr)
if (new_host.length() <= org_host.length()) {
Redirect r { addy, org_host, new_host };
vec_redirects.push_back(r);
} else {
// Inform user (by console or log file?) that one of the entries in filename is too long.
// TBH, I dont know how long (# of chars) they are allowed to be, should we check in Cheat-Engine?
}
} else {
// Could not convert string representation (hex 0x?) to actual addy
}
} else {
// It was a silly comment starting with '#'
}
}
return r;
return vec_redirects;
}


struct hostent* __stdcall hook_gethostbyname(const char* name) {
if (dns_redirects.count(name)) {
name = dns_redirects[name].c_str();
bool set_redirects(uintptr_t moduleBase, std::vector<Redirect> vec_redirects) {
bool ok = true;
unsigned char* dst; // where we will write the new host string to
DWORD srcProtection, _; // for VirtualProtect, idk if its really needed?
for (Redirect r : vec_redirects) {
dst = (unsigned char*) (moduleBase + r.addy); // addy stored in cfg = offset from Blur.exe; so we add it to the base (moduleBase is almost always 0x40000)
VirtualProtect(dst, r.org_host.length(), PAGE_EXECUTE_READWRITE, &srcProtection);
// copy chars over, im sure there is more elegant way to do it...
for (unsigned int i = 0; i < r.new_host.length(); i++) {
// checking if the original chars match, unused so far...
ok = ok && (dst[i] == r.org_host[i]);
dst[i] = r.new_host[i];
}
// set the rest to null chars just in case
for (unsigned int i = r.new_host.length(); i < r.org_host.length(); i++) {
dst[i] = '\0';
}
VirtualProtect(dst, r.org_host.length(), srcProtection, &_);
}
return gethostbyname(name);
return ok;
}


BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
switch(fdwReason) {
switch(fdwReason) {
case DLL_PROCESS_ATTACH: {
dns_redirects = get_dns_redirects();

uintptr_t moduleBase = (uintptr_t) GetModuleHandle(NULL);
void* src = (void*) (moduleBase + HOOK_NET_FUNC_ADDY);
void* callArg = VirtualAlloc(0, sizeof(uintptr_t), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
*(uintptr_t*) callArg = (uintptr_t) hook_gethostbyname;

DWORD srcProtection, _;
VirtualProtect(src, OP_CALL_LEN, PAGE_EXECUTE_READWRITE, &srcProtection);
*(uintptr_t*) (((uint8_t*)src) + 2) = (uintptr_t) callArg;
VirtualProtect(src, OP_CALL_LEN, srcProtection, &_);
std::vector<Redirect> vec_redirects = load_redirects(DNS_FILE_NAME);
bool ok = set_redirects(moduleBase, vec_redirects);
if (ok) {
// Inform?
} else {
// IDK, restore?
}
break;

} case DLL_THREAD_ATTACH: { // Do thread-specific initialization.
Expand Down

0 comments on commit ac6d976

Please sign in to comment.