Skip to content

Commit

Permalink
Fix an issue with being unable to hook specific APIs under certain
Browse files Browse the repository at this point in the history
versions of Windows.  Make the default hook type configurable at runtime
via the option "hook-type".  Only usable for 32-bit analyses currently, it
supports the following values: "direct", "indirect", and "safe".  Added a
new hook type selectable by the "safe" option which uses a detours-style
hook when possible.  Default to relative jump hooks for our deep IE hooks.
Add GetTickCount64 hooking.  Don't log some unnecessary APIs.
  • Loading branch information
spender-sandbox committed Jan 15, 2016
1 parent 0458acc commit 17436b6
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 30 deletions.
17 changes: 17 additions & 0 deletions config.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "config.h"
#include "misc.h"
#include "log.h"
#include "hooking.h"

int read_config(void)
{
Expand All @@ -41,6 +42,12 @@ int read_config(void)
}

g_config.force_sleepskip = -1;
#ifdef _WIN64
g_config.hook_type = HOOK_JMP_INDIRECT;
#else
g_config.hook_type = HOOK_HOTPATCH_JMP_INDIRECT;
#endif

memset(buf, 0, sizeof(buf));
while (fgets(buf, sizeof(buf), fp) != NULL)
{
Expand Down Expand Up @@ -132,6 +139,16 @@ int read_config(void)
else if (!strcmp(key, "debug")) {
g_config.debug = atoi(value);
}
else if (!strcmp(key, "hook-type")) {
#ifndef _WIN64
if (!strcmp(value, "direct"))
g_config.hook_type = HOOK_JMP_DIRECT;
else if (!strcmp(value, "indirect"))
g_config.hook_type = HOOK_JMP_INDIRECT;
else if (!strcmp(value, "safe"))
g_config.hook_type = HOOK_SAFEST;
#endif
}
else if (!strcmp(key, "disable_hook_content")) {
g_config.disable_hook_content = value[0] == '1';
}
Expand Down
3 changes: 3 additions & 0 deletions config.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ struct _g_config {
// Debugging level (1 = display exceptions, 2 = display all exceptions)
int debug;

// Default hook type (may be overridden for specific functions)
int hook_type;

// Disable hook content
int disable_hook_content;

Expand Down
34 changes: 9 additions & 25 deletions cuckoomon.c
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,8 @@ static hook_t g_hooks[] = {
HOOK(kernel32, GetSystemTime),
HOOK(kernel32, GetSystemTimeAsFileTime),
HOOK(kernel32, GetTickCount),
HOOK(ntdll, NtQuerySystemTime),
HOOK(kernel32, GetTickCount64),
HOOK(ntdll, NtQuerySystemTime),
HOOK(user32, GetLastInputInfo),
HOOK(winmm, timeGetTime),
//
Expand Down Expand Up @@ -540,22 +541,13 @@ static hook_t g_hooks[] = {
HOOK(cryptsp, CryptCreateHash),
};

// get a random hooking method, except for hook_jmp_direct
//#define HOOKTYPE randint(HOOK_NOP_JMP_DIRECT, HOOK_MOV_EAX_INDIRECT_PUSH_RETN)
// error testing with hook_jmp_direct only
#ifdef _WIN64
#define HOOKTYPE HOOK_JMP_INDIRECT
#else
#define HOOKTYPE HOOK_HOTPATCH_JMP_INDIRECT
#endif

void set_hooks_dll(const wchar_t *library)
{
int i;

for (i = 0; i < ARRAYSIZE(g_hooks); i++) {
if(!wcsicmp(g_hooks[i].library, library)) {
if (hook_api(&g_hooks[i], HOOKTYPE) < 0)
if (hook_api(&g_hooks[i], g_config.hook_type) < 0)
pipe("WARNING:Unable to hook %z", g_hooks[i].funcname);
}
}
Expand Down Expand Up @@ -647,7 +639,7 @@ void set_hooks()
// now, hook each api :)
for (i = 0; i < ARRAYSIZE(g_hooks); i++) {
//pipe("INFO:Hooking %z", g_hooks[i].funcname);
if (hook_api(&g_hooks[i], HOOKTYPE) < 0)
if (hook_api(&g_hooks[i], g_config.hook_type) < 0)
pipe("WARNING:Unable to hook %z", g_hooks[i].funcname);
}

Expand Down Expand Up @@ -831,7 +823,7 @@ BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)

get_lasterrors(&lasterror);

if(dwReason == DLL_PROCESS_ATTACH) {
if (dwReason == DLL_PROCESS_ATTACH) {
unsigned int i;
DWORD pids[MAX_PROTECTED_PIDS];
unsigned int length = sizeof(pids);
Expand All @@ -840,19 +832,11 @@ BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
complete, and then did a successful createremotethread, so just do a cheap check for our hooks and fake that
we loaded successfully
*/
#ifdef _WIN64
#if HOOKTYPE != HOOK_JMP_INDIRECT
#error Update hook check
#endif
if (((PUCHAR)WaitForDebugEvent)[0] == 0xff && ((PUCHAR)WaitForDebugEvent)[1] == 0x25)
/* Doesn't handle all hook types, modify as necessary */
if (!memcmp((PUCHAR)WaitForDebugEvent, "\x8b\xff\xff\x25", 4) || !memcmp((PUCHAR)WaitForDebugEvent, "\xff\x25", 2) ||
!memcmp((PUCHAR)WaitForDebugEvent, "\x8b\xff\xe9", 3) || !memcmp((PUCHAR)WaitForDebugEvent, "\xe9", 1) ||
!memcmp((PUCHAR)WaitForDebugEvent, "\xeb\xf9", 2))
goto early_abort;
#else
#if HOOKTYPE != HOOK_HOTPATCH_JMP_INDIRECT
#error Update hook check
#endif
if (((PUCHAR)WaitForDebugEvent)[0] == 0x8b && ((PUCHAR)WaitForDebugEvent)[1] == 0xff && ((PUCHAR)WaitForDebugEvent)[2] == 0xff && ((PUCHAR)WaitForDebugEvent)[3] == 0x25)
goto early_abort;
#endif

g_our_dll_base = (ULONG_PTR)hModule;
g_our_dll_size = get_image_size(g_our_dll_base);
Expand Down
8 changes: 8 additions & 0 deletions hook_process.c
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,10 @@ HOOKDEF(NTSTATUS, WINAPI, NtProtectVirtualMemory,
ret = Old_NtProtectVirtualMemory(ProcessHandle, BaseAddress,
NumberOfBytesToProtect, NewAccessProtection, OldAccessProtection);

/* Don't log an uninteresting case */
if (OldAccessProtection && *OldAccessProtection == NewAccessProtection)
return ret;

memset(&meminfo, 0, sizeof(meminfo));
if (NT_SUCCESS(ret)) {
lasterror_t lasterrors;
Expand Down Expand Up @@ -572,6 +576,10 @@ HOOKDEF(BOOL, WINAPI, VirtualProtectEx,
ret = Old_VirtualProtectEx(hProcess, lpAddress, dwSize, flNewProtect,
lpflOldProtect);

/* Don't log an uninteresting case */
if (lpflOldProtect && *lpflOldProtect == flNewProtect)
return ret;

memset(&meminfo, 0, sizeof(meminfo));
if (ret) {
lasterror_t lasterrors;
Expand Down
12 changes: 12 additions & 0 deletions hook_sleep.c
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,18 @@ HOOKDEF(DWORD, WINAPI, GetTickCount,
return ret;
}

HOOKDEF(ULONGLONG, WINAPI, GetTickCount64,
void
) {
ULONGLONG ret = Old_GetTickCount64();

// add the time we've skipped
ret += (time_skipped.QuadPart / 10000);

return ret;
}


HOOKDEF(NTSTATUS, WINAPI, NtQuerySystemTime,
_Out_ PLARGE_INTEGER SystemTime
) {
Expand Down
1 change: 1 addition & 0 deletions hooking.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ enum {
HOOK_SPECIAL_JMP,
HOOK_NATIVE_JMP_INDIRECT,
HOOK_HOTPATCH_JMP_INDIRECT,
HOOK_SAFEST,
HOOK_TECHNIQUE_MAXTYPE,
};
#else
Expand Down
40 changes: 35 additions & 5 deletions hooking_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,14 @@ static int hook_api_native_jmp_indirect(hook_t *h, unsigned char *from,
return hook_api_jmp_indirect(h, from, to);
}

static int hook_api_safest(hook_t *h, unsigned char *from, unsigned char *to)
{
hook_api_jmp_direct(h, from - 5, to);
*from++ = 0xeb;
*from++ = 0xf9;
return 0;
}

hook_data_t *alloc_hookdata_near(void *addr)
{
DWORD oldprot;
Expand Down Expand Up @@ -621,6 +629,7 @@ int hook_api(hook_t *h, int type)
/* HOOK_SPECIAL_JMP */ {&hook_api_special_jmp, 7},
/* HOOK_NATIVE_JMP_INDIRECT */ {&hook_api_native_jmp_indirect, 11 },
/* HOOK_HOTPATCH_JMP_INDIRECT */{ &hook_api_hotpatch_jmp_indirect, 8 },
/* HOOK_SAFEST */{ &hook_api_safest, 2 },
};

// is this address already hooked?
Expand All @@ -631,7 +640,7 @@ int hook_api(hook_t *h, int type)
// resolve the address to hook
addr = h->addr;

if(addr == NULL && h->library != NULL && h->funcname != NULL) {
if(addr == NULL && h->library != NULL && h->funcname != NULL) {
HMODULE hmod = GetModuleHandleW(h->library);
/* if the DLL isn't loaded, don't bother attempting anything else */
if (hmod == NULL)
Expand All @@ -646,12 +655,18 @@ int hook_api(hook_t *h, int type)
}
addr = (unsigned char *)get_near_rel_target(&baseaddr[instroff]);
}
else if (!strcmp(h->funcname, "JsEval"))
else if (!strcmp(h->funcname, "JsEval")) {
type = HOOK_JMP_DIRECT;
addr = (unsigned char *)get_jseval_addr(hmod);
else if (!strcmp(h->funcname, "COleScript_ParseScriptText"))
}
else if (!strcmp(h->funcname, "COleScript_ParseScriptText")) {
type = HOOK_JMP_DIRECT;
addr = (unsigned char *)get_olescript_parsescripttext_addr(hmod);
else if (!strcmp(h->funcname, "CDocument_write"))
}
else if (!strcmp(h->funcname, "CDocument_write")) {
type = HOOK_JMP_DIRECT;
addr = (unsigned char *)get_cdocument_write_addr(hmod);
}
else
addr = (unsigned char *)GetProcAddress(hmod, h->funcname);
}
Expand Down Expand Up @@ -720,6 +735,14 @@ int hook_api(hook_t *h, int type)
if (!strcmp(h->funcname, "GetSystemTime"))
type = HOOK_JMP_DIRECT;

/* Some versions of Windows will leave us with a short jump over
a looped pause instruction in the bytes we want to modify for a
small number of APIs (GetTickCount/GetSystemTimeAsFileTime)
*/
if (!memcmp(addr, "\x8b\xff\x55\x8b\xec\xeb\x02", 7)) {
type = HOOK_JMP_DIRECT;
}

// check if this is a valid hook type
if (type < 0 && type >= ARRAYSIZE(hook_types)) {
pipe("WARNING: Provided invalid hook type: %d", type);
Expand All @@ -741,6 +764,10 @@ int hook_api(hook_t *h, int type)
if (address_already_hooked(addr))
return 0;

if (type == HOOK_SAFEST && (memcmp(addr, "\x8b\xff", 2) ||
(memcmp(addr - 5, "\xcc\xcc\xcc\xcc\xcc", 5) && memcmp(addr - 5, "\x90\x90\x90\x90\x90", 5))))
type = HOOK_JMP_DIRECT;

// make the address writable
if (VirtualProtect(addr, hook_types[type].len, PAGE_EXECUTE_READWRITE,
&old_protect)) {
Expand All @@ -764,7 +791,10 @@ int hook_api(hook_t *h, int type)
// Add unhook detection for our newly created hook.
// Ensure any changes behind our hook are also caught by
// making the buffersize 16.
unhook_detect_add_region(h, addr, orig, addr, 16);
if (type == HOOK_SAFEST)
unhook_detect_add_region(h, addr - 5, orig, addr, 16);
else
unhook_detect_add_region(h, addr, orig, addr, 16);

// if successful, assign the trampoline address to *old_func
if (ret == 0) {
Expand Down
4 changes: 4 additions & 0 deletions hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -1921,6 +1921,10 @@ extern HOOKDEF(DWORD, WINAPI, GetTickCount,
void
);

extern HOOKDEF(ULONGLONG, WINAPI, GetTickCount64,
void
);

extern HOOKDEF(NTSTATUS, WINAPI, NtQuerySystemTime,
_Out_ PLARGE_INTEGER SystemTime
);
Expand Down

0 comments on commit 17436b6

Please sign in to comment.