mirror of
https://github.com/UzixLS/KernelEx.git
synced 2025-07-18 23:11:19 +03:00
740 lines
21 KiB
C++
Executable File
740 lines
21 KiB
C++
Executable File
/*
|
|
* KernelEx
|
|
* Copyright (C) 2008-2010, 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 <tlhelp32.h>
|
|
#include <cassert>
|
|
#include <cstdio>
|
|
#include <cstdarg>
|
|
#include "debug.h"
|
|
#include "pemanip.h"
|
|
#include "loadstub.h"
|
|
#include "setup.h"
|
|
#include "wininit.h"
|
|
#include "version.h"
|
|
#include "resource.h"
|
|
|
|
#define CODE_SEG ".text"
|
|
#define DATA_SEG ".data"
|
|
#define INIT_SEG "_INIT"
|
|
|
|
|
|
Setup::Setup(char* _backup_file) : backup_file(strupr(_backup_file))
|
|
{
|
|
h_kernel32 = GetModuleHandle("KERNEL32");
|
|
|
|
detect_old_version();
|
|
detect_downgrade();
|
|
|
|
pemem.OpenMemory(h_kernel32);
|
|
if (!pemem.HasTarget())
|
|
ShowError(IDS_FAILOPEN, "KERNEL32 memory image");
|
|
|
|
version = get_signature_ver();
|
|
|
|
OSVERSIONINFOA osv;
|
|
osv.dwOSVersionInfoSize = sizeof(osv);
|
|
|
|
GetVersionEx(&osv);
|
|
if ((osv.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
|
|
|| (osv.dwMajorVersion != 4)
|
|
|| (osv.dwMinorVersion != 10 && osv.dwMinorVersion != 90))
|
|
ShowError(IDS_WINVER);
|
|
|
|
//on WinMe and file called "setup.exe" we get 4.10 (lol)
|
|
if (osv.dwMinorVersion == 90)
|
|
{
|
|
DBGPRINTF(("Detected Windows Me\n"));
|
|
is_winme = true;
|
|
}
|
|
else
|
|
{
|
|
DBGPRINTF(("Detected Windows 98\n"));
|
|
is_winme = false;
|
|
}
|
|
}
|
|
|
|
bool Setup::detect_old_version()
|
|
{
|
|
typedef void (WINAPI *KV_t)(char *);
|
|
KV_t h_KVersion;
|
|
char buf[32];
|
|
|
|
h_KVersion = (KV_t)GetProcAddress(h_kernel32, "KUPVersion");
|
|
if (!h_KVersion)
|
|
h_KVersion = (KV_t)GetProcAddress(h_kernel32, "KEXVersion");
|
|
if (!h_KVersion)
|
|
return false;
|
|
h_KVersion(buf);
|
|
if (strcmp(buf, "4") < 0)
|
|
ShowError(IDS_OLDKEX);
|
|
return true;
|
|
}
|
|
|
|
void Setup::detect_downgrade()
|
|
{
|
|
typedef unsigned long (*kexGetKEXVersion_t)();
|
|
kexGetKEXVersion_t kexGetKEXVersion_pfn;
|
|
HMODULE h_kernelex;
|
|
unsigned long version;
|
|
|
|
h_kernelex = LoadLibrary("KERNELEX.DLL");
|
|
|
|
//no KernelEx installed, continue
|
|
if (!h_kernelex)
|
|
return;
|
|
|
|
kexGetKEXVersion_pfn = (kexGetKEXVersion_t) GetProcAddress(h_kernelex, "kexGetKEXVersion");
|
|
version = kexGetKEXVersion_pfn();
|
|
FreeLibrary(h_kernelex);
|
|
|
|
//trying to downgrade - forbid
|
|
if (version > VERSION_CODE)
|
|
ShowError(IDS_DOWNGRADE);
|
|
}
|
|
|
|
int Setup::find_pattern(DWORD offset, int size, const short* pattern,
|
|
int pat_len, DWORD* found_loc)
|
|
{
|
|
DWORD end_offset = offset + size - pat_len;
|
|
int found = 0;
|
|
|
|
for (DWORD i = offset ; i <= end_offset ; i++)
|
|
{
|
|
if (pattern[0] < 0 || *(unsigned char*)i == pattern[0])
|
|
{
|
|
int j;
|
|
for (j = 1 ; j < pat_len ; j++)
|
|
{
|
|
if (pattern[j] >= 0 && *(unsigned char*)(i + j) != pattern[j])
|
|
break;
|
|
}
|
|
if (j == pat_len) //pattern found
|
|
{
|
|
*found_loc = i;
|
|
found++;
|
|
}
|
|
}
|
|
}
|
|
return found;
|
|
}
|
|
|
|
void Setup::set_pattern(DWORD loc, const short* new_pattern, int pat_len)
|
|
{
|
|
unsigned char* offset = (unsigned char*) loc;
|
|
const short* pat_ptr = new_pattern;
|
|
|
|
while (pat_len--)
|
|
{
|
|
if (*pat_ptr != -1)
|
|
*offset = *pat_ptr & 0xff;
|
|
offset++;
|
|
pat_ptr++;
|
|
}
|
|
}
|
|
|
|
int Setup::get_signature_ver()
|
|
{
|
|
DWORD ptr;
|
|
KernelEx_dataseg* dseg = NULL;
|
|
DWORD sign_len = sizeof(KEX_SIGNATURE) - 1;
|
|
|
|
DWORD data = (DWORD) pemem.GetSectionByName(DATA_SEG);
|
|
int data_size = pemem.GetSectionSize(DATA_SEG);
|
|
|
|
ptr = data + data_size - sign_len;
|
|
while (ptr >= data)
|
|
{
|
|
if (!memcmp((void*)ptr, KEX_SIGNATURE, sign_len))
|
|
{
|
|
dseg = (KernelEx_dataseg*) ptr;
|
|
break;
|
|
}
|
|
ptr--;
|
|
}
|
|
|
|
if (!dseg)
|
|
{
|
|
DBGPRINTF(("Signature not found\n"));
|
|
return -1;
|
|
}
|
|
else
|
|
DBGPRINTF(("Signature found @ 0x%08x\n", ptr));
|
|
|
|
return dseg->version;
|
|
}
|
|
|
|
void Setup::disable_platform_check()
|
|
{
|
|
static const short pattern[] = {
|
|
0x66,0x8b,0x46,0x48,0x66,0x3d,0x04,0x00,0x0f,0x87,0x9c,0x01,0x00,0x00,
|
|
0x75,0x0b,0x66,0x83,0x7e,0x4a,0x0a,0x0f,0x87,0x8f,0x01,0x00,0x00,0x66,
|
|
0x81,0x7e,0x04,0x4c,0x01,
|
|
};
|
|
static const short after[] = {
|
|
0xeb,0x19,0x46,0x48,0x66,0x3d,0x04,0x00,0x0f,0x87,0x9c,0x01,0x00,0x00,
|
|
0x75,0x0b,0x66,0x83,0x7e,0x4a,0x0a,0x0f,0x87,0x8f,0x01,0x00,0x00,0x66,
|
|
0x81,0x7e,0x04,0x4c,0x01,
|
|
};
|
|
|
|
DWORD offset = (DWORD) pefile.GetSectionByName(CODE_SEG);
|
|
int size = pefile.GetSectionSize(CODE_SEG);
|
|
int length = sizeof(pattern) / sizeof(short);
|
|
DWORD found_loc;
|
|
int found = find_pattern(offset, size, pattern, length, &found_loc);
|
|
if (found != 1)
|
|
{
|
|
if (!found) ShowError(IDS_NOPAT, "disable_platform_check");
|
|
else ShowError(IDS_MULPAT, "disable_platform_check");
|
|
}
|
|
DBGPRINTF(("%s: pattern found @ 0x%08x\n", "disable_platform_check",
|
|
pefile.PointerToRva((void*) found_loc) + pefile.GetImageBase()));
|
|
set_pattern(found_loc, after, length);
|
|
}
|
|
|
|
void Setup::disable_resource_check()
|
|
{
|
|
static const short pattern[] = {
|
|
0x3d,0x00,0x80,0x00,0x00,0x72,
|
|
};
|
|
static const short after[] = {
|
|
0x3d,0x00,0x80,0x00,0x00,0xeb,
|
|
};
|
|
|
|
DWORD offset = (DWORD) pefile.GetSectionByName(CODE_SEG);
|
|
int size = pefile.GetSectionSize(CODE_SEG);
|
|
int length = sizeof(pattern) / sizeof(short);
|
|
DWORD found_loc;
|
|
int found = find_pattern(offset, size, pattern, length, &found_loc);
|
|
if (found != 1)
|
|
{
|
|
if (!found) ShowError(IDS_NOPAT, "disable_resource_check");
|
|
else ShowError(IDS_MULPAT, "disable_resource_check");
|
|
}
|
|
DBGPRINTF(("%s: pattern found @ 0x%08x\n", "disable_resource_check",
|
|
pefile.PointerToRva((void*) found_loc) + pefile.GetImageBase()));
|
|
set_pattern(found_loc, after, length);
|
|
}
|
|
|
|
//no named/rcdata resource types mirroring
|
|
void Setup::disable_named_and_rcdata_resources_mirroring()
|
|
{
|
|
static const short pattern[] = {
|
|
0x66,0x8B,0x40,0x0E,0x66,0x89,0x45,0xDA,0x8B,0x45, -1,0x66,0x8B,0x48,
|
|
0x0C,0x66,0x89,0x4D,0xD8,0x66,0x8B,0x45,0xE0,0x8B,0x4D,0xD4,0x66,0x89,
|
|
0x01,0x83,0x45,0xD4,0x02,0x66,0x8B,0x45,0xDA,0x66,0x03,0x45,0xD8,0x66,
|
|
0x89,0x45,0x8C,0x8B,0x4D,0xD4,0x66,0x89,0x01,0x83,0x45,0xD4,0x02
|
|
};
|
|
static const short after[] = {
|
|
0x66,0x8B,0x48,0x0E,0x66,0x03,0x48,0x0C,0x66,0x89,0x4D,0x8C,0x8B,0x45,
|
|
0xA4,0x83,0x38,0x0A,0x74,0x40,0x83,0x38,0x00,0x79,0x04,0x3B,0xC0,0xEB,
|
|
0x37,0x66,0x8B,0x45,0xE0,0x8B,0x4D,0xD4,0x66,0x89,0x01,0x83,0xC1,0x02,
|
|
0x66,0x8B,0x45,0x8C,0x66,0x89,0x01,0x83,0xC1,0x02,0x89,0x4D,0xD4
|
|
};
|
|
|
|
DWORD offset = (DWORD) pefile.GetSectionByName(CODE_SEG);
|
|
int size = pefile.GetSectionSize(CODE_SEG);
|
|
int length = sizeof(pattern) / sizeof(short);
|
|
DWORD found_loc;
|
|
int found = find_pattern(offset, size, pattern, length, &found_loc);
|
|
if (found != 1)
|
|
{
|
|
if (!found) ShowError(IDS_NOPAT, "disable_named_and_rcdata_resources_mirroring");
|
|
else ShowError(IDS_MULPAT, "disable_named_and_rcdata_resources_mirroring");
|
|
}
|
|
DBGPRINTF(("%s: pattern found @ 0x%08x\n", "disable_named_and_rcdata_resources_mirroring",
|
|
pefile.PointerToRva((void*) found_loc) + pefile.GetImageBase()));
|
|
set_pattern(found_loc, after, length);
|
|
}
|
|
|
|
//change obfuscator to non-negative IDs
|
|
void Setup::positive_pids_patch()
|
|
{
|
|
static const short pattern[] = {
|
|
0xB9,0x01,0x00,0xFF,0xFF,-1,0x23,0xD1,0x33,0xD1
|
|
};
|
|
static const short after[] = {
|
|
0xB9,0x01,0x00,0xFF,0x4F,-1,0x23,0xD1,0x2B,0xD1
|
|
};
|
|
|
|
DWORD offset = (DWORD) pefile.GetSectionByName(INIT_SEG);
|
|
int size = pefile.GetSectionSize(INIT_SEG);
|
|
int length = sizeof(pattern) / sizeof(short);
|
|
DWORD found_loc;
|
|
int found = find_pattern(offset, size, pattern, length, &found_loc);
|
|
if (found != 1)
|
|
{
|
|
if (!found) ShowError(IDS_NOPAT, "positive_pids_patch");
|
|
else ShowError(IDS_MULPAT, "positive_pids_patch");
|
|
}
|
|
DBGPRINTF(("%s: pattern found @ 0x%08x\n", "positive_pids_patch",
|
|
pefile.PointerToRva((void*) found_loc) + pefile.GetImageBase()));
|
|
set_pattern(found_loc, after, length);
|
|
}
|
|
|
|
void Setup::mod_imte_alloc()
|
|
{
|
|
//VA BFF8745C, RVA 1745C, file 15A5C, sec E45C
|
|
static const short pattern[] = {
|
|
0x66,0xff,0x05,-1,-1,-1,0xbf,0x6a,0x3c,0xe8,
|
|
};
|
|
static const short after[] = {
|
|
0x66,0xff,0x05,-1,-1,-1,0xbf,0x6a,0x40,0xe8,
|
|
};
|
|
|
|
DWORD offset = (DWORD) pefile.GetSectionByName(CODE_SEG);
|
|
int size = pefile.GetSectionSize(CODE_SEG);
|
|
int length = sizeof(pattern) / sizeof(short);
|
|
DWORD found_loc;
|
|
int found = find_pattern(offset, size, pattern, length, &found_loc);
|
|
if (found != 1)
|
|
{
|
|
if (!found) ShowError(IDS_NOPAT, "mod_imte_alloc");
|
|
else ShowError(IDS_MULPAT, "mod_imte_alloc");
|
|
}
|
|
DBGPRINTF(("%s: pattern found @ 0x%08x\n", "mod_imte_alloc",
|
|
pefile.PointerToRva((void*) found_loc) + pefile.GetImageBase()));
|
|
set_pattern(found_loc, after, length);
|
|
}
|
|
|
|
void Setup::mod_mr_alloc()
|
|
{
|
|
static const short pattern[] = {
|
|
0x75,0xF6,0x8D,0x04,-1,0x1C,0x00,0x00,0x00,0x50
|
|
};
|
|
static const short after[] = {
|
|
0x75,0xF6,0x8D,0x04,-1,0x24,0x00,0x00,0x00,0x50
|
|
};
|
|
|
|
DWORD offset = (DWORD) pefile.GetSectionByName(CODE_SEG);
|
|
int size = pefile.GetSectionSize(CODE_SEG);
|
|
int length = sizeof(pattern) / sizeof(short);
|
|
DWORD found_loc;
|
|
int found = find_pattern(offset, size, pattern, length, &found_loc);
|
|
if (found != 1)
|
|
{
|
|
if (!found) ShowError(IDS_NOPAT, "mod_mr_alloc");
|
|
else ShowError(IDS_MULPAT, "mod_mr_alloc");
|
|
}
|
|
DBGPRINTF(("%s: pattern found @ 0x%08x\n", "mod_mr_alloc",
|
|
pefile.PointerToRva((void*) found_loc) + pefile.GetImageBase()));
|
|
set_pattern(found_loc, after, length);
|
|
}
|
|
|
|
void Setup::mod_pdb_alloc()
|
|
{
|
|
static const short pattern[] = {
|
|
0x53,0x56,0x57,0x6A,0x06,0x68,0xC4,0x00,0x00,0x00,0xE8
|
|
};
|
|
static const short after[] = {
|
|
0x53,0x56,0x57,0x6A,0x06,0x68,0xC8,0x00,0x00,0x00,0xE8
|
|
};
|
|
|
|
DWORD offset = (DWORD) pefile.GetSectionByName(CODE_SEG);
|
|
int size = pefile.GetSectionSize(CODE_SEG);
|
|
int length = sizeof(pattern) / sizeof(short);
|
|
DWORD found_loc;
|
|
int found = find_pattern(offset, size, pattern, length, &found_loc);
|
|
if (found != 1)
|
|
{
|
|
if (!found) ShowError(IDS_NOPAT, "mod_pdb_alloc");
|
|
else ShowError(IDS_MULPAT, "mod_pdb_alloc");
|
|
}
|
|
DBGPRINTF(("%s: pattern found @ 0x%08x\n", "mod_pdb_alloc",
|
|
pefile.PointerToRva((void*) found_loc) + pefile.GetImageBase()));
|
|
set_pattern(found_loc, after, length);
|
|
}
|
|
|
|
void Setup::find_ExportFromX()
|
|
{
|
|
static const short pattern[] = {
|
|
0x8B,0x0D,-1,-1,-1,-1,0x0F,0xBF,0x40,0x10,0x8B,0x14,0x81,0x8B,0x44,
|
|
0x24,0x14,0x3D,0x00,0x00,0x01,0x00,0x8B,0x4A,0x04,0x73,0x15,-1,0x1D,
|
|
-1,-1,-1,-1,0x75,0x04,0x6A,0x32,0xEB,0x3E,0x50,0x51,0xE8,-2,-2,-2,-2,
|
|
0xEB,0x0C,0xFF,0x74,0x24,0x14,0x6A,0x00,0x51,0xE8,-2,-2,-2,-2,0x83,
|
|
0x7F,0x54,0x00,0x8B,0xF0
|
|
};
|
|
|
|
DWORD offset = (DWORD) pefile.GetSectionByName(CODE_SEG);
|
|
int size = pefile.GetSectionSize(CODE_SEG);
|
|
int length = sizeof(pattern) / sizeof(short);
|
|
DWORD found_loc;
|
|
int found = find_pattern(offset, size,pattern, length, &found_loc);
|
|
if (found != 1)
|
|
{
|
|
if (!found) ShowError(IDS_NOPAT, "exportfromX");
|
|
else ShowError(IDS_MULPAT, "exportfromX");
|
|
}
|
|
DBGPRINTF(("%s: pattern found @ 0x%08x\n", "exportfromX",
|
|
pefile.PointerToRva((void*) found_loc) + pefile.GetImageBase()));
|
|
gpa_ExportFromOrdinal_call = found_loc + 0x29;
|
|
gpa_ExportFromName_call = found_loc + 0x37;
|
|
_ExportFromOrdinal = decode_call(gpa_ExportFromOrdinal_call, 5);
|
|
_ExportFromName = decode_call(gpa_ExportFromName_call, 5);
|
|
DWORD start = (DWORD) pefile.RvaToPointer(_ExportFromName);
|
|
for (DWORD a = start ; a < start + 0x100 ; a++)
|
|
if (is_call_ref(a, _ExportFromOrdinal))
|
|
EFN_EFO_call = a;
|
|
}
|
|
|
|
void Setup::find_IsKnownDLL()
|
|
{
|
|
static const short pattern[] = {
|
|
0xFF,0x75,0xFC,0x8D,0x8D,0xF0,0xFE,0xFF,0xFF,0x51,0xE8,-2,-2,-2,-2,
|
|
0x85,0xC0,0x75,0x1E,0x8D,0x85,0xE8,0xFD,0xFF,0xFF,
|
|
0x8D,0x8D,0xF0,0xFE,0xFF,0xFF,0x50,0x51
|
|
};
|
|
|
|
DWORD offset = (DWORD) pefile.GetSectionByName(CODE_SEG);
|
|
int size = pefile.GetSectionSize(CODE_SEG);
|
|
int length = sizeof(pattern) / sizeof(short);
|
|
DWORD found_loc;
|
|
int found = find_pattern(offset, size,pattern, length, &found_loc);
|
|
if (found != 1)
|
|
{
|
|
if (!found) ShowError(IDS_NOPAT, "IsKnownDLL");
|
|
else ShowError(IDS_MULPAT, "IsKnownDLL");
|
|
}
|
|
DBGPRINTF(("%s: pattern found @ 0x%08x\n", "IsKnownDLL",
|
|
pefile.PointerToRva((void*) found_loc) + pefile.GetImageBase()));
|
|
IsKnownDLL_call = found_loc + 10;
|
|
_IsKnownDLL = decode_call(IsKnownDLL_call, 5);
|
|
}
|
|
|
|
void Setup::find_FLoadTreeNotify1()
|
|
{
|
|
static const short pattern[] = {
|
|
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
|
|
};
|
|
|
|
DWORD offset = (DWORD) pefile.GetSectionByName(CODE_SEG);
|
|
int size = pefile.GetSectionSize(CODE_SEG);
|
|
int length = sizeof(pattern) / sizeof(short);
|
|
DWORD found_loc;
|
|
int found = find_pattern(offset, size,pattern, length, &found_loc);
|
|
if (found != 1)
|
|
{
|
|
if (!found) ShowError(IDS_NOPAT, "FLoadTreeNotify1");
|
|
else ShowError(IDS_MULPAT, "FLoadTreeNotify1");
|
|
}
|
|
DBGPRINTF(("%s: pattern found @ 0x%08x\n", "FLoadTreeNotify1",
|
|
pefile.PointerToRva((void*) found_loc) + pefile.GetImageBase()));
|
|
FLoadTreeNotify_call1 = found_loc + 16;
|
|
_FLoadTreeNotify = decode_call(FLoadTreeNotify_call1, 5);
|
|
}
|
|
|
|
void Setup::find_FLoadTreeNotify2()
|
|
{
|
|
static const short pattern[] = {
|
|
0x6A,0x00,0x57,0xE8,-1,-1,-1,-1,0x6A,0x00,0x56,0xE8,-2,-2,-2,-2,
|
|
0x85,0xC0,0x74,0x12,0x56,0xE8,-1,-1,-1,-1,0x68,0x5A,0x04,0x00,0x00,
|
|
0x33,0xF6,0xE8,-1,-1,-1,-1
|
|
};
|
|
|
|
DWORD offset = (DWORD) pefile.GetSectionByName(CODE_SEG);
|
|
int size = pefile.GetSectionSize(CODE_SEG);
|
|
int length = sizeof(pattern) / sizeof(short);
|
|
DWORD found_loc;
|
|
int found = find_pattern(offset, size,pattern, length, &found_loc);
|
|
if (found != 1)
|
|
{
|
|
if (!found) ShowError(IDS_NOPAT, "FLoadTreeNotify2");
|
|
else ShowError(IDS_MULPAT, "FLoadTreeNotify2");
|
|
}
|
|
DBGPRINTF(("%s: pattern found @ 0x%08x\n", "FLoadTreeNotify2",
|
|
pefile.PointerToRva((void*) found_loc) + pefile.GetImageBase()));
|
|
FLoadTreeNotify_call2 = found_loc + 11;
|
|
}
|
|
|
|
void Setup::kill_process(const char* name)
|
|
{
|
|
PROCESSENTRY32 pe32;
|
|
void * h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
|
|
|
if (h == INVALID_HANDLE_VALUE)
|
|
return;
|
|
|
|
pe32.dwSize = sizeof(PROCESSENTRY32);
|
|
|
|
Process32First(h, &pe32);
|
|
do
|
|
{
|
|
if (strstr(pe32.szExeFile, name))
|
|
{
|
|
DBGPRINTF(("Terminating process: %s... ", name));
|
|
HANDLE hp = OpenProcess(PROCESS_TERMINATE, FALSE, pe32.th32ProcessID);
|
|
if (hp == INVALID_HANDLE_VALUE)
|
|
{
|
|
DBGPRINTF(("open fail\n"));
|
|
continue;
|
|
}
|
|
if (TerminateProcess(hp, 0))
|
|
DBGPRINTF(("ok\n"));
|
|
else
|
|
DBGPRINTF(("fail\n"));
|
|
CloseHandle(hp);
|
|
}
|
|
}
|
|
while (Process32Next(h, &pe32));
|
|
|
|
CloseHandle(h);
|
|
}
|
|
|
|
DWORD Setup::decode_call(DWORD addr, int len)
|
|
{
|
|
unsigned char* code = (unsigned char*)addr;
|
|
|
|
if (len == 5 && *code == 0xe8) /* call rel32 */
|
|
{
|
|
return (DWORD)(pefile.PointerToRva(code) + 5 + *(DWORD*)(code + 1));
|
|
}
|
|
else if (len == 6 && code[0] == 0xff
|
|
&& code[1] == 0x15) /* call m32 */
|
|
{
|
|
return *(DWORD*)(code + 2);
|
|
}
|
|
else return 0;
|
|
}
|
|
|
|
bool Setup::is_call_ref(DWORD loc, DWORD target)
|
|
{
|
|
DWORD addr = decode_call(loc, 5); // size of call imm32 opcode
|
|
if (addr == target)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
// Both addresses have to be from the same section!
|
|
void Setup::set_call_ref(DWORD loc, DWORD target)
|
|
{
|
|
DWORD rel;
|
|
|
|
assert(*(BYTE*) loc == 0xe8);
|
|
|
|
rel = target - (loc + 5);
|
|
*(DWORD*)(loc + 1) = rel;
|
|
}
|
|
|
|
bool Setup::is_fixupc(DWORD addr)
|
|
{
|
|
if (*(DWORD*)(addr - 5) == 0xDAC)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
sstring Setup::get_temp_file_name()
|
|
{
|
|
char tmpdir[MAX_PATH];
|
|
char target[MAX_PATH];
|
|
|
|
GetSystemDirectory(tmpdir, sizeof(tmpdir));
|
|
GetTempFileName(tmpdir, "kex", 0, target);
|
|
|
|
return target;
|
|
}
|
|
|
|
void Setup::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);
|
|
DBGPRINTF(("%s\n", out));
|
|
MessageBox(NULL, out, "KernelEx Setup", MB_OK | MB_ICONERROR);
|
|
exit(id);
|
|
}
|
|
|
|
void Setup::install()
|
|
{
|
|
upgrade = false;
|
|
|
|
if (version >= 0)
|
|
{
|
|
if (version == KEX_STUB_VER)
|
|
{
|
|
DBGPRINTF(("No need to upgrade\n"));
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
upgrade = true;
|
|
}
|
|
}
|
|
|
|
char kernel32path[MAX_PATH];
|
|
GetModuleFileName(h_kernel32, kernel32path, sizeof(kernel32path));
|
|
|
|
pefile.OpenFile(upgrade ? backup_file : kernel32path, 0x10000);
|
|
if (!pefile.HasTarget())
|
|
{
|
|
if (upgrade)
|
|
ShowError(IDS_FAILOPENBACKUP, backup_file, kernel32path);
|
|
else
|
|
ShowError(IDS_FAILOPEN, kernel32path);
|
|
}
|
|
|
|
find_ExportFromX();
|
|
find_IsKnownDLL();
|
|
find_FLoadTreeNotify1();
|
|
find_FLoadTreeNotify2();
|
|
disable_platform_check();
|
|
disable_resource_check();
|
|
disable_named_and_rcdata_resources_mirroring();
|
|
positive_pids_patch();
|
|
mod_imte_alloc();
|
|
mod_mr_alloc();
|
|
mod_pdb_alloc();
|
|
|
|
KernelEx_codeseg* cseg;
|
|
KernelEx_dataseg* dseg;
|
|
if (!pefile.AllocSectionSpace(CODE_SEG,
|
|
sizeof(KernelEx_codeseg), (void**) &cseg, sizeof(DWORD)))
|
|
ShowError(IDS_FAILSEC, CODE_SEG);
|
|
if (!pefile.AllocSectionSpace(DATA_SEG,
|
|
sizeof(KernelEx_dataseg), (void**) &dseg, sizeof(DWORD)))
|
|
ShowError(IDS_FAILSEC, DATA_SEG);
|
|
|
|
memcpy(cseg->signature, "KrnlEx", 6);
|
|
cseg->version = KEX_STUB_VER;
|
|
for (int i = 0 ; i < JTAB_SIZE ; i++)
|
|
{
|
|
cseg->jmp_stub[i].opcode = 0x25ff;
|
|
cseg->jmp_stub[i].addr = (DWORD)
|
|
pefile.PointerToRva(&dseg->jtab[i]) + pefile.GetImageBase();
|
|
cseg->jmp_stub[i].nop = 0x9090;
|
|
}
|
|
|
|
memcpy(dseg->signature, "KrnlEx", 6);
|
|
dseg->version = KEX_STUB_VER;
|
|
dseg->jtab[JTAB_EFO_DYN] = _ExportFromOrdinal + pefile.GetImageBase();
|
|
dseg->jtab[JTAB_EFO_STA] = _ExportFromOrdinal + pefile.GetImageBase();
|
|
dseg->jtab[JTAB_EFN_DYN] = _ExportFromName + pefile.GetImageBase();
|
|
dseg->jtab[JTAB_EFN_STA] = _ExportFromName + pefile.GetImageBase();
|
|
dseg->jtab[JTAB_KNO_DLL] = _IsKnownDLL + pefile.GetImageBase();
|
|
dseg->jtab[JTAB_FLD_TRN] = _FLoadTreeNotify + pefile.GetImageBase();
|
|
|
|
//exportfromx patch
|
|
DWORD code = (DWORD) pefile.GetSectionByName(CODE_SEG);
|
|
int code_size = pefile.GetSectionSize(CODE_SEG);
|
|
|
|
int efo_cnt = 0;
|
|
int efn_cnt = 0;
|
|
|
|
for (DWORD a = code ; a < code + code_size ; a++)
|
|
{
|
|
if (is_call_ref(a, _ExportFromOrdinal))
|
|
{
|
|
DWORD file_loc = a;
|
|
if (a == EFN_EFO_call)
|
|
continue;
|
|
if (a == gpa_ExportFromOrdinal_call)
|
|
set_call_ref(file_loc, (DWORD) &cseg->jmp_stub[JTAB_EFO_DYN]);
|
|
else
|
|
set_call_ref(file_loc, (DWORD) &cseg->jmp_stub[JTAB_EFO_STA]);
|
|
DBGPRINTF(("EFO: address %08x\n", pefile.PointerToRva((void*) a)
|
|
+ pefile.GetImageBase()));
|
|
efo_cnt++;
|
|
}
|
|
else if (is_call_ref(a, _ExportFromName))
|
|
{
|
|
DWORD file_loc = a;
|
|
if (is_fixupc(a))
|
|
continue;
|
|
if (a == gpa_ExportFromName_call)
|
|
set_call_ref(file_loc, (DWORD) &cseg->jmp_stub[JTAB_EFN_DYN]);
|
|
else
|
|
set_call_ref(file_loc, (DWORD) &cseg->jmp_stub[JTAB_EFN_STA]);
|
|
DBGPRINTF(("EFN: address %08x\n", pefile.PointerToRva((void*) a)
|
|
+ pefile.GetImageBase()));
|
|
efn_cnt++;
|
|
}
|
|
}
|
|
|
|
if (efo_cnt != 2 || efn_cnt != 2)
|
|
ShowError(IDS_ERRCHECK);
|
|
|
|
//isknowndll patch
|
|
set_call_ref(IsKnownDLL_call, (DWORD) &cseg->jmp_stub[JTAB_KNO_DLL]);
|
|
DBGPRINTF(("KNO_DLL: address %08x\n", pefile.PointerToRva((void*) IsKnownDLL_call)
|
|
+ pefile.GetImageBase()));
|
|
|
|
//FLoadTreeNotify patch
|
|
set_call_ref(FLoadTreeNotify_call1, (DWORD) &cseg->jmp_stub[JTAB_FLD_TRN]);
|
|
DBGPRINTF(("FLD_TRN: address %08x\n", pefile.PointerToRva((void*) FLoadTreeNotify_call1)
|
|
+ pefile.GetImageBase()));
|
|
set_call_ref(FLoadTreeNotify_call2, (DWORD) &cseg->jmp_stub[JTAB_FLD_TRN]);
|
|
DBGPRINTF(("FLD_TRN: address %08x\n", pefile.PointerToRva((void*) FLoadTreeNotify_call2)
|
|
+ pefile.GetImageBase()));
|
|
|
|
// backup original file
|
|
if (!upgrade)
|
|
{
|
|
if (!CopyFile(kernel32path, backup_file, FALSE))
|
|
ShowError(IDS_FAILBAK, backup_file);
|
|
}
|
|
|
|
// save patched file
|
|
sstring tmp_file = get_temp_file_name();
|
|
pefile.SaveFile(tmp_file);
|
|
|
|
if (is_winme)
|
|
{
|
|
kill_process("\\STATEMGR.EXE");
|
|
kill_process("\\STMGR.EXE");
|
|
}
|
|
|
|
Wininit.add(kernel32path, tmp_file);
|
|
|
|
if (is_winme)
|
|
{
|
|
char path[MAX_PATH];
|
|
GetWindowsDirectory(path, sizeof(path));
|
|
if (path[strlen(path) - 1] != '\\')
|
|
strcat(path, "\\");
|
|
strcat(path, "WININIT.LOG");
|
|
Wininit.add("NUL", path);
|
|
path[3] = '\0';
|
|
strcat(path, "_RESTORE\\TEMP");
|
|
Wininit.add("DIRNUL", path);
|
|
}
|
|
|
|
Wininit.save();
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
DBGPRINTF(("KernelEx setup program running\n"));
|
|
if (argc != 2)
|
|
return 1;
|
|
|
|
Setup setup(argv[1]);
|
|
setup.install();
|
|
DBGPRINTF(("Setup finished\n"));
|
|
return 0;
|
|
}
|