1
0
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:
UzixLS
2018-11-03 16:18:57 +03:00
commit d4e0420295
295 changed files with 28034 additions and 0 deletions

131
core/Core.rc Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,6 @@
#ifndef __WILDCMP_H
#define __WILDCMP_H
int wildcmp(const char*, const char*);
#endif