localizebugfix/memory.cpp

195 lines
5.0 KiB
C++
Raw Permalink Normal View History

2015-05-06 11:17:22 +03:00
/*
* Localize Bug Fix
* Copyright (c) 2013 - 2014 AGHL.RU Dev Team
*
* http://aghl.ru/forum/ - Russian Half-Life and Adrenaline Gamer Community
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*
*/
#include "memory.h"
#ifdef _WIN32
int lib_load_info(void *addr,lib_t *lib)
{
MEMORY_BASIC_INFORMATION mem;
VirtualQuery(addr,&mem,sizeof(mem));
IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER*)mem.AllocationBase;
IMAGE_NT_HEADERS *pe = (IMAGE_NT_HEADERS*)((dword)dos + (dword)dos->e_lfanew);
if(pe->Signature != IMAGE_NT_SIGNATURE)
return 0;
lib->base = (char *)mem.AllocationBase;
lib->size = (size_t)pe->OptionalHeader.SizeOfImage;
return 1;
}
#else
char *lib_find_symbol(lib_t *lib,const char *symbol)
{
return (char *)dlsym(lib->handle,symbol);
}
static ElfW(Addr) dlsize(void *base)
{
int i;
ElfW(Ehdr) *ehdr;
ElfW(Phdr) *phdr;
ElfW(Addr) end;
ehdr = (ElfW(Ehdr)*)base;
phdr = (ElfW(Phdr)*)((ElfW(Addr))ehdr + ehdr->e_phoff);
for(i = 0; i < ehdr->e_phnum; ++i)
{
if(phdr[i].p_type == PT_LOAD)
end = phdr[i].p_vaddr + phdr[i].p_memsz;
}
return end;
}
int lib_load_info(void *addr,lib_t *lib)
{
Dl_info info;
if(!dladdr(addr,&info) || !info.dli_fbase || !info.dli_fname)
return 0;
lib->base = (char *)info.dli_fbase;
lib->size = dlsize(info.dli_fbase);
lib->handle = dlopen(info.dli_fname,RTLD_NOW);
return 1;
}
#endif
static inline int mem_compare_c(const char *addr,const char *pattern,const char *pattern_end)
{
const char *c;
for(c = pattern; c < pattern_end; ++c, ++addr)
{
if(*c == *addr || *c == '\x2A')
continue;
return 0;
}
return 1;
}
static char *mem_find_ref_c(char *pos,char *end,int opcode,dword ref,int relative)
{
for(; pos < end; ++pos)
{
if(*pos == opcode)
{
if(relative)
{
if((dword)pos + 5 + *(dword *)(pos + 1) == ref)
return pos;
}
else
{
if(*(dword *)(pos + 1) == ref)
return pos;
}
}
}
return NULL;
}
char *mem_find_pattern(char *pos,int range,const char *pattern,int len)
{
char *end;
const char *pattern_end;
pattern_end = pattern + len;
for(end = pos + range - len; pos < end; ++pos)
{
if(mem_compare_c(pos,pattern,pattern_end))
return pos;
}
return NULL;
}
static char *lib_find_string_push(lib_t *lib,const char *string)
{
char *addr;
addr = mem_find_pattern(lib->base,lib->size,string,strlen(string) + 1);
return mem_find_ref_c(lib->base,lib->base + lib->size - 5,'\x68',(dword)addr,0);
}
char *mem_find_ref(char *start,int range,int opcode,dword ref,int relative)
{
return mem_find_ref_c(start,start + range - 5,opcode,ref,relative);
}
char *lib_find_pattern(lib_t *lib,const char *pattern,int len)
{
return mem_find_pattern(lib->base,lib->size,pattern,len);
}
char *lib_find_pattern_fstr(lib_t *lib,const char *string,int range,const char *pattern,int len)
{
char *addr;
addr = lib_find_string_push(lib,string);
if(addr)
{
if(range < 0)
{
addr += range;
range = -range;
}
return mem_find_pattern(addr,range,pattern,len);
}
return NULL;
}
int mem_change_protection(void *addr,const char *patch,int len)
{
#ifdef _WIN32
static HANDLE process = 0;
DWORD OldProtection,NewProtection = PAGE_EXECUTE_READWRITE;
if(!process)
process = GetCurrentProcess();
FlushInstructionCache(process,addr,len);
if(VirtualProtect(addr,len,NewProtection,&OldProtection))
{
memcpy(addr,patch,len);
return VirtualProtect(addr,len,OldProtection,&NewProtection);
}
#else
size_t size = sysconf(_SC_PAGESIZE);
void *alignedAddress = Align(addr);
if(Align(addr + len - 1) != alignedAddress)
size *= 2;
if(!mprotect(alignedAddress,size,(PROT_READ|PROT_WRITE|PROT_EXEC)))
{
memcpy(addr,patch,len);
return !mprotect(alignedAddress,size,(PROT_READ|PROT_EXEC));
}
#endif
return 0;
}