mirror of
https://git.suyu.dev/suyu/Yucom.git
synced 2025-12-21 21:26:03 +01:00
lsteamclient: Get memory for SteamClient interface within native steamclient.dll loader range.
CW-Bug-ID: #19605 For Mafia II.
This commit is contained in:
parent
b3c6c677bc
commit
7a90ff74ce
39 changed files with 331 additions and 187 deletions
|
|
@ -9,6 +9,7 @@
|
|||
#include "winbase.h"
|
||||
#include "winnls.h"
|
||||
#include "winuser.h"
|
||||
#include "winternl.h"
|
||||
#include "wine/debug.h"
|
||||
#include "wine/list.h"
|
||||
#include "steam_defs.h"
|
||||
|
|
@ -232,6 +233,144 @@ void steamclient_free_stringlist(const char **out)
|
|||
}
|
||||
}
|
||||
|
||||
static BYTE *alloc_start, *alloc_end;
|
||||
|
||||
static BOOL allocated_from_steamclient_dll( void *ptr )
|
||||
{
|
||||
return (BYTE *)ptr >= alloc_start && (BYTE *)ptr < alloc_end;
|
||||
}
|
||||
|
||||
static void *get_mem_from_steamclient_dll(size_t size, unsigned int version)
|
||||
{
|
||||
static BYTE * const error_ptr = (BYTE *)~(ULONG_PTR)0;
|
||||
static const unsigned int magic = 0x53ba947a;
|
||||
static struct
|
||||
{
|
||||
unsigned int version;
|
||||
size_t size;
|
||||
void *ptr;
|
||||
}
|
||||
allocated[32];
|
||||
static unsigned int allocated_count;
|
||||
static BYTE *alloc_base;
|
||||
unsigned int i;
|
||||
|
||||
if (alloc_base == error_ptr)
|
||||
{
|
||||
/* Previously failed to locate the section. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (alloc_base && (IsBadReadPtr(alloc_start, sizeof(magic)) || *(unsigned int *)alloc_start != magic))
|
||||
{
|
||||
TRACE("steamclient.dll reloaded.\n");
|
||||
alloc_base = alloc_start = alloc_end = NULL;
|
||||
allocated_count = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < allocated_count; ++i)
|
||||
{
|
||||
if (allocated[i].version == version)
|
||||
{
|
||||
if (allocated[i].size != size)
|
||||
{
|
||||
FIXME("Size does not match.\n");
|
||||
return NULL;
|
||||
}
|
||||
return allocated[i].ptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (allocated_count == ARRAY_SIZE(allocated))
|
||||
{
|
||||
FIXME("Too many interface versions.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!alloc_base)
|
||||
{
|
||||
const IMAGE_SECTION_HEADER *sec;
|
||||
const IMAGE_NT_HEADERS *nt;
|
||||
HMODULE mod;
|
||||
|
||||
if (!(mod = GetModuleHandleW(L"steamclient.dll")))
|
||||
{
|
||||
/* That is steamclient64.dll for x64 but no known use cases on x64.*/
|
||||
WARN("Module not found, err %u.\n", GetLastError());
|
||||
alloc_base = error_ptr;
|
||||
return NULL;
|
||||
}
|
||||
if (!(nt = RtlImageNtHeader(mod)))
|
||||
{
|
||||
FIXME("Got NULL NT image headers.\n");
|
||||
alloc_base = error_ptr;
|
||||
return NULL;
|
||||
}
|
||||
sec = (const IMAGE_SECTION_HEADER *)((const BYTE *)&nt->OptionalHeader + nt->FileHeader.SizeOfOptionalHeader);
|
||||
for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
|
||||
{
|
||||
if (!memcmp(sec[i].Name, ".data", 5))
|
||||
{
|
||||
alloc_start = alloc_base = (BYTE *)mod + sec[i].VirtualAddress;
|
||||
alloc_end = alloc_base + sec[i].SizeOfRawData;
|
||||
if (alloc_end - alloc_start < sizeof(magic))
|
||||
{
|
||||
ERR(".data section is too small.\n");
|
||||
alloc_base = error_ptr;
|
||||
return NULL;
|
||||
}
|
||||
TRACE("Found .data section, start %p, end %p.\n", alloc_base, alloc_end);
|
||||
*(unsigned int *)alloc_base = magic;
|
||||
alloc_base += sizeof(unsigned int);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == nt->FileHeader.NumberOfSections)
|
||||
{
|
||||
FIXME(".data section not found.\n");
|
||||
alloc_base = error_ptr;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (alloc_end - alloc_base < size)
|
||||
{
|
||||
FIXME("Not enough section size left.\n");
|
||||
return NULL;
|
||||
}
|
||||
allocated[allocated_count].version = version;
|
||||
allocated[allocated_count].size = size;
|
||||
allocated[allocated_count].ptr = alloc_base;
|
||||
alloc_base += size;
|
||||
|
||||
return allocated[allocated_count++].ptr;
|
||||
}
|
||||
|
||||
void *alloc_mem_for_iface(size_t size, const char *iface_version)
|
||||
{
|
||||
const char steamclient_iface_name[] = "SteamClient";
|
||||
unsigned int version;
|
||||
void *ret;
|
||||
|
||||
/* Mafia II depends on SteamClient interface pointer to point inside
|
||||
* native Windows steamclient.dll. */
|
||||
if (strncmp(iface_version, steamclient_iface_name, ARRAY_SIZE(steamclient_iface_name) - 1))
|
||||
goto fallback;
|
||||
|
||||
version = atoi(iface_version + ARRAY_SIZE(steamclient_iface_name) - 1);
|
||||
if (!version)
|
||||
{
|
||||
FIXME("Could not get iface version from %s.\n", iface_version);
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
if ((ret = get_mem_from_steamclient_dll(size, version)))
|
||||
return ret;
|
||||
|
||||
fallback:
|
||||
return HeapAlloc(GetProcessHeap(), 0, size);
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
static const uint32 vk_to_xkeysym[0xFF] = {
|
||||
0, /* 0x0 Undefined */
|
||||
|
|
@ -417,13 +556,16 @@ void *create_win_interface(const char *name, void *linux_side)
|
|||
{
|
||||
if (!strcmp(name, constructors[i].iface_version))
|
||||
{
|
||||
ret = constructors[i].ctor(linux_side);
|
||||
if (allocated_from_steamclient_dll(ret))
|
||||
break;
|
||||
|
||||
e = HeapAlloc(GetProcessHeap(), 0, sizeof(*e));
|
||||
e->name = constructors[i].iface_version;
|
||||
e->linux_side = linux_side;
|
||||
e->interface = constructors[i].ctor(linux_side);
|
||||
e->interface = ret;
|
||||
list_add_tail(&steamclient_interfaces, &e->entry);
|
||||
|
||||
ret = e->interface;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue