1
0
mirror of https://github.com/UzixLS/KernelEx.git synced 2025-07-19 07:21:20 +03:00

import KernelEx-4.5.2

This commit is contained in:
UzixLS
2018-11-03 16:24:01 +03:00
parent 2948e23961
commit 37f6b55f9e
54 changed files with 2142 additions and 1505 deletions

47
vxd/KernelEx.def Executable file
View File

@ -0,0 +1,47 @@
;
; KernelEx
; Copyright (C) 2011, 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.
;
VXD VKRNLEX DYNAMIC
DESCRIPTION 'KernelEx Virtual Device'
SEGMENTS
_LPTEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE
_LTEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE
_LDATA CLASS 'LCODE' PRELOAD NONDISCARDABLE
_TEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE
_DATA CLASS 'LCODE' PRELOAD NONDISCARDABLE
CONST CLASS 'LCODE' PRELOAD NONDISCARDABLE
_TLS CLASS 'LCODE' PRELOAD NONDISCARDABLE
_BSS CLASS 'LCODE' PRELOAD NONDISCARDABLE
_ITEXT CLASS 'ICODE' DISCARDABLE
_IDATA CLASS 'ICODE' DISCARDABLE
_PTEXT CLASS 'PCODE' NONDISCARDABLE
_PDATA CLASS 'PDATA' NONDISCARDABLE SHARED
_STEXT CLASS 'SCODE' RESIDENT
_SDATA CLASS 'SCODE' RESIDENT
_DBOSTART CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_DBOCODE CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_DBODATA CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_16ICODE CLASS '16ICODE' PRELOAD DISCARDABLE
_RCODE CLASS 'RCODE'
EXPORTS
_VKRNLEX_DDB @1

42
vxd/debug.cpp Executable file
View File

@ -0,0 +1,42 @@
/*
* 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.
*
*/
extern "C" {
#include <basedef.h>
#include <vmm.h>
};
#include <string.h>
#include <malloc.h>
#include "debug.h"
void debug_printf(const char* fmt, ...)
{
char* newfmt = (char*) alloca(strlen(fmt) + 10);
strcpy(newfmt, "VKRNLEX: ");
strcat(newfmt, fmt);
strcat(newfmt, "\n");
__asm lea eax,(fmt + 4)
__asm push eax
__asm push newfmt
VMMCall(_Debug_Printf_Service)
__asm add esp, 2*4
}

32
vxd/debug.h Executable file
View File

@ -0,0 +1,32 @@
/*
* KernelEx
* Copyright (C) 2011, 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
#ifdef _DEBUG
void debug_printf(const char* fmt, ...);
#define DBGPRINTF(x) debug_printf x
#else
#define DBGPRINTF(x) do {} while (0)
#endif
#endif

77
vxd/interface.h Executable file
View File

@ -0,0 +1,77 @@
/*
* KernelEx
* Copyright (C) 2008-2011, 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 __INTERFACE_H
#define __INTERFACE_H
/* Update this whenever patching functions are changed. */
#define KEX_STUB_VER 11
#define KEX_SIGNATURE "KrnlEx"
enum
{
JTAB_EFO_DYN,
JTAB_EFO_STA,
JTAB_EFN_DYN,
JTAB_EFN_STA,
JTAB_KNO_DLL,
JTAB_FLD_TRN,
JTAB_SYS_CHK,
JTAB_RES_CHK,
JTAB_SIZE
};
#include <pshpack1.h>
struct KernelEx_codeseg
{
char signature[6]; /* "KrnlEx" */
unsigned short version;
struct
{
WORD opcode; /* 0xFF 0x25 */
DWORD addr; /* address to jtab */
WORD nop; /* dword align */
} jmp_stub[JTAB_SIZE];
};
struct KernelEx_dataseg
{
char signature[6]; /* "KrnlEx" */
unsigned short version;
DWORD jtab[JTAB_SIZE];
};
#include <poppack.h>
/*
* IOCTL Support
*/
#define IOCTL_CONNECT 1
struct ioctl_connect_params
{
WORD vxd_version;
bool status;
KernelEx_dataseg* stub_ptr;
};
#endif

223
vxd/patch.cpp Executable file
View File

@ -0,0 +1,223 @@
/*
* KernelEx
* Copyright (C) 2010-2011, 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 <cassert>
#include "patch.h"
#include "debug.h"
extern "C" {
#define WANTVXDWRAPS
#include <vmm.h>
#include <vxdwraps.h>
};
#ifdef _DEBUG
const struct
{
MessageID id;
const char* desc;
}
MessageText[] =
{
IDS_NOPAT, "ERROR: %s: pattern not found",
IDS_MULPAT, "ERROR: %s: multiple pattern matches",
IDS_FAILSEC, "ERROR: Failed to allocate %s section memory",
IDS_ERRCHECK, "ERROR: Checksum error",
IDS_WINVER, "Incompatible Windows version",
IDS_DOWNGRADE, "Can't downgrade. Please uninstall currently installed version of KernelEx before continuing.",
};
#endif
void Patch::ShowError(MessageID id, ...)
{
#ifdef _DEBUG
const char* format = NULL;
char out[512];
va_list vargs;
va_start(vargs, id);
for (int i = 0 ; i < sizeof(MessageText) / sizeof(MessageText[0]) ; i++)
{
if (MessageText[i].id == id)
{
format = MessageText[i].desc;
break;
}
}
assert(format != NULL);
_Vsprintf(out, const_cast<char*>(format), vargs);
va_end(vargs);
strcat(out, "\n");
debug_printf(out);
#endif
abort();
}
int Patch::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 Patch::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++;
}
pagelock(loc, pat_len);
}
DWORD Patch::decode_call(DWORD addr, int len)
{
unsigned char* code = (unsigned char*)addr;
/* CALL rel32 */
if (code[0] == 0xe8)
{
if (len && len == 5 || !len)
return (DWORD)((DWORD)code + 5 + *(INT32*)(code + 1));
}
/* CALL imm32 */
else if (code[0] == 0xff && code[1] == 0x15)
{
if (len && len == 6 || !len)
return *(DWORD*)(code + 2);
}
/* unmatched */
return 0;
}
DWORD Patch::decode_jmp(DWORD addr, int len)
{
unsigned char* code = (unsigned char*)addr;
/* JMP rel8 */
if (code[0] == 0xeb)
{
if (len && len == 2 || !len)
return (DWORD)((DWORD)code + 2 + *(INT8*)(code + 1));
}
/* JMP rel32 */
else if (code[0] == 0xe9)
{
if (len && len == 5 || !len)
return (DWORD)((DWORD)code + 5 + *(INT32*)(code + 1));
}
/* JMP imm32 */
else if (code[0] == 0xff && code[1] == 0x25)
{
if (len && len == 6 || !len)
return *(DWORD*)(code + 2);
}
/* Jxx rel8 */
else if (code[0] >= 0x70 && code[0] < 0x7f || code[0] == 0xe3)
{
if (len && len == 2 || !len)
return (DWORD)((DWORD)code + 2 + *(INT8*)(code + 1));
}
/* Jxx rel32 */
else if (code[0] == 0x0f && code[1] >= 0x80 && code[1] <= 0x8f)
{
if (len && len == 6 || !len)
return (DWORD)((DWORD)code + 6 + *(INT32*)(code + 2));
}
/* unmatched */
return 0;
}
bool Patch::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 Patch::set_call_ref(DWORD loc, DWORD target)
{
DWORD rel;
assert(*(BYTE*) loc == 0xe8);
rel = target - (loc + 5);
*(DWORD*)(loc + 1) = rel;
pagelock(loc + 1, sizeof(DWORD));
}
// Both addresses have to be from the same section!
void Patch::set_jmp_ref(DWORD loc, DWORD target)
{
DWORD rel;
unsigned char* code = (unsigned char*)loc;
if (code[0] == 0xe9)
{
rel = target - (loc + 5);
*(DWORD*)(loc + 1) = rel;
pagelock(loc + 1, sizeof(DWORD));
}
else if (code[0] == 0x0f && code[1] >= 0x80 && code[1] <= 0x8f)
{
rel = target - (loc + 6);
*(DWORD*)(loc + 2) = rel;
pagelock(loc + 2, sizeof(DWORD));
}
else assert(false);
}
void Patch::pagelock(DWORD addr, DWORD count)
{
_LinPageLock(PAGE(addr), NPAGES((addr & PAGEMASK) + count), 0);
}

53
vxd/patch.h Executable file
View File

@ -0,0 +1,53 @@
/*
* KernelEx
* Copyright (C) 2010-2011, 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 __PATCH_H
#define __PATCH_H
enum MessageID
{
IDS_NOPAT,
IDS_MULPAT,
IDS_FAILSEC,
IDS_ERRCHECK,
IDS_WINVER,
IDS_DOWNGRADE,
};
class Patch
{
public:
Patch() {}
virtual bool apply() = 0;
protected:
void ShowError(MessageID id, ...);
static int find_pattern(DWORD offset, int size, const short* pattern, int pat_len, DWORD* found_loc);
void set_pattern(DWORD loc, const short* new_pattern, int pat_len);
DWORD decode_call(DWORD addr, int len = 0);
DWORD decode_jmp(DWORD addr, int len = 0);
bool is_call_ref(DWORD loc, DWORD target);
void set_call_ref(DWORD loc, DWORD target);
void set_jmp_ref(DWORD loc, DWORD target);
void pagelock(DWORD addr, DWORD count);
};
#endif

178
vxd/patch_ifsmgr.cpp Executable file
View File

@ -0,0 +1,178 @@
/*
* KernelEx
* Copyright (C) 2011, 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.
*
*/
extern "C" {
#define WANTVXDWRAPS
#include <basedef.h>
#include <vmm.h>
#include <vxdwraps.h>
};
#include "patch_ifsmgr.h"
#include "debug.h"
#include "util.h"
#define __IFSMGR_CheckLocks 0x00400056
/*
* This is a fix against a problem where you can't access a locked file
* through memory mapping object.
*
* Why accessing a locked file through memory mapping object doesn't work?
*
* IFSMgr normally checks if the process is an owner of the lock
* and depending on that either allows to access the file or not.
*
* This works fine in case scenario 1. where the file is read directly.
*
* Accessing a file through memory mapping object is a different beast.
* The file is loaded into memory by the system on demand, through a page
* fault trap (see 2.), this causes a read of a page-sized chunk of file.
* However this time it is the system not the application who's reading
* the file, so process ID is set to -1. This value is not checked
* against when the file is verified for access regarding the locks.
*
* The fix is to allow the access to a locked file if PID is -1.
*/
#if 0 /* Test case */
int main()
{
HANDLE file, mapp;
void* view;
char buf[4096];
BOOL ret;
DWORD dw;
file = CreateFileA("File.txt", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
NULL);
ret = LockFile(file, 128, 0, 1, 0);
SetFilePointer(file, 32768, 0, 0);
SetEndOfFile(file);
mapp = CreateFileMapping(file, NULL, PAGE_READWRITE, 0, 32768, NULL);
view = MapViewOfFile(mapp, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 32768);
SetFilePointer(file, 0, 0, 0);
//!!!!! 1. This works out of the box
ReadFile(file, buf, 4096, &dw, NULL);
//!!!!! 2. This triggers a crash without the fix
memcpy(buf, view, 4096);
UnmapViewOfFile(view);
CloseHandle(mapp);
UnlockFile(file, 128, 0, 1, 0);
CloseHandle(file);
}
#endif
__declspec(naked)
int IFSMGR_CheckLocks_fixed(
void* handle,
DWORD pos,
DWORD count,
DWORD owner,
DWORD finst,
DWORD flags
)
{
__asm {
push ebp
mov ebp,esp
push ebx
push esi
push edi
mov eax,[ebp+10h]
or eax,eax
jnz _L1
sub eax,eax
jmp _exit_grant
_L1:
mov edi,[ebp+0Ch]
lea ecx,[eax+edi-1]
cmp ecx,edi
jnb _L2
jmp _exit_forbid
_L2:
mov esi,[ebp+8]
sub eax,eax
cmp [esi+0Ch],edi
jb _exit_grant
cmp [esi+8],ecx
ja _exit_grant
mov edx,[esi]
cmp esi,edx
jz _exit_grant
//the fix
mov ebx,[ebp+14h]
cmp ebx,-1
jz _exit_grant
//end of the fix
_loop:
cmp [edx+8],ecx
ja _exit_grant
cmp [edx+0Ch],edi
jb _next
//check lock owner
mov ebx,[ebp+14h]
cmp [edx+14h],ebx
jnz _owner_mismatch
//check file handle
mov ebx,[ebp+18h]
cmp [edx+18h],ebx
jz _next
_owner_mismatch:
mov ebx,[edx+10h]
and ebx,[ebp+1Ch]
test bl,1
jz _exit_forbid
_next:
mov edx,[edx]
cmp esi,edx
jnz _loop
jmp _exit_grant
_exit_forbid:
mov eax,21h
_exit_grant:
pop edi
pop esi
pop ebx
pop ebp
ret
}
}
bool Patch_ifsmgr::apply()
{
DBGPRINTF(("Applying IFSMGR_CheckLocks fix... "));
ULONG serviceid = GetVxDServiceOrdinal(IFSMGR_CheckLocks);
bool ret = Hook_Device_Service(serviceid, (ULONG) IFSMGR_CheckLocks_fixed);
DBGPRINTF((ret ? "... ok" : "... error"));
return ret;
}

33
vxd/patch_ifsmgr.h Executable file
View File

@ -0,0 +1,33 @@
/*
* KernelEx
* Copyright (C) 2011, 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 __PATCH_IFSMGR_H
#define __PATCH_IFSMGR_H
#include "patch.h"
class Patch_ifsmgr : public Patch
{
public:
bool apply();
};
#endif

494
vxd/patch_kernel32.cpp Executable file
View File

@ -0,0 +1,494 @@
/*
* KernelEx
* Copyright (C) 2011, 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.
*
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "pemanip.h"
#include "patch_kernel32.h"
#include "interface.h"
#include "debug.h"
#define CODE_SEG ".text"
#define DATA_SEG ".data"
#define INIT_SEG "_INIT"
Patch_kernel32::Patch_kernel32(PEmanip& pem) : pefile(pem)
{
stub_address = 0;
code_seg_start = (DWORD) pefile.GetSectionByName(CODE_SEG);
code_seg_size = pefile.GetSectionSize(CODE_SEG);
data_seg_start = (DWORD) pefile.GetSectionByName(DATA_SEG);
data_seg_size = pefile.GetSectionSize(DATA_SEG);
}
bool Patch_kernel32::apply()
{
if (find_signature())
{
DBGPRINTF(("KERNEL32 already patched by previous KernelEx version"));
DBGPRINTF(("Make sure pure KERNEL32 is installed before proceeding"));
return false;
}
DBGPRINTF(("Preparing KERNEL32 for KernelEx... "));
if (!find_ExportFromX())
return false;
if (!find_IsKnownDLL())
return false;
if (!find_FLoadTreeNotify1())
return false;
if (!find_FLoadTreeNotify2())
return false;
if (!prepare_subsystem_check())
return false;
if (!find_resource_check1())
return false;
if (!find_resource_check2())
return false;
if (!disable_named_and_rcdata_resources_mirroring())
return false;
if (!mod_imte_alloc())
return false;
if (!mod_mr_alloc())
return false;
if (!mod_pdb_alloc())
return false;
if (!create_stubs())
return false;
DBGPRINTF(("... all done!"));
return true;
}
bool Patch_kernel32::find_signature()
{
DWORD ptr;
KernelEx_dataseg* dseg = NULL;
DWORD sign_len = sizeof(KEX_SIGNATURE) - 1;
ptr = data_seg_start + data_seg_size - sign_len;
ptr = PEmanip::ALIGN(ptr, sizeof(DWORD));
while (ptr >= data_seg_start)
{
if (!memcmp((void*) ptr, KEX_SIGNATURE, sign_len))
{
dseg = (KernelEx_dataseg*) ptr;
break;
}
ptr -= sizeof(DWORD);
}
return dseg != NULL;
}
bool Patch_kernel32::prepare_subsystem_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[] = {
0x66,0x83,0x7E,0x48,0x04,0x75,0x05,0x66,0x83,0x7E,0x4A,0x0A,0xE9,0x00,
0x00,0x00,0x00,0x0F,0x87,0x93,0x01,0x00,0x00,0x90,0x90,0x90,0x90,0x66,
0x81,0x7e,0x04,0x4c,0x01,
};
int length = sizeof(pattern) / sizeof(short);
DWORD found_loc;
int found = find_pattern(code_seg_start, code_seg_size, pattern, length, &found_loc);
if (found != 1)
{
if (!found) ShowError(IDS_NOPAT, "subsystem_check");
else ShowError(IDS_MULPAT, "subsystem_check");
return false;
}
DBGPRINTF(("%s: pattern found @ 0x%08x", "subsystem_check", found_loc));
set_pattern(found_loc, after, length);
SubsysCheck_jmp = found_loc + 12;
_SubsysCheckPerform = decode_jmp(SubsysCheck_jmp, 5);
return true;
}
bool Patch_kernel32::find_resource_check1()
{
static const short pattern[] = {
0x6A,0x00,0x8D,0x45,0xE0,0x50,0xFF,0x75,0xA4,0xFF,0x75,0xD0,0x8D,0x45,
0xCC,0x50,0xFF,0x75,0x08,0xE8,-2,-2,-2,-2,0x85,0xC0
};
int length = sizeof(pattern) / sizeof(short);
DWORD found_loc;
int found = find_pattern(code_seg_start, code_seg_size, pattern, length, &found_loc);
if (found != 1)
{
if (!found) ShowError(IDS_NOPAT, "resource_check1");
else ShowError(IDS_MULPAT, "resource_check1");
return false;
}
DBGPRINTF(("%s: pattern found @ 0x%08x", "resource_check1", found_loc));
GetOrdinal_call1 = found_loc + 19;
_GetOrdinal = decode_call(GetOrdinal_call1, 5);
return true;
}
bool Patch_kernel32::find_resource_check2()
{
static const short pattern[] = {
0x66,0x8B,0x45,0xE0,0x66,0x2D,0x06,0x80,0x66,0x3D,0x01,0x00,0x1B,0xC0,
0xF7,0xD8,0x50,0x8D,0x45,0xDE,0x50,0xFF,0x75, -1,0xFF,0x75,0xD0,0x8D,
0x45,0xCC,0x50,0xFF,0x75,0x08,0xE8, -2, -2, -2, -2,0x85,0xC0
};
int length = sizeof(pattern) / sizeof(short);
DWORD found_loc;
int found = find_pattern(code_seg_start, code_seg_size, pattern, length, &found_loc);
if (found != 1)
{
if (!found) ShowError(IDS_NOPAT, "resource_check2");
else ShowError(IDS_MULPAT, "resource_check2");
return false;
}
DBGPRINTF(("%s: pattern found @ 0x%08x", "resource_check2", found_loc));
GetOrdinal_call2 = found_loc + 34;
return true;
}
//no named/rcdata resource types mirroring
bool Patch_kernel32::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
};
int length = sizeof(pattern) / sizeof(short);
DWORD found_loc;
int found = find_pattern(code_seg_start, code_seg_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");
return false;
}
DBGPRINTF(("%s: pattern found @ 0x%08x", "disable_named_and_rcdata_resources_mirroring", found_loc));
set_pattern(found_loc, after, length);
return true;
}
bool Patch_kernel32::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,
};
int length = sizeof(pattern) / sizeof(short);
DWORD found_loc;
int found = find_pattern(code_seg_start, code_seg_size, pattern, length, &found_loc);
if (found != 1)
{
if (!found) ShowError(IDS_NOPAT, "mod_imte_alloc");
else ShowError(IDS_MULPAT, "mod_imte_alloc");
return false;
}
DBGPRINTF(("%s: pattern found @ 0x%08x", "mod_imte_alloc", found_loc));
set_pattern(found_loc, after, length);
return true;
}
bool Patch_kernel32::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
};
int length = sizeof(pattern) / sizeof(short);
DWORD found_loc;
int found = find_pattern(code_seg_start, code_seg_size, pattern, length, &found_loc);
if (found != 1)
{
if (!found) ShowError(IDS_NOPAT, "mod_mr_alloc");
else ShowError(IDS_MULPAT, "mod_mr_alloc");
return false;
}
DBGPRINTF(("%s: pattern found @ 0x%08x", "mod_mr_alloc", found_loc));
set_pattern(found_loc, after, length);
return true;
}
bool Patch_kernel32::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
};
int length = sizeof(pattern) / sizeof(short);
DWORD found_loc;
int found = find_pattern(code_seg_start, code_seg_size, pattern, length, &found_loc);
if (found != 1)
{
if (!found) ShowError(IDS_NOPAT, "mod_pdb_alloc");
else ShowError(IDS_MULPAT, "mod_pdb_alloc");
return false;
}
DBGPRINTF(("%s: pattern found @ 0x%08x", "mod_pdb_alloc", found_loc));
set_pattern(found_loc, after, length);
return true;
}
bool Patch_kernel32::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
};
int length = sizeof(pattern) / sizeof(short);
DWORD found_loc;
int found = find_pattern(code_seg_start, code_seg_size, pattern, length, &found_loc);
if (found != 1)
{
if (!found) ShowError(IDS_NOPAT, "exportfromX");
else ShowError(IDS_MULPAT, "exportfromX");
return false;
}
DBGPRINTF(("%s: pattern found @ 0x%08x", "exportfromX", found_loc));
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 = _ExportFromName;
for (DWORD a = start ; a < start + 0x100 ; a++)
{
if (is_call_ref(a, _ExportFromOrdinal))
{
EFN_EFO_call = a;
return true;
}
}
DBGPRINTF(("EFN_EFO_call not found"));
return false;
}
bool Patch_kernel32::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
};
int length = sizeof(pattern) / sizeof(short);
DWORD found_loc;
int found = find_pattern(code_seg_start, code_seg_size, pattern, length, &found_loc);
if (found != 1)
{
if (!found) ShowError(IDS_NOPAT, "IsKnownDLL");
else ShowError(IDS_MULPAT, "IsKnownDLL");
return false;
}
DBGPRINTF(("%s: pattern found @ 0x%08x", "IsKnownDLL", found_loc));
IsKnownDLL_call = found_loc + 10;
_IsKnownDLL = decode_call(IsKnownDLL_call, 5);
return true;
}
bool Patch_kernel32::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
};
int length = sizeof(pattern) / sizeof(short);
DWORD found_loc;
int found = find_pattern(code_seg_start, code_seg_size, pattern, length, &found_loc);
if (found != 1)
{
if (!found) ShowError(IDS_NOPAT, "FLoadTreeNotify1");
else ShowError(IDS_MULPAT, "FLoadTreeNotify1");
return false;
}
DBGPRINTF(("%s: pattern found @ 0x%08x", "FLoadTreeNotify1", found_loc));
FLoadTreeNotify_call1 = found_loc + 16;
_FLoadTreeNotify = decode_call(FLoadTreeNotify_call1, 5);
return true;
}
bool Patch_kernel32::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
};
int length = sizeof(pattern) / sizeof(short);
DWORD found_loc;
int found = find_pattern(code_seg_start, code_seg_size, pattern, length, &found_loc);
if (found != 1)
{
if (!found) ShowError(IDS_NOPAT, "FLoadTreeNotify2");
else ShowError(IDS_MULPAT, "FLoadTreeNotify2");
return false;
}
DBGPRINTF(("%s: pattern found @ 0x%08x", "FLoadTreeNotify2", found_loc));
FLoadTreeNotify_call2 = found_loc + 11;
return true;
}
bool Patch_kernel32::create_stubs()
{
KernelEx_codeseg* cseg;
KernelEx_dataseg* dseg;
if (!pefile.AllocSectionSpace(CODE_SEG,
sizeof(KernelEx_codeseg), (void**) &cseg, sizeof(DWORD)))
{
ShowError(IDS_FAILSEC, CODE_SEG);
return false;
}
if (!pefile.AllocSectionSpace(DATA_SEG,
sizeof(KernelEx_dataseg), (void**) &dseg, sizeof(DWORD)))
{
ShowError(IDS_FAILSEC, DATA_SEG);
return false;
}
pagelock(pefile.GetImageBase(), 1);
pagelock((DWORD) cseg, sizeof(KernelEx_codeseg));
pagelock((DWORD) dseg, sizeof(KernelEx_dataseg));
stub_address = dseg;
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) &dseg->jtab[i];
cseg->jmp_stub[i].nop = 0x9090;
}
memcpy(dseg->signature, "KrnlEx", 6);
dseg->version = KEX_STUB_VER;
dseg->jtab[JTAB_EFO_DYN] = _ExportFromOrdinal;
dseg->jtab[JTAB_EFO_STA] = _ExportFromOrdinal;
dseg->jtab[JTAB_EFN_DYN] = _ExportFromName;
dseg->jtab[JTAB_EFN_STA] = _ExportFromName;
dseg->jtab[JTAB_KNO_DLL] = _IsKnownDLL;
dseg->jtab[JTAB_FLD_TRN] = _FLoadTreeNotify;
dseg->jtab[JTAB_SYS_CHK] = _SubsysCheckPerform;
dseg->jtab[JTAB_RES_CHK] = _GetOrdinal;
//exportfromx patch
int efo_cnt = 0;
int efn_cnt = 0;
for (DWORD a = code_seg_start ; a < code_seg_start + code_seg_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(("%s: address 0x%08x", "EFO", a));
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(("%s: address 0x%08x", "EFN", a));
efn_cnt++;
}
}
if (efo_cnt != 2 || efn_cnt != 2)
{
ShowError(IDS_ERRCHECK);
return false;
}
//isknowndll patch
set_call_ref(IsKnownDLL_call, (DWORD) &cseg->jmp_stub[JTAB_KNO_DLL]);
DBGPRINTF(("%s: address 0x%08x", "KNO_DLL", IsKnownDLL_call));
//FLoadTreeNotify patch
set_call_ref(FLoadTreeNotify_call1, (DWORD) &cseg->jmp_stub[JTAB_FLD_TRN]);
DBGPRINTF(("%s: address 0x%08x", "FLD_TRN1", FLoadTreeNotify_call1));
set_call_ref(FLoadTreeNotify_call2, (DWORD) &cseg->jmp_stub[JTAB_FLD_TRN]);
DBGPRINTF(("%s: address 0x%08x", "FLD_TRN2", FLoadTreeNotify_call2));
//subsys check patch
set_jmp_ref(SubsysCheck_jmp, (DWORD) &cseg->jmp_stub[JTAB_SYS_CHK]);
DBGPRINTF(("%s: address 0x%08x", "SYS_CHK", SubsysCheck_jmp));
//resource check patch
set_call_ref(GetOrdinal_call1, (DWORD) &cseg->jmp_stub[JTAB_RES_CHK]);
DBGPRINTF(("%s: address 0x%08x", "RES_CHK1", GetOrdinal_call1));
set_call_ref(GetOrdinal_call2, (DWORD) &cseg->jmp_stub[JTAB_RES_CHK]);
DBGPRINTF(("%s: address 0x%08x", "RES_CHK2", GetOrdinal_call2));
return true;
}
bool Patch_kernel32::is_fixupc(DWORD addr)
{
if (*(DWORD*)(addr - 5) == 0xDAC)
return true;
return false;
}

77
vxd/patch_kernel32.h Executable file
View File

@ -0,0 +1,77 @@
/*
* KernelEx
* Copyright (C) 2011, 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 __PATCH_KERNEL32_H
#define __PATCH_KERNEL32_H
#include "patch.h"
#include "interface.h"
class PEmanip;
class Patch_kernel32 : public Patch
{
public:
Patch_kernel32(PEmanip& pem);
bool apply();
KernelEx_dataseg* stub_address;
private:
bool find_signature();
bool prepare_subsystem_check();
bool find_resource_check1();
bool find_resource_check2();
bool disable_named_and_rcdata_resources_mirroring();
bool mod_imte_alloc();
bool mod_mr_alloc();
bool mod_pdb_alloc();
bool find_ExportFromX();
bool find_IsKnownDLL();
bool find_FLoadTreeNotify1();
bool find_FLoadTreeNotify2();
bool create_stubs();
bool is_fixupc(DWORD addr);
PEmanip& pefile;
DWORD code_seg_start;
DWORD code_seg_size;
DWORD data_seg_start;
DWORD data_seg_size;
DWORD _GetOrdinal;
DWORD _ExportFromOrdinal;
DWORD _ExportFromName;
DWORD _IsKnownDLL;
DWORD _FLoadTreeNotify;
DWORD _SubsysCheckPerform;
DWORD GetOrdinal_call1;
DWORD GetOrdinal_call2;
DWORD gpa_ExportFromOrdinal_call;
DWORD gpa_ExportFromName_call;
DWORD EFN_EFO_call;
DWORD IsKnownDLL_call;
DWORD FLoadTreeNotify_call1;
DWORD FLoadTreeNotify_call2;
DWORD SubsysCheck_jmp;
};
#endif

200
vxd/pemanip.cpp Executable file
View File

@ -0,0 +1,200 @@
/*
* KernelEx
* Copyright (C) 2008-2009, 2011, 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 "pemanip.h"
#include "debug.h"
#include <cstring>
extern "C" {
#define WANTVXDWRAPS
#include <vmm.h>
#include <vxdwraps.h>
};
PEmanip::PEmanip()
{
ZeroInit();
}
PEmanip::PEmanip(void* memory)
{
ZeroInit();
OpenMemory(memory);
}
void PEmanip::ZeroInit()
{
MZh = NULL;
PEh = NULL;
section_hdrs = NULL;
target_len = 0;
image_base = 0;
has_target = false;
}
void PEmanip::Close()
{
ZeroInit();
}
bool PEmanip::OpenMemory(void* memory)
{
if (has_target)
return false;
MZh = (IMAGE_DOS_HEADER*) memory;
if (MZh->e_magic == IMAGE_DOS_SIGNATURE)
{
PEh = (IMAGE_NT_HEADERS*) ((DWORD) MZh + MZh->e_lfanew);
if ((PEh->Signature == IMAGE_NT_SIGNATURE)
&& (PEh->FileHeader.Machine == IMAGE_FILE_MACHINE_I386)
&& (PEh->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC))
{
section_hdrs = (IMAGE_SECTION_HEADER*)
((DWORD) PEh
+ PEh->FileHeader.SizeOfOptionalHeader
+ sizeof(IMAGE_FILE_HEADER)
+ sizeof(DWORD));
image_base = (DWORD)memory;
has_target = true;
target_len = PEh->OptionalHeader.SizeOfImage;
return true;
}
}
return false;
}
IMAGE_SECTION_HEADER* PEmanip::RvaToSection(DWORD Rva)
{
IMAGE_SECTION_HEADER* section = section_hdrs;
for (int i = 0 ; i < PEh->FileHeader.NumberOfSections ; i++)
{
if ((Rva >= section->VirtualAddress)
&& (Rva < (section->VirtualAddress + section->Misc.VirtualSize)))
{
return section;
}
section++;
}
return NULL;
}
IMAGE_SECTION_HEADER* PEmanip::FindSectionByName(const char* name)
{
IMAGE_SECTION_HEADER* section = section_hdrs;
for (int i = 0 ; i < PEh->FileHeader.NumberOfSections ; i++)
{
if (!strncmp((char*) section->Name, name, sizeof(section->Name)))
return section;
section++;
}
return NULL;
}
void* PEmanip::GetSectionByName(const char* name)
{
IMAGE_SECTION_HEADER* section = FindSectionByName(name);
if (section)
return RvaToPointer(section->VirtualAddress);
return NULL;
}
DWORD PEmanip::GetSectionSize(const char* name)
{
IMAGE_SECTION_HEADER* section = FindSectionByName(name);
if (section)
return section->Misc.VirtualSize;
return 0;
}
bool PEmanip::AllocSectionSpace(const char* name, int needed_space, void** ptr, int align)
{
IMAGE_SECTION_HEADER* Section = FindSectionByName(name);
if (!Section || align < 1 || needed_space < 0)
return false;
if (!needed_space)
return true;
DWORD current_size = ALIGN(Section->Misc.VirtualSize, align);
DWORD new_size = current_size + needed_space;
DWORD max_size = (Section + 1)->VirtualAddress - Section->VirtualAddress;
int available_space = max_size - current_size;
DBGPRINTF(("Allocating space in section '%s' avail: %d needed: %d",
name, available_space, needed_space));
if (available_space < needed_space)
{
DBGPRINTF(("Not enough space in section!"));
return false;
}
Section->Misc.VirtualSize = new_size;
if (ptr)
*ptr = RvaToPointer(Section->VirtualAddress + current_size);
return true;
}
DWORD PEmanip::GetExportedAPI(const char* func)
{
IMAGE_EXPORT_DIRECTORY* Exports = (IMAGE_EXPORT_DIRECTORY*)
RvaToPointer(PEh->OptionalHeader
.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
if (Exports)
{
DWORD* Names = (DWORD*) RvaToPointer(Exports->AddressOfNames);
for (DWORD i = 0 ; i < Exports->NumberOfNames ; i++)
{
if (!strcmp(func, (char*) RvaToPointer(*Names)))
{
WORD* OrdinalTable = (WORD*) RvaToPointer(Exports->AddressOfNameOrdinals);
WORD Index = OrdinalTable[i];
DWORD* FunctionTable = (DWORD*) RvaToPointer(Exports->AddressOfFunctions);
DWORD Address = (DWORD) FunctionTable[Index];
return Address;
}
Names++;
}
}
return 0;
}
void* PEmanip::CreateBackup()
{
if (!has_target)
return NULL;
void* mem = _HeapAllocate(target_len, HEAPSWAP);
memcpy(mem, MZh, target_len);
return mem;
}

91
vxd/pemanip.h Executable file
View File

@ -0,0 +1,91 @@
/*
* KernelEx
* Copyright (C) 2008-2009, 2011, 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 _SETUP_PEMANIP_H
#define _SETUP_PEMANIP_H
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winnt.h>
class PEmanip
{
public:
PEmanip();
PEmanip(void* memory);
bool HasTarget();
bool OpenMemory(void* memory);
void Close();
IMAGE_NT_HEADERS* GetPEHeader();
IMAGE_SECTION_HEADER* RvaToSection(DWORD Rva);
void* RvaToPointer(DWORD Rva);
DWORD PointerToRva(void* pointer);
void* GetSectionByName(const char* name);
DWORD GetSectionSize(const char* name);
bool AllocSectionSpace(const char* name, int needed_space, void** ptr, int align = 1);
DWORD GetExportedAPI(const char* func);
DWORD GetImageBase();
void* CreateBackup();
static unsigned long ALIGN(unsigned long x, unsigned long y);
private:
void ZeroInit();
IMAGE_SECTION_HEADER* FindSectionByName(const char* name);
bool has_target;
int target_len;
IMAGE_DOS_HEADER* MZh;
IMAGE_NT_HEADERS* PEh;
IMAGE_SECTION_HEADER* section_hdrs;
DWORD image_base;
};
inline bool PEmanip::HasTarget()
{
return has_target;
}
inline IMAGE_NT_HEADERS* PEmanip::GetPEHeader()
{
return PEh;
}
inline unsigned long PEmanip::ALIGN(unsigned long x, unsigned long y)
{
return (x + y - 1) & (~(y - 1));
}
inline DWORD PEmanip::GetImageBase()
{
return image_base;
}
inline void* PEmanip::RvaToPointer(DWORD Rva)
{
return (void*)(Rva + image_base);
}
inline DWORD PEmanip::PointerToRva(void* pointer)
{
return (DWORD) pointer - image_base;
}
#endif

50
vxd/util.c Executable file
View File

@ -0,0 +1,50 @@
/*
* KernelEx
* Copyright (C) 2011, 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 <basedef.h>
#include <vmm.h>
void __cdecl abort(void)
{
__asm int 3
}
int __cdecl _purecall (void)
{
abort();
return 0;
}
void __cdecl _assert(const char* expr, const char* file, unsigned line)
{
_Debug_Printf_Service("Assertion failed: '%s' in %s line %d", expr, file, line);
abort();
}
void __declspec(naked) _stdcall RtlUnwind(
PVOID TargetFrame,
PVOID TargetIp,
PVOID ExceptionRecord,
PVOID ReturnValue
)
{
VMMJmp(ObsoleteRtlUnwind);
}

72
vxd/util.h Executable file
View File

@ -0,0 +1,72 @@
/*
* KernelEx
* Copyright (C) 2011, 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 __UTIL_H
#define __UTIL_H
#define __STR(x) #x
#define STR(x) __STR(x)
#define EXTERNC extern "C"
#define _Declare_Virtual_Device(name, ver_major, ver_minor, ctrl_proc, device_num, init_order, V86_proc, PM_proc, ref_data) \
BOOL __stdcall ControlDispatcher(DWORD, DWORD, DWORD, DWORD, DWORD, DWORD); \
\
void __declspec(naked) name##_CTRL(void) \
{ \
__asm PUSH EDI \
__asm PUSH ESI \
__asm PUSH EDX \
__asm PUSH ECX \
__asm PUSH EBX \
__asm PUSH EAX \
__asm CALL ctrl_proc \
__asm CMP EAX, TRUE \
__asm RET \
} \
\
EXTERNC struct VxD_Desc_Block name##_DDB = \
{ \
0, DDK_VERSION, device_num, ver_major, ver_minor, 0, \
#name, init_order, (ULONG)name##_CTRL, (ULONG)V86_proc, (ULONG)PM_proc, \
0, 0, ref_data, 0, 0, 0, 'Prev', sizeof(struct VxD_Desc_Block), \
'Rsv1', 'Rsv2', 'Rsv3' \
}
#pragma warning (disable:4035) // turn off no return code warning
static inline
bool Hook_Device_Service(ULONG service, ULONG hookproc)
{
_asm mov eax, [service]
_asm mov esi, [hookproc]
VMMCall(Hook_Device_Service)
_asm setnc al
#ifndef __BOOL_DEFINED
_asm movzx eax, al
#endif
}
#pragma warning (default:4035) // turn on no return code warning
#endif

170
vxd/vxd.dsp Executable file
View File

@ -0,0 +1,170 @@
# Microsoft Developer Studio Project File - Name="VxD" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=VxD - 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 "vxd.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 "vxd.mak" CFG="VxD - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "VxD - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "VxD - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "VxD - 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 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /O2 /D "NDEBUG" /FD /GF /c
# 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 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 /subsystem:console /machine:I386
# ADD LINK32 vxdwraps.clb libc.lib /nologo /map /machine:I386 /nodefaultlib /out:"Release/VKrnlEx.vxd" /vxd /ignore:4078 /ignore:4039
# SUBTRACT LINK32 /pdb:none
!ELSEIF "$(CFG)" == "VxD - 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 /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /Zi /Od /D "_DEBUG" /FD /GF /Gs /c
# SUBTRACT CPP /Gy
# 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 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 /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 vxdwraps.clb libc.lib /nologo /incremental:no /map /debug /machine:I386 /nodefaultlib /out:"Debug/VKrnlEx.vxd" /vxd /ignore:4078 /ignore:4039
# SUBTRACT LINK32 /pdb:none
!ENDIF
# Begin Target
# Name "VxD - Win32 Release"
# Name "VxD - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\debug.cpp
!IF "$(CFG)" == "VxD - Win32 Release"
# PROP Exclude_From_Build 1
!ELSEIF "$(CFG)" == "VxD - Win32 Debug"
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\KernelEx.def
# End Source File
# Begin Source File
SOURCE=.\patch.cpp
# End Source File
# Begin Source File
SOURCE=.\patch_ifsmgr.cpp
# End Source File
# Begin Source File
SOURCE=.\patch_kernel32.cpp
# End Source File
# Begin Source File
SOURCE=.\pemanip.cpp
# End Source File
# Begin Source File
SOURCE=.\util.c
# End Source File
# Begin Source File
SOURCE=.\vxdmain.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\interface.h
# End Source File
# Begin Source File
SOURCE=.\patch.h
# End Source File
# Begin Source File
SOURCE=.\patch_ifsmgr.h
# End Source File
# Begin Source File
SOURCE=.\patch_kernel32.h
# End Source File
# Begin Source File
SOURCE=.\pemanip.h
# End Source File
# Begin Source File
SOURCE=.\util.h
# End Source File
# Begin Source File
SOURCE=.\vxdmain.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"
# End Group
# End Target
# End Project

244
vxd/vxdmain.cpp Executable file
View File

@ -0,0 +1,244 @@
/*
* KernelEx
* Copyright (C) 2011, 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.
*
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
extern "C" {
#define WANTVXDWRAPS
#include <vmm.h>
#include <debug.h>
#include <vxdwraps.h>
#include <vwin32.h>
};
#include <winerror.h>
#include "vxdmain.h"
#include "util.h"
#include "debug.h"
#include "pemanip.h"
#include "patch_kernel32.h"
#include "patch_ifsmgr.h"
#include "interface.h"
#define V_MAJOR 1
#define V_MINOR 0
_Declare_Virtual_Device(VKRNLEX, V_MAJOR, V_MINOR, ControlDispatcher, UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER, 0, 0, 0);
DWORD ( _stdcall *VKernelEx_W32_Proc[] )(DWORD, PDIOCPARAMETERS) = {
VKernelEx_IOCTL_Connect
};
#define MAX_VKERNELEX_W32_API (sizeof(VKernelEx_W32_Proc)/sizeof(DWORD))
static ioctl_connect_params s_connect_params;
BOOL __stdcall ControlDispatcher(
DWORD dwControlMessage,
DWORD EBX,
DWORD ECX,
DWORD EDX,
DWORD ESI,
DWORD EDI)
{
switch(dwControlMessage)
{
case SYS_CRITICAL_INIT:
return VKernelEx_Critical_Init();
case DEVICE_INIT:
return VKernelEx_Dynamic_Init();
case SYS_DYNAMIC_DEVICE_INIT:
return VKernelEx_Dynamic_Init();
case SYS_DYNAMIC_DEVICE_EXIT:
return VKernelEx_Dynamic_Exit();
case W32_DEVICEIOCONTROL:
return VKernelEx_W32_DeviceIOControl(ECX, EDX, (PDIOCPARAMETERS) ESI);
case BEGIN_PM_APP:
return VKernelEx_Begin_PM_App(EBX);
case CREATE_PROCESS:
return VKernelEx_Create_Process(EDX);
case DESTROY_PROCESS:
return VKernelEx_Destroy_Process(EDX);
default:
return TRUE;
}
}
/****************************************************************************
VKernelEx_W32_DeviceIOControl
****************************************************************************/
DWORD _stdcall VKernelEx_W32_DeviceIOControl(
DWORD dwService,
DWORD hDevice,
PDIOCPARAMETERS lpDIOCParms
)
{
DWORD dwRetVal = 0;
// DIOC_OPEN is sent when VxD is loaded w/ CreateFile
// (this happens just after SYS_DYNAMIC_INIT)
if (dwService == DIOC_OPEN)
{
DBGPRINTF(("WIN32 DEVIOCTL supported here!"));
// Must return 0 to tell WIN32 that this VxD supports DEVIOCTL
dwRetVal = 0;
}
// DIOC_CLOSEHANDLE is sent when VxD is unloaded w/ CloseHandle
// (this happens just before SYS_DYNAMIC_EXIT)
else if (dwService == DIOC_CLOSEHANDLE)
{
// Dispatch to cleanup proc
dwRetVal = VKernelEx_CleanUp();
}
else if (dwService > MAX_VKERNELEX_W32_API)
{
// Returning a positive value will cause the WIN32 DeviceIOControl
// call to return FALSE, the error code can then be retrieved
// via the WIN32 GetLastError
dwRetVal = ERROR_NOT_SUPPORTED;
}
else
{
// CALL requested service
dwRetVal = (VKernelEx_W32_Proc[dwService-1])(hDevice, lpDIOCParms);
}
return dwRetVal;
}
DWORD _stdcall VKernelEx_IOCTL_Connect(DWORD hDevice, PDIOCPARAMETERS lpDIOCParms)
{
DBGPRINTF(("VKernelEx_IOCTL_Connect"));
if (lpDIOCParms->cbOutBuffer < sizeof(s_connect_params))
return ERROR_INVALID_PARAMETER;
memcpy((void*) lpDIOCParms->lpvOutBuffer, &s_connect_params, sizeof(s_connect_params));
*(DWORD*) lpDIOCParms->lpcbBytesReturned = sizeof(s_connect_params);
return NO_ERROR;
}
BOOL _stdcall VKernelEx_Create_Process(DWORD pid)
{
return VXD_SUCCESS;
}
BOOL _stdcall VKernelEx_Destroy_Process(DWORD pid)
{
return VXD_SUCCESS;
}
BOOL _stdcall VKernelEx_Begin_PM_App(HVM hVM)
{
WORD version;
void* k32ptr;
void* backup = NULL;
bool allOK = false;
if (!Test_Sys_VM_Handle(hVM))
return TRUE;
version = Get_VMM_Version();
if (version >= 0x045A)
k32ptr = (void*) 0xBFF60000; //WINME
else
k32ptr = (void*) 0xBFF70000; //WIN98
__try
{
WORD sign = 0;
__try
{
sign = *(WORD*) k32ptr;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
if (sign == 'ZM')
{
DBGPRINTF(("KERNEL32 located @ 0x%08x", k32ptr));
PEmanip pem;
pem.OpenMemory(k32ptr);
backup = pem.CreateBackup();
Patch_kernel32 patch(pem);
if (patch.apply())
{
allOK = true;
s_connect_params.status = true;
s_connect_params.vxd_version = MAKEWORD(V_MINOR, V_MAJOR);
s_connect_params.stub_ptr = patch.stub_address;
}
}
else
DBGPRINTF(("couldn't locate KERNEL32"));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
if (!allOK)
{
DBGPRINTF(("KERNEL32 patch failed!"));
if (backup != NULL)
memcpy(k32ptr, backup, _HeapGetSize(backup, 0));
}
if (backup != NULL)
_HeapFree(backup, 0);
return TRUE;
}
BOOL _stdcall VKernelEx_Dynamic_Exit(void)
{
DBGPRINTF(("Exit"));
return VXD_SUCCESS;
}
DWORD _stdcall VKernelEx_CleanUp(void)
{
DBGPRINTF(("Cleaning Up"));
return VXD_SUCCESS;
}
#pragma VxD_ICODE_SEG
#pragma VxD_IDATA_SEG
BOOL _stdcall VKernelEx_Critical_Init(void)
{
DBGPRINTF(("KernelEx Virtual Device v" STR(V_MAJOR) "." STR(V_MINOR)));
DBGPRINTF(("Critical Init"));
Patch_ifsmgr patch;
patch.apply();
return VXD_SUCCESS;
}
BOOL _stdcall VKernelEx_Dynamic_Init(void)
{
DBGPRINTF(("Init"));
return VXD_SUCCESS;
}

35
vxd/vxdmain.h Executable file
View File

@ -0,0 +1,35 @@
/*
* KernelEx
* Copyright (C) 2011, 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 __VXDMAIN_H
#define __VXDMAIN_H
BOOL _stdcall VKernelEx_Critical_Init(void);
BOOL _stdcall VKernelEx_Dynamic_Init(void);
BOOL _stdcall VKernelEx_Dynamic_Exit(void);
DWORD _stdcall VKernelEx_W32_DeviceIOControl(DWORD, DWORD, PDIOCPARAMETERS);
DWORD _stdcall VKernelEx_CleanUp(void);
DWORD _stdcall VKernelEx_IOCTL_Connect(DWORD, PDIOCPARAMETERS);
BOOL _stdcall VKernelEx_Create_Process(DWORD pid);
BOOL _stdcall VKernelEx_Destroy_Process(DWORD pid);
BOOL _stdcall VKernelEx_Begin_PM_App(HVM hVM);
#endif