mirror of
https://github.com/UzixLS/KernelEx.git
synced 2025-07-18 23:11:19 +03:00
816 lines
21 KiB
C++
Executable File
816 lines
21 KiB
C++
Executable File
/*
|
|
* 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"
|
|
#include "ModInit.h"
|
|
#ifdef _DEBUG
|
|
#include "apilog.h"
|
|
#endif
|
|
|
|
using namespace std;
|
|
|
|
char system_path[MAX_PATH];
|
|
int system_path_len;
|
|
|
|
static PLONG jtab;
|
|
static LONG old_jtab[JTAB_SIZE];
|
|
static HKEY known_dlls_key;
|
|
|
|
FLoadTreeNotify_t FLoadTreeNotify;
|
|
|
|
|
|
/** Get API configuration for selected module.
|
|
* @param module Target module.
|
|
* @param cp Value receives configuration information for extended API.
|
|
* @return True to use extended API, false use standard API.
|
|
*/
|
|
static bool get_config(MODREF* moduleMR, config_params& cp)
|
|
{
|
|
IMTE** pmteModTable = *ppmteModTable;
|
|
PDB98* ppdbCur = *pppdbCur;
|
|
volatile MODREF_KEX module(moduleMR);
|
|
MODREF_KEX process(ppdbCur->pExeMODREF);
|
|
|
|
//shared modules should use standard api
|
|
if (IS_SHARED(pmteModTable[module.mr.mteIndex]->baseAddress))
|
|
return false;
|
|
|
|
//if settings are already known, exit immediatelly
|
|
if (module.as.flags & LDR_VALID_FLAG)
|
|
goto __end;
|
|
|
|
//we need process settings to know if process.LDR_OVERRIDE_PROC_MOD is set
|
|
if (!(process.as.flags & LDR_VALID_FLAG))
|
|
{
|
|
//try to take settings from database...
|
|
pmteModTable = *ppmteModTable;
|
|
process.as = SettingsDB::instance
|
|
.get_appsetting(pmteModTable[process.mr.mteIndex]->pszFileName);
|
|
|
|
//...if settings are not there, take them from parent process...
|
|
if (!(process.as.flags & LDR_VALID_FLAG))
|
|
{
|
|
PDB98* ppdbParent = ppdbCur->ParentPDB;
|
|
|
|
//...IF there is parent process and...
|
|
if (ppdbParent && !(ppdbParent->Flags & (fTerminated | fTerminating |
|
|
fNearlyTerminating | fDosProcess | fWin16Process)))
|
|
{
|
|
MODREF_KEX parent(ppdbParent->pExeMODREF);
|
|
|
|
//...unless parent disallows us to inherit them
|
|
if ((parent.as.flags & LDR_VALID_FLAG) && !(parent.as.flags & LDR_NO_INHERIT))
|
|
{
|
|
process.as = parent.as;
|
|
#ifdef _DEBUG //don't inherit log flag
|
|
process.as.flags &= ~LDR_LOG_APIS;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//at this point we know whether override is enabled or not
|
|
if ((process.as.flags & LDR_VALID_FLAG))
|
|
{
|
|
//if it is then take process settings
|
|
if (process.as.flags & LDR_OVERRIDE_PROC_MOD)
|
|
{
|
|
module.as = process.as;
|
|
goto __end;
|
|
}
|
|
}
|
|
//if process still doesn't have settings, set some reasonable defaults
|
|
else
|
|
{
|
|
if (apiconfmgr.are_extensions_disabled())
|
|
{
|
|
process.as.flags = LDR_VALID_FLAG | LDR_KEX_DISABLE;
|
|
}
|
|
else
|
|
{
|
|
process.as.conf = apiconfmgr.get_default_configuration();
|
|
process.as.flags = LDR_VALID_FLAG;
|
|
}
|
|
}
|
|
|
|
//if module == process then we've already got everything we need
|
|
if (&module.as == &process.as)
|
|
goto __end;
|
|
|
|
//lookup module settings in database
|
|
pmteModTable = *ppmteModTable;
|
|
module.as = SettingsDB::instance
|
|
.get_appsetting(pmteModTable[module.mr.mteIndex]->pszFileName);
|
|
|
|
if (module.as.flags & LDR_VALID_FLAG)
|
|
{
|
|
#ifdef _DEBUG //copy log flag from process to module
|
|
if (process.as.flags & LDR_LOG_APIS)
|
|
module.as.flags |= LDR_LOG_APIS;
|
|
#endif
|
|
goto __end;
|
|
}
|
|
|
|
//if module has no settings, take them from process
|
|
module.as = process.as;
|
|
|
|
__end:
|
|
DBGASSERT(module.as.flags & LDR_VALID_FLAG);
|
|
if (module.as.flags & LDR_KEX_DISABLE)
|
|
return false;
|
|
|
|
DBGASSERT(module.as.conf != NULL);
|
|
cp.apiconf = module.as.conf;
|
|
#ifdef _DEBUG
|
|
cp.log_apis = (module.as.flags & LDR_LOG_APIS) != 0;
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
/** 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;
|
|
}
|
|
|
|
/** Resolves address where target function is in non-shared api library.
|
|
* Checks if api library is loaded for process, if it isn't it is loaded.
|
|
* Code executes either under process CS (dynamic resolve) or system CS
|
|
* (static resolve).
|
|
* @param addr Encoded api library ID + offset in this api library
|
|
* @param caller Module that requests api from api library.
|
|
* @param is_static True if implicit (static), false if explicit (GetProcAddress) resolve
|
|
* @return Valid address to function for calling process.
|
|
*/
|
|
static PROC resolve_nonshared_addr(DWORD addr, MODREF* caller, BOOL is_static)
|
|
{
|
|
MODREF* mr;
|
|
WORD idx;
|
|
DWORD img_base;
|
|
int api_lib_num;
|
|
char dllpath[MAX_PATH];
|
|
ApiLibrary* apilib;
|
|
IMTE** pmteModTable = *ppmteModTable;
|
|
ModuleInitializer* mi = ModuleInitializer::get_instance(true);
|
|
|
|
api_lib_num = (addr >> 24) - 0xc0;
|
|
DBGASSERT(api_lib_num > 0); //ensure apilib ID isn't STD's
|
|
apilib = apilibmgr.get_apilib_by_index(api_lib_num);
|
|
DBGASSERT(apilib != NULL);
|
|
DBGASSERT(!apilib->is_shared());
|
|
idx = 0xff00 + api_lib_num;
|
|
|
|
//first check if api library has already been loaded
|
|
img_base = mi->get_handle_for_index(idx);
|
|
if (img_base != 0)
|
|
return (PROC)(img_base + (addr & 0x00ffffff));
|
|
|
|
//if not - load it
|
|
|
|
DBGPRINTF(("Loading non-shared apilib: %s req. by: %s [PID=%08x]\n",
|
|
apilib->apilib_name, pmteModTable[caller->mteIndex]->pszModName,
|
|
GetCurrentProcessId()));
|
|
|
|
apilib->get_dll_path(dllpath);
|
|
|
|
_EnterSysLevel(krnl32lock);
|
|
mr = MRLoadTree(dllpath);
|
|
if (!mr)
|
|
{
|
|
FreeLibRemove();
|
|
_LeaveSysLevel(krnl32lock);
|
|
return 0;
|
|
}
|
|
mi->add_module(mr);
|
|
_LeaveSysLevel(krnl32lock);
|
|
|
|
if (!is_static)
|
|
{
|
|
DBGPRINTF(("Explicit load: initializing tree %s [PID=%08x]\n",
|
|
apilib->apilib_name, GetCurrentProcessId()));
|
|
|
|
if (FLoadTreeNotify(mr, FALSE))
|
|
{
|
|
FreeLibTree(mr);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
pmteModTable = *ppmteModTable;
|
|
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));
|
|
}
|
|
|
|
/** Performs resolver actions on new process attach.
|
|
* @return TRUE on success, FALSE otherwise.
|
|
*/
|
|
BOOL resolver_process_attach()
|
|
{
|
|
//reference all shared api libraries
|
|
ApiLibrary* lib;
|
|
int i = 1;
|
|
while ((lib = apilibmgr.get_apilib_by_index(i++)) != NULL)
|
|
{
|
|
if (lib->is_shared())
|
|
{
|
|
char dllpath[MAX_PATH];
|
|
lib->get_dll_path(dllpath);
|
|
if (!LoadLibrary(dllpath))
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/** Original ExportFromOrdinal function. @see ExportFromOrdinal */
|
|
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;
|
|
}
|
|
|
|
/** Original ExportFromName function. @see ExportFromName */
|
|
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;
|
|
}
|
|
|
|
/** Encode function pointer + API library information into single dword.
|
|
* @see decode_address
|
|
* @param addr Absolute address.
|
|
* @param apilib Pointer to API library.
|
|
* @return Encoded pointer.
|
|
*/
|
|
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)
|
|
{
|
|
//normal address (shared or nonshared library)
|
|
//or ordinal number for export forwarding
|
|
if (addr < 0xc0000000 || addr >= 0xffff0000)
|
|
return addr;
|
|
|
|
//extremely rare scenario: driver hijacked apis so the address is now
|
|
//above 0xc0000000 and we use these for encoded apilib addresses
|
|
//so we have to create a stub in shared arena with proper address
|
|
return (DWORD) new redir_stub(addr, false);
|
|
}
|
|
|
|
//non-shared apilib
|
|
if (!apilib->is_shared())
|
|
{
|
|
//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;
|
|
}
|
|
|
|
/** Decodes pointers created with encode_address.
|
|
* @see encode_address
|
|
* @param p Encoded pointer.
|
|
* @param target_NThdr Target module NT header.
|
|
* @param caller Calling module ref.
|
|
* @param is_static True if implicit resolve, false if explicit.
|
|
* @return Decoded function pointer.
|
|
*/
|
|
inline PROC decode_address(DWORD p, IMAGE_NT_HEADERS* target_NThdr, MODREF* caller, BOOL is_static)
|
|
{
|
|
//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 (!IS_SHARED(p))
|
|
return (PROC)(p + target_NThdr->OptionalHeader.ImageBase);
|
|
//non-shared api library
|
|
if (p >= 0xc0000000)
|
|
return resolve_nonshared_addr(p, caller, is_static);
|
|
//shared system or api library
|
|
return (PROC) p;
|
|
}
|
|
|
|
/** Performs function resolve by ordinal number.
|
|
* @param target Target module, module from which we want function.
|
|
* @param caller Calling module, module which wants function.
|
|
* @param is_static True if static resolve, false if dynamic.
|
|
* @param ordinal Function ordinal number.
|
|
* @return Function pointer.
|
|
*/
|
|
PROC WINAPI ExportFromOrdinal(IMTE_KEX* target, MODREF* caller, BOOL is_static, WORD ordinal)
|
|
{
|
|
PROC ret;
|
|
|
|
//if caller is unknown - assume it is process's exe
|
|
if (!caller)
|
|
caller = (*pppdbCur)->pExeMODREF;
|
|
|
|
config_params cp;
|
|
if (get_config(caller, cp))
|
|
{
|
|
WORD mod_index = target->mod_index;
|
|
|
|
if (!mod_index)
|
|
mod_index = resolve_mod_index(target);
|
|
|
|
DBGASSERT(mod_index);
|
|
mod_index--;
|
|
|
|
if (!cp.apiconf->is_table_empty(mod_index))
|
|
ret = decode_address(cp.apiconf->get(mod_index, ordinal),
|
|
target->pNTHdr, caller, is_static);
|
|
else
|
|
ret = OriExportFromOrdinal(target->pNTHdr, ordinal);
|
|
#ifdef _DEBUG
|
|
if (ret && cp.log_apis)
|
|
{
|
|
IMTE* icaller = (*ppmteModTable)[caller->mteIndex];
|
|
if (DWORD(ret) < target->pNTHdr->OptionalHeader.ImageBase
|
|
+ target->pNTHdr->OptionalHeader.BaseOfData)
|
|
ret = create_log_stub(icaller->pszModName, target->pszModName, ordinal, ret);
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
ret = OriExportFromOrdinal(target->pNTHdr, ordinal);
|
|
|
|
if (!ret && is_static)
|
|
{
|
|
DBGPRINTF(("%s: unresolved export %s:%d\n",
|
|
((*ppmteModTable)[caller->mteIndex])->pszModName,
|
|
target->pszModName, ordinal));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/** Performs function resolve by name.
|
|
* @param target Target module, module from which we want function.
|
|
* @param caller Calling module, module which wants function.
|
|
* @param is_static True if static resolve, false if dynamic.
|
|
* @param hint Hint number, tells resolver where to start search.
|
|
* @param name Function name.
|
|
* @return Function pointer.
|
|
*/
|
|
PROC WINAPI ExportFromName(IMTE_KEX* target, MODREF* caller, BOOL is_static, WORD hint, LPCSTR name)
|
|
{
|
|
PROC ret;
|
|
|
|
//if caller is unknown - assume it is process's exe
|
|
if (!caller)
|
|
caller = (*pppdbCur)->pExeMODREF;
|
|
|
|
config_params cp;
|
|
if (get_config(caller, cp))
|
|
{
|
|
WORD mod_index = target->mod_index;
|
|
|
|
if (!mod_index)
|
|
mod_index = resolve_mod_index(target);
|
|
|
|
DBGASSERT(mod_index);
|
|
mod_index--;
|
|
|
|
if (!cp.apiconf->is_table_empty(mod_index))
|
|
ret = decode_address(cp.apiconf->get(mod_index, hint, name),
|
|
target->pNTHdr, caller, is_static);
|
|
else
|
|
ret = OriExportFromName(target->pNTHdr, hint, name);
|
|
#ifdef _DEBUG
|
|
if (ret && cp.log_apis)
|
|
{
|
|
IMTE* icaller = (*ppmteModTable)[caller->mteIndex];
|
|
if (DWORD(ret) < target->pNTHdr->OptionalHeader.ImageBase
|
|
+ target->pNTHdr->OptionalHeader.BaseOfData)
|
|
ret = create_log_stub(icaller->pszModName, target->pszModName, name, ret);
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
ret = OriExportFromName(target->pNTHdr, hint, name);
|
|
|
|
if (!ret && is_static)
|
|
{
|
|
DBGPRINTF(("%s: unresolved export %s:%s\n",
|
|
((*ppmteModTable)[caller->mteIndex])->pszModName,
|
|
target->pszModName, name));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/** Determines whether process has API extensions enabled. */
|
|
bool are_extensions_enabled()
|
|
{
|
|
config_params cp;
|
|
MODREF* exe = (*pppdbCur)->pExeMODREF;
|
|
DBGASSERT(exe != NULL);
|
|
return get_config(exe, cp);
|
|
}
|
|
|
|
typedef BOOL (__stdcall *IsKnownDLL_t)(char*, const char*);
|
|
|
|
static BOOL WINAPI IsKnownKexDLL(char* name, const char* ext)
|
|
{
|
|
LONG res;
|
|
DWORD type;
|
|
char path[MAX_PATH];
|
|
DWORD size = sizeof(path);
|
|
|
|
if (ext && strcmp(ext, "DLL") != 0)
|
|
return FALSE;
|
|
|
|
if ((*pppdbCur)->pExeMODREF == NULL)
|
|
return FALSE;
|
|
|
|
if (are_extensions_enabled())
|
|
{
|
|
//workaround windows bug
|
|
int pos = strlen(name) - 4;
|
|
if (pos > 0 && name[pos] == '.')
|
|
name[pos] = '\0';
|
|
|
|
res = RegQueryValueEx(known_dlls_key, name, NULL, &type, (BYTE*) path, &size);
|
|
}
|
|
else
|
|
res = ERROR_INVALID_FUNCTION;
|
|
|
|
if (res == ERROR_SUCCESS && type == REG_SZ)
|
|
{
|
|
memcpy(name, (const char*) kernelex_dir, kernelex_dir.length());
|
|
memcpy(name + kernelex_dir.length(), path, size);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
IsKnownDLL_t IsKnownDLL = (IsKnownDLL_t) old_jtab[JTAB_KNO_DLL];
|
|
return IsKnownDLL(name, NULL);
|
|
}
|
|
}
|
|
|
|
static BOOL WINAPI KexLoadTreeNotify(MODREF* mr, BOOL is_static)
|
|
{
|
|
ModuleInitializer* mi = ModuleInitializer::get_instance(false);
|
|
if (mi && mi->has_initialize() && !mi->initialize_modules())
|
|
return TRUE;
|
|
|
|
return FLoadTreeNotify(mr, is_static);
|
|
}
|
|
|
|
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, LOWORD(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->mod_index = 0;
|
|
for (MODREF* mr = imte->pMR ; mr != NULL ; mr = mr->pNextMteMR)
|
|
{
|
|
MODREF_KEX kmr(mr);
|
|
kmr.as.conf = NULL;
|
|
kmr.as.flags = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
_LeaveSysLevel(krnl32lock);
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
|
|
void dump_imtes(void)
|
|
{
|
|
WORD imteMax = *pimteMax;
|
|
IMTE** pmteModTable = *ppmteModTable;
|
|
int total = 0;
|
|
|
|
printf("Dumping IMTEs...\n");
|
|
for (WORD i = 0 ; i < imteMax ; i++)
|
|
{
|
|
IMTE_KEX* imte = (IMTE_KEX*) pmteModTable[i];
|
|
if (imte)
|
|
{
|
|
printf("%s\n", imte->pszFileName);
|
|
|
|
for (MODREF* mr = imte->pMR ; mr != NULL ; mr = mr->pNextMteMR)
|
|
{
|
|
MODREF_KEX kmr(mr);
|
|
printf("\t%02x %-7s %-12s\n",
|
|
kmr.as.flags,
|
|
kmr.as.conf ? kmr.as.conf->get_name() : "none",
|
|
pmteModTable[mr->ppdb->pExeMODREF->mteIndex]->pszModName);
|
|
}
|
|
|
|
total++;
|
|
}
|
|
}
|
|
printf("\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;
|
|
FLoadTreeNotify = (FLoadTreeNotify_t) jtab[JTAB_FLD_TRN];
|
|
|
|
system_path_len = GetSystemDirectory(system_path, sizeof(system_path));
|
|
RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\KernelEx\\KnownDLLs", &known_dlls_key);
|
|
|
|
SettingsDB::instance.flush_all();
|
|
|
|
return 1;
|
|
}
|
|
|
|
void resolver_uninit()
|
|
{
|
|
DBGPRINTF(("resolver_uninit()\n"));
|
|
RegCloseKey(known_dlls_key);
|
|
SettingsDB::instance.clear();
|
|
reset_imtes();
|
|
}
|
|
|
|
void resolver_hook()
|
|
{
|
|
DBGPRINTF(("resolver_hook()\n"));
|
|
old_jtab[JTAB_EFO_DYN] = InterlockedExchange(jtab + JTAB_EFO_DYN, (LONG) ExportFromOrdinalDynamic_thunk);
|
|
old_jtab[JTAB_EFO_STA] = InterlockedExchange(jtab + JTAB_EFO_STA, (LONG) ExportFromOrdinalStatic_thunk);
|
|
old_jtab[JTAB_EFN_DYN] = InterlockedExchange(jtab + JTAB_EFN_DYN, (LONG) ExportFromNameDynamic_thunk);
|
|
old_jtab[JTAB_EFN_STA] = InterlockedExchange(jtab + JTAB_EFN_STA, (LONG) ExportFromNameStatic_thunk);
|
|
old_jtab[JTAB_KNO_DLL] = InterlockedExchange(jtab + JTAB_KNO_DLL, (LONG) IsKnownKexDLL);
|
|
old_jtab[JTAB_FLD_TRN] = InterlockedExchange(jtab + JTAB_FLD_TRN, (LONG) KexLoadTreeNotify);
|
|
}
|
|
|
|
void resolver_unhook()
|
|
{
|
|
DBGPRINTF(("resolver_unhook()\n"));
|
|
for (int i = 0 ; i < JTAB_SIZE ; i++)
|
|
InterlockedExchange(jtab + i, old_jtab[i]);
|
|
}
|