mirror of
https://github.com/rehlds/localizebugfix.git
synced 2025-01-12 16:57:54 +03:00
195 lines
5.0 KiB
C++
195 lines
5.0 KiB
C++
/*
|
|
* 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;
|
|
}
|
|
|