mirror of
https://github.com/UzixLS/KernelEx.git
synced 2025-07-18 23:11:19 +03:00
import KernelEx-4.0-RC1
This commit is contained in:
131
core/Core.rc
Normal file
131
core/Core.rc
Normal file
@ -0,0 +1,131 @@
|
||||
#include "resource.h"
|
||||
#include "version.h"
|
||||
#define _QUOTEME(x) #x
|
||||
#define QUOTEME(x) _QUOTEME(x)
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "afxres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Neutral resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
||||
#pragma code_page(1250)
|
||||
#endif //_WIN32
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// String Table
|
||||
//
|
||||
|
||||
STRINGTABLE DISCARDABLE
|
||||
BEGIN
|
||||
IDS_NOTREADY "System is not KernelEx-ready.\nPlease reinstall KernelEx."
|
||||
IDS_STUBMISMATCH "Stub version mismatch (expected: %d, got: %d).\nPlease reinstall KernelEx."
|
||||
IDS_OLDVER "Another KernelEx version has been detected: %s.\nPlease uninstall all other versions and reinstall latest version."
|
||||
END
|
||||
|
||||
#endif // Neutral resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Polish resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_PLK)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_POLISH, SUBLANG_DEFAULT
|
||||
#pragma code_page(1250)
|
||||
#endif //_WIN32
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"#include ""afxres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
#ifndef _MAC
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION RCVERSION
|
||||
PRODUCTVERSION RCVERSION
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "000004b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Xeno86\0"
|
||||
VALUE "FileDescription", "KernelEx Core\0"
|
||||
VALUE "FileVersion", QUOTEME(RCVERSION) "\0"
|
||||
VALUE "InternalName", "KernelEx\0"
|
||||
VALUE "LegalCopyright", "Copyright <20> 2009, Xeno86\0"
|
||||
VALUE "OriginalFilename", "KernelEx.dll\0"
|
||||
VALUE "ProductName", "KernelEx\0"
|
||||
VALUE "ProductVersion", VERSION_STR "\0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x0, 1200
|
||||
END
|
||||
END
|
||||
|
||||
#endif // !_MAC
|
||||
|
||||
#endif // Polish resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
257
core/SettingsDB.cpp
Normal file
257
core/SettingsDB.cpp
Normal file
@ -0,0 +1,257 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include "SettingsDB.h"
|
||||
#include "apiconfmgr.h"
|
||||
#include "internals.h"
|
||||
#include "resolver.h"
|
||||
#include "debug.h"
|
||||
#include "wildcmp.h"
|
||||
|
||||
SettingsDB SettingsDB::instance;
|
||||
|
||||
SettingsDB::SettingsDB()
|
||||
{
|
||||
InitializeCriticalSection(&cs);
|
||||
}
|
||||
|
||||
SettingsDB::~SettingsDB()
|
||||
{
|
||||
DeleteCriticalSection(&cs);
|
||||
}
|
||||
|
||||
void SettingsDB::clear()
|
||||
{
|
||||
EnterCriticalSection(&cs);
|
||||
db.clear();
|
||||
appsetting as;
|
||||
as.flags = LDR_KEX_DISABLE;
|
||||
db.insert(pair<sstring,appsetting>(own_path, as));
|
||||
LeaveCriticalSection(&cs);
|
||||
}
|
||||
|
||||
void SettingsDB::flush_all()
|
||||
{
|
||||
EnterCriticalSection(&cs);
|
||||
clear();
|
||||
parse_configs();
|
||||
parse_flags();
|
||||
LeaveCriticalSection(&cs);
|
||||
}
|
||||
|
||||
void SettingsDB::parse_configs()
|
||||
{
|
||||
LONG result;
|
||||
HKEY key;
|
||||
DWORD index = 0;
|
||||
char path[MAX_PATH];
|
||||
DWORD path_len;
|
||||
char name[256];
|
||||
DWORD name_len;
|
||||
DWORD type;
|
||||
|
||||
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\KernelEx\\AppSettings\\Configs",
|
||||
0, KEY_QUERY_VALUE, &key);
|
||||
if (result != ERROR_SUCCESS)
|
||||
{
|
||||
DBGPRINTF(("AppSettings\\Configs key missing\n"));
|
||||
return;
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
appsetting as;
|
||||
map<sstring,appsetting>* pdb;
|
||||
|
||||
path_len = sizeof(path);
|
||||
name_len = sizeof(name);
|
||||
result = RegEnumValue(key, index, path, &path_len, NULL, &type, (LPBYTE)name, &name_len);
|
||||
index++;
|
||||
if (result == ERROR_NO_MORE_ITEMS)
|
||||
break;
|
||||
if (result != ERROR_SUCCESS)
|
||||
break;
|
||||
if (type != REG_SZ)
|
||||
continue;
|
||||
name[sizeof(name) - 1] = '\0';
|
||||
as.conf = ApiConfigurationManager::get_api_configuration(name);
|
||||
if (!as.conf)
|
||||
continue;
|
||||
|
||||
strupr(path);
|
||||
if (strchr(path, '*') || strchr(path, '?'))
|
||||
pdb = &db_wild;
|
||||
else
|
||||
pdb = &db;
|
||||
|
||||
pdb->insert(pair<sstring, appsetting>(path, as));
|
||||
}
|
||||
RegCloseKey(key);
|
||||
}
|
||||
|
||||
//note: call it after parse_configs()
|
||||
void SettingsDB::parse_flags()
|
||||
{
|
||||
LONG result;
|
||||
HKEY key;
|
||||
DWORD index = 0;
|
||||
char path[MAX_PATH];
|
||||
DWORD path_len;
|
||||
unsigned long flags;
|
||||
DWORD flags_len;
|
||||
DWORD type;
|
||||
|
||||
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\KernelEx\\AppSettings\\Flags",
|
||||
0, KEY_QUERY_VALUE, &key);
|
||||
if (result != ERROR_SUCCESS)
|
||||
{
|
||||
DBGPRINTF(("AppSettings\\Flags key missing\n"));
|
||||
return;
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
map<sstring,appsetting>* pdb;
|
||||
path_len = sizeof(path);
|
||||
flags_len = sizeof(flags);
|
||||
result = RegEnumValue(key, index, path, &path_len, NULL, &type, (LPBYTE)&flags, &flags_len);
|
||||
index++;
|
||||
if (result == ERROR_NO_MORE_ITEMS)
|
||||
break;
|
||||
if (result != ERROR_SUCCESS)
|
||||
break;
|
||||
if (type != REG_DWORD)
|
||||
continue;
|
||||
|
||||
strupr(path);
|
||||
if (strchr(path, '*') || strchr(path, '?'))
|
||||
pdb = &db_wild;
|
||||
else
|
||||
pdb = &db;
|
||||
|
||||
map<sstring,appsetting>::iterator it = pdb->find(path);
|
||||
if (it == pdb->end())
|
||||
{
|
||||
appsetting as;
|
||||
as.flags = flags;
|
||||
pdb->insert(pair<sstring,appsetting>(path, as));
|
||||
}
|
||||
else
|
||||
{
|
||||
it->second.flags = flags;
|
||||
}
|
||||
}
|
||||
RegCloseKey(key);
|
||||
}
|
||||
|
||||
appsetting SettingsDB::get_appsetting(const char* path)
|
||||
{
|
||||
map<sstring,appsetting>::const_iterator it;
|
||||
|
||||
EnterCriticalSection(&cs);
|
||||
//try full path first
|
||||
it = db.find(path);
|
||||
if (it == db.end())
|
||||
{
|
||||
//then try wildcard matching
|
||||
for (it = db_wild.begin() ; it != db_wild.end() ; it++)
|
||||
{
|
||||
if (wildcmp(it->first.get(), path))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool atend = it == db.end() || it == db_wild.end();
|
||||
LeaveCriticalSection(&cs);
|
||||
if (!atend)
|
||||
return it->second;
|
||||
else
|
||||
return appsetting();
|
||||
}
|
||||
|
||||
void SettingsDB::write_single(const char* path, const char* conf_name, BYTE flags)
|
||||
{
|
||||
LONG result;
|
||||
HKEY key;
|
||||
appsetting as;
|
||||
|
||||
//convert path to uppercase
|
||||
char path2[MAX_PATH];
|
||||
strncpy(path2, path, sizeof(path2));
|
||||
strupr(path2);
|
||||
|
||||
//check if configuration name is valid
|
||||
as.conf = ApiConfigurationManager::get_api_configuration(conf_name);
|
||||
as.flags = flags;
|
||||
|
||||
//write config
|
||||
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
"Software\\KernelEx\\AppSettings\\Configs", 0, KEY_WRITE, &key);
|
||||
if (result == ERROR_SUCCESS)
|
||||
{
|
||||
if (!as.conf || as.conf == ApiConfigurationManager::get_default_configuration())
|
||||
RegSetValueEx(key, path, 0, REG_SZ, (const BYTE*) "default",
|
||||
sizeof("default"));
|
||||
else
|
||||
RegSetValueEx(key, path, 0, REG_SZ, (const BYTE*) conf_name,
|
||||
strlen(conf_name) + 1);
|
||||
RegCloseKey(key);
|
||||
}
|
||||
|
||||
//write flags
|
||||
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
"Software\\KernelEx\\AppSettings\\Flags", 0, KEY_WRITE, &key);
|
||||
if (result == ERROR_SUCCESS)
|
||||
{
|
||||
RegSetValueEx(key, path, 0, REG_DWORD, (BYTE*) &as.flags, sizeof(as.flags));
|
||||
RegCloseKey(key);
|
||||
}
|
||||
|
||||
//add to DB
|
||||
EnterCriticalSection(&cs);
|
||||
db.erase(path2);
|
||||
db.insert(pair<sstring,appsetting>(path2, as));
|
||||
LeaveCriticalSection(&cs);
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
void SettingsDB::dump_db()
|
||||
{
|
||||
map<sstring, appsetting>::const_iterator it;
|
||||
|
||||
dbgprintf("User settings:\n");
|
||||
for (it = db.begin() ; it != db.end() ; it++)
|
||||
{
|
||||
ApiConfiguration* conf = it->second.conf;
|
||||
dbgprintf("%-40s %-10s %02x\n", it->first.get(),
|
||||
conf ? conf->get_name() : "unknown", it->second.flags);
|
||||
}
|
||||
|
||||
dbgprintf("\nPredefined settings:\n");
|
||||
for (it = db_wild.begin() ; it != db_wild.end() ; it++)
|
||||
{
|
||||
ApiConfiguration* conf = it->second.conf;
|
||||
dbgprintf("%-40s %-10s %02x\n", it->first.get(),
|
||||
conf ? conf->get_name() : "unknown", it->second.flags);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
66
core/SettingsDB.h
Normal file
66
core/SettingsDB.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SETTINGSDB_H
|
||||
#define __SETTINGSDB_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4786)
|
||||
#endif
|
||||
|
||||
#include "sstring.hpp"
|
||||
#include <map>
|
||||
#include "apiconf.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct appsetting
|
||||
{
|
||||
appsetting() : conf(NULL), flags(0) {}
|
||||
ApiConfiguration* conf;
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
class SettingsDB
|
||||
{
|
||||
public:
|
||||
static SettingsDB instance;
|
||||
|
||||
~SettingsDB();
|
||||
void clear();
|
||||
void flush_all();
|
||||
appsetting get_appsetting(const char* path);
|
||||
void write_single(const char* path, const char* conf_name, BYTE flags);
|
||||
#ifdef _DEBUG
|
||||
void dump_db();
|
||||
#endif
|
||||
|
||||
private:
|
||||
map<sstring, appsetting> db;
|
||||
map<sstring, appsetting> db_wild;
|
||||
CRITICAL_SECTION cs;
|
||||
|
||||
SettingsDB();
|
||||
void parse_configs();
|
||||
void parse_flags();
|
||||
};
|
||||
|
||||
#endif
|
601
core/apiconf.cpp
Normal file
601
core/apiconf.cpp
Normal file
@ -0,0 +1,601 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2008-2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <algorithm>
|
||||
#include "apilib.h"
|
||||
#include "apiconf.h"
|
||||
#include "resolver.h"
|
||||
#include "internals.h"
|
||||
#include "debug.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
ApiConfiguration::ApiConfiguration(const char* name)
|
||||
{
|
||||
initialized = prepare(name);
|
||||
if (!initialized)
|
||||
DBGPRINTF(("Failed to allocate memory\n"));
|
||||
}
|
||||
|
||||
ApiConfiguration::ApiConfiguration(const char* new_name, const ApiConfiguration& src)
|
||||
{
|
||||
if (!prepare(new_name))
|
||||
goto __error;
|
||||
|
||||
if (src.used_apilibs)
|
||||
{
|
||||
void* mem = malloc(src.used_apilibs_count * sizeof(ApiLibrary*));
|
||||
if (!mem)
|
||||
goto __error;
|
||||
|
||||
used_apilibs = (const ApiLibrary**) mem;
|
||||
copy(src.used_apilibs, src.used_apilibs + src.used_apilibs_count, used_apilibs);
|
||||
used_apilibs_count = src.used_apilibs_count;
|
||||
}
|
||||
|
||||
for (int i = 0 ; i < src.api_tables_count ; i++)
|
||||
{
|
||||
void* mem;
|
||||
const ModuleApi& stab = src.api_tables[i];
|
||||
ModuleApi& dtab = api_tables[i];
|
||||
|
||||
mem = malloc(stab.named_apis_count * sizeof(NamedApi));
|
||||
if (!mem)
|
||||
goto __error;
|
||||
|
||||
dtab.named_apis = (NamedApi*) mem;
|
||||
dtab.named_apis_count = stab.named_apis_count;
|
||||
copy(stab.named_apis, stab.named_apis + stab.named_apis_count,
|
||||
dtab.named_apis);
|
||||
|
||||
mem = malloc(stab.unnamed_apis_count * sizeof(PROC));
|
||||
if (!mem)
|
||||
goto __error;
|
||||
|
||||
dtab.unnamed_apis = (PDWORD) mem;
|
||||
dtab.unnamed_apis_count = stab.unnamed_apis_count;
|
||||
copy(stab.unnamed_apis, stab.unnamed_apis + stab.unnamed_apis_count,
|
||||
dtab.unnamed_apis);
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
return;
|
||||
|
||||
__error:
|
||||
DBGPRINTF(("Failed to allocate memory\n"));
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
ApiConfiguration::~ApiConfiguration()
|
||||
{
|
||||
for (int i = 0 ; i < api_tables_count ; i++)
|
||||
{
|
||||
free(api_tables[i].named_apis);
|
||||
free(api_tables[i].unnamed_apis);
|
||||
}
|
||||
free(conf_name);
|
||||
free(api_tables);
|
||||
free(used_apilibs);
|
||||
}
|
||||
|
||||
bool ApiConfiguration::prepare(const char* name)
|
||||
{
|
||||
int size = strlen(name) + 1;
|
||||
conf_name = (char*) malloc(size);
|
||||
if (!conf_name)
|
||||
return false;
|
||||
|
||||
strcpy(conf_name, name);
|
||||
|
||||
api_tables = (ModuleApi*) calloc(new_overridden_mod_cnt, sizeof(ModuleApi));
|
||||
if (!api_tables)
|
||||
return false;
|
||||
|
||||
api_tables_count = new_overridden_mod_cnt;
|
||||
used_apilibs = NULL;
|
||||
used_apilibs_count = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ApiConfiguration::add_to_used_apilibs(const ApiLibrary* apilib)
|
||||
{
|
||||
for (int i = 0 ; i < used_apilibs_count ; i++)
|
||||
{
|
||||
if (used_apilibs[i] == apilib)
|
||||
return true;
|
||||
}
|
||||
|
||||
//not found => add to list
|
||||
void* mem = realloc(used_apilibs, (used_apilibs_count + 1) * sizeof(ApiLibrary*));
|
||||
if (!mem)
|
||||
return false;
|
||||
|
||||
used_apilibs = (const ApiLibrary**) mem;
|
||||
used_apilibs[used_apilibs_count++] = apilib;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ApiConfiguration::merge(const ApiLibrary* apilib)
|
||||
{
|
||||
if (!apilib)
|
||||
return false;
|
||||
|
||||
if (!add_to_used_apilibs(apilib))
|
||||
return false;
|
||||
|
||||
for (int i = 0 ; i < new_overridden_mod_cnt ; i++)
|
||||
{
|
||||
const apilib_api_table* psrc = apilib->api_tables;
|
||||
while (psrc->target_library)
|
||||
{
|
||||
if (!strcmpi(psrc->target_library, new_overridden_mod_nms[i]))
|
||||
{
|
||||
if (i >= api_tables_count)
|
||||
{
|
||||
void* mem = recalloc(api_tables, new_overridden_mod_cnt * sizeof(ModuleApi));
|
||||
if (!mem)
|
||||
return false;
|
||||
api_tables = (ModuleApi*) mem;
|
||||
api_tables_count = new_overridden_mod_cnt;
|
||||
}
|
||||
ModuleApi* pdst = api_tables + i;
|
||||
|
||||
//join ordinal apis
|
||||
|
||||
unsigned short max_ord;
|
||||
if (psrc->ordinal_apis_count)
|
||||
max_ord = psrc->ordinal_apis[psrc->ordinal_apis_count - 1].ord;
|
||||
else
|
||||
max_ord = 0;
|
||||
|
||||
if (pdst->unnamed_apis_count < max_ord)
|
||||
{
|
||||
void* mem = recalloc(pdst->unnamed_apis, max_ord * sizeof(PROC));
|
||||
if (!mem)
|
||||
return false;
|
||||
pdst->unnamed_apis = (PDWORD) mem;
|
||||
pdst->unnamed_apis_count = max_ord;
|
||||
}
|
||||
|
||||
//join tables
|
||||
for (int i = psrc->ordinal_apis_count - 1 ; i >= 0 ; i--)
|
||||
{
|
||||
const apilib_unnamed_api& pua = psrc->ordinal_apis[i];
|
||||
pdst->unnamed_apis[pua.ord - 1] = encode_address(pua.addr, apilib);
|
||||
}
|
||||
|
||||
//join named apis
|
||||
|
||||
const apilib_named_api* sfirst = psrc->named_apis;
|
||||
const apilib_named_api* slast = sfirst + psrc->named_apis_count;
|
||||
NamedApi* dfirst = pdst->named_apis;
|
||||
NamedApi* dlast = dfirst + pdst->named_apis_count;
|
||||
|
||||
//check how much space is needed first
|
||||
int space = 0;
|
||||
while (sfirst != slast && dfirst != dlast)
|
||||
{
|
||||
int cmp_result = strcmp(dfirst->api_name, sfirst->name);
|
||||
if (cmp_result < 0)
|
||||
{
|
||||
dfirst++;
|
||||
}
|
||||
else if (cmp_result == 0)
|
||||
{
|
||||
dfirst++;
|
||||
sfirst++;
|
||||
while (sfirst != slast && !strcmp(sfirst->name, (sfirst - 1)->name))
|
||||
sfirst++;
|
||||
}
|
||||
else
|
||||
{
|
||||
space++;
|
||||
sfirst++;
|
||||
while (sfirst != slast && !strcmp(sfirst->name, (sfirst - 1)->name))
|
||||
sfirst++;
|
||||
}
|
||||
}
|
||||
|
||||
//entries after end of dest
|
||||
while (sfirst != slast)
|
||||
{
|
||||
sfirst++;
|
||||
space++;
|
||||
}
|
||||
|
||||
//allocate new mem
|
||||
if (space)
|
||||
{
|
||||
void* mem = realloc(pdst->named_apis,
|
||||
(pdst->named_apis_count + space) * sizeof(NamedApi));
|
||||
if (!mem)
|
||||
return false;
|
||||
|
||||
pdst->named_apis = (NamedApi*) mem;
|
||||
}
|
||||
|
||||
sfirst = psrc->named_apis;
|
||||
dfirst = pdst->named_apis;
|
||||
dlast = dfirst + pdst->named_apis_count;
|
||||
pdst->named_apis_count += space;
|
||||
|
||||
//join tables
|
||||
while (sfirst != slast && dfirst != dlast)
|
||||
{
|
||||
int cmp_result = strcmp(dfirst->api_name, sfirst->name);
|
||||
if (cmp_result < 0)
|
||||
dfirst++;
|
||||
else if (cmp_result == 0)
|
||||
{
|
||||
//same apis => update address
|
||||
(dfirst++)->address = encode_address((sfirst++)->addr, apilib);
|
||||
while (sfirst != slast && !strcmp(sfirst->name, (sfirst - 1)->name))
|
||||
sfirst++;
|
||||
}
|
||||
else //cmp_result > 0
|
||||
{
|
||||
//insert new api
|
||||
copy_backward(dfirst, dlast, dlast + 1);
|
||||
dlast++;
|
||||
dfirst->api_name = sfirst->name;
|
||||
dfirst->address = encode_address(sfirst->addr, apilib);
|
||||
dfirst++;
|
||||
sfirst++;
|
||||
while (sfirst != slast && !strcmp(sfirst->name, (sfirst - 1)->name))
|
||||
sfirst++;
|
||||
}
|
||||
}
|
||||
|
||||
//entries after end of dest
|
||||
while (sfirst != slast)
|
||||
{
|
||||
dfirst->api_name = sfirst->name;
|
||||
dfirst->address = encode_address(sfirst->addr, apilib);
|
||||
dfirst++;
|
||||
sfirst++;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
psrc++;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ApiConfiguration::merge(const char* module, unsigned short ordinal,
|
||||
const ApiLibrary* apilib, int id)
|
||||
{
|
||||
if (!apilib)
|
||||
return false;
|
||||
|
||||
const apilib_api_table* psrc = apilib->api_tables;
|
||||
|
||||
while (psrc->target_library)
|
||||
{
|
||||
if (!strcmpi(module, psrc->target_library))
|
||||
break;
|
||||
psrc++;
|
||||
}
|
||||
|
||||
if (!psrc->target_library)
|
||||
return false;
|
||||
|
||||
apilib_unnamed_api to_find;
|
||||
to_find.ord = ordinal;
|
||||
|
||||
const apilib_unnamed_api* first = psrc->ordinal_apis;
|
||||
const apilib_unnamed_api* last = first + psrc->ordinal_apis_count;
|
||||
|
||||
const apilib_unnamed_api* low = lower_bound(first, last, to_find);
|
||||
|
||||
if (low == last || to_find < *low)
|
||||
return false;
|
||||
|
||||
low += id;
|
||||
|
||||
if (low >= last || to_find < *low)
|
||||
return false;
|
||||
|
||||
int i;
|
||||
for (i = 0 ; i < new_overridden_mod_cnt ; i++)
|
||||
if (!strcmpi(module, new_overridden_mod_nms[i]))
|
||||
break;
|
||||
|
||||
if (i == new_overridden_mod_cnt)
|
||||
return false;
|
||||
|
||||
if (!add_to_used_apilibs(apilib))
|
||||
return false;
|
||||
|
||||
if (api_tables_count <= i)
|
||||
{
|
||||
void* mem = recalloc(api_tables, new_overridden_mod_cnt * sizeof(ModuleApi));
|
||||
if (!mem)
|
||||
return false;
|
||||
api_tables = (ModuleApi*) mem;
|
||||
api_tables_count = new_overridden_mod_cnt;
|
||||
}
|
||||
|
||||
ModuleApi* pdst = api_tables + i;
|
||||
if (pdst->unnamed_apis_count < ordinal)
|
||||
{
|
||||
void* mem = recalloc(pdst->unnamed_apis, ordinal * sizeof(PROC));
|
||||
if (!mem)
|
||||
return false;
|
||||
pdst->unnamed_apis = (PDWORD) mem;
|
||||
pdst->unnamed_apis_count = ordinal;
|
||||
}
|
||||
|
||||
pdst->unnamed_apis[ordinal - 1] = encode_address(low->addr, apilib);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ApiConfiguration::merge(const char* module, const char* api_name,
|
||||
const ApiLibrary* apilib, int id)
|
||||
{
|
||||
if (!apilib)
|
||||
return false;
|
||||
|
||||
const apilib_api_table* psrc = apilib->api_tables;
|
||||
|
||||
while (psrc->target_library)
|
||||
{
|
||||
if (!strcmpi(module, psrc->target_library))
|
||||
break;
|
||||
psrc++;
|
||||
}
|
||||
|
||||
if (!psrc->target_library)
|
||||
return false;
|
||||
|
||||
apilib_named_api to_find;
|
||||
to_find.name = api_name;
|
||||
|
||||
const apilib_named_api* first = psrc->named_apis;
|
||||
const apilib_named_api* last = first + psrc->named_apis_count;
|
||||
|
||||
const apilib_named_api* low = lower_bound(first, last, to_find);
|
||||
|
||||
if (low == last || to_find < *low)
|
||||
return false;
|
||||
|
||||
low += id;
|
||||
|
||||
if (low >= last || to_find < *low)
|
||||
return false;
|
||||
|
||||
int i;
|
||||
for (i = 0 ; i < new_overridden_mod_cnt ; i++)
|
||||
if (!strcmpi(module, new_overridden_mod_nms[i]))
|
||||
break;
|
||||
|
||||
if (i == new_overridden_mod_cnt)
|
||||
return false;
|
||||
|
||||
if (!add_to_used_apilibs(apilib))
|
||||
return false;
|
||||
|
||||
if (api_tables_count <= i)
|
||||
{
|
||||
void* mem = recalloc(api_tables, new_overridden_mod_cnt * sizeof(ModuleApi));
|
||||
if (!mem)
|
||||
return false;
|
||||
api_tables = (ModuleApi*) mem;
|
||||
api_tables_count = new_overridden_mod_cnt;
|
||||
}
|
||||
|
||||
ModuleApi* pdst = api_tables + i;
|
||||
NamedApi* dfirst = pdst->named_apis;
|
||||
NamedApi* dlast = dfirst + pdst->named_apis_count;
|
||||
|
||||
NamedApi dto_find;
|
||||
dto_find.api_name = api_name;
|
||||
|
||||
NamedApi* dlow = lower_bound(dfirst, dlast, dto_find);
|
||||
|
||||
//scenario 1: existing entry
|
||||
if (dlow < dlast && !(dto_find < *dlow))
|
||||
{
|
||||
dlow->address = encode_address(low->addr, apilib);
|
||||
}
|
||||
//scenario 2: no matching entry
|
||||
else
|
||||
{
|
||||
void* mem = realloc(pdst->named_apis,
|
||||
(pdst->named_apis_count + 1) * sizeof(NamedApi));
|
||||
if (!mem)
|
||||
return false;
|
||||
|
||||
pdst->named_apis = (NamedApi*) mem;
|
||||
pdst->named_apis_count++;
|
||||
|
||||
dlow = (NamedApi*)((DWORD) dlow - (DWORD) dfirst + (DWORD) pdst->named_apis);
|
||||
dfirst = pdst->named_apis;
|
||||
dlast = dfirst + pdst->named_apis_count;
|
||||
copy_backward(dlow, dlast - 1, dlast);
|
||||
dlow->api_name = low->name;
|
||||
dlow->address = encode_address(low->addr, apilib);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ApiConfiguration::erase(const char* module, unsigned short ordinal)
|
||||
{
|
||||
int i;
|
||||
for (i = 0 ; i < new_overridden_mod_cnt ; i++)
|
||||
if (!strcmpi(module, new_overridden_mod_nms[i]))
|
||||
break;
|
||||
|
||||
if (i == new_overridden_mod_cnt || i >= api_tables_count)
|
||||
return false;
|
||||
|
||||
ModuleApi* pdst = api_tables + i;
|
||||
if (pdst->unnamed_apis_count < ordinal)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
pdst->unnamed_apis[ordinal - 1] = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ApiConfiguration::erase(const char* module, const char* api_name)
|
||||
{
|
||||
int i;
|
||||
for (i = 0 ; i < new_overridden_mod_cnt ; i++)
|
||||
if (!strcmpi(module, new_overridden_mod_nms[i]))
|
||||
break;
|
||||
|
||||
if (i == new_overridden_mod_cnt || i >= api_tables_count)
|
||||
return false;
|
||||
|
||||
ModuleApi* pdst = api_tables + i;
|
||||
NamedApi* dfirst = pdst->named_apis;
|
||||
NamedApi* dlast = dfirst + pdst->named_apis_count;
|
||||
|
||||
NamedApi dto_find;
|
||||
dto_find.api_name = api_name;
|
||||
|
||||
NamedApi* dlow = lower_bound(dfirst, dlast, dto_find);
|
||||
|
||||
if (dlow >= dlast || dto_find < *dlow)
|
||||
return false;
|
||||
|
||||
copy(dlow + 1, dlast, dlow);
|
||||
pdst->named_apis_count--;
|
||||
//should I realloc memory after deleting entry?
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Get api address given api table number and api name.
|
||||
* @param table_id Valid api table number.
|
||||
* @param hint Loader hint.
|
||||
* @param api_name Api name.
|
||||
* @return Api address or 0 if api address not found.
|
||||
*/
|
||||
unsigned long ApiConfiguration::get(unsigned short table_id,
|
||||
unsigned short hint, const char* api_name)
|
||||
{
|
||||
NamedApi* named_apis;
|
||||
unsigned short named_apis_count;
|
||||
int lo, hi, curr;
|
||||
|
||||
named_apis = api_tables[table_id].named_apis;
|
||||
named_apis_count = api_tables[table_id].named_apis_count;
|
||||
|
||||
if (hint < named_apis_count)
|
||||
{
|
||||
int res = strcmp(api_name, named_apis[hint].api_name);
|
||||
if (res > 0)
|
||||
{
|
||||
lo = hint + 1;
|
||||
hi = named_apis_count - 1;
|
||||
}
|
||||
else if (res < 0)
|
||||
{
|
||||
lo = 0;
|
||||
hi = hint - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return named_apis[hint].address;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lo = 0;
|
||||
hi = named_apis_count - 1;
|
||||
}
|
||||
curr = (hi + lo) >> 1;
|
||||
|
||||
while (lo <= hi)
|
||||
{
|
||||
int res = strcmp(api_name, named_apis[curr].api_name);
|
||||
if (res > 0)
|
||||
{
|
||||
lo = curr + 1;
|
||||
}
|
||||
else if (res < 0)
|
||||
{
|
||||
hi = curr - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return named_apis[curr].address;
|
||||
}
|
||||
curr = (hi + lo) >> 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Get api address given api table number and api ordinal.
|
||||
* @param table_id Valid api table number.
|
||||
* @param api_ordinal Api ordinal number.
|
||||
* @return Api address or 0 if api address not found.
|
||||
*/
|
||||
unsigned long ApiConfiguration::get(unsigned short table_id,
|
||||
unsigned short api_ordinal)
|
||||
{
|
||||
unsigned long* unnamed_apis;
|
||||
unsigned short unnamed_apis_count;
|
||||
|
||||
unnamed_apis = api_tables[table_id].unnamed_apis;
|
||||
unnamed_apis_count = api_tables[table_id].unnamed_apis_count;
|
||||
|
||||
if (api_ordinal > unnamed_apis_count)
|
||||
return 0;
|
||||
|
||||
return unnamed_apis[api_ordinal - 1];
|
||||
}
|
||||
|
||||
bool ApiConfiguration::is_initialized()
|
||||
{
|
||||
return initialized;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
void ApiConfiguration::dump()
|
||||
{
|
||||
dbgprintf("ApiConfiguration %s\n", get_name());
|
||||
for (int i = 0 ; i < api_tables_count ; i++)
|
||||
{
|
||||
dbgprintf("Covered module #%d: %s\n", i, overridden_module_names[i]);
|
||||
dbgprintf("Named apis (count = %d)\n", api_tables[i].named_apis_count);
|
||||
for (int j = 0 ; j < api_tables[i].named_apis_count ; j++)
|
||||
dbgprintf("\t%-32s %08x\n", api_tables[i].named_apis[j].api_name,
|
||||
api_tables[i].named_apis[j].address);
|
||||
dbgprintf("Unnamed apis (count = %d)\n", api_tables[i].unnamed_apis_count);
|
||||
for (int j = 0 ; j < api_tables[i].unnamed_apis_count ; j++)
|
||||
dbgprintf("\t%-5d %08x\n", j, api_tables[i].unnamed_apis[j]);
|
||||
dbgprintf("\n");
|
||||
}
|
||||
dbgprintf("\n");
|
||||
}
|
||||
|
||||
#endif
|
106
core/apiconf.h
Normal file
106
core/apiconf.h
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2008-2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __APICONF_H
|
||||
#define __APICONF_H
|
||||
|
||||
#include "apilib.h"
|
||||
|
||||
class ApiConfiguration
|
||||
{
|
||||
struct NamedApi
|
||||
{
|
||||
const char* api_name; /* function name */
|
||||
unsigned long address; /* function address */
|
||||
bool operator<(const NamedApi& a) const;
|
||||
};
|
||||
|
||||
struct ModuleApi
|
||||
{
|
||||
unsigned short named_apis_count;
|
||||
unsigned short unnamed_apis_count;
|
||||
NamedApi* named_apis;
|
||||
unsigned long* unnamed_apis; /* function addresses */
|
||||
};
|
||||
|
||||
public:
|
||||
ApiConfiguration(const char* name);
|
||||
ApiConfiguration(const char* new_name, const ApiConfiguration& src);
|
||||
~ApiConfiguration();
|
||||
|
||||
bool is_table_empty(unsigned short table_id);
|
||||
const char* get_name();
|
||||
|
||||
bool merge(const ApiLibrary* apilib);
|
||||
bool merge(const char* module, unsigned short ordinal,
|
||||
const ApiLibrary* apilib, int id);
|
||||
bool merge(const char* module, const char* api_name,
|
||||
const ApiLibrary* apilib, int id);
|
||||
bool erase(const char* module, unsigned short ordinal);
|
||||
bool erase(const char* module, const char* api_name);
|
||||
unsigned long get(unsigned short table_id, unsigned short hint, const char* api_name);
|
||||
unsigned long get(unsigned short table_id, unsigned short api_ordinal);
|
||||
bool is_initialized();
|
||||
|
||||
#ifdef _DEBUG
|
||||
void dump();
|
||||
#endif
|
||||
|
||||
friend class ApiConfigurationManager;
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
ModuleApi* api_tables;
|
||||
unsigned short api_tables_count;
|
||||
char* conf_name;
|
||||
const ApiLibrary** used_apilibs;
|
||||
int used_apilibs_count;
|
||||
bool initialized;
|
||||
|
||||
bool prepare(const char* name);
|
||||
bool add_to_used_apilibs(const ApiLibrary* apilib);
|
||||
};
|
||||
|
||||
inline bool ApiConfiguration::NamedApi::operator<(const NamedApi& a) const
|
||||
{
|
||||
return strcmp(this->api_name, a.api_name) < 0;
|
||||
}
|
||||
|
||||
/** Returns true if selected api table is empty or invalid.
|
||||
* @return True if selected api table is empty or invalid, false otherwise.
|
||||
*/
|
||||
inline bool ApiConfiguration::is_table_empty(unsigned short table_id)
|
||||
{
|
||||
if (table_id >= api_tables_count)
|
||||
return true;
|
||||
return api_tables[table_id].unnamed_apis_count ? false : true;
|
||||
}
|
||||
|
||||
/** Retrieves api configuration name.
|
||||
* @return Api configuration name.
|
||||
*/
|
||||
inline const char* ApiConfiguration::get_name()
|
||||
{
|
||||
return conf_name;
|
||||
}
|
||||
|
||||
#endif
|
537
core/apiconfmgr.cpp
Normal file
537
core/apiconfmgr.cpp
Normal file
@ -0,0 +1,537 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2008-2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include "debug.h"
|
||||
#include "internals.h"
|
||||
#include "resolver.h"
|
||||
#include "apiconfmgr.h"
|
||||
|
||||
#define ALLOC_CAPACITY 10
|
||||
|
||||
ApiConfiguration** ApiConfigurationManager::curr_apiconf_ptrs = NULL;
|
||||
int ApiConfigurationManager::curr_apiconf_cnt = 0;
|
||||
ApiConfiguration** ApiConfigurationManager::prev_apiconf_ptrs = NULL;
|
||||
int ApiConfigurationManager::prev_apiconf_cnt = 0;
|
||||
ApiConfiguration* ApiConfigurationManager::default_apiconf = NULL;
|
||||
|
||||
//TODO: I should check if new ApiConfiguration is identical to existing one
|
||||
//and deallocate it if this is true
|
||||
|
||||
ApiConfigurationManager::ApiConfigurationManager()
|
||||
{
|
||||
new_apiconf_ptrs = NULL;
|
||||
new_apiconf_cnt = 0;
|
||||
strcpy(core_conf_file, kernelex_dir.get());
|
||||
strcat(core_conf_file, "core.ini");
|
||||
}
|
||||
|
||||
ApiConfigurationManager::~ApiConfigurationManager()
|
||||
{
|
||||
for (int i = 0 ; i < new_apiconf_cnt ; i++)
|
||||
delete new_apiconf_ptrs[i];
|
||||
if (new_apiconf_ptrs)
|
||||
free(new_apiconf_ptrs);
|
||||
}
|
||||
|
||||
bool ApiConfigurationManager::add_apiconf(ApiConfiguration* ac)
|
||||
{
|
||||
//allocate space for new ApiConfigurations
|
||||
if (new_apiconf_cnt % ALLOC_CAPACITY == 0)
|
||||
{
|
||||
void* new_block = realloc(new_apiconf_ptrs,
|
||||
(new_apiconf_cnt + ALLOC_CAPACITY) * sizeof(ApiConfiguration*));
|
||||
|
||||
if (!new_block)
|
||||
{
|
||||
DBGPRINTF(("Failed to add api configuration to list of new ACs\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
new_apiconf_ptrs = (ApiConfiguration**) new_block;
|
||||
}
|
||||
|
||||
//add to table of new ApiConfigurations
|
||||
new_apiconf_ptrs[new_apiconf_cnt++] = ac;
|
||||
return true;
|
||||
}
|
||||
|
||||
ApiConfiguration* ApiConfigurationManager::get_new_apiconf(const char* conf_name)
|
||||
{
|
||||
for (int i = 0 ; i < new_apiconf_cnt ; i++)
|
||||
if (!strcmp(new_apiconf_ptrs[i]->conf_name, conf_name))
|
||||
return new_apiconf_ptrs[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ApiConfiguration* ApiConfigurationManager::get_api_configuration(const char* conf_name)
|
||||
{
|
||||
if (!strcmp("default", conf_name))
|
||||
return get_default_configuration();
|
||||
|
||||
for (int i = 0 ; i < curr_apiconf_cnt ; i++)
|
||||
if (!strcmp(curr_apiconf_ptrs[i]->conf_name, conf_name))
|
||||
return curr_apiconf_ptrs[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ApiConfigurationManager::reload_api_configurations()
|
||||
{
|
||||
DBGPRINTF(("Reloading api configurations\n"));
|
||||
|
||||
default_apiconf_index = GetPrivateProfileInt(
|
||||
"ApiConfigurations", "default", 0, core_conf_file);
|
||||
|
||||
for (int i = 0 ; i < 65536 ; i++)
|
||||
{
|
||||
char num[6];
|
||||
char apiconf_name[256];
|
||||
ApiConfiguration* apiconf = NULL;
|
||||
|
||||
sprintf(num, "%d", i);
|
||||
if (!GetPrivateProfileString("ApiConfigurations", num, "",
|
||||
apiconf_name, sizeof(apiconf_name), core_conf_file))
|
||||
{
|
||||
//no more entries
|
||||
if (i <= default_apiconf_index)
|
||||
{
|
||||
DBGPRINTF(("Failed to load default api configuration - aborting\n"));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
DBGPRINTF(("Processing api configuration #%s: %s\n", num, apiconf_name));
|
||||
|
||||
char buf[256];
|
||||
|
||||
if (!GetPrivateProfileString(apiconf_name, "inherit", "", buf,
|
||||
sizeof(buf), core_conf_file) || !strcmpi(buf, "none"))
|
||||
{
|
||||
//no inherit
|
||||
apiconf = new ApiConfiguration(apiconf_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
ApiConfiguration* src_conf = get_new_apiconf(buf);
|
||||
if (!src_conf)
|
||||
{
|
||||
DBGPRINTF(("Cannot inherit: %s. Configuration not found\n", buf));
|
||||
goto __error;
|
||||
}
|
||||
|
||||
apiconf = new ApiConfiguration(apiconf_name, *src_conf);
|
||||
}
|
||||
|
||||
if (!apiconf || !apiconf->is_initialized())
|
||||
{
|
||||
DBGPRINTF(("Failed to create new api configuration object\n"));
|
||||
goto __error;
|
||||
}
|
||||
|
||||
if (!join_apilibs(apiconf) || !parse_overrides(apiconf) || !add_apiconf(apiconf))
|
||||
goto __error;
|
||||
|
||||
continue;
|
||||
|
||||
__error:
|
||||
if (apiconf)
|
||||
delete apiconf;
|
||||
if (i == default_apiconf_index)
|
||||
{
|
||||
DBGPRINTF(("Failed to load default api configuration - aborting\n"));
|
||||
return;
|
||||
}
|
||||
} //for loop
|
||||
|
||||
DBGPRINTF(("No more api configurations\n"));
|
||||
|
||||
FullCritLock();
|
||||
|
||||
if (commit_changes())
|
||||
{
|
||||
DBGPRINTF(("Re-add api libraries for previous api configurations\n"));
|
||||
for (int i = 0 ; i < prev_apiconf_cnt ; i++)
|
||||
for (int j = 0 ; j < prev_apiconf_ptrs[i]->used_apilibs_count ; j++)
|
||||
if (!libmgr.load_apilib(prev_apiconf_ptrs[i]->used_apilibs[j]->apilib_name))
|
||||
DBGPRINTF(("Error\n"));
|
||||
|
||||
libmgr.commit_changes();
|
||||
}
|
||||
else
|
||||
DBGPRINTF(("Bailing out\n"));
|
||||
|
||||
FullCritUnlock();
|
||||
}
|
||||
|
||||
bool ApiConfigurationManager::join_apilibs(ApiConfiguration* apiconf)
|
||||
{
|
||||
char buf[256];
|
||||
|
||||
if (!GetPrivateProfileString(apiconf->get_name(), "contents", "",
|
||||
buf, sizeof(buf), core_conf_file) || !strcmpi(buf, "none"))
|
||||
{
|
||||
DBGPRINTF(("No contents found\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
char buf2[256];
|
||||
|
||||
strupr(buf);
|
||||
strcpy(buf2, buf);
|
||||
char* lib = strtok(buf, ",");
|
||||
while (lib)
|
||||
{
|
||||
if (!libmgr.load_apilib(lib))
|
||||
{
|
||||
DBGPRINTF(("Failed to load api library: %s\n", lib));
|
||||
return false;
|
||||
}
|
||||
lib = strtok(NULL, ",");
|
||||
}
|
||||
|
||||
//merge has to be done in a separate loop because STD
|
||||
//api library is based on other loaded api libraries
|
||||
lib = strtok(buf2, ",");
|
||||
while (lib)
|
||||
{
|
||||
if (!apiconf->merge(libmgr.get_new_apilib(lib)))
|
||||
{
|
||||
DBGPRINTF(("Failed to merge api library: %s\n", lib));
|
||||
return false;
|
||||
}
|
||||
lib = strtok(NULL, ",");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ApiConfigurationManager::parse_overrides(ApiConfiguration* apiconf)
|
||||
{
|
||||
//parse names and ordinal overrides
|
||||
char buf[MAX_PATH];
|
||||
char section_data[32767];
|
||||
DWORD res;
|
||||
|
||||
//first try [conf.names.xx]
|
||||
strcpy(buf, apiconf->get_name());
|
||||
strcat(buf, ".names");
|
||||
if (isWinMe())
|
||||
strcat(buf, ".me");
|
||||
else
|
||||
strcat(buf, ".98");
|
||||
|
||||
res = GetPrivateProfileSection(buf, section_data, sizeof(section_data),
|
||||
core_conf_file);
|
||||
|
||||
//else try [conf.names]
|
||||
if (!res)
|
||||
{
|
||||
strcpy(buf, apiconf->get_name());
|
||||
strcat(buf, ".names");
|
||||
res = GetPrivateProfileSection(buf, section_data, sizeof(section_data),
|
||||
core_conf_file);
|
||||
}
|
||||
|
||||
if (res)
|
||||
{
|
||||
DBGPRINTF(("Parsing named api overrides\n"));
|
||||
|
||||
char* line = section_data;
|
||||
while (*line)
|
||||
{
|
||||
char* module;
|
||||
char* api_name;
|
||||
char* apilib_name;
|
||||
int id;
|
||||
|
||||
char* p = line;
|
||||
char* oldline = line;
|
||||
line += strlen(line) + 1;
|
||||
|
||||
module = p;
|
||||
p = strchr(p, '.');
|
||||
if (!p)
|
||||
{
|
||||
DBGPRINTF(("Error parsing line: %s\n", oldline));
|
||||
continue;
|
||||
}
|
||||
*p++ = '\0';
|
||||
strcpy(buf, module);
|
||||
strcat(buf, ".DLL");
|
||||
module = buf;
|
||||
api_name = p;
|
||||
p = strchr(p, '=');
|
||||
if (!p)
|
||||
{
|
||||
DBGPRINTF(("Error parsing line: %s\n", oldline));
|
||||
continue;
|
||||
}
|
||||
*p++ = '\0';
|
||||
apilib_name = p;
|
||||
p = strchr(p, '.');
|
||||
if (!p)
|
||||
id = 0;
|
||||
else
|
||||
{
|
||||
*p++ = '\0';
|
||||
id = atoi(p);
|
||||
if (id < 0)
|
||||
{
|
||||
DBGPRINTF(("Error parsing line: %s\n", oldline));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
strupr(apilib_name);
|
||||
if (!strcmp(apilib_name, "NONE"))
|
||||
{
|
||||
if (!apiconf->erase(module, api_name))
|
||||
{
|
||||
DBGPRINTF(("Failed to merge named api overrides\n"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!apiconf->merge(module, api_name,
|
||||
libmgr.get_new_apilib(apilib_name), id))
|
||||
{
|
||||
DBGPRINTF(("Failed to merge named api overrides\n"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//first try [conf.ordinals.xx]
|
||||
strcpy(buf, apiconf->get_name());
|
||||
strcat(buf, ".ordinals");
|
||||
|
||||
if (isWinMe())
|
||||
strcat(buf, ".me");
|
||||
else
|
||||
strcat(buf, ".98");
|
||||
|
||||
//else try [conf.ordinals]
|
||||
res = GetPrivateProfileSection(buf, section_data, sizeof(section_data),
|
||||
core_conf_file);
|
||||
|
||||
if (!res)
|
||||
{
|
||||
strcpy(buf, apiconf->get_name());
|
||||
strcat(buf, ".ordinals");
|
||||
res = GetPrivateProfileSection(buf, section_data, sizeof(section_data),
|
||||
core_conf_file);
|
||||
}
|
||||
|
||||
if (res)
|
||||
{
|
||||
DBGPRINTF(("Parsing ordinal api overrides\n"));
|
||||
|
||||
char* line = section_data;
|
||||
while (*line)
|
||||
{
|
||||
char* module;
|
||||
char* ordinal_s;
|
||||
int ordinal;
|
||||
char* apilib_name;
|
||||
int id;
|
||||
|
||||
char* p = line;
|
||||
char* oldline = line;
|
||||
line += strlen(line) + 1;
|
||||
|
||||
module = p;
|
||||
p = strchr(p, '.');
|
||||
if (!p)
|
||||
{
|
||||
DBGPRINTF(("Error parsing line: %s\n", oldline));
|
||||
continue;
|
||||
}
|
||||
*p++ = '\0';
|
||||
strcpy(buf, module);
|
||||
strcat(buf, ".DLL");
|
||||
module = buf;
|
||||
ordinal_s = p;
|
||||
p = strchr(p, '=');
|
||||
if (!p)
|
||||
{
|
||||
DBGPRINTF(("Error parsing line: %s\n", oldline));
|
||||
continue;
|
||||
}
|
||||
*p++ = '\0';
|
||||
ordinal = atoi(ordinal_s);
|
||||
if (ordinal < 1 || ordinal > 65535)
|
||||
{
|
||||
DBGPRINTF(("Error parsing line: %s\n", oldline));
|
||||
continue;
|
||||
}
|
||||
apilib_name = p;
|
||||
p = strchr(p, '.');
|
||||
if (!p)
|
||||
id = 0;
|
||||
else
|
||||
{
|
||||
*p++ = '\0';
|
||||
id = atoi(p);
|
||||
if (id < 0)
|
||||
{
|
||||
DBGPRINTF(("Error parsing line: %s\n", oldline));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
strupr(apilib_name);
|
||||
if (!strcmp(apilib_name, "NONE"))
|
||||
{
|
||||
if (!apiconf->erase(module, (WORD) ordinal))
|
||||
{
|
||||
DBGPRINTF(("Failed to merge ordinal api overrides\n"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!apiconf->merge(module, (WORD) ordinal,
|
||||
libmgr.get_new_apilib(apilib_name), id))
|
||||
{
|
||||
DBGPRINTF(("Failed to merge ordinal api overrides\n"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ApiConfigurationManager::commit_changes()
|
||||
{
|
||||
DBGPRINTF(("Updating api configuration list\n"));
|
||||
|
||||
//calculate number of apiconf in use
|
||||
WORD imteMax = *pimteMax;
|
||||
IMTE** pmteModTable = *ppmteModTable;
|
||||
int used = 0;
|
||||
for (int j = 0 ; j < curr_apiconf_cnt ; j++)
|
||||
{
|
||||
for (WORD i = 0 ; i < imteMax ; i++)
|
||||
{
|
||||
IMTE_KEX* imte = (IMTE_KEX*) pmteModTable[i];
|
||||
if (imte && imte->config == curr_apiconf_ptrs[j])
|
||||
{
|
||||
used++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int j = 0 ; j < prev_apiconf_cnt ; j++)
|
||||
{
|
||||
for (WORD i = 0 ; i < imteMax ; i++)
|
||||
{
|
||||
IMTE_KEX* imte = (IMTE_KEX*) pmteModTable[i];
|
||||
if (imte && imte->config == prev_apiconf_ptrs[j])
|
||||
{
|
||||
used++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//alloc space for new_prev
|
||||
ApiConfiguration** new_prev;
|
||||
new_prev = (ApiConfiguration**) malloc(used * sizeof(ApiConfiguration*));
|
||||
if (!new_prev)
|
||||
{
|
||||
DBGPRINTF(("Failed to allocate memory\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
int cnt = 0;
|
||||
|
||||
//move used entries from curr and prev to new_prev, free unused
|
||||
for (int j = 0 ; j < curr_apiconf_cnt ; j++)
|
||||
{
|
||||
WORD i;
|
||||
for (i = 0 ; i < imteMax ; i++)
|
||||
{
|
||||
IMTE_KEX* imte = (IMTE_KEX*) pmteModTable[i];
|
||||
if (imte && imte->config == curr_apiconf_ptrs[j])
|
||||
{
|
||||
new_prev[cnt++] = curr_apiconf_ptrs[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == imteMax)
|
||||
delete curr_apiconf_ptrs[j];
|
||||
}
|
||||
for (int j = 0 ; j < prev_apiconf_cnt ; j++)
|
||||
{
|
||||
WORD i;
|
||||
for (i = 0 ; i < imteMax ; i++)
|
||||
{
|
||||
IMTE_KEX* imte = (IMTE_KEX*) pmteModTable[i];
|
||||
if (imte && imte->config == prev_apiconf_ptrs[j])
|
||||
{
|
||||
new_prev[cnt++] = prev_apiconf_ptrs[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == imteMax)
|
||||
delete curr_apiconf_ptrs[j];
|
||||
}
|
||||
|
||||
//replace prev with new_prev
|
||||
free(prev_apiconf_ptrs);
|
||||
prev_apiconf_ptrs = new_prev;
|
||||
prev_apiconf_cnt = cnt;
|
||||
|
||||
//replace curr with new
|
||||
free(curr_apiconf_ptrs);
|
||||
curr_apiconf_ptrs = new_apiconf_ptrs;
|
||||
curr_apiconf_cnt = new_apiconf_cnt;
|
||||
new_apiconf_ptrs = NULL;
|
||||
new_apiconf_cnt = 0;
|
||||
|
||||
//set default apiconf
|
||||
if (default_apiconf_index >= 0)
|
||||
default_apiconf = curr_apiconf_ptrs[default_apiconf_index];
|
||||
else
|
||||
default_apiconf = NULL;
|
||||
|
||||
DBGPRINTF(("Default api configuration is: %s\n",
|
||||
default_apiconf ? default_apiconf->get_name() : "system"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
void ApiConfigurationManager::dump_configurations()
|
||||
{
|
||||
dbgprintf("Dumping all api configurations (count = %d) ...\n\n", curr_apiconf_cnt);
|
||||
for (int i = 0 ; i < curr_apiconf_cnt ; i++)
|
||||
{
|
||||
curr_apiconf_ptrs[i]->dump();
|
||||
}
|
||||
dbgprintf("End dump\n\n");
|
||||
}
|
||||
|
||||
#endif
|
67
core/apiconfmgr.h
Normal file
67
core/apiconfmgr.h
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2008-2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __APICONFMGR_H
|
||||
#define __APICONFMGR_H
|
||||
|
||||
#include "apiconf.h"
|
||||
|
||||
class ApiConfigurationManager
|
||||
{
|
||||
public:
|
||||
ApiConfigurationManager();
|
||||
~ApiConfigurationManager();
|
||||
void reload_api_configurations();
|
||||
static ApiConfiguration* get_api_configuration(const char* conf_name);
|
||||
static ApiConfiguration* get_default_configuration();
|
||||
|
||||
#ifdef _DEBUG
|
||||
static void dump_configurations();
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
char core_conf_file[MAX_PATH];
|
||||
ApiConfiguration** new_apiconf_ptrs;
|
||||
int new_apiconf_cnt;
|
||||
int default_apiconf_index;
|
||||
ApiLibraryManager libmgr;
|
||||
|
||||
static ApiConfiguration** curr_apiconf_ptrs;
|
||||
static int curr_apiconf_cnt;
|
||||
static ApiConfiguration** prev_apiconf_ptrs;
|
||||
static int prev_apiconf_cnt;
|
||||
static ApiConfiguration* default_apiconf;
|
||||
|
||||
bool join_apilibs(ApiConfiguration* apiconf);
|
||||
bool parse_overrides(ApiConfiguration* apiconf);
|
||||
bool add_apiconf(ApiConfiguration* ac);
|
||||
ApiConfiguration* get_new_apiconf(const char* conf_name);
|
||||
bool commit_changes();
|
||||
};
|
||||
|
||||
inline ApiConfiguration* ApiConfigurationManager::get_default_configuration()
|
||||
{
|
||||
return default_apiconf;
|
||||
}
|
||||
|
||||
#endif
|
704
core/apilib.cpp
Normal file
704
core/apilib.cpp
Normal file
@ -0,0 +1,704 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2008-2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include "apilib.h"
|
||||
#include <algorithm>
|
||||
#include "resolver.h"
|
||||
#include "internals.h"
|
||||
#include "debug.h"
|
||||
#include "is_sorted.hpp"
|
||||
#include "pemanip.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define ALLOC_CAPACITY 10
|
||||
|
||||
ApiLibrary** ApiLibraryManager::apilib_ptrs = NULL;
|
||||
int ApiLibraryManager::apilib_cnt = 0;
|
||||
|
||||
int overridden_module_count;
|
||||
const char** overridden_module_names;
|
||||
const char** new_overridden_mod_nms;
|
||||
int new_overridden_mod_cnt;
|
||||
|
||||
ApiLibraryManager::ApiLibraryManager()
|
||||
{
|
||||
new_apilib_ptrs = NULL;
|
||||
new_apilib_cnt = 0;
|
||||
new_overridden_mod_nms = NULL;
|
||||
new_overridden_mod_cnt = 0;
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
ApiLibraryManager::~ApiLibraryManager()
|
||||
{
|
||||
rollback_changes();
|
||||
}
|
||||
|
||||
bool ApiLibraryManager::initialize()
|
||||
{
|
||||
ApiLibrary* std_apilib;
|
||||
|
||||
new_apilib_cnt = 0;
|
||||
new_apilib_ptrs = (ApiLibrary**) malloc(ALLOC_CAPACITY * sizeof(ApiLibrary*));
|
||||
|
||||
if (!new_apilib_ptrs)
|
||||
goto __error;
|
||||
|
||||
std_apilib = (ApiLibrary*) malloc(sizeof(ApiLibrary) + strlen("STD"));
|
||||
|
||||
if (!std_apilib)
|
||||
goto __error;
|
||||
|
||||
strcpy(std_apilib->apilib_name, "STD");
|
||||
std_apilib->mod_handle = NULL;
|
||||
std_apilib->api_tables = NULL;
|
||||
std_apilib->index = 0;
|
||||
|
||||
//copy previous STD api library tables and overridden module names
|
||||
if (overridden_module_count)
|
||||
{
|
||||
int size = (overridden_module_count / ALLOC_CAPACITY + 1) * ALLOC_CAPACITY;
|
||||
|
||||
std_apilib->api_tables = (apilib_api_table*)
|
||||
malloc((size + 1) * sizeof(apilib_api_table));
|
||||
|
||||
if (!std_apilib->api_tables)
|
||||
goto __error;
|
||||
|
||||
apilib_api_table* prev_std_tab = apilib_ptrs[0]->api_tables;
|
||||
copy(prev_std_tab, prev_std_tab + size + 1, std_apilib->api_tables);
|
||||
|
||||
new_overridden_mod_nms = (const char**) malloc(size * sizeof(char*));
|
||||
|
||||
if (!new_overridden_mod_nms)
|
||||
goto __error;
|
||||
|
||||
copy(overridden_module_names, overridden_module_names + size,
|
||||
new_overridden_mod_nms);
|
||||
|
||||
new_overridden_mod_cnt = overridden_module_count;
|
||||
}
|
||||
|
||||
new_apilib_ptrs[new_apilib_cnt++] = std_apilib;
|
||||
|
||||
initialized = true;
|
||||
return true;
|
||||
|
||||
__error:
|
||||
free(new_overridden_mod_nms);
|
||||
if (std_apilib)
|
||||
free(std_apilib->api_tables);
|
||||
free(std_apilib);
|
||||
free(new_apilib_ptrs);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ApiLibraryManager::load_apilib(const char* apilib_name)
|
||||
{
|
||||
if (!initialized && !initialize())
|
||||
{
|
||||
DBGPRINTF(("Failed to initialize api library manager\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (new_apilib_cnt >= 0xff)
|
||||
{
|
||||
DBGPRINTF(("Too many api libraries loaded\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
//STD is a special api library name
|
||||
if (!strcmp(apilib_name, "STD"))
|
||||
return true;
|
||||
|
||||
//check if library wasn't loaded in this instance
|
||||
for (int i = 0 ; i < new_apilib_cnt ; i++)
|
||||
if (!strcmp(new_apilib_ptrs[i]->apilib_name, apilib_name))
|
||||
return true;
|
||||
|
||||
ApiLibrary* apilib;
|
||||
bool already_loaded = false;
|
||||
|
||||
DBGPRINTF(("Loading api library: %s... ", apilib_name));
|
||||
|
||||
//check if library wasn't previously loaded
|
||||
for (int i = 0 ; i < apilib_cnt ; i++)
|
||||
{
|
||||
if (!strcmp(apilib_ptrs[i]->apilib_name, apilib_name))
|
||||
{
|
||||
DBGPRINTF(("already loaded... "));
|
||||
apilib = apilib_ptrs[i];
|
||||
already_loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
//if it wasn't loaded
|
||||
if (!already_loaded)
|
||||
{
|
||||
char dllpath[MAX_PATH];
|
||||
int size = sizeof(ApiLibrary) + strlen(apilib_name);
|
||||
|
||||
apilib = (ApiLibrary*) malloc(size);
|
||||
|
||||
if (!apilib)
|
||||
{
|
||||
DBGPRINTF(("Failed to allocate memory\n"));
|
||||
goto __error;
|
||||
}
|
||||
|
||||
strcpy(apilib->apilib_name, apilib_name);
|
||||
|
||||
strcpy(dllpath, kernelex_dir.get());
|
||||
strcat(dllpath, apilib_name);
|
||||
apilib->mod_handle = LoadLibrary(dllpath);
|
||||
|
||||
if (!apilib->mod_handle)
|
||||
{
|
||||
DBGPRINTF(("Failed to load api library\n"));
|
||||
goto __error;
|
||||
}
|
||||
|
||||
fgat_t get_api_table;
|
||||
get_api_table = (fgat_t) GetProcAddress(
|
||||
apilib->mod_handle, "get_api_table");
|
||||
|
||||
if (!get_api_table)
|
||||
{
|
||||
DBGPRINTF(("Failed to get api library entry point\n"));
|
||||
goto __error;
|
||||
}
|
||||
|
||||
const apilib_api_table* file_api_tables;
|
||||
file_api_tables = get_api_table();
|
||||
|
||||
if (!file_api_tables)
|
||||
{
|
||||
DBGPRINTF(("Failed to get api tables\n"));
|
||||
goto __error;
|
||||
}
|
||||
|
||||
apilib->api_tables = make_shared_api_tables(file_api_tables);
|
||||
|
||||
if (!apilib->api_tables)
|
||||
{
|
||||
DBGPRINTF(("Failed to create shared api tables\n"));
|
||||
goto __error;
|
||||
}
|
||||
|
||||
DBGPRINTF(("loaded @ 0x%08x... ", (DWORD) apilib->mod_handle));
|
||||
}
|
||||
|
||||
//allocate space for new ApiLibraries
|
||||
if (new_apilib_cnt % ALLOC_CAPACITY == 0)
|
||||
{
|
||||
void* new_block = realloc(new_apilib_ptrs,
|
||||
(new_apilib_cnt + ALLOC_CAPACITY) * sizeof(ApiLibrary*));
|
||||
|
||||
if (!new_block)
|
||||
{
|
||||
DBGPRINTF(("Failed to allocate memory\n"));
|
||||
goto __error;
|
||||
}
|
||||
|
||||
new_apilib_ptrs = (ApiLibrary**) new_block;
|
||||
}
|
||||
|
||||
// DBGPRINTF(("Listing modules overridden by api library:\n"));
|
||||
for (apilib_api_table* p = apilib->api_tables ; p->target_library ; p++)
|
||||
{
|
||||
// DBGPRINTF((" * %s\n", p->target_library));
|
||||
add_overridden_module(p->target_library);
|
||||
}
|
||||
|
||||
//set or update index value which is used by encode_address()
|
||||
//and to update mod_index in commit_changes()
|
||||
apilib->index = new_apilib_cnt;
|
||||
|
||||
//add to table of new ApiLibraries
|
||||
new_apilib_ptrs[new_apilib_cnt++] = apilib;
|
||||
|
||||
DBGPRINTF(("ok\n"));
|
||||
return true;
|
||||
|
||||
__error:
|
||||
if (!already_loaded && apilib)
|
||||
{
|
||||
if (apilib->mod_handle)
|
||||
FreeLibrary(apilib->mod_handle);
|
||||
if (apilib->api_tables)
|
||||
free(apilib->api_tables);
|
||||
free(apilib);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ApiLibrary* ApiLibraryManager::get_new_apilib(const char* apilib_name)
|
||||
{
|
||||
for (int i = 0 ; i < new_apilib_cnt ; i++)
|
||||
if (!strcmp(new_apilib_ptrs[i]->apilib_name, apilib_name))
|
||||
return new_apilib_ptrs[i];
|
||||
DBGPRINTF(("Api library %s not found\n", apilib_name));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ApiLibrary* ApiLibraryManager::get_apilib(int index)
|
||||
{
|
||||
if (index < 0 || index >= apilib_cnt)
|
||||
return NULL;
|
||||
|
||||
DBGASSERT(apilib_ptrs[index]);
|
||||
DBGASSERT(apilib_ptrs[index]->index == index);
|
||||
return apilib_ptrs[index];
|
||||
}
|
||||
|
||||
bool ApiLibraryManager::are_api_tables_sorted(const apilib_api_table* tab)
|
||||
{
|
||||
for (const apilib_api_table* p = tab ; p->target_library ; p++)
|
||||
{
|
||||
if (!::is_sorted(p->named_apis, p->named_apis + p->named_apis_count))
|
||||
return false;
|
||||
|
||||
if (!::is_sorted(p->ordinal_apis, p->ordinal_apis + p->ordinal_apis_count))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
apilib_api_table* ApiLibraryManager::make_shared_api_tables(const apilib_api_table* in)
|
||||
{
|
||||
bool copy_strings = (size_t) in < 0x80000000 ? true : false;
|
||||
bool sorted = are_api_tables_sorted(in);
|
||||
|
||||
if (!sorted)
|
||||
{
|
||||
DBGPRINTF(("Error: api tables are not sorted\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!copy_strings && sorted)
|
||||
{
|
||||
//nothing bad will happen if I call HeapFree
|
||||
//on non-HeapAlloc'ed mem later right?
|
||||
return const_cast<apilib_api_table*>(in);
|
||||
}
|
||||
|
||||
int size = required_api_table_space(in, copy_strings);
|
||||
apilib_api_table* out = (apilib_api_table*) malloc(size);
|
||||
|
||||
if (!out)
|
||||
return NULL;
|
||||
|
||||
int i;
|
||||
char* pstr = (char*) out + size;
|
||||
|
||||
//copy apilib_api_tables
|
||||
const apilib_api_table* pin;
|
||||
apilib_api_table* pout;
|
||||
|
||||
for (pin = in, pout = out ; pin->target_library ; pin++, pout++)
|
||||
{
|
||||
if (copy_strings)
|
||||
{
|
||||
pstr -= strlen(pin->target_library) + 1;
|
||||
strcpy(pstr, pin->target_library);
|
||||
pout->target_library = pstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
pout->target_library = pin->target_library;
|
||||
}
|
||||
}
|
||||
*pout++ = *pin++; //terminating NULL entry
|
||||
|
||||
//copy apilib_named_apis
|
||||
const apilib_named_api* pina;
|
||||
apilib_named_api* pona;
|
||||
pona = (apilib_named_api*) pout;
|
||||
|
||||
for (pin = in, pout = out ; pin->target_library ; pin++, pout++)
|
||||
{
|
||||
pout->named_apis = pona;
|
||||
pout->named_apis_count = pin->named_apis_count;
|
||||
|
||||
for (i = 0, pina = pin->named_apis ; i < pin->named_apis_count ; i++, pina++, pona++)
|
||||
{
|
||||
if (copy_strings)
|
||||
{
|
||||
pstr -= strlen(pina->name) + 1;
|
||||
strcpy(pstr, pina->name);
|
||||
pona->name = pstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
pona->name = pina->name;
|
||||
}
|
||||
pona->addr = pina->addr;
|
||||
}
|
||||
}
|
||||
|
||||
//copy apilib_unnamed_apis
|
||||
const apilib_unnamed_api* piua;
|
||||
apilib_unnamed_api* poua;
|
||||
poua = (apilib_unnamed_api*) pona;
|
||||
|
||||
for (pin = in, pout = out ; pin->target_library ; pin++, pout++)
|
||||
{
|
||||
pout->ordinal_apis = poua;
|
||||
pout->ordinal_apis_count = pin->ordinal_apis_count;
|
||||
|
||||
for (i = 0, piua = pin->ordinal_apis ; i < pin->ordinal_apis_count ; i++, piua++, poua++)
|
||||
{
|
||||
*poua = *piua;
|
||||
}
|
||||
}
|
||||
|
||||
// //sort the tables
|
||||
// if (!sorted)
|
||||
// {
|
||||
// while (pout-- != out)
|
||||
// {
|
||||
// stable_sort(pout->named_apis, pout->named_apis + pout->named_apis_count);
|
||||
// stable_sort(pout->ordinal_apis, pout->ordinal_apis + pout->ordinal_apis_count);
|
||||
// }
|
||||
// }
|
||||
|
||||
//finish line
|
||||
return out;
|
||||
}
|
||||
|
||||
int ApiLibraryManager::required_api_table_space(const apilib_api_table* tab, bool copy_strings)
|
||||
{
|
||||
int space = 0;
|
||||
|
||||
for (const apilib_api_table* p = tab ; p->target_library ; p++)
|
||||
{
|
||||
space += sizeof(apilib_api_table);
|
||||
space += p->named_apis_count * sizeof(apilib_named_api);
|
||||
space += p->ordinal_apis_count * sizeof(apilib_unnamed_api);
|
||||
|
||||
if (copy_strings)
|
||||
{
|
||||
space += strlen(p->target_library) + 1;
|
||||
for (int i = 0 ; i < p->named_apis_count ; i++)
|
||||
space += strlen(p->named_apis[i].name) + 1;
|
||||
}
|
||||
}
|
||||
space += sizeof(apilib_api_table);
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
bool ApiLibraryManager::add_overridden_module(const char* mod)
|
||||
{
|
||||
apilib_api_table*& std_api_table = new_apilib_ptrs[0]->api_tables;
|
||||
|
||||
//ensure that module isn't already on list
|
||||
for (int i = 0 ; i < new_overridden_mod_cnt ; i++)
|
||||
{
|
||||
if (!strcmpi(new_overridden_mod_nms[i], mod))
|
||||
return true;
|
||||
}
|
||||
|
||||
//allocate space for new overridden modules
|
||||
if (new_overridden_mod_cnt % ALLOC_CAPACITY == 0)
|
||||
{
|
||||
void* new_block = realloc(new_overridden_mod_nms,
|
||||
(new_overridden_mod_cnt + ALLOC_CAPACITY) * sizeof(char*));
|
||||
|
||||
if (!new_block)
|
||||
{
|
||||
DBGPRINTF(("Failed to allocate memory\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
new_overridden_mod_nms = (const char**) new_block;
|
||||
|
||||
new_block = realloc(std_api_table,
|
||||
(new_overridden_mod_cnt + 1 + ALLOC_CAPACITY) * sizeof(apilib_api_table));
|
||||
//+ 1 because api_tables are NULL terminated
|
||||
|
||||
if (!new_block)
|
||||
{
|
||||
DBGPRINTF(("Failed to allocate memory\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
std_api_table = (apilib_api_table*) new_block;
|
||||
}
|
||||
|
||||
if (!parse_system_dll(mod, &std_api_table[new_overridden_mod_cnt]))
|
||||
return false;
|
||||
|
||||
//add to table of overridden modules
|
||||
new_overridden_mod_nms[new_overridden_mod_cnt]
|
||||
= std_api_table[new_overridden_mod_cnt].target_library;
|
||||
new_overridden_mod_cnt++;
|
||||
|
||||
memset(&std_api_table[new_overridden_mod_cnt], 0, sizeof(apilib_api_table));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ApiLibraryManager::parse_system_dll(const char* dll_name, apilib_api_table* api_tab)
|
||||
{
|
||||
PEmanip pemod;
|
||||
HMODULE mem_dll = GetModuleHandle(dll_name);
|
||||
|
||||
if (mem_dll)
|
||||
{
|
||||
if (!pemod.OpenMemory(mem_dll))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
char path[MAX_PATH];
|
||||
GetSystemDirectory(path, sizeof(path));
|
||||
strcat(path, "\\");
|
||||
strcat(path, dll_name);
|
||||
|
||||
if (!pemod.OpenFile(path))
|
||||
return false;
|
||||
}
|
||||
|
||||
IMAGE_NT_HEADERS* PEh = pemod.GetPEHeader();
|
||||
DWORD ExportsRva = PEh->OptionalHeader
|
||||
.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
||||
|
||||
IMAGE_EXPORT_DIRECTORY* Exports = (IMAGE_EXPORT_DIRECTORY*)
|
||||
pemod.RvaToPointer(ExportsRva);
|
||||
|
||||
DWORD ExportsSize = PEh->OptionalHeader
|
||||
.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
|
||||
|
||||
if (!Exports || !ExportsSize)
|
||||
return false;
|
||||
|
||||
DWORD* Names = (DWORD*) pemod.RvaToPointer(Exports->AddressOfNames);
|
||||
WORD* OrdinalTable = (WORD*) pemod.RvaToPointer(Exports->AddressOfNameOrdinals);
|
||||
DWORD* FunctionTable = (DWORD*) pemod.RvaToPointer(Exports->AddressOfFunctions);
|
||||
|
||||
unsigned long offset = PEh->OptionalHeader.ImageBase >= 0x80000000
|
||||
? PEh->OptionalHeader.ImageBase : 0;
|
||||
|
||||
//calculate required space
|
||||
int space = 0;
|
||||
|
||||
space += sizeof(apilib_unnamed_api) * (Exports->NumberOfFunctions + 1);
|
||||
space += sizeof(apilib_named_api) * (Exports->NumberOfNames + 1);
|
||||
|
||||
DWORD* pname = Names;
|
||||
for (DWORD i = 0 ; i < Exports->NumberOfNames ; i++)
|
||||
space += strlen((char*) pemod.RvaToPointer(*pname++)) + 1;
|
||||
|
||||
void* mem = malloc(space);
|
||||
|
||||
if (!mem)
|
||||
return false;
|
||||
|
||||
char* pstr = (char*) mem + space;
|
||||
|
||||
// read exports by name
|
||||
apilib_named_api* pna = (apilib_named_api*) mem;
|
||||
api_tab->named_apis = pna;
|
||||
api_tab->named_apis_count = Exports->NumberOfNames;
|
||||
pname = Names;
|
||||
for (DWORD i = 0 ; i < Exports->NumberOfNames ; i++, pna++)
|
||||
{
|
||||
WORD ord = OrdinalTable[i];
|
||||
DWORD addr = FunctionTable[ord];
|
||||
char* api_name = (char*) pemod.RvaToPointer(*pname++);
|
||||
|
||||
pstr -= strlen(api_name) + 1;
|
||||
strcpy(pstr, api_name);
|
||||
pna->name = pstr;
|
||||
|
||||
//export forwarding case
|
||||
if (addr >= ExportsRva && addr < ExportsRva + ExportsSize)
|
||||
addr = 0xffff0000 | ord + Exports->Base;
|
||||
else
|
||||
addr += offset;
|
||||
|
||||
pna->addr = addr;
|
||||
}
|
||||
|
||||
// read exports by ordinals
|
||||
apilib_unnamed_api* pua = (apilib_unnamed_api*) pna;
|
||||
api_tab->ordinal_apis = pua;
|
||||
api_tab->ordinal_apis_count = Exports->NumberOfFunctions;
|
||||
DBGASSERT(Exports->NumberOfFunctions < 0x10000);
|
||||
|
||||
for (DWORD i = 0 ; i < Exports->NumberOfFunctions ; i++, pua++)
|
||||
{
|
||||
DWORD addr = FunctionTable[i];
|
||||
|
||||
pua->ord = (WORD)(Exports->Base + i);
|
||||
|
||||
//export forwarding case
|
||||
if (addr >= ExportsRva && addr < ExportsRva + ExportsSize)
|
||||
addr = 0xffff0000 | i + Exports->Base;
|
||||
else
|
||||
addr += offset;
|
||||
|
||||
pua->addr = addr;
|
||||
}
|
||||
|
||||
char* new_mod = (char*) malloc(strlen(dll_name) + 1);
|
||||
if (!new_mod)
|
||||
{
|
||||
DBGPRINTF(("Failed to allocate memory\n"));
|
||||
return false;
|
||||
}
|
||||
strcpy(new_mod, dll_name);
|
||||
strupr(new_mod);
|
||||
api_tab->target_library = new_mod;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ApiLibraryManager::rollback_changes()
|
||||
{
|
||||
if (!initialized)
|
||||
return;
|
||||
|
||||
//STD api library case
|
||||
//unload new system module override tables <overridden_mod_cnt;new_overridden_mod_cnt)
|
||||
for (apilib_api_table* p = &new_apilib_ptrs[0]->api_tables
|
||||
[overridden_module_count] ; p->target_library ; p++)
|
||||
free((void*) p->named_apis); //consistent with parse_system_dll
|
||||
free(new_apilib_ptrs[0]->api_tables);
|
||||
free(new_apilib_ptrs[0]);
|
||||
|
||||
//other api libraries
|
||||
for (int i = 1 ; i < new_apilib_cnt ; i++)
|
||||
{
|
||||
if (apilib_ptrs)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 1 ; j < apilib_cnt ; j++)
|
||||
if (new_apilib_ptrs[i] == apilib_ptrs[j])
|
||||
break;
|
||||
|
||||
if (j != apilib_cnt)
|
||||
continue;
|
||||
}
|
||||
FreeLibrary(new_apilib_ptrs[i]->mod_handle);
|
||||
free(new_apilib_ptrs[i]->api_tables);
|
||||
free(new_apilib_ptrs[i]);
|
||||
}
|
||||
|
||||
free(new_apilib_ptrs);
|
||||
new_apilib_ptrs = NULL;
|
||||
new_apilib_cnt = 0;
|
||||
|
||||
for (int i = overridden_module_count ; i < new_overridden_mod_cnt ; i++)
|
||||
free((void*) new_overridden_mod_nms[i]);
|
||||
|
||||
free(new_overridden_mod_nms);
|
||||
new_overridden_mod_nms = NULL;
|
||||
new_overridden_mod_cnt = 0;
|
||||
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
void ApiLibraryManager::commit_changes()
|
||||
{
|
||||
if (!initialized)
|
||||
return;
|
||||
|
||||
ApiLibrary** old_apilib_ptrs = apilib_ptrs;
|
||||
int old_apilib_cnt = apilib_cnt;
|
||||
|
||||
//LOCK ALL CRITICAL SECTIONS!
|
||||
apilib_ptrs = new_apilib_ptrs;
|
||||
apilib_cnt = new_apilib_cnt;
|
||||
free(overridden_module_names);
|
||||
overridden_module_names = new_overridden_mod_nms;
|
||||
overridden_module_count = new_overridden_mod_cnt;
|
||||
|
||||
//update old api library mod_index values to new
|
||||
//set all non-overridden modules to 'not checked'
|
||||
WORD imteMax = *pimteMax;
|
||||
IMTE** pmteModTable = *ppmteModTable;
|
||||
for (WORD i = 0 ; i < imteMax ; i++)
|
||||
{
|
||||
IMTE_KEX* imte = (IMTE_KEX*) pmteModTable[i];
|
||||
if (imte)
|
||||
{
|
||||
WORD index = imte->mod_index;
|
||||
if (index >= 0xff00 && index < 0xffff)
|
||||
{
|
||||
int api_lib_num = index & 0xff;
|
||||
DBGASSERT(api_lib_num != 0); //reserved for STD apilib
|
||||
DBGASSERT(api_lib_num >= old_apilib_cnt);
|
||||
imte->mod_index = old_apilib_ptrs[api_lib_num]->index + 0xff00;
|
||||
}
|
||||
else if (index == 0xffff)
|
||||
imte->mod_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//set mod_index for newly loaded api libraries
|
||||
for (int i = 1 ; i < apilib_cnt ; i++)
|
||||
{
|
||||
ApiLibrary* apilib = apilib_ptrs[i];
|
||||
MODREF* mr = MRFromHLib(apilib->mod_handle);
|
||||
DBGASSERT(mr);
|
||||
((IMTE_KEX*) pmteModTable[mr->mteIndex])->mod_index = 0xff00 + i;
|
||||
}
|
||||
//UNLOCK ALL CRITICAL SECTIONS!
|
||||
|
||||
new_overridden_mod_nms = NULL;
|
||||
new_overridden_mod_cnt = 0;
|
||||
new_apilib_ptrs = NULL;
|
||||
new_apilib_cnt = 0;
|
||||
|
||||
//STD api library case
|
||||
if (old_apilib_cnt > 0)
|
||||
{
|
||||
free(old_apilib_ptrs[0]->api_tables);
|
||||
free(old_apilib_ptrs[0]);
|
||||
}
|
||||
|
||||
//other api libraries
|
||||
for (int i = 1 ; i < old_apilib_cnt ; i++)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 1 ; j < apilib_cnt ; j++)
|
||||
if (old_apilib_ptrs[i] == apilib_ptrs[j])
|
||||
break;
|
||||
|
||||
if (j != apilib_cnt)
|
||||
continue;
|
||||
|
||||
FreeLibrary(old_apilib_ptrs[i]->mod_handle);
|
||||
free(old_apilib_ptrs[i]->api_tables);
|
||||
free(old_apilib_ptrs[i]);
|
||||
}
|
||||
|
||||
free(old_apilib_ptrs);
|
||||
|
||||
initialized = false;
|
||||
}
|
||||
|
69
core/apilib.h
Normal file
69
core/apilib.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2008-2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __APILIB_H
|
||||
#define __APILIB_H
|
||||
|
||||
#include "kexcoresdk.h"
|
||||
|
||||
struct ApiLibrary
|
||||
{
|
||||
apilib_api_table* api_tables;
|
||||
HMODULE mod_handle;
|
||||
int index;
|
||||
char apilib_name[1]; // variable size array
|
||||
};
|
||||
|
||||
class ApiLibraryManager
|
||||
{
|
||||
public:
|
||||
ApiLibraryManager();
|
||||
~ApiLibraryManager();
|
||||
bool load_apilib(const char* apilib_name);
|
||||
ApiLibrary* get_new_apilib(const char* apilib_name);
|
||||
static ApiLibrary* get_apilib(int index);
|
||||
void commit_changes();
|
||||
void rollback_changes();
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
bool initialized;
|
||||
ApiLibrary** new_apilib_ptrs;
|
||||
int new_apilib_cnt;
|
||||
|
||||
static ApiLibrary** apilib_ptrs;
|
||||
static int apilib_cnt;
|
||||
|
||||
bool initialize();
|
||||
bool are_api_tables_sorted(const apilib_api_table* tab);
|
||||
apilib_api_table* make_shared_api_tables(const apilib_api_table* in);
|
||||
int required_api_table_space(const apilib_api_table* tab, bool copy_strings);
|
||||
bool add_overridden_module(const char* mod);
|
||||
bool parse_system_dll(const char* dll_name, apilib_api_table* api_tab);
|
||||
};
|
||||
|
||||
extern int overridden_module_count;
|
||||
extern const char** overridden_module_names;
|
||||
extern const char** new_overridden_mod_nms;
|
||||
extern int new_overridden_mod_cnt;
|
||||
|
||||
#endif
|
8
core/core.def
Normal file
8
core/core.def
Normal file
@ -0,0 +1,8 @@
|
||||
LIBRARY KernelEx.dll BASE=0xBFA00000
|
||||
SECTIONS
|
||||
.text SHARED
|
||||
.bss SHARED
|
||||
.data SHARED
|
||||
.edata SHARED
|
||||
.rdata SHARED
|
||||
.idata SHARED
|
289
core/core.dsp
Normal file
289
core/core.dsp
Normal file
@ -0,0 +1,289 @@
|
||||
# Microsoft Developer Studio Project File - Name="Core" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
||||
|
||||
CFG=Core - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "core.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "core.mak" CFG="Core - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "Core - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE "Core - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
MTL=midl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "Core - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "KERNELEX_EXPORTS" /YX /FD /c
|
||||
# ADD CPP /nologo /W3 /O2 /I "." /I "../common" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "KEXCORE_EXPORTS" /YX /FD /GF /c
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x415 /d "NDEBUG"
|
||||
# ADD RSC /l 0x415 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib advapi32.lib ..\kexcrt\kexcrt.lib libc.lib /nologo /entry:"PreDllMain@12" /dll /map /machine:I386 /nodefaultlib /out:"Release/KernelEx.dll" /implib:"../common/KernelEx.lib" /ignore:4092 /OPT:NOWIN98
|
||||
# SUBTRACT LINK32 /pdb:none
|
||||
|
||||
!ELSEIF "$(CFG)" == "Core - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "KERNELEX_EXPORTS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /ML /W3 /Gm /Zi /Od /I "." /I "../common" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "KEXCORE_EXPORTS" /YX /FD /GZ /GF /c
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x415 /d "_DEBUG"
|
||||
# ADD RSC /l 0x415 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib advapi32.lib ..\kexcrt\kexcrt.lib libc.lib /nologo /entry:"PreDllMain@12" /dll /incremental:no /map /debug /machine:I386 /nodefaultlib /out:"Debug/KernelEx.dll" /implib:"../common/KernelEx.lib" /ignore:4092 /OPT:NOWIN98
|
||||
# SUBTRACT LINK32 /pdb:none
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "Core - Win32 Release"
|
||||
# Name "Core - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\apiconf.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\apiconfmgr.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\apilib.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\core.def
|
||||
|
||||
!IF "$(CFG)" == "Core - Win32 Release"
|
||||
|
||||
# Begin Custom Build
|
||||
OutDir=.\Release
|
||||
ProjDir=.
|
||||
InputPath=.\core.def
|
||||
|
||||
BuildCmds= \
|
||||
link /LIB /NOLOGO /MACHINE:IX86 /DEF:$(ProjDir)\k32ord.def /OUT:$(OutDir)\k32ord.lib
|
||||
|
||||
"$(OutDir)\k32ord.lib" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
|
||||
$(BuildCmds)
|
||||
|
||||
"$(OutDir)\k32ord.exp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
|
||||
$(BuildCmds)
|
||||
# End Custom Build
|
||||
|
||||
!ELSEIF "$(CFG)" == "Core - Win32 Debug"
|
||||
|
||||
# Begin Custom Build
|
||||
OutDir=.\Debug
|
||||
ProjDir=.
|
||||
InputPath=.\core.def
|
||||
|
||||
BuildCmds= \
|
||||
link /LIB /NOLOGO /MACHINE:IX86 /DEF:$(ProjDir)\k32ord.def /OUT:$(OutDir)\k32ord.lib
|
||||
|
||||
"$(OutDir)\k32ord.lib" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
|
||||
$(BuildCmds)
|
||||
|
||||
"$(OutDir)\k32ord.exp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
|
||||
$(BuildCmds)
|
||||
# End Custom Build
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\debug.cpp
|
||||
|
||||
!IF "$(CFG)" == "Core - Win32 Release"
|
||||
|
||||
# PROP Exclude_From_Build 1
|
||||
|
||||
!ELSEIF "$(CFG)" == "Core - Win32 Debug"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\debugproto.cpp
|
||||
|
||||
!IF "$(CFG)" == "Core - Win32 Release"
|
||||
|
||||
# PROP Exclude_From_Build 1
|
||||
|
||||
!ELSEIF "$(CFG)" == "Core - Win32 Debug"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\internals.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\k32ord.def
|
||||
# PROP Exclude_From_Build 1
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\kexcoresdk.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\main.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\pemanip.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\resolver.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\SettingsDB.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\sharedmem.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\thunks.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wildcmp.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\apiconf.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\apiconfmgr.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\apilib.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\debug.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\debugproto.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\internals.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\kexcoresdk.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\pemanip.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\resolver.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\SettingsDB.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\sharedmem.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\structs.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\thunks.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\version.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wildcmp.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\core.rc
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
32
core/core.ini
Normal file
32
core/core.ini
Normal file
@ -0,0 +1,32 @@
|
||||
[ApiConfigurations]
|
||||
;configuration 0 is default configuration
|
||||
default=0
|
||||
0=BASE
|
||||
1=conf1
|
||||
2=conf2
|
||||
|
||||
[BASE]
|
||||
inherit=none
|
||||
contents=std,kexbases,kexbasen
|
||||
|
||||
[BASE.names]
|
||||
KERNEL32.GetVersion=std
|
||||
KERNEL32.GetAtomNameA=kexbases.1
|
||||
KERNEL32.GetComputerNameW=none
|
||||
|
||||
[BASE.ordinals]
|
||||
KERNEL32.1=none
|
||||
|
||||
[conf1]
|
||||
inherit=base
|
||||
contents=none
|
||||
|
||||
[conf1.names]
|
||||
KERNEL32.GetVersion=kexbases.2
|
||||
|
||||
[conf2]
|
||||
inherit=conf1
|
||||
contents=none
|
||||
|
||||
[conf2.ordinals]
|
||||
KERNEL32.1=std
|
56
core/debug.cpp
Normal file
56
core/debug.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "debug.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <windows.h>
|
||||
|
||||
#define BUFLEN 256
|
||||
|
||||
extern "C"
|
||||
int vsnprintf(char *buffer, size_t n, const char *format, va_list ap);
|
||||
|
||||
void dbgvprintf(const char* format, void* _argp)
|
||||
{
|
||||
char msg[BUFLEN];
|
||||
va_list argp = (va_list) _argp;
|
||||
HANDLE console_out = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
int cnt = vsnprintf(msg, sizeof(msg), format, argp);
|
||||
|
||||
if (console_out == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
OutputDebugString(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD dummy;
|
||||
WriteFile(console_out, msg, cnt < 0 ? BUFLEN - 1 : cnt, &dummy, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void dbgprintf(const char* format, ...)
|
||||
{
|
||||
va_list argp;
|
||||
va_start(argp, format);
|
||||
dbgvprintf(format, argp);
|
||||
va_end(argp);
|
||||
}
|
57
core/debug.h
Normal file
57
core/debug.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2008-2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DEBUG_H
|
||||
#define __DEBUG_H
|
||||
|
||||
#ifndef _DEBUG
|
||||
|
||||
#define DBGPRINTF(x) do { } while (0)
|
||||
#define DBGASSERT(x) do { } while (0)
|
||||
|
||||
#else
|
||||
|
||||
#define DBGPRINTF(x) dbgprintf x
|
||||
#define DBGASSERT(x) \
|
||||
if (!(x)) \
|
||||
do \
|
||||
{ \
|
||||
dbgprintf("ASSERTION FAILED: file: %s, line: %d\n", __FILE__, __LINE__); \
|
||||
DebugBreak(); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void dbgvprintf(const char* format, void* _argp);
|
||||
void dbgprintf(const char* format, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}; /* extern "C" */
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
41
core/debugproto.cpp
Normal file
41
core/debugproto.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "debugproto.h"
|
||||
#include <windows.h>
|
||||
#include "apiconfmgr.h"
|
||||
#include "resolver.h"
|
||||
#include "SettingsDB.h"
|
||||
|
||||
void kexDbgDumpConfigurations(void)
|
||||
{
|
||||
ApiConfigurationManager::dump_configurations();
|
||||
}
|
||||
|
||||
void kexDbgDumpImtes(void)
|
||||
{
|
||||
dump_imtes();
|
||||
}
|
||||
|
||||
void kexDbgDumpAppSettings(void)
|
||||
{
|
||||
SettingsDB::instance.dump_db();
|
||||
}
|
48
core/debugproto.h
Normal file
48
core/debugproto.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DEBUGPROTO_H
|
||||
#define __DEBUGPROTO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef KEXCORE_EXPORTS
|
||||
#define _KEXCOREIMP __declspec(dllexport)
|
||||
#else
|
||||
#define _KEXCOREIMP __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
|
||||
_KEXCOREIMP int kexInit(void);
|
||||
_KEXCOREIMP int kexUninit(void);
|
||||
_KEXCOREIMP void kexDbgDumpConfigurations(void);
|
||||
_KEXCOREIMP void kexDbgDumpImtes(void);
|
||||
_KEXCOREIMP void kexDbgDumpAppSettings(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}; /* extern "C" */
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
505
core/internals.cpp
Normal file
505
core/internals.cpp
Normal file
@ -0,0 +1,505 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2008-2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <cstdio>
|
||||
#include "internals.h"
|
||||
#include <tlhelp32.h>
|
||||
#include "resolver.h"
|
||||
#include "debug.h"
|
||||
#include "pemanip.h"
|
||||
|
||||
static bool is_winme;
|
||||
|
||||
IMTE*** ppmteModTable = NULL;
|
||||
HMODULE h_kernel32;
|
||||
CRITICAL_SECTION* krnl32lock = NULL;
|
||||
PDB98** pppdbCur = NULL;
|
||||
WORD* pimteMax = NULL;
|
||||
|
||||
MRFromHLib_t MRFromHLib = NULL;
|
||||
TIDtoTDB_t TIDtoTDB = NULL;
|
||||
PIDtoPDB_t PIDtoPDB = NULL;
|
||||
MRLoadTree_t MRLoadTree = NULL;
|
||||
FreeLibTree_t FreeLibTree = NULL;
|
||||
FLoadTreeNotify_t FLoadTreeNotify = NULL;
|
||||
FreeLibRemove_t FreeLibRemove = NULL;
|
||||
|
||||
sstring kernelex_dir("");
|
||||
sstring own_path("");
|
||||
|
||||
HANDLE fullcritlock_hndl = NULL;
|
||||
|
||||
//FIXME: CreateToolhelp32Snapshot + Process32First/Next should be replaced by
|
||||
// plstPdb + PnodGetLstElem() + SetLstCurElem() (see DumpProcesses())
|
||||
void FullCritLock()
|
||||
{
|
||||
PROCESSENTRY32 pe;
|
||||
BOOL result;
|
||||
|
||||
DBGPRINTF(("FullCritLock\n"));
|
||||
if (fullcritlock_hndl)
|
||||
{
|
||||
DBGPRINTF(("Error: lock already acquired\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
_EnterSysLevel(krnl32lock);
|
||||
fullcritlock_hndl = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
DBGASSERT(fullcritlock_hndl != INVALID_HANDLE_VALUE);
|
||||
|
||||
pe.dwSize = sizeof(pe);
|
||||
result = Process32First(fullcritlock_hndl, &pe);
|
||||
DBGASSERT(result != FALSE);
|
||||
do
|
||||
{
|
||||
PDB98* pdb;
|
||||
pdb = PIDtoPDB(pe.th32ProcessID);
|
||||
_EnterSysLevel(&pdb->CriticalSection);
|
||||
}
|
||||
while (Process32Next(fullcritlock_hndl, &pe));
|
||||
}
|
||||
|
||||
void FullCritUnlock()
|
||||
{
|
||||
PROCESSENTRY32 pe;
|
||||
BOOL result;
|
||||
|
||||
if (!fullcritlock_hndl)
|
||||
{
|
||||
DBGPRINTF(("Error: not locked\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
pe.dwSize = sizeof(pe);
|
||||
result = Process32First(fullcritlock_hndl, &pe);
|
||||
DBGASSERT(result != FALSE);
|
||||
do
|
||||
{
|
||||
PDB98* pdb;
|
||||
pdb = PIDtoPDB(pe.th32ProcessID);
|
||||
_LeaveSysLevel(&pdb->CriticalSection);
|
||||
}
|
||||
while (Process32Next(fullcritlock_hndl, &pe));
|
||||
|
||||
CloseHandle(fullcritlock_hndl);
|
||||
fullcritlock_hndl = NULL;
|
||||
|
||||
_LeaveSysLevel(krnl32lock);
|
||||
DBGPRINTF(("FullCritUnlock\n"));
|
||||
}
|
||||
|
||||
bool isWinMe()
|
||||
{
|
||||
return is_winme;
|
||||
}
|
||||
|
||||
void ShowError(UINT id, ...)
|
||||
{
|
||||
char format[512];
|
||||
char out[512];
|
||||
va_list vargs;
|
||||
|
||||
va_start(vargs, id);
|
||||
if (!LoadString(GetModuleHandle(NULL), id, format, sizeof(format)))
|
||||
sprintf(out, "ERROR: Missing string resource %d", id);
|
||||
else
|
||||
_vsnprintf(out, sizeof(out), format, vargs);
|
||||
va_end(vargs);
|
||||
MessageBox(NULL, out, "KernelEx Core", MB_OK | MB_ICONERROR);
|
||||
}
|
||||
|
||||
DWORD* find_unique_pattern(void* start, int size, const short* pattern, int pat_len, const char* pat_name)
|
||||
{
|
||||
unsigned char* pos = (unsigned char*) start;
|
||||
unsigned char* end_pos = pos + size - pat_len;
|
||||
unsigned char* found_loc = NULL;
|
||||
int found = 0;
|
||||
|
||||
while (pos <= end_pos)
|
||||
{
|
||||
if (pattern[0] < 0 || *pos == pattern[0])
|
||||
{
|
||||
int j;
|
||||
for (j = 1 ; j < pat_len ; j++)
|
||||
{
|
||||
if (pattern[j] >= 0 && pos[j] != pattern[j])
|
||||
break;
|
||||
}
|
||||
if (j == pat_len) //pattern found
|
||||
{
|
||||
found++;
|
||||
if (!found_loc)
|
||||
found_loc = pos;
|
||||
}
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (found != 1)
|
||||
{
|
||||
if (!found)
|
||||
DBGPRINTF(("%s: pattern not found\n", pat_name));
|
||||
else
|
||||
DBGPRINTF(("%s: pattern not unique, found occurrences: %d\n", pat_name, found));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (int i = 0 ; i < pat_len ; i++)
|
||||
if (pattern[i] == -2)
|
||||
return (DWORD*) &found_loc[i];
|
||||
|
||||
DBGPRINTF(("%s: invalid pattern\n", pat_name));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static DWORD decode_calljmp(DWORD* addr)
|
||||
{
|
||||
unsigned char* code = (unsigned char*)addr;
|
||||
|
||||
if (code[-1] == 0xe8 || code[-1] == 0xe9) /* call/jmp rel32 */
|
||||
{
|
||||
return (DWORD)(code + 4 + *(DWORD*)code);
|
||||
}
|
||||
else if (code[-2] == 0xff
|
||||
&& (code[-1] == 0x15 || code[-1] == 0x25)) /* call/jmp m32 */
|
||||
{
|
||||
return *(DWORD*)code;
|
||||
}
|
||||
else if (code[-1] == 0xeb) /* jmp rel8 */
|
||||
{
|
||||
return (DWORD)(code + 1 + *(char*)code);
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
|
||||
MODREF* MRfromCallerAddr(DWORD addr)
|
||||
{
|
||||
MODREF* mr;
|
||||
PDB98* ppdbCur = *pppdbCur;
|
||||
IMTE** pmteModTable = *ppmteModTable;
|
||||
|
||||
mr = ppdbCur->pExeMODREF;
|
||||
if (mr)
|
||||
{
|
||||
IMTE* imte = pmteModTable[mr->mteIndex];
|
||||
IMAGE_NT_HEADERS* nthdr = imte->pNTHdr;
|
||||
DWORD img_base = nthdr->OptionalHeader.ImageBase;
|
||||
if (addr >= img_base && addr < img_base + nthdr->OptionalHeader.SizeOfImage)
|
||||
return mr;
|
||||
}
|
||||
mr = ppdbCur->MODREFList;
|
||||
if (mr)
|
||||
{
|
||||
do
|
||||
{
|
||||
IMTE* imte = pmteModTable[mr->mteIndex];
|
||||
IMAGE_NT_HEADERS* nthdr = imte->pNTHdr;
|
||||
DWORD img_base = nthdr->OptionalHeader.ImageBase;
|
||||
if (addr >= img_base && addr < img_base + nthdr->OptionalHeader.SizeOfImage)
|
||||
return mr;
|
||||
mr = mr->pNextModRef;
|
||||
}
|
||||
while (mr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* find win32 mutex */
|
||||
static CRITICAL_SECTION* find_krnl32lock()
|
||||
{
|
||||
CRITICAL_SECTION* ret;
|
||||
|
||||
const char* pat_name = "Win32 lock";
|
||||
short pat[] = {0x55,0xA1,-2,-2,-2,-2,0x8B,0xEC,0x56,0x57,0x33,0xF6,0x50,0xE8};
|
||||
int pat_len = sizeof(pat) / sizeof(short);
|
||||
|
||||
DWORD* res = find_unique_pattern(iGetProcAddress(h_kernel32, "VirtualQueryEx"), pat_len, pat, pat_len, pat_name);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
ret = *(CRITICAL_SECTION**)*res;
|
||||
DBGPRINTF(("%s @ 0x%08x\n", pat_name, ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* find current process PDB */
|
||||
static PDB98** find_curPDB()
|
||||
{
|
||||
PDB98** ret;
|
||||
|
||||
const char* pat_name = "pppdbCur";
|
||||
short pat[] = {0xA1,-2,-2,-2,-2,0xFF,0x30,0xE8,-1,-1,-1,-1,0xC3};
|
||||
int pat_len = sizeof(pat) / sizeof(short);
|
||||
|
||||
DWORD* res = find_unique_pattern(iGetProcAddress(h_kernel32, "GetCurrentProcessId"), pat_len, pat, pat_len, pat_name);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
ret = *(PDB98***)*res;
|
||||
DBGPRINTF(("%s @ 0x%08x\n", pat_name, ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* find global module tables */
|
||||
static IMTE*** find_mod_table()
|
||||
{
|
||||
IMTE*** ret;
|
||||
|
||||
const char* pat_name = "Module table";
|
||||
short pat[] = {0x8B,0x0D,-2,-2,-2,-2};
|
||||
int pat_len = sizeof(pat) / sizeof(short);
|
||||
|
||||
DWORD* res = find_unique_pattern(iGetProcAddress(h_kernel32, (LPSTR)23), 0x20, pat, pat_len, pat_name);
|
||||
|
||||
ret = (IMTE***)*res;
|
||||
DBGPRINTF(("%s @ 0x%08x\n", pat_name, ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static MRFromHLib_t find_MRFromHLib()
|
||||
{
|
||||
MRFromHLib_t ret;
|
||||
|
||||
const char* pat_name = "MRFromHLib";
|
||||
short pat[] = {0xE8,-2,-2,-2,-2};
|
||||
int pat_len = sizeof(pat) / sizeof(short);
|
||||
|
||||
DWORD* res = find_unique_pattern(iGetProcAddress(h_kernel32, (LPSTR)23), 0x20, pat, pat_len, pat_name);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
ret = (MRFromHLib_t)decode_calljmp(res);
|
||||
DBGPRINTF(("%s @ 0x%08x\n", pat_name, ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static WORD* find_pimteMax()
|
||||
{
|
||||
WORD* ret;
|
||||
PEmanip pe(h_kernel32);
|
||||
if (!pe.HasTarget())
|
||||
return NULL;
|
||||
|
||||
const char* pat_name = "pimteMax";
|
||||
short pat[] = {0x66,0x8B,0x44,0x24,0x04,0x66,-1,0x05,-2,-2,-2,-2,-1,0x17,0x8B,0x0D,-1,-1,-1,-1,0x0F,0xBF,0xC0,0x8B,0x04,0x81,0x85,0xC0,0x74,0x07,0x8B,0x40,0x04,0x85,0xC0,0x75,0x09};
|
||||
int pat_len = sizeof(pat) / sizeof(short);
|
||||
const char* sec_name = ".text";
|
||||
|
||||
DWORD* res = find_unique_pattern(pe.GetSectionByName(sec_name), pe.GetSectionSize(sec_name), pat, pat_len, pat_name);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
ret = (WORD*) *res;
|
||||
DBGPRINTF(("%s @ 0x%08x\n", pat_name, ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static TIDtoTDB_t find_TIDtoTDB()
|
||||
{
|
||||
TIDtoTDB_t ret;
|
||||
PEmanip pe(h_kernel32);
|
||||
if (!pe.HasTarget())
|
||||
return NULL;
|
||||
|
||||
const char* pat_name = "TIDtoTDB";
|
||||
short pat[] = {0x89,-1,0xFF,0x75,0xFC,0xFF,0x77,0x14,0xE8,-2,-2,-2,-2,0x50};
|
||||
int pat_len = sizeof(pat) / sizeof(short);
|
||||
const char* sec_name = ".text";
|
||||
|
||||
DWORD* res = find_unique_pattern(pe.GetSectionByName(sec_name), pe.GetSectionSize(sec_name), pat, pat_len, pat_name);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
ret = (TIDtoTDB_t)decode_calljmp(res);
|
||||
DBGPRINTF(("%s @ 0x%08x\n", pat_name, ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PIDtoPDB_t find_PIDtoPDB()
|
||||
{
|
||||
PIDtoPDB_t ret;
|
||||
|
||||
const char* pat_name = "PIDtoPDB";
|
||||
short pat[] = {0xFF,0x74,0x24,0x0C,0xE8,-2,-2,-2,-2};
|
||||
int pat_len = sizeof(pat) / sizeof(short);
|
||||
|
||||
DWORD* res = find_unique_pattern(iGetProcAddress(h_kernel32, "OpenProcess"), pat_len, pat, pat_len, pat_name);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
ret = (PIDtoPDB_t)decode_calljmp(res);
|
||||
DBGPRINTF(("%s @ 0x%08x\n", pat_name, ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static MRLoadTree_t find_MRLoadTree()
|
||||
{
|
||||
MRLoadTree_t ret;
|
||||
PEmanip pe(h_kernel32);
|
||||
if (!pe.HasTarget())
|
||||
return NULL;
|
||||
|
||||
const char* pat_name = "MRLoadTree";
|
||||
short pat[] = {0x33,0xF6,0xE8,-1,-1,-1,-1,0x39,0x35,-1,-1,-1,-1,0x74,0x11,0xA1,-1,-1,-1,-1,0x50,0xE8,-1,-1,-1,-1,0x89,0x35,-1,-1,-1,-1,0xFF,0x74,0x24,0x14,0xE8,-2,-2,-2,-2,0x8B,0xF0,0x85,0xF6};
|
||||
int pat_len = sizeof(pat) / sizeof(short);
|
||||
const char* sec_name = ".text";
|
||||
|
||||
DWORD* res = find_unique_pattern(pe.GetSectionByName(sec_name), pe.GetSectionSize(sec_name), pat, pat_len, pat_name);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
ret = (MRLoadTree_t)decode_calljmp(res);
|
||||
DBGPRINTF(("%s @ 0x%08x\n", pat_name, ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static FreeLibTree_t find_FreeLibTree()
|
||||
{
|
||||
FreeLibTree_t ret;
|
||||
|
||||
const char* pat_name = "FreeLibTree";
|
||||
short pat[] = {0x75,0x09,0x6A,0x06,0xE8,-1,-1,-1,-1,0xEB,0x08,0x50,0xE8,-2,-2,-2,-2,0x8B,0xF0};
|
||||
int pat_len = sizeof(pat) / sizeof(short);
|
||||
|
||||
DWORD* res = find_unique_pattern(iGetProcAddress(h_kernel32, "FreeLibrary"), 0x80, pat, pat_len, pat_name);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
ret = (FreeLibTree_t)decode_calljmp(res);
|
||||
DBGPRINTF(("%s @ 0x%08x\n", pat_name, ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static FLoadTreeNotify_t find_FLoadTreeNotify()
|
||||
{
|
||||
FLoadTreeNotify_t ret;
|
||||
PEmanip pe(h_kernel32);
|
||||
if (!pe.HasTarget())
|
||||
return NULL;
|
||||
|
||||
const char* pat_name = "FLoadTreeNotify";
|
||||
short pat[] = {0x56,0xA1,-1,-1,-1,-1,0x6A,0x01,0x8B,0x08,0xFF,0xB1,0x98,0x00,0x00,0x00,0xE8,-2,-2,-2,-2,0x83,0xF8,0x01,0x1B,0xF6,0xF7,0xDE,0x85,0xF6};
|
||||
int pat_len = sizeof(pat) / sizeof(short);
|
||||
const char* sec_name = ".text";
|
||||
|
||||
DWORD* res = find_unique_pattern(pe.GetSectionByName(sec_name), pe.GetSectionSize(sec_name), pat, pat_len, pat_name);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
ret = (FLoadTreeNotify_t)decode_calljmp(res);
|
||||
DBGPRINTF(("%s @ 0x%08x\n", pat_name, ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static FreeLibRemove_t find_FreeLibRemove()
|
||||
{
|
||||
FreeLibRemove_t ret;
|
||||
PEmanip pe(h_kernel32);
|
||||
if (!pe.HasTarget())
|
||||
return NULL;
|
||||
|
||||
const char* pat_name = "FreeLibRemove";
|
||||
short pat[] = {0x8B,0xF0,0x85,0xF6,0x75,0x05,0xE8,-2,-2,-2,-2,0xA1,-1,-1,-1,-1,0x50};
|
||||
int pat_len = sizeof(pat) / sizeof(short);
|
||||
const char* sec_name = ".text";
|
||||
|
||||
DWORD* res = find_unique_pattern(pe.GetSectionByName(sec_name), pe.GetSectionSize(sec_name), pat, pat_len, pat_name);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
ret = (FreeLibRemove_t)decode_calljmp(res);
|
||||
DBGPRINTF(("%s @ 0x%08x\n", pat_name, ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool find_kernelex_install_dir()
|
||||
{
|
||||
//registry value InstallDir is written by the installer
|
||||
HKEY key;
|
||||
DWORD type;
|
||||
char path[MAX_PATH];
|
||||
DWORD len = sizeof(path);
|
||||
DWORD attr;
|
||||
long result;
|
||||
|
||||
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\KernelEx",
|
||||
0, KEY_QUERY_VALUE, &key);
|
||||
if (result != ERROR_SUCCESS)
|
||||
{
|
||||
DBGPRINTF(("Failed to open KernelEx registry key\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
result = RegQueryValueEx(key, "InstallDir", NULL, &type,
|
||||
(BYTE*)path, &len);
|
||||
RegCloseKey(key);
|
||||
if (result != ERROR_SUCCESS || type != REG_SZ || len == 0)
|
||||
{
|
||||
DBGPRINTF(("Failed to read InstallDir registry value\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (path[strlen(path) - 1] == '\\')
|
||||
path[strlen(path) - 1] = '\0';
|
||||
|
||||
attr = GetFileAttributes(path);
|
||||
if (attr == 0xffffffff || !(attr & FILE_ATTRIBUTE_DIRECTORY))
|
||||
{
|
||||
DBGPRINTF(("KernelEx directory [%s] doesn't exist\n", path));
|
||||
return false;
|
||||
}
|
||||
|
||||
DBGPRINTF(("KernelEx directory: %s\n", path));
|
||||
strcat(path, "\\");
|
||||
kernelex_dir = path;
|
||||
return true;
|
||||
}
|
||||
|
||||
int internals_init()
|
||||
{
|
||||
DBGPRINTF(("internals_init()\n"));
|
||||
h_kernel32 = GetModuleHandle("kernel32");
|
||||
ppmteModTable = find_mod_table();
|
||||
krnl32lock = find_krnl32lock();
|
||||
pppdbCur = find_curPDB();
|
||||
MRFromHLib = find_MRFromHLib();
|
||||
pimteMax = find_pimteMax();
|
||||
TIDtoTDB = find_TIDtoTDB();
|
||||
PIDtoPDB = find_PIDtoPDB();
|
||||
MRLoadTree = find_MRLoadTree();
|
||||
FreeLibTree = find_FreeLibTree();
|
||||
FLoadTreeNotify = find_FLoadTreeNotify();
|
||||
FreeLibRemove = find_FreeLibRemove();
|
||||
bool instdir_rslt = find_kernelex_install_dir();
|
||||
is_winme = (GetVersion() == 0xc0005a04);
|
||||
|
||||
if (!h_kernel32 || !ppmteModTable || !krnl32lock || !pppdbCur || !MRFromHLib
|
||||
|| !pimteMax || !TIDtoTDB || !PIDtoPDB || !MRLoadTree || !FreeLibTree
|
||||
|| !FLoadTreeNotify || !FreeLibRemove || !instdir_rslt)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void internals_uninit()
|
||||
{
|
||||
DBGPRINTF(("internals_uninit()\n"));
|
||||
}
|
100
core/internals.h
Normal file
100
core/internals.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2008-2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __INTERNALS_H
|
||||
#define __INTERNALS_H
|
||||
|
||||
#include "structs.h"
|
||||
#include "sharedmem.h"
|
||||
#include "sstring.hpp"
|
||||
#include "resource.h"
|
||||
|
||||
/** MSVC for-loop workaround. */
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER < 1201
|
||||
#define for if (0); else for
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern IMTE*** ppmteModTable;
|
||||
extern HMODULE h_kernel32;
|
||||
extern CRITICAL_SECTION* krnl32lock;
|
||||
extern PDB98** pppdbCur;
|
||||
extern WORD* pimteMax;
|
||||
|
||||
extern sstring kernelex_dir;
|
||||
extern sstring own_path;
|
||||
|
||||
void FullCritLock();
|
||||
void FullCritUnlock();
|
||||
void ShowError(UINT id, ...);
|
||||
bool isWinMe();
|
||||
|
||||
typedef MODREF* (__stdcall *MRFromHLib_t)(HMODULE);
|
||||
typedef TDB98* (__stdcall *TIDtoTDB_t)(DWORD);
|
||||
typedef PDB98* (__stdcall *PIDtoPDB_t)(DWORD);
|
||||
typedef MODREF* (__stdcall * MRLoadTree_t)(LPCSTR);
|
||||
typedef BOOL (__stdcall * FreeLibTree_t)(MODREF*);
|
||||
typedef BOOL (__stdcall * FLoadTreeNotify_t)(MODREF*, BOOL);
|
||||
typedef VOID (__stdcall * FreeLibRemove_t)(VOID);
|
||||
|
||||
extern MRFromHLib_t MRFromHLib;
|
||||
|
||||
/** Convert Thread ID into pointer to Thread Database.
|
||||
* @param tid Thread ID.
|
||||
* @return Pointer to Thread Database.
|
||||
*/
|
||||
extern TIDtoTDB_t TIDtoTDB;
|
||||
|
||||
/** Convert Process ID into pointer to Process Database.
|
||||
* @param pid Process ID.
|
||||
* @return Pointer to Process Database.
|
||||
*/
|
||||
extern PIDtoPDB_t PIDtoPDB;
|
||||
|
||||
extern MRLoadTree_t MRLoadTree;
|
||||
extern FreeLibTree_t FreeLibTree;
|
||||
extern FLoadTreeNotify_t FLoadTreeNotify;
|
||||
extern FreeLibRemove_t FreeLibRemove;
|
||||
|
||||
MODREF* MRfromCallerAddr(DWORD addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void __stdcall _EnterSysLevel(CRITICAL_SECTION*);
|
||||
void __stdcall _LeaveSysLevel(CRITICAL_SECTION*);
|
||||
|
||||
ULONG __stdcall VxDCall1(ULONG);
|
||||
ULONG __stdcall VxDCall2(ULONG, ULONG);
|
||||
ULONG __stdcall VxDCall3(ULONG, ULONG, ULONG);
|
||||
ULONG __stdcall VxDCall4(ULONG, ULONG, ULONG, ULONG);
|
||||
ULONG __stdcall VxDCall5(ULONG, ULONG, ULONG, ULONG, ULONG);
|
||||
ULONG __stdcall VxDCall6(ULONG, ULONG, ULONG, ULONG, ULONG, ULONG);
|
||||
ULONG __stdcall VxDCall7(ULONG, ULONG, ULONG, ULONG, ULONG, ULONG, ULONG);
|
||||
ULONG __stdcall VxDCall8(ULONG, ULONG, ULONG, ULONG, ULONG, ULONG, ULONG, ULONG);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
14
core/k32ord.def
Normal file
14
core/k32ord.def
Normal file
@ -0,0 +1,14 @@
|
||||
LIBRARY KERNEL32.dll
|
||||
|
||||
EXPORTS
|
||||
CommonUnimpStub@0 @17 NONAME
|
||||
VxDCall1@4 @1 NONAME
|
||||
VxDCall2@8 @2 NONAME
|
||||
VxDCall3@12 @3 NONAME
|
||||
VxDCall4@16 @4 NONAME
|
||||
VxDCall5@20 @5 NONAME
|
||||
VxDCall6@24 @6 NONAME
|
||||
VxDCall7@28 @7 NONAME
|
||||
VxDCall8@32 @8 NONAME
|
||||
_EnterSysLevel@4 @97 NONAME
|
||||
_LeaveSysLevel@4 @98 NONAME
|
87
core/kexcoresdk.cpp
Normal file
87
core/kexcoresdk.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2008-2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include "version.h"
|
||||
#include <stdarg.h>
|
||||
#include "kexcoresdk.h"
|
||||
#include "resolver.h"
|
||||
#include "internals.h"
|
||||
#include "SettingsDB.h"
|
||||
#include "debug.h"
|
||||
|
||||
unsigned long kexGetKEXVersion()
|
||||
{
|
||||
return VERSION_CODE;
|
||||
}
|
||||
|
||||
void kexDebugPrint(const char* format, ...)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
va_list argp;
|
||||
va_start(argp, format);
|
||||
dbgvprintf(format, argp);
|
||||
va_end(argp);
|
||||
#endif
|
||||
}
|
||||
|
||||
DWORD kexGetVersion()
|
||||
{
|
||||
return GetVersion();
|
||||
}
|
||||
|
||||
PROC kexGetProcAddress(HMODULE hModule, PCSTR lpProcName)
|
||||
{
|
||||
return iGetProcAddress(hModule, lpProcName);
|
||||
}
|
||||
|
||||
void* kexPIDtoPDB(DWORD pid)
|
||||
{
|
||||
return PIDtoPDB(pid);
|
||||
}
|
||||
|
||||
void* kexTIDtoTDB(DWORD tid)
|
||||
{
|
||||
return TIDtoTDB(tid);
|
||||
}
|
||||
|
||||
void kexGetModuleSettings(const char* module,
|
||||
char* conf_name, BYTE* ldr_flags)
|
||||
{
|
||||
appsetting as = SettingsDB::instance.get_appsetting(module);
|
||||
if (!as.conf)
|
||||
strcpy(conf_name, "default");
|
||||
else
|
||||
strncpy(conf_name, as.conf->get_name(), 256);
|
||||
*ldr_flags = as.flags;
|
||||
conf_name[255] = '\0';
|
||||
}
|
||||
|
||||
void kexSetModuleSettings(const char* module,
|
||||
const char* conf_name, BYTE ldr_flags)
|
||||
{
|
||||
SettingsDB::instance.write_single(module, conf_name, ldr_flags);
|
||||
}
|
||||
|
||||
void kexFlushAppSettings(void)
|
||||
{
|
||||
SettingsDB::instance.flush_all();
|
||||
}
|
217
core/main.cpp
Normal file
217
core/main.cpp
Normal file
@ -0,0 +1,217 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2008-2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include "version.h"
|
||||
#include "kexcoresdk.h"
|
||||
#include "debug.h"
|
||||
#include "apiconfmgr.h"
|
||||
#include "internals.h"
|
||||
|
||||
extern int internals_init();
|
||||
extern void internals_uninit();
|
||||
extern int resolver_init();
|
||||
extern void resolver_uninit();
|
||||
extern void resolver_hook();
|
||||
extern void resolver_unhook();
|
||||
|
||||
static int init_count = 0;
|
||||
|
||||
static void prepare()
|
||||
{
|
||||
ApiConfigurationManager acm;
|
||||
acm.reload_api_configurations();
|
||||
}
|
||||
|
||||
//these should be visible only in debug builds
|
||||
#ifdef _DEBUG
|
||||
extern "C" _KEXCOREIMP
|
||||
#endif
|
||||
int kexInit()
|
||||
{
|
||||
if (init_count > 0)
|
||||
return ++init_count;
|
||||
|
||||
DBGPRINTF(("KernelEx Core v%s by Xeno86\n", VERSION_STR));
|
||||
DBGPRINTF(("Initializing...\n"));
|
||||
|
||||
if (!internals_init())
|
||||
goto __error1;
|
||||
|
||||
prepare();
|
||||
|
||||
if (!resolver_init())
|
||||
goto __error2;
|
||||
|
||||
resolver_hook();
|
||||
|
||||
DBGPRINTF(("Initialized successfully\n"));
|
||||
return ++init_count;
|
||||
|
||||
__error2:
|
||||
internals_uninit();
|
||||
__error1:
|
||||
DBGPRINTF(("Initialization failure\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//these should be visible only in debug builds
|
||||
#ifdef _DEBUG
|
||||
extern "C" _KEXCOREIMP
|
||||
#endif
|
||||
int kexUninit()
|
||||
{
|
||||
if (init_count == 0)
|
||||
return 0;
|
||||
if (init_count > 1)
|
||||
return --init_count;
|
||||
|
||||
DBGPRINTF(("Uninitializing\n"));
|
||||
resolver_unhook();
|
||||
resolver_uninit();
|
||||
internals_uninit();
|
||||
return --init_count;
|
||||
}
|
||||
|
||||
extern "C" _KEXCOREIMP
|
||||
DWORD WINAPI MprStart(LPVOID)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Check if loaded into shared memory area.
|
||||
* @param addr Address to which loaded.
|
||||
* @return TRUE if loaded to shared memory, FALSE otherwise.
|
||||
*/
|
||||
static bool ensure_shared_memory(DWORD addr)
|
||||
{
|
||||
if (addr < 0x80000000)
|
||||
{
|
||||
MessageBox(NULL, "KernelEx not loaded into shared memory!",
|
||||
"Critical Error", MB_ICONERROR | MB_OK);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_failsafe_mode()
|
||||
{
|
||||
return GetSystemMetrics(SM_CLEANBOOT) != 0;
|
||||
}
|
||||
|
||||
static int load_count(DWORD addr)
|
||||
{
|
||||
if (!ppmteModTable)
|
||||
return 1;
|
||||
IMTE** pmteModTable = *ppmteModTable;
|
||||
return pmteModTable[MRfromCallerAddr(addr)->mteIndex]->cUsage;
|
||||
}
|
||||
|
||||
static void get_own_path(HMODULE base)
|
||||
{
|
||||
char path[MAX_PATH];
|
||||
GetModuleFileName(base, path, sizeof(path));
|
||||
own_path = path;
|
||||
}
|
||||
|
||||
static bool detect_old_version()
|
||||
{
|
||||
typedef void (WINAPI *KV_t)(char *);
|
||||
KV_t h_KVersion;
|
||||
char buf[32];
|
||||
|
||||
h_KVersion = (KV_t)GetProcAddress(GetModuleHandle("kernel32"), "KUPVersion");
|
||||
if (!h_KVersion)
|
||||
h_KVersion = (KV_t)GetProcAddress(GetModuleHandle("kernel32"), "KEXVersion");
|
||||
if (!h_KVersion)
|
||||
return false;
|
||||
h_KVersion(buf);
|
||||
ShowError(IDS_OLDVER, buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** CRT startup routine declaration. */
|
||||
extern "C"
|
||||
BOOL WINAPI _DllMainCRTStartup(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
|
||||
|
||||
/** Pre-init code executed before CRT startup code. */
|
||||
extern "C"
|
||||
BOOL APIENTRY PreDllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
|
||||
{
|
||||
BOOL ret = TRUE;
|
||||
|
||||
if (reason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
if (!ensure_shared_memory((DWORD)instance))
|
||||
return FALSE;
|
||||
|
||||
if (is_failsafe_mode())
|
||||
return FALSE;
|
||||
|
||||
DisableThreadLibraryCalls(instance);
|
||||
|
||||
if (load_count((DWORD) instance) == 1)
|
||||
{
|
||||
if (detect_old_version())
|
||||
return FALSE;
|
||||
|
||||
//very important - without this memory allocation won't work
|
||||
if (!create_shared_heap())
|
||||
return FALSE;
|
||||
|
||||
//we are in shared memory so CRT init code should be called only once
|
||||
//globally (by default it would be called on every process attach)
|
||||
ret = _DllMainCRTStartup(instance, reason, reserved);
|
||||
|
||||
get_own_path(instance);
|
||||
}
|
||||
}
|
||||
else if (reason == DLL_PROCESS_DETACH)
|
||||
{
|
||||
if (load_count((DWORD) instance) == 1)
|
||||
{
|
||||
ret = _DllMainCRTStartup(instance, reason, reserved);
|
||||
destroy_shared_heap();
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Entry point. Called by CRT startup code. */
|
||||
extern "C"
|
||||
BOOL APIENTRY DllMain(HINSTANCE instance, DWORD reason, BOOL load_static)
|
||||
{
|
||||
if (reason == DLL_PROCESS_ATTACH && GetModuleHandle("MPREXE.EXE"))
|
||||
{
|
||||
return kexInit();
|
||||
}
|
||||
|
||||
//for additional safety - auto uninit on core unload
|
||||
if (reason == DLL_PROCESS_DETACH
|
||||
&& load_count((DWORD) instance) == 1 && init_count > 0)
|
||||
{
|
||||
init_count = 1;
|
||||
kexUninit();
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
676
core/resolver.cpp
Normal file
676
core/resolver.cpp
Normal file
@ -0,0 +1,676 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2008-2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <algorithm>
|
||||
#include "debug.h"
|
||||
#include "resolver.h"
|
||||
#include "apiconf.h"
|
||||
#include "apiconfmgr.h"
|
||||
#include "internals.h"
|
||||
#include "../setup/loadstub.h"
|
||||
#include "thunks.h"
|
||||
#include "SettingsDB.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
char system_path[MAX_PATH];
|
||||
int system_path_len;
|
||||
|
||||
static PLONG jtab;
|
||||
static LONG old_jtab[4];
|
||||
|
||||
|
||||
/** Get API configuration for selected module.
|
||||
* @param module Target module.
|
||||
* @return Pointer to API configuration or NULL to not use extended API.
|
||||
*/
|
||||
static ApiConfiguration* get_config(MODREF* moduleMR)
|
||||
{
|
||||
IMTE** pmteModTable = *ppmteModTable;
|
||||
PDB98* ppdbCur = *pppdbCur;
|
||||
IMTE_KEX* module = (IMTE_KEX*) pmteModTable[moduleMR->mteIndex];
|
||||
IMTE_KEX* process = (IMTE_KEX*) pmteModTable[ppdbCur->pExeMODREF->mteIndex];
|
||||
ApiConfiguration* conf;
|
||||
BYTE flags;
|
||||
|
||||
//unless override flag is set try to get module configuration first
|
||||
if (!(process->flags & LDR_OVERRIDE_PROC_MOD))
|
||||
{
|
||||
if (!(module->flags & LDR_VALID_FLAG))
|
||||
{
|
||||
appsetting as = SettingsDB::instance.get_appsetting(module->pszFileName);
|
||||
module->config = as.conf;
|
||||
module->flags = as.flags | LDR_VALID_FLAG;
|
||||
}
|
||||
conf = module->config;
|
||||
flags = module->flags;
|
||||
|
||||
if (flags & LDR_KEX_DISABLE)
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
conf = NULL;
|
||||
|
||||
//if above failed or override flag was set try to get process configuration
|
||||
if (!conf)
|
||||
{
|
||||
if (!(process->flags & LDR_VALID_FLAG))
|
||||
{
|
||||
appsetting as = SettingsDB::instance.get_appsetting(process->pszFileName);
|
||||
process->config = as.conf;
|
||||
process->flags = as.flags | LDR_VALID_FLAG;
|
||||
}
|
||||
conf = process->config;
|
||||
flags = process->flags;
|
||||
|
||||
if (flags & LDR_KEX_DISABLE)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//if no process configuration then get parent configuration
|
||||
if (!conf)
|
||||
{
|
||||
PDB98* ppdbParent = ppdbCur->ParentPDB;
|
||||
|
||||
if (ppdbParent && !(ppdbParent->Flags & (fTerminated | fTerminating |
|
||||
fNearlyTerminating | fDosProcess | fWin16Process)))
|
||||
{
|
||||
IMTE_KEX* parent = (IMTE_KEX*) pmteModTable[ppdbParent->pExeMODREF->mteIndex];
|
||||
conf = parent->config;
|
||||
flags = parent->flags;
|
||||
|
||||
if (flags & LDR_KEX_DISABLE)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & LDR_LOG_APIS)
|
||||
{
|
||||
//TODO: not implemented yet
|
||||
DBGPRINTF(("Resolver flag LDR_LOG_APIS not implemented\n"));
|
||||
}
|
||||
|
||||
if (flags & LDR_FILTER_APIS)
|
||||
{
|
||||
//TODO: not implemented yet
|
||||
DBGPRINTF(("Resolver flag LDR_FILTER_APIS not implemented\n"));
|
||||
}
|
||||
|
||||
//finally if everything else fails take default configuration
|
||||
if (!conf)
|
||||
conf = ApiConfigurationManager::get_default_configuration();
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
/** Finds overridden module index for target module.
|
||||
* @param target Module from which functions are imported.
|
||||
* @return Index or 0xffff if module doesn't have entry in API configuration tables.
|
||||
*/
|
||||
static WORD resolve_mod_index(IMTE_KEX* target)
|
||||
{
|
||||
const char* file_name;
|
||||
|
||||
/* Skip non-system modules */
|
||||
if (target->cbFileName - target->cbModName - 1 != system_path_len
|
||||
|| strncmp(system_path, target->pszFileName, system_path_len))
|
||||
return target->mod_index = 0xffff;
|
||||
|
||||
file_name = target->pszModName;
|
||||
|
||||
for (int i = 0 ; i < overridden_module_count ; i++)
|
||||
if (strcmp(file_name, overridden_module_names[i]) == 0)
|
||||
return target->mod_index = i + 1;
|
||||
|
||||
/* No override API list for target module available. */
|
||||
return target->mod_index = 0xffff;
|
||||
}
|
||||
|
||||
static PROC resolve_nonshared_addr(DWORD addr, MODREF* caller, PMODREF** refmod)
|
||||
{
|
||||
MODREF* mr;
|
||||
WORD idx;
|
||||
DWORD img_base;
|
||||
int api_lib_num;
|
||||
char dllpath[MAX_PATH];
|
||||
ApiLibrary* apilib;
|
||||
IMTE** pmteModTable = *ppmteModTable;
|
||||
static MODREF* buffer[1024];
|
||||
|
||||
DBGASSERT(addr >= 0xc0000000);
|
||||
api_lib_num = (addr >> 24) - 0xc0;
|
||||
DBGASSERT(api_lib_num > 0); //ensure apilib ID isn't STD's
|
||||
apilib = ApiLibraryManager::get_apilib(api_lib_num);
|
||||
DBGASSERT(apilib != NULL);
|
||||
DBGASSERT((DWORD) apilib->mod_handle < 0x80000000);
|
||||
idx = 0xff00 + api_lib_num;
|
||||
|
||||
//first check if api library has already been loaded
|
||||
mr = (*pppdbCur)->MODREFList;
|
||||
do
|
||||
{
|
||||
IMTE_KEX* imte = (IMTE_KEX*) pmteModTable[mr->mteIndex];
|
||||
if (imte->mod_index == idx)
|
||||
{
|
||||
IMAGE_NT_HEADERS* nthdr = imte->pNTHdr;
|
||||
img_base = nthdr->OptionalHeader.ImageBase;
|
||||
return (PROC)(img_base + (addr & 0x00ffffff));
|
||||
}
|
||||
mr = mr->pNextModRef;
|
||||
}
|
||||
while (mr);
|
||||
|
||||
//if not - load it
|
||||
|
||||
strcpy(dllpath, kernelex_dir.get());
|
||||
strcat(dllpath, apilib->apilib_name);
|
||||
|
||||
_EnterSysLevel(krnl32lock);
|
||||
mr = MRLoadTree(dllpath);
|
||||
if (!mr)
|
||||
{
|
||||
FreeLibRemove();
|
||||
_LeaveSysLevel(krnl32lock);
|
||||
return 0;
|
||||
}
|
||||
_LeaveSysLevel(krnl32lock);
|
||||
|
||||
if (refmod) //static resolve (implicit)
|
||||
{
|
||||
for (int i = 0 ; i < caller->cImportedModules ; i++)
|
||||
buffer[i] = caller->ImplicitImports[i].pMR;
|
||||
|
||||
//FIXME: this will cause problems if apilib references another non-shared apilib!!
|
||||
//it is okay to use global buffer because static resolve code is protected by k32 lock
|
||||
**refmod = mr;
|
||||
*refmod += buffer - &caller->ImplicitImports[0].pMR;
|
||||
}
|
||||
else //dynamic resolve (GetProcAddress)
|
||||
{
|
||||
if (FLoadTreeNotify(mr, 0))
|
||||
{
|
||||
FreeLibTree(mr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
IMTE_KEX* imte = (IMTE_KEX*) pmteModTable[mr->mteIndex];
|
||||
|
||||
img_base = imte->pNTHdr->OptionalHeader.ImageBase;
|
||||
|
||||
if (img_base == (DWORD) apilib->mod_handle)
|
||||
DBGASSERT(imte->mod_index == apilib->index + 0xff00);
|
||||
|
||||
imte->mod_index = idx;
|
||||
|
||||
return (PROC)(img_base + (addr & 0x00ffffff));
|
||||
}
|
||||
|
||||
static PROC WINAPI OriExportFromOrdinal(IMAGE_NT_HEADERS* PEh, WORD ordinal)
|
||||
{
|
||||
DWORD img_base;
|
||||
IMAGE_EXPORT_DIRECTORY* Exports;
|
||||
DWORD export_table_size;
|
||||
DWORD export_no;
|
||||
DWORD export_cnt;
|
||||
DWORD* function_table;
|
||||
DWORD addr;
|
||||
|
||||
export_table_size = PEh->OptionalHeader
|
||||
.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
|
||||
|
||||
if (!export_table_size)
|
||||
return NULL;
|
||||
|
||||
img_base = PEh->OptionalHeader.ImageBase;
|
||||
Exports = (IMAGE_EXPORT_DIRECTORY *)(img_base + PEh->OptionalHeader
|
||||
.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
|
||||
|
||||
export_no = ordinal - Exports->Base;
|
||||
export_cnt = Exports->NumberOfFunctions;
|
||||
|
||||
if (!export_cnt || export_no > export_cnt)
|
||||
return NULL;
|
||||
|
||||
function_table = (DWORD*)(Exports->AddressOfFunctions + img_base);
|
||||
addr = function_table[export_no];
|
||||
|
||||
if (!addr)
|
||||
return NULL;
|
||||
|
||||
addr += img_base;
|
||||
|
||||
//handle export forwarding case
|
||||
if (addr >= (DWORD)Exports && addr < (DWORD)Exports + export_table_size)
|
||||
{
|
||||
char module_name[MAX_PATH];
|
||||
char* p;
|
||||
char c;
|
||||
HMODULE hmod;
|
||||
|
||||
p = module_name;
|
||||
do
|
||||
{
|
||||
c = *(char*) addr;
|
||||
addr++;
|
||||
if (c == '.') break;
|
||||
*p = c;
|
||||
p++;
|
||||
}
|
||||
while (c);
|
||||
*p = '\0';
|
||||
|
||||
hmod = GetModuleHandle(module_name); //should be IGetModuleHandle
|
||||
if (!hmod)
|
||||
return NULL;
|
||||
|
||||
return GetProcAddress(hmod, (char*) addr); //should be IGetProcAddress
|
||||
}
|
||||
|
||||
return (PROC) addr;
|
||||
}
|
||||
|
||||
static PROC WINAPI OriExportFromName(IMAGE_NT_HEADERS* PEh, WORD hint, LPCSTR name)
|
||||
{
|
||||
DWORD img_base;
|
||||
IMAGE_EXPORT_DIRECTORY* Exports;
|
||||
DWORD* names;
|
||||
WORD* ordinals;
|
||||
int lo;
|
||||
int hi;
|
||||
int curr;
|
||||
int res;
|
||||
|
||||
if (!PEh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
|
||||
return NULL;
|
||||
|
||||
img_base = PEh->OptionalHeader.ImageBase;
|
||||
Exports = (IMAGE_EXPORT_DIRECTORY *)(img_base + PEh->OptionalHeader
|
||||
.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
|
||||
|
||||
hi = Exports->NumberOfNames;
|
||||
|
||||
if (!hi)
|
||||
return NULL;
|
||||
|
||||
ordinals = (WORD*)(Exports->AddressOfNameOrdinals + img_base);
|
||||
names = (DWORD*)(img_base + Exports->AddressOfNames);
|
||||
|
||||
if (hint < hi)
|
||||
{
|
||||
res = strcmp(name, (char*)(names[hint] + img_base));
|
||||
if (!res)
|
||||
{
|
||||
return OriExportFromOrdinal(PEh, (WORD)(Exports->Base + ordinals[hint]));
|
||||
}
|
||||
else if (res > 0)
|
||||
{
|
||||
lo = hint + 1;
|
||||
hi--;
|
||||
}
|
||||
else
|
||||
{
|
||||
lo = 0;
|
||||
hi = hint - 1;
|
||||
}
|
||||
curr = (hi + lo) >> 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
lo = 0;
|
||||
hi--;
|
||||
curr = hi >> 1;
|
||||
}
|
||||
|
||||
while (lo <= hi)
|
||||
{
|
||||
res = strcmp(name, (char*)(names[curr] + img_base));
|
||||
if (!res)
|
||||
{
|
||||
return OriExportFromOrdinal(PEh, (WORD)(Exports->Base + ordinals[curr]));
|
||||
}
|
||||
else if (res > 0)
|
||||
{
|
||||
lo = curr + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
hi = curr - 1;
|
||||
}
|
||||
curr = (hi + lo) >> 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD encode_address(DWORD addr, const ApiLibrary* apilib)
|
||||
{
|
||||
//note: rules have to be the same as in decode_address
|
||||
int index = apilib->index;
|
||||
|
||||
//ensure that we haven't run out of indexes
|
||||
DBGASSERT(index + 0xc0 < 0xff);
|
||||
|
||||
//STD apilib
|
||||
if (index == 0)
|
||||
return addr;
|
||||
|
||||
//non-shared apilib
|
||||
if ((DWORD) apilib->mod_handle < 0x80000000)
|
||||
{
|
||||
//max non-shared apilib size 16MB
|
||||
DBGASSERT(addr - (DWORD) apilib->mod_handle < 0x01000000);
|
||||
|
||||
return ((0xc0 + index) << 24) + addr - (DWORD) apilib->mod_handle;
|
||||
}
|
||||
//shared apilib
|
||||
return addr;
|
||||
}
|
||||
|
||||
inline PROC decode_address(DWORD p, IMAGE_NT_HEADERS* target_NThdr, MODREF* caller, PMODREF** refmod)
|
||||
{
|
||||
//note: rules have to be the same as in encode_address
|
||||
//zero address
|
||||
if (!p)
|
||||
return (PROC) p;
|
||||
//export forwarding - ordinal number
|
||||
if ((p & 0xffff0000) == 0xffff0000)
|
||||
return OriExportFromOrdinal(target_NThdr, LOWORD(p));
|
||||
//non-shared system library
|
||||
if (p < 0x80000000)
|
||||
return (PROC)(p + target_NThdr->OptionalHeader.ImageBase);
|
||||
//non-shared api library
|
||||
if (p >= 0xc0000000)
|
||||
return resolve_nonshared_addr(p, caller, refmod);
|
||||
//shared system or api library
|
||||
return (PROC) p;
|
||||
}
|
||||
|
||||
PROC WINAPI ExportFromOrdinal(IMTE_KEX* target, MODREF* caller, PMODREF** refmod, WORD ordinal)
|
||||
{
|
||||
PROC ret;
|
||||
|
||||
//if caller is unknown - assume it is process's exe
|
||||
if (!caller)
|
||||
caller = (*pppdbCur)->pExeMODREF;
|
||||
|
||||
ApiConfiguration* apiconf = get_config(caller);
|
||||
if (apiconf)
|
||||
{
|
||||
WORD mod_index = target->mod_index;
|
||||
|
||||
if (!mod_index)
|
||||
mod_index = resolve_mod_index(target);
|
||||
|
||||
DBGASSERT(mod_index);
|
||||
mod_index--;
|
||||
|
||||
if (!apiconf->is_table_empty(mod_index))
|
||||
ret = decode_address(apiconf->get(mod_index, ordinal),
|
||||
target->pNTHdr, caller, refmod);
|
||||
else
|
||||
ret = OriExportFromOrdinal(target->pNTHdr, ordinal);
|
||||
}
|
||||
else
|
||||
ret = OriExportFromOrdinal(target->pNTHdr, ordinal);
|
||||
|
||||
if (!ret && refmod)
|
||||
DBGPRINTF(("%s: unresolved export %s:%d\n",
|
||||
((*ppmteModTable)[caller->mteIndex])->pszModName,
|
||||
target->pszModName, ordinal));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
PROC WINAPI ExportFromName(IMTE_KEX* target, MODREF* caller, PMODREF** refmod, WORD hint, LPCSTR name)
|
||||
{
|
||||
PROC ret;
|
||||
|
||||
//if caller is unknown - assume it is process's exe
|
||||
if (!caller)
|
||||
caller = (*pppdbCur)->pExeMODREF;
|
||||
|
||||
ApiConfiguration* apiconf = get_config(caller);
|
||||
if (apiconf)
|
||||
{
|
||||
WORD mod_index = target->mod_index;
|
||||
|
||||
if (!mod_index)
|
||||
mod_index = resolve_mod_index(target);
|
||||
|
||||
DBGASSERT(mod_index);
|
||||
mod_index--;
|
||||
|
||||
if (!apiconf->is_table_empty(mod_index))
|
||||
ret = decode_address(apiconf->get(mod_index, hint, name),
|
||||
target->pNTHdr, caller, refmod);
|
||||
else
|
||||
ret = OriExportFromName(target->pNTHdr, hint, name);
|
||||
}
|
||||
else
|
||||
ret = OriExportFromName(target->pNTHdr, hint, name);
|
||||
|
||||
if (!ret && refmod)
|
||||
DBGPRINTF(("%s: unresolved export %s:%s\n",
|
||||
((*ppmteModTable)[caller->mteIndex])->pszModName,
|
||||
target->pszModName, name));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
//todo: vGetProcAddress_new
|
||||
PROC WINAPI GetProcAddress_new(HMODULE hModule, LPCSTR lpProcName)
|
||||
{
|
||||
DWORD caller = *((DWORD*)&hModule - 1);
|
||||
PDB98* ppdbCur = *pppdbCur;
|
||||
MODREF* mod_mr;
|
||||
IMAGE_NT_HEADERS* peh;
|
||||
PROC ret;
|
||||
|
||||
_EnterSysLevel(&ppdbCur->CriticalSection);
|
||||
mod_mr = MRFromHLib(hModule);
|
||||
if (!mod_mr)
|
||||
{
|
||||
_SetError(ERROR_INVALID_HANDLE);
|
||||
ret = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
IMTE_KEX* target = (IMTE_KEX*) pmteModTable[mod_mr->mteIndex];
|
||||
|
||||
if (HIWORD(lpProcName))
|
||||
{
|
||||
ret = ExportFromName(target, (IMTE_KEX*) IMTEfromCallerAddr(caller), 0, lpProcName);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = ExportFromOrdinal(target, (IMTE_KEX*) IMTEfromCallerAddr(caller), (WORD) lpProcName);
|
||||
}
|
||||
if (!ppdbCur->DebuggeeCB || _CheckMustComplete())
|
||||
{
|
||||
if (!ret)
|
||||
_SetError(ERROR_PROC_NOT_FOUND);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = _DEBCreateDIT(*((DWORD*)ppdbCur->DebuggeeCB + 5), ret);
|
||||
}
|
||||
|
||||
}
|
||||
_LeaveSysLevel(&ppdbCur->CriticalSection);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
PROC WINAPI iGetProcAddress(HMODULE hModule, LPCSTR lpProcName)
|
||||
{
|
||||
IMAGE_DOS_HEADER* dos_hdr;
|
||||
IMAGE_NT_HEADERS* nt_hdr;
|
||||
|
||||
dos_hdr = (IMAGE_DOS_HEADER*) hModule;
|
||||
nt_hdr = (IMAGE_NT_HEADERS*)((int)dos_hdr + dos_hdr->e_lfanew);
|
||||
|
||||
if ((DWORD)lpProcName < 0x10000)
|
||||
return OriExportFromOrdinal(nt_hdr, (WORD)lpProcName);
|
||||
return OriExportFromName(nt_hdr, 0, lpProcName);
|
||||
}
|
||||
|
||||
static IMAGE_SECTION_HEADER* get_data_section()
|
||||
{
|
||||
int i;
|
||||
IMAGE_DOS_HEADER* MZh = (IMAGE_DOS_HEADER*) GetModuleHandle("kernel32");
|
||||
IMAGE_NT_HEADERS* PEh = (IMAGE_NT_HEADERS*) ((int)MZh + MZh->e_lfanew);
|
||||
IMAGE_SECTION_HEADER* section = (IMAGE_SECTION_HEADER*)
|
||||
((int)PEh
|
||||
+ PEh->FileHeader.SizeOfOptionalHeader
|
||||
+ sizeof(IMAGE_FILE_HEADER)
|
||||
+ sizeof(DWORD));
|
||||
for (i = 0 ; i < PEh->FileHeader.NumberOfSections ; i++)
|
||||
{
|
||||
if (!strcmpi((char*) section->Name, ".data"))
|
||||
return section;
|
||||
section++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void reset_imtes()
|
||||
{
|
||||
DBGPRINTF(("Reseting IMTEs\n"));
|
||||
_EnterSysLevel(krnl32lock);
|
||||
|
||||
WORD imteMax = *pimteMax;
|
||||
IMTE** pmteModTable = *ppmteModTable;
|
||||
for (WORD i = 0 ; i < imteMax ; i++)
|
||||
{
|
||||
IMTE_KEX* imte = (IMTE_KEX*) pmteModTable[i];
|
||||
if (imte)
|
||||
{
|
||||
imte->config = NULL;
|
||||
imte->flags = 0;
|
||||
imte->mod_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_LeaveSysLevel(krnl32lock);
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
void dump_imtes(void)
|
||||
{
|
||||
WORD imteMax = *pimteMax;
|
||||
IMTE** pmteModTable = *ppmteModTable;
|
||||
int total = 0;
|
||||
|
||||
dbgprintf("Dumping IMTEs...\n");
|
||||
dbgprintf("%-6s %-12s %s %s %s\n", "No.", "Process", "Module", "Config", "Flags");
|
||||
for (WORD i = 0 ; i < imteMax ; i++)
|
||||
{
|
||||
IMTE_KEX* imte = (IMTE_KEX*) pmteModTable[i];
|
||||
if (imte)
|
||||
{
|
||||
dbgprintf("#%-5d %-12s %s %s %02x\n", i,
|
||||
pmteModTable[imte->pMR->ppdb->pExeMODREF->mteIndex]->pszSModName,
|
||||
imte->pszFileName,
|
||||
imte->config ? imte->config->get_name() : "unknown",
|
||||
imte->flags);
|
||||
total++;
|
||||
}
|
||||
}
|
||||
dbgprintf("\nEnd dump total %d IMTEs\n\n", total);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int resolver_init()
|
||||
{
|
||||
DBGPRINTF(("resolver_init()\n"));
|
||||
DWORD ptr;
|
||||
KernelEx_dataseg* dseg = NULL;
|
||||
IMAGE_SECTION_HEADER* section = get_data_section();
|
||||
DWORD sign_len = sizeof(KEX_SIGNATURE) - 1;
|
||||
|
||||
if (!section)
|
||||
return 0;
|
||||
|
||||
ptr = (DWORD) h_kernel32 + section->VirtualAddress + section->Misc.VirtualSize - sign_len;
|
||||
while (ptr >= (DWORD) h_kernel32 + section->VirtualAddress)
|
||||
{
|
||||
if (!memcmp((void*)ptr, KEX_SIGNATURE, sign_len))
|
||||
{
|
||||
dseg = (KernelEx_dataseg*) ptr;
|
||||
break;
|
||||
}
|
||||
ptr--;
|
||||
}
|
||||
|
||||
if (!dseg)
|
||||
{
|
||||
DBGPRINTF(("Signature not found\n"));
|
||||
ShowError(IDS_NOTREADY);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
DBGPRINTF(("Signature found @ 0x%08x\n", ptr));
|
||||
|
||||
if (dseg->version != KEX_STUB_VER)
|
||||
{
|
||||
DBGPRINTF(("Wrong stub version, expected: %d, got: %d\n",
|
||||
KEX_STUB_VER, dseg->version));
|
||||
ShowError(IDS_STUBMISMATCH, KEX_STUB_VER, dseg->version);
|
||||
return 0;
|
||||
}
|
||||
|
||||
jtab = (PLONG) dseg->jtab;
|
||||
|
||||
system_path_len = GetSystemDirectory(system_path, sizeof(system_path));
|
||||
|
||||
SettingsDB::instance.flush_all();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void resolver_uninit()
|
||||
{
|
||||
SettingsDB::instance.clear();
|
||||
reset_imtes();
|
||||
}
|
||||
|
||||
void resolver_hook()
|
||||
{
|
||||
DBGPRINTF(("resolver_hook()\n"));
|
||||
old_jtab[0] = InterlockedExchange(jtab + JTAB_EFO_DYN, (LONG) ExportFromOrdinalDynamic_thunk);
|
||||
old_jtab[1] = InterlockedExchange(jtab + JTAB_EFO_STA, (LONG) ExportFromOrdinalStatic_thunk);
|
||||
old_jtab[2] = InterlockedExchange(jtab + JTAB_EFN_DYN, (LONG) ExportFromNameDynamic_thunk);
|
||||
old_jtab[3] = InterlockedExchange(jtab + JTAB_EFN_STA, (LONG) ExportFromNameStatic_thunk);
|
||||
}
|
||||
|
||||
void resolver_unhook()
|
||||
{
|
||||
DBGPRINTF(("resolver_unhook()\n"));
|
||||
InterlockedExchange(jtab + JTAB_EFO_DYN, old_jtab[0]);
|
||||
InterlockedExchange(jtab + JTAB_EFO_STA, old_jtab[1]);
|
||||
InterlockedExchange(jtab + JTAB_EFN_DYN, old_jtab[2]);
|
||||
InterlockedExchange(jtab + JTAB_EFN_STA, old_jtab[3]);
|
||||
}
|
61
core/resolver.h
Normal file
61
core/resolver.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2008-2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __RESOLVER_H
|
||||
#define __RESOLVER_H
|
||||
|
||||
#include "structs.h"
|
||||
#include "apilib.h"
|
||||
|
||||
/***** loader flags *****/
|
||||
#define LDR_KEX_DISABLE 1 /* disable KernelEx API extensions for this module */
|
||||
#define LDR_OVERRIDE_PROC_MOD 2 /* use same configuration and flags for all modules in a process */
|
||||
#define LDR_LOG_APIS 4 /* enable API tracing */
|
||||
#define LDR_FILTER_APIS 8 /* allow to control single APIs - enable, disable, switch */
|
||||
#define LDR_VALID_FLAG 128 /* denotes that flags field is valid */
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
class ApiConfiguration;
|
||||
|
||||
struct IMTE_KEX : public IMTE
|
||||
{
|
||||
ApiConfiguration* config; /* pointer to API configuration required by the module
|
||||
* 0 - not checked */
|
||||
BYTE flags; /* loader flags */
|
||||
BYTE unused; /* unused */
|
||||
WORD mod_index; /* this value minus 1 is index into MODAPI table in API configurations
|
||||
* 0xff00-0xfffe - api libraries
|
||||
* 0 - not checked, 0xffff - not an overridden module */
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
DWORD encode_address(DWORD addr, const ApiLibrary* apilib);
|
||||
PROC WINAPI iGetProcAddress(HMODULE hModule, LPCSTR lpProcName);
|
||||
PROC WINAPI ExportFromOrdinal(IMTE_KEX* target, MODREF* caller, PMODREF** refmod, WORD ordinal);
|
||||
PROC WINAPI ExportFromName(IMTE_KEX* target, MODREF* caller, PMODREF** refmod, WORD hint, LPCSTR name);
|
||||
|
||||
#ifdef _DEBUG
|
||||
void dump_imtes(void);
|
||||
#endif
|
||||
|
||||
#endif
|
18
core/resource.h
Normal file
18
core/resource.h
Normal file
@ -0,0 +1,18 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Developer Studio generated include file.
|
||||
// Used by Core.rc
|
||||
//
|
||||
#define IDS_NOTREADY 1
|
||||
#define IDS_STUBMISMATCH 2
|
||||
#define IDS_OLDVER 3
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1000
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
87
core/sharedmem.cpp
Normal file
87
core/sharedmem.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2008-2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include "sharedmem.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define HEAP_SHARED 0x04000000
|
||||
|
||||
HANDLE shared_heap;
|
||||
|
||||
int create_shared_heap()
|
||||
{
|
||||
shared_heap = HeapCreate(HEAP_SHARED, 0, 0x100000);
|
||||
return shared_heap ? 1 : 0;
|
||||
}
|
||||
|
||||
void destroy_shared_heap()
|
||||
{
|
||||
HeapDestroy(shared_heap);
|
||||
}
|
||||
|
||||
void* malloc(size_t size)
|
||||
{
|
||||
return HeapAlloc(shared_heap, 0, size);
|
||||
}
|
||||
|
||||
void* calloc(size_t count, size_t size)
|
||||
{
|
||||
return HeapAlloc(shared_heap, HEAP_ZERO_MEMORY, count * size);
|
||||
}
|
||||
|
||||
void free(void* ptr)
|
||||
{
|
||||
DBGASSERT(ptr == NULL || (DWORD)ptr >= 0x80000000);
|
||||
if (ptr)
|
||||
HeapFree(shared_heap, 0, ptr);
|
||||
}
|
||||
|
||||
void* realloc(void* ptr, size_t size)
|
||||
{
|
||||
DBGASSERT(ptr == NULL || (DWORD)ptr >= 0x80000000);
|
||||
if (ptr)
|
||||
return HeapReAlloc(shared_heap, 0, ptr, size);
|
||||
else
|
||||
return HeapAlloc(shared_heap, 0, size);
|
||||
}
|
||||
|
||||
void* recalloc(void* ptr, size_t size)
|
||||
{
|
||||
DBGASSERT(ptr == NULL || (DWORD)ptr >= 0x80000000);
|
||||
if (ptr)
|
||||
return HeapReAlloc(shared_heap, HEAP_ZERO_MEMORY, ptr, size);
|
||||
else
|
||||
return HeapAlloc(shared_heap, HEAP_ZERO_MEMORY, size);
|
||||
}
|
||||
|
||||
void* operator new(size_t size)
|
||||
{
|
||||
void* mem = malloc(size);
|
||||
DBGASSERT(mem);
|
||||
return mem;
|
||||
}
|
||||
|
||||
void operator delete(void* ptr)
|
||||
{
|
||||
DBGASSERT((DWORD)ptr >= 0x80000000);
|
||||
free(ptr);
|
||||
}
|
42
core/sharedmem.h
Normal file
42
core/sharedmem.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2008-2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SHAREDMEM_H
|
||||
#define __SHAREDMEM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int create_shared_heap();
|
||||
void destroy_shared_heap();
|
||||
|
||||
void* malloc(size_t size);
|
||||
void* calloc(size_t count, size_t size);
|
||||
void free(void* ptr);
|
||||
void* realloc(void* ptr, size_t size);
|
||||
void* recalloc(void* ptr, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
315
core/structs.h
Normal file
315
core/structs.h
Normal file
@ -0,0 +1,315 @@
|
||||
#ifndef __STRUCTS_H
|
||||
#define __STRUCTS_H
|
||||
|
||||
#define WIN98_K32OBJ_SEMAPHORE 0x1
|
||||
#define WIN98_K32OBJ_EVENT 0x2
|
||||
#define WIN98_K32OBJ_MUTEX 0x3
|
||||
#define WIN98_K32OBJ_CRITICAL_SECTION 0x4
|
||||
#define WIN98_K32OBJ_CHANGE 0x5
|
||||
#define WIN98_K32OBJ_PROCESS 0x6
|
||||
#define WIN98_K32OBJ_THREAD 0x7
|
||||
#define WIN98_K32OBJ_FILE 0x8
|
||||
#define WIN98_K32OBJ_CONSOLE 0x9
|
||||
#define WIN98_K32OBJ_SCREEN_BUFFER 0xA
|
||||
#define WIN98_K32OBJ_MAILSLOT 0xB
|
||||
#define WIN98_K32OBJ_SERIAL 0xC
|
||||
#define WIN98_K32OBJ_MEM_MAPPED_FILE 0xD
|
||||
#define WIN98_K32OBJ_PIPE 0xE
|
||||
#define WIN98_K32OBJ_DEVICE_IOCTL 0xF
|
||||
#define WIN98_K32OBJ_TOOLHELP_SNAPSHOT 0x10
|
||||
#define WIN98_K32OBJ_SOCKET 0x11
|
||||
|
||||
// Process Database flags (WIN95)
|
||||
#define fDebugSingle 0x00000001 // Set if process is being debugged
|
||||
#define fCreateProcessEvent 0x00000002 // Set in debugged process after starting
|
||||
#define fExitProcessEvent 0x00000004 // Might be set in debugged process at exit time
|
||||
#define fWin16Process 0x00000008 // 16-bit process
|
||||
#define fDosProcess 0x00000010 // DOS process
|
||||
#define fConsoleProcess 0x00000020 // 32-bit console process
|
||||
#define fFileApisAreOem 0x00000040 // SetFileAPIsToOEM
|
||||
#define fNukeProcess 0x00000080
|
||||
#define fServiceProcess 0x00000100 // RegisterServiceProcess
|
||||
#define fLoginScriptHack 0x00000800 // Might be a Novell network login process
|
||||
#define fSendDllNotifications 0x00200000
|
||||
#define fDebugEventPending 0x00400000 // e.g. stopped in debugger
|
||||
#define fNearlyTerminating 0x00800000
|
||||
#define fFaulted 0x08000000
|
||||
#define fTerminating 0x10000000
|
||||
#define fTerminated 0x20000000
|
||||
#define fInitError 0x40000000
|
||||
#define fSignaled 0x80000000
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
// Structured Exception Handler
|
||||
typedef struct _SEH {
|
||||
struct _SEH *pNext;
|
||||
FARPROC pfnHandler;
|
||||
} SEH, *PSEH;
|
||||
|
||||
typedef struct _HANDLE_TABLE_ENTRY {
|
||||
DWORD flags; // Valid flags depend on what type of object this is
|
||||
PVOID pObject; // Pointer to the object that the handle refers to
|
||||
} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;
|
||||
|
||||
// Handle Table
|
||||
typedef struct _HANDLE_TABLE {
|
||||
DWORD cEntries; // Max number of handles in table
|
||||
HANDLE_TABLE_ENTRY array[1]; // An array (number is given by cEntries)
|
||||
} HANDLE_TABLE, *PHANDLE_TABLE;
|
||||
|
||||
struct _PDB98;
|
||||
|
||||
// MODREF
|
||||
typedef struct _MODREF { // Size = 0x1C + 4*cImportedModules
|
||||
struct _MODREF* pNextModRef; // 00 Pointer to next process's MODREF in list
|
||||
struct _MODREF* pPrevModRef; // 04 Pointer to previous process's MODREF in list
|
||||
struct _MODREF* pNextMteMR; // 08 Next MODREF in IMTE list ??
|
||||
struct _MODREF* pPrevMteMR; // 0C Prev MODREF in IMTE list ??
|
||||
WORD mteIndex; // 10 Index to global array of pointers to IMTEs
|
||||
WORD cUsage; // 12 ref count
|
||||
WORD flags; // 14 flags
|
||||
WORD cImportedModules; // 16 Number of modules imported implicitly
|
||||
struct _PDB98* ppdb; // 18 Pointer to process database
|
||||
union { // 1C
|
||||
PSTR pszModuleName;
|
||||
struct _MODREF* pMR;
|
||||
} ImplicitImports[1]; // * cImportedModules
|
||||
} MODREF, *PMODREF;
|
||||
|
||||
// IMTE
|
||||
typedef struct _IMTE { // Size = 0x3C
|
||||
DWORD unknown1; // 00
|
||||
IMAGE_NT_HEADERS* pNTHdr; // 04 pointer to shared PE header for module
|
||||
DWORD unknown2; // 08
|
||||
PSTR pszFileName; // 0C long path name
|
||||
PSTR pszModName; // 10 long module name
|
||||
WORD cbFileName; // 14 long path name length
|
||||
WORD cbModName; // 16 long module name length
|
||||
DWORD unknown3; // 18
|
||||
DWORD cSections; // 1C number of sections in the module
|
||||
DWORD unknown4; // 20
|
||||
DWORD baseAddress; // 24 module base address before relocation
|
||||
WORD hModule16; // 28 16-bit selector to NE header
|
||||
WORD cUsage; // 2A usage count
|
||||
PMODREF pMR; // 2C pointer to MODREF structure
|
||||
PSTR pszSFileName; // 30 short path name
|
||||
WORD cbSFileName; // 34 short path name length
|
||||
PSTR pszSModName; // 36 short module name
|
||||
WORD cbSModName; // 3A short module name length
|
||||
} IMTE, *PIMTE;
|
||||
|
||||
// Environment Database
|
||||
typedef struct _ENVIRONMENT_DATABASE {
|
||||
PSTR pszEnvironment; //00 Pointer to Process Environment
|
||||
DWORD un1; //04 (always 0)
|
||||
PSTR pszCmdLine; //08 Pointer to command line
|
||||
PSTR pszCurrDirectory; //0C Pointer to current directory
|
||||
LPSTARTUPINFOA pStartupInfo; //10 Pointer to STARTUPINFOA struct
|
||||
HANDLE hStdIn; //14 Standard Input handle
|
||||
HANDLE hStdOut; //18 Standard Output handle
|
||||
HANDLE hStdErr; //1C Standard Error handle
|
||||
DWORD un2; //20 (always 1)
|
||||
DWORD InheritConsole; //24 Inherit console from parent
|
||||
DWORD BreakType; //28 Handle console events (like CTRL+C)
|
||||
DWORD BreakSem; //2C Pointer to K32OBJ_SEMAPHORE
|
||||
DWORD BreakEvent; //30 Pointer to K32OBJ_EVENT
|
||||
DWORD BreakThreadID; //34 Pointer to K32OBJ_THREAD
|
||||
DWORD BreakHandlers; //38 Pointer to list of installed console control handlers
|
||||
} EDB, *PEDB;
|
||||
|
||||
// Process Database
|
||||
typedef struct _PDB98 { // Size = 0xC4 (from Kernel32)
|
||||
BYTE Type; // 00 Kernel object type = K32OBJ_PROCESS (6)
|
||||
BYTE Unknown_A; // 01 (align ?)
|
||||
WORD cReference; // 02 Number of references to process
|
||||
DWORD Unknown_B; // 04 Pointer to ???
|
||||
DWORD Unknown1; // 08 (zero)
|
||||
DWORD pEvent; // 0C Event for process waiting
|
||||
DWORD TerminationStatus; // 10 GetExitCodeProcess
|
||||
DWORD Unknown2; // 14 May be used for private purposes
|
||||
HANDLE DefaultHeap; // 18 GetProcessHeap
|
||||
PCONTEXT MemoryContext; // 1C Pointer to process context
|
||||
DWORD Flags; // 20 Flags
|
||||
DWORD pPSP; // 24 Linear address of DOS PSP
|
||||
WORD PSPSelector; // 28 Selector to DOS PSP
|
||||
WORD MTEIndex; // 2A Index into global module table
|
||||
WORD cThreads; // 2C Threads.ItemCount
|
||||
WORD cNotTermThreads; // 2E Threads.ItemCount
|
||||
WORD Unknown3; // 30 (zero)
|
||||
WORD cRing0Threads; // 32 Normally Threads.ItemCount (except kernel32)
|
||||
HANDLE HeapHandle; // 34 Kernel32 shared heap
|
||||
DWORD w16TDB; // 38 Win16 task database selector
|
||||
DWORD MemMappedFiles; // 3C List of memory mapped files
|
||||
PEDB pEDB; // 40 Pointer to Environment Database
|
||||
PHANDLE_TABLE pHandleTable; // 44 Pointer to Handle Table
|
||||
struct _PDB98* ParentPDB; // 48 Pointer to parent process (PDB)
|
||||
PMODREF MODREFList; // 4C Pointer to list of modules
|
||||
DWORD ThreadList; // 50 Pointer to list of threads
|
||||
DWORD DebuggeeCB; // 54 Debuggee context block
|
||||
DWORD LocalHeapFreeHead; // 58 Free list for process default heap
|
||||
DWORD InitialRing0ID; // 5C Meaning unknown
|
||||
CRITICAL_SECTION CriticalSection; // 60 For synchronizing threads
|
||||
DWORD Unknown4[3]; // 78
|
||||
DWORD pConsole; // 84 Output console
|
||||
DWORD tlsInUseBits1; // 88 Status of TLS indexes 0 - 31
|
||||
DWORD tlsInUseBits2; // 8C Status of TLS indexes 32 - 63
|
||||
DWORD ProcessDWORD; // 90 Undocumented API GetProcessDword, meaning unknown
|
||||
struct _PDB98* ProcessGroup; // 94 Master process PDB (in debugging)
|
||||
PMODREF pExeMODREF; // 98 Points to exe's module structure
|
||||
DWORD TopExcFilter; // 9C SetUnhandledExceptionFilter
|
||||
DWORD PriorityClass; // A0 PriorityClass (8 = NORMAL)
|
||||
DWORD HeapList; // A4 List of heaps
|
||||
DWORD HeapHandleList; // A8 List of moveable memory blocks
|
||||
DWORD HeapPointer; // AC Pointer to one moveable memory block, meaning unknown
|
||||
DWORD pConsoleProvider; // B0 Console for DOS apps
|
||||
WORD EnvironSelector; // B4 Environment database selector
|
||||
WORD ErrorMode; // B6 SetErrorMode
|
||||
DWORD pEventLoadFinished; // B8 Signaled when the process has finished loading
|
||||
WORD UTState; // BC Universal thunking, meaning unknown
|
||||
WORD Unknown5; // BE (zero)
|
||||
DWORD Unknown6; // C0
|
||||
} PDB98, *PPDB98;
|
||||
|
||||
// Process Database
|
||||
typedef struct _PDBME { // Size = 0xC4 (from Kernel32)
|
||||
BYTE Type; // 00 Kernel object type = K32OBJ_PROCESS (6)
|
||||
BYTE Unknown_A; // 01 (align ?)
|
||||
WORD cReference; // 02 Number of references to process
|
||||
DWORD Unknown_B; // 04 Pointer to ???
|
||||
DWORD Unknown1; // 08 (zero)
|
||||
DWORD pEvent; // 0C Event for process waiting
|
||||
DWORD TerminationStatus; // 10 GetExitCodeProcess
|
||||
DWORD Unknown2; // 14 May be used for private purposes
|
||||
DWORD DefaultHeap; // 18 GetProcessHeap
|
||||
DWORD MemoryContext; // 1C Pointer to process context
|
||||
DWORD Flags; // 20 Flags
|
||||
DWORD pPSP; // 24 Linear address of DOS PSP
|
||||
WORD PSPSelector; // 28 Selector to DOS PSP
|
||||
WORD MTEIndex; // 2A Index into global module table
|
||||
WORD cThreads; // 2C Threads.ItemCount
|
||||
WORD cNotTermThreads; // 2E Threads.ItemCount
|
||||
WORD Unknown3; // 30 (zero)
|
||||
WORD cRing0Threads; // 32 Normally Threads.ItemCount (except kernel32)
|
||||
HANDLE HeapHandle; // 34 Kernel32 shared heap
|
||||
DWORD w16TDB; // 38 Win16 task database selector
|
||||
DWORD MemMappedFiles; // 3C List of memory mapped files
|
||||
PEDB pEDB; // 40 Pointer to Environment Database
|
||||
PHANDLE_TABLE pHandleTable; // 44 Pointer to Handle Table
|
||||
struct _PDBME* ParentPDB; // 48 Pointer to parent process (PDB)
|
||||
PMODREF MODREFList; // 4C Pointer to list of modules
|
||||
DWORD ThreadList; // 50 Pointer to list of threads
|
||||
DWORD DebuggeeCB; // 54 Debuggee context block
|
||||
DWORD LocalHeapFreeHead; // 58 Free list for process default heap
|
||||
DWORD InitialRing0ID; // 5C Meaning unknown
|
||||
CRITICAL_SECTION CriticalSection; // 60 For synchronizing threads
|
||||
DWORD Unknown4[2]; // 78
|
||||
DWORD pConsole; // 80 Output console
|
||||
DWORD tlsInUseBits1; // 84 Status of TLS indexes 0 - 31
|
||||
DWORD tlsInUseBits2; // 88 Status of TLS indexes 32 - 63
|
||||
DWORD ProcessDWORD; // 8C Undocumented API GetProcessDword, meaning unknown
|
||||
DWORD Unknown_C; // 90 Unknown
|
||||
struct _PDBME* ProcessGroup; // 94 Master process PDB (in debugging)
|
||||
PMODREF pExeMODREF; // 98 Points to exe's module structure
|
||||
DWORD TopExcFilter; // 9C SetUnhandledExceptionFilter
|
||||
DWORD PriorityClass; // A0 PriorityClass (8 = NORMAL)
|
||||
DWORD HeapList; // A4 List of heaps
|
||||
DWORD HeapHandleList; // A8 List of moveable memory blocks
|
||||
DWORD HeapPointer; // AC Pointer to one moveable memory block, meaning unknown
|
||||
DWORD pConsoleProvider; // B0 Console for DOS apps
|
||||
WORD EnvironSelector; // B4 Environment database selector
|
||||
WORD ErrorMode; // B6 SetErrorMode
|
||||
DWORD pEventLoadFinished; // B8 Signaled when the process has finished loading
|
||||
WORD UTState; // BC Universal thunking, meaning unknown
|
||||
WORD Unknown5; // BE (zero)
|
||||
DWORD Unknown6; // C0
|
||||
} PDBME, *PPDBME;
|
||||
|
||||
// Thread Information Block (FS:[0x18])
|
||||
typedef struct _TIB98 { // Size = 0x38
|
||||
PSEH pvExcept; // 00 Head of exception record list
|
||||
PVOID pvStackUserTop; // 04 Top of user stack
|
||||
PVOID pvStackUserBase; // 08 Base of user stack
|
||||
WORD pvTDB; // 0C Ptr to win-16 task database
|
||||
WORD pvThunksSS; // 0E SS selector used for thunking to 16 bits
|
||||
DWORD SelmanList; // 10 Pointer to selector manager list
|
||||
PVOID pvArbitrary; // 14 Available for application use
|
||||
struct _TIB98 *pTIBSelf; // 18 Linear address of TIB structure
|
||||
WORD TIBFlags; // 1C TIBF_WIN32 = 1, TIBF_TRAP = 2
|
||||
WORD Win16MutexCount; // 1E Win16Lock
|
||||
DWORD DebugContext; // 20 Pointer to debug context structure
|
||||
DWORD pCurrentPriority; // 24 Pointer to DWORD containing current priority level
|
||||
DWORD pvQueue; // 28 Message Queue selector
|
||||
PVOID *pvTLSArray; // 2C Thread Local Storage (TLS) array
|
||||
PVOID *pProcess; // 30 Pointer to owning process database (PDB)
|
||||
DWORD Unknown; // 34 Pointer to ???
|
||||
} TIB98, *PTIB98;
|
||||
|
||||
typedef struct _TDBX98 TDBX98;
|
||||
|
||||
// Thread database (FS:[0x18] - 0x8)
|
||||
typedef struct _TDB98 { // Size = 0x228 (from Kernel32)
|
||||
WORD Type; // 00 K32 object type
|
||||
WORD cReference; // 02 Reference count
|
||||
DWORD pSomeEvent; // 04 K32 event object used when someone waits on the thread object
|
||||
TIB98 tib; // 08 Thread information block (TIB)
|
||||
DWORD Unknown; // 40
|
||||
DWORD Flags; // 44 Flags
|
||||
DWORD TerminationStatus; // 48 Exit code
|
||||
WORD TIBSelector; // 4C Selector used in FS to point to TIB
|
||||
WORD EmulatorSelector; // 4E Memory block for saving x87 state
|
||||
DWORD cHandles; // 50 Handle count
|
||||
DWORD Ring0Thread; // 54 R0 thread control block (TCB)
|
||||
TDBX98 *pTDBX; // 58 R0 thread database extension (TDBX)
|
||||
DWORD un1[109]; // 5C
|
||||
DWORD APISuspendCount; // 210 Count of SuspendThread's minus ResumeThread's
|
||||
} TDB98, *PTDB98;
|
||||
|
||||
typedef struct _TDBME { // Size = 0x228 (from Kernel32)
|
||||
WORD Type; // 00 K32 object type
|
||||
WORD cReference; // 02 Reference count
|
||||
DWORD pSomeEvent; // 04 K32 event object used when someone waits on the thread object
|
||||
TIB98 tib; // 08 Thread information block (TIB)
|
||||
DWORD Unknown; // 40
|
||||
DWORD Unknown2; // 44
|
||||
WORD TIBSelector; // 46 Selector used in FS to point to TIB
|
||||
DWORD TerminationStatus; // 48 Exit code
|
||||
DWORD Flags; // 4C Flags
|
||||
DWORD cHandles; // 50 Handle count
|
||||
DWORD Ring0Thread; // 54 R0 thread control block (TCB)
|
||||
DWORD Unknown3; // 58 Selector for ???
|
||||
DWORD un1[11]; // 5C
|
||||
TDBX98 *pTDBX; // 88
|
||||
DWORD un2[97]; // 8C
|
||||
DWORD APISuspendCount; // 210 Count of SuspendThread's minus ResumeThread's
|
||||
} TDBME, *PTDBME;
|
||||
|
||||
// Thread database extension
|
||||
typedef struct _TDBX98 {
|
||||
DWORD un0; // 00
|
||||
TDB98 *ptdb; // 04 R3 thread database
|
||||
PDB98 *ppdb; // 08 R3 process database
|
||||
DWORD ContextHandle; // 0C R0 memory context
|
||||
DWORD Ring0Thread; // 10 R0 thread control block [TCB *]
|
||||
DWORD WaitNodeList; // 14 Anchor of things we're waiting on [WAITNODE *]
|
||||
DWORD WaitFlags; // 18 Blocking flags
|
||||
DWORD un1; // 1C
|
||||
DWORD TimeOutHandle; // 20
|
||||
DWORD WakeParam; // 24
|
||||
DWORD BlockHandle; // 28 R0 semaphore on which thread will wait inside VWIN32
|
||||
DWORD BlockState; // 2C
|
||||
DWORD SuspendCount; // 30
|
||||
DWORD SuspendHandle; // 34
|
||||
DWORD MustCompleteCount; // 38 Count of EnterMustComplete's minus LeaveMustComplete's
|
||||
DWORD WaitExFlags; // 3C Flags
|
||||
DWORD SyncWaitCount; // 40
|
||||
DWORD QueuedSyncFuncs; // 44
|
||||
DWORD UserAPCList; // 48
|
||||
DWORD KernAPCList; // 4C
|
||||
DWORD pPMPSPSelector; // 50
|
||||
DWORD BlockedOnID; // 54
|
||||
} TDBX98, *PTDBX98;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
106
core/thunks.cpp
Normal file
106
core/thunks.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2008-2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include "thunks.h"
|
||||
#include "internals.h"
|
||||
#include "resolver.h"
|
||||
|
||||
__declspec(naked)
|
||||
PROC ExportFromOrdinalStatic_thunk(IMAGE_NT_HEADERS* PEh, WORD ordinal)
|
||||
{
|
||||
__asm {
|
||||
mov eax, [ebp-4Ch] //tested w98fe 1998, w98se 2222, w98se 2226, wme 3000
|
||||
mov ecx, [eax]
|
||||
mov ax, [ecx+10h]
|
||||
movzx eax, ax
|
||||
mov edx, ppmteModTable
|
||||
mov edx, [edx]
|
||||
mov eax, [edx+4*eax]
|
||||
push eax //target IMTE
|
||||
push dword ptr [esp+4] //return address
|
||||
mov eax, [ebp+8]
|
||||
mov [esp+8], eax //caller MODREF
|
||||
lea eax, [ebp-4Ch]
|
||||
mov dword ptr [esp+12], eax
|
||||
jmp ExportFromOrdinal
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked)
|
||||
PROC ExportFromNameStatic_thunk(IMAGE_NT_HEADERS* PEh, WORD hint, LPCSTR name)
|
||||
{
|
||||
__asm {
|
||||
mov eax, [ebp-4Ch] //tested w98fe 1998, w98se 2222, w98se 2226, wme 3000
|
||||
mov ecx, [eax]
|
||||
mov ax, [ecx+10h]
|
||||
movzx eax, ax
|
||||
mov edx, ppmteModTable
|
||||
mov edx, [edx]
|
||||
mov eax, [edx+4*eax]
|
||||
push eax //target IMTE
|
||||
push dword ptr [esp+4] //return address
|
||||
mov eax, [ebp+8]
|
||||
mov [esp+8], eax //caller MODREF
|
||||
lea eax, [ebp-4Ch]
|
||||
mov dword ptr [esp+12], eax
|
||||
jmp ExportFromName
|
||||
}
|
||||
}
|
||||
|
||||
/* stack on entry:
|
||||
* ret_addr
|
||||
* PEh
|
||||
* ordinal
|
||||
* edi
|
||||
* esi
|
||||
* ebx
|
||||
* caller_addr
|
||||
*/
|
||||
__declspec(naked)
|
||||
PROC ExportFromOrdinalDynamic_thunk(IMAGE_NT_HEADERS* PEh, WORD ordinal)
|
||||
{
|
||||
__asm {
|
||||
push edx //target IMTE
|
||||
push dword ptr [esp+4]
|
||||
push dword ptr [esp+20h] //tested w98se 2225
|
||||
call MRfromCallerAddr
|
||||
add esp, 4
|
||||
mov [esp+8], eax //caller MODREF
|
||||
mov dword ptr [esp+12], 0
|
||||
jmp ExportFromOrdinal
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked)
|
||||
PROC ExportFromNameDynamic_thunk(IMAGE_NT_HEADERS* PEh, WORD hint, LPCSTR name)
|
||||
{
|
||||
__asm {
|
||||
push edx //target IMTE
|
||||
push dword ptr [esp+4]
|
||||
push dword ptr [esp+24h] //tested w98se 2225
|
||||
call MRfromCallerAddr
|
||||
add esp, 4
|
||||
mov [esp+8], eax //caller MODREF
|
||||
mov dword ptr [esp+12], 0
|
||||
jmp ExportFromName
|
||||
}
|
||||
}
|
30
core/thunks.h
Normal file
30
core/thunks.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2008-2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __THUNKS_H
|
||||
#define __THUNKS_H
|
||||
|
||||
PROC ExportFromOrdinalStatic_thunk(IMAGE_NT_HEADERS* PEh, WORD ordinal);
|
||||
PROC ExportFromNameStatic_thunk(IMAGE_NT_HEADERS* PEh, WORD hint, LPCSTR name);
|
||||
PROC ExportFromOrdinalDynamic_thunk(IMAGE_NT_HEADERS* PEh, WORD ordinal);
|
||||
PROC ExportFromNameDynamic_thunk(IMAGE_NT_HEADERS* PEh, WORD hint, LPCSTR name);
|
||||
|
||||
#endif
|
29
core/version.h
Normal file
29
core/version.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* KernelEx
|
||||
* Copyright (C) 2009, Xeno86
|
||||
*
|
||||
* This file is part of KernelEx source code.
|
||||
*
|
||||
* KernelEx 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; version 2 of the License.
|
||||
*
|
||||
* KernelEx 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 GNU Make; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __VERSION_H
|
||||
#define __VERSION_H
|
||||
|
||||
#define VERSION_STR "4.0 RC 1"
|
||||
#define VERSION_CODE 0x0400000B
|
||||
#define RCVERSION 4, 0, 1, 0
|
||||
|
||||
#endif
|
37
core/wildcmp.cpp
Normal file
37
core/wildcmp.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
//public domain wildcard match function by Jack Handy
|
||||
#include "wildcmp.h"
|
||||
|
||||
int wildcmp(const char *wild, const char *string) {
|
||||
const char *cp = 0, *mp = 0;
|
||||
while ((*string) && (*wild != '*')) {
|
||||
if ((*wild != *string) && (*wild != '?')) {
|
||||
return 0;
|
||||
}
|
||||
wild++;
|
||||
string++;
|
||||
}
|
||||
|
||||
while (*string) {
|
||||
if (*wild == '*') {
|
||||
if (!*++wild) {
|
||||
return 1;
|
||||
}
|
||||
mp = wild;
|
||||
cp = string+1;
|
||||
} else if ((*wild == *string) || (*wild == '?')) {
|
||||
wild++;
|
||||
string++;
|
||||
} else {
|
||||
if (!cp || !mp)
|
||||
return 0;
|
||||
wild = mp;
|
||||
string = cp++;
|
||||
}
|
||||
}
|
||||
|
||||
while (*wild == '*') {
|
||||
wild++;
|
||||
}
|
||||
|
||||
return !*wild;
|
||||
}
|
6
core/wildcmp.h
Normal file
6
core/wildcmp.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef __WILDCMP_H
|
||||
#define __WILDCMP_H
|
||||
|
||||
int wildcmp(const char*, const char*);
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user