* Copyright (c) 2005-2008 VMware, Inc. All rights reserved.
* **********************************************************/
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
Hook three times the same guy with different hooks
VirtualProtect()
VirtualProtect()
VirtualProtect()
and make sure that they get properly executed
since we'd have a cache consistency problem when leaving RWX
Then we have a real hook that doesn't let the syscall through,
therefore TWO writes are considered bad and we have a security violation.
*/
#include "tools.h"
#include <windows.h>
const char *hookfn = "VirtualProtect";
#define NDEP
#define FARAWAY_DLL "ADVAPI32.DLL"
const char *faraway_hook = "RegOpenKeyA";
#define NAKED __declspec(naked)
* find a function with the same prologue or actually do some real
* work to get it copied around.
*/
NAKED
hooker1()
{
#if 0
asm {
pusha
pushf
}
asm {
popf
popa
}
asm {
push ebp
mov ebp,esp
push dword ptr [ebp+0x14]
}
#endif
}
enum { HOOK_SIZE = 0x1000 };
* machines, for now keeping here
*/
void
unset_x(DWORD *hooktarget, DWORD prot)
{
DWORD prev;
DWORD size = HOOK_SIZE;
int res = VirtualProtect(hooktarget, size, prot, &prev);
DWORD gle = GetLastError();
print("VirtualProtect(%s[" PFX "],%d," PFX ",prev) = %d GLE=" PFMT " prev=" PFMT "\n",
hookfn, (hooktarget , 0), size, prot, res, gle, prev);
}
void
hook(DWORD *hooktarget)
{
DWORD prev;
DWORD size = HOOK_SIZE;
DWORD prot = PAGE_EXECUTE_READWRITE;
int res = VirtualProtect(hooktarget, size, prot, &prev);
DWORD gle = GetLastError();
print("VirtualProtect(%s[" PFX "],%d," PFX ",prev) = %d GLE=" PFMT " prev=" PFMT "\n",
hookfn, (hooktarget , 0), size, prot, res, gle, prev);
*hooktarget = *hooktarget;
}
void
ret_hook(DWORD *hooktarget)
{
DWORD old_code = *hooktarget;
DWORD prev = 0xbadcde;
DWORD size = HOOK_SIZE;
int res;
*hooktarget = 0x900010c2;
res = VirtualProtect(hooktarget, size, PAGE_EXECUTE_READWRITE, &prev);
print("VirtualProtect(%s[" PFX "],%d,PAGE_EXECUTE_READWRITE,prev) = %d GLE=" PFMT
" prev=" PFMT "\n",
hookfn, (hooktarget , 0), size, (res , 0),
GetLastError(), prev);
*hooktarget = old_code;
}
char *
prot_string(uint prot)
{
uint ignore_extras = prot & ~(PAGE_GUARD | PAGE_NOCACHE | PAGE_WRITECOMBINE);
switch (ignore_extras) {
case PAGE_NOACCESS: return "----";
case PAGE_READONLY: return "r---";
case PAGE_READWRITE: return "rw--";
case PAGE_WRITECOPY: return "rw-c";
case PAGE_EXECUTE: return "--x-";
case PAGE_EXECUTE_READ: return "r-x-";
case PAGE_EXECUTE_READWRITE: return "rwx-";
case PAGE_EXECUTE_WRITECOPY: return "rwxc";
}
return "(error)";
}
bool
prot_is_executable(uint prot)
{
prot &= ~(PAGE_GUARD | PAGE_NOCACHE | PAGE_WRITECOMBINE);
return (prot == PAGE_EXECUTE || prot == PAGE_EXECUTE_READ ||
prot == PAGE_EXECUTE_READWRITE || prot == PAGE_EXECUTE_WRITECOPY);
}
void
query(DWORD *hooktarget)
{
MEMORY_BASIC_INFORMATION mbi;
DWORD res = VirtualQuery(hooktarget, &mbi, sizeof(mbi));
if (res == sizeof(mbi)) {
print("VirtualQuery(" PFX ") = %d GLE=" PFMT " prev=" PFMT " %s\n",
(hooktarget , 0), res, GetLastError(), mbi.Protect,
prot_string(mbi.Protect));
print(" DEP => %s\n", prot_is_executable(mbi.Protect) ? "ok" : "NOT EXECUTABLE");
} else {
print("VirtualQuery(" PFX ") = %d GLE=" PFMT "\n", (hooktarget , 0),
res, GetLastError());
}
}
int
main()
{
HANDLE kern32 = GetModuleHandle(TEXT("KERNEL32.DLL"));
DWORD *addr_hook = (DWORD *)GetProcAddress(kern32, hookfn);
HANDLE far_dll = LoadLibrary(TEXT(FARAWAY_DLL));
DWORD *unset_hook = (DWORD *)GetProcAddress(far_dll, faraway_hook);
INIT();
#ifdef NDEP
assert(far_dll != NULL);
assert(unset_hook != NULL);
assert(((ptr_int_t)unset_hook >> 12) != ((ptr_int_t)addr_hook >> 12));
print("unset X bit\n");
unset_x(unset_hook, PAGE_WRITECOPY);
unset_x(unset_hook, PAGE_READWRITE);
unset_x(unset_hook, PAGE_READWRITE | PAGE_GUARD);
unset_x(unset_hook, PAGE_READWRITE | PAGE_GUARD);
print("ready to hook far\n");
hook(unset_hook);
print("doublecheck flags\n");
query(unset_hook);
#endif
print("ready to hook\n");
hook(addr_hook);
print("one more\n");
hook(addr_hook);
print("now third ...\n");
hook(addr_hook);
print("doublecheck flags\n");
query(addr_hook);
print("check consistency ...\n");
ret_hook(addr_hook);
hook(addr_hook);
print("hooking done with\n");
}