add relocate_hook to improve api hooking, fix dll name string comparison (no case sensitive), fix used after free on win32, add more hooks related to async file access
This commit is contained in:
@@ -53,6 +53,9 @@
|
||||
/* #undef HAVE_GETC_UNLOCKED */
|
||||
/* #undef HAVE_GETDELIM */
|
||||
/* #undef HAVE_GETLINE */
|
||||
#define HAVE_CREATEIOCOMPLETIONPORT 1
|
||||
#define HAVE_GETQUEUEDCOMPLETIONSTATUS 1
|
||||
#define HAVE_GETOVERLAPPEDRESULT 1
|
||||
#define HAVE_GETPAGESIZE 1
|
||||
/* #undef HAVE_GETTIMEOFDAY */
|
||||
/* #undef HAVE_GLIBC_FILE */
|
||||
|
||||
+65
-2
@@ -61,6 +61,15 @@ static BOOL (__stdcall *ORIG(ReadFile))(HANDLE, LPVOID, DWORD, LPDWORD,
|
||||
static BOOL (__stdcall *ORIG(ReadFileEx))(HANDLE, LPVOID, DWORD, LPDWORD,
|
||||
LPOVERLAPPED, LPOVERLAPPED_COMPLETION_ROUTINE);
|
||||
#endif
|
||||
#if defined HAVE_CREATEIOCOMPLETIONPORT
|
||||
static HANDLE (__stdcall *ORIG(CreateIoCompletionPort))(HANDLE, HANDLE, ULONG_PTR, DWORD);
|
||||
#endif
|
||||
#if defined HAVE_GETQUEUEDCOMPLETIONSTATUS
|
||||
static BOOL (__stdcall *ORIG(GetQueuedCompletionStatus))(HANDLE, LPDWORD, PULONG_PTR, LPOVERLAPPED *, DWORD);
|
||||
#endif
|
||||
#if defined HAVE_GETOVERLAPPEDRESULT
|
||||
static BOOL (__stdcall *ORIG(GetOverlappedResult))(HANDLE, LPOVERLAPPED, LPDWORD, BOOL);
|
||||
#endif
|
||||
#if defined HAVE_CREATEFILEMAPPINGA
|
||||
static HANDLE (__stdcall *ORIG(CreateFileMappingA))(HANDLE, LPSECURITY_ATTRIBUTES,
|
||||
DWORD, DWORD, DWORD, LPCSTR);
|
||||
@@ -200,6 +209,57 @@ BOOL __stdcall NEW(ReadFileEx)(HANDLE hFile, LPVOID lpBuffer,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined HAVE_CREATEIOCOMPLETIONPORT
|
||||
HANDLE __stdcall NEW(CreateIoCompletionPort)(HANDLE FileHandle, HANDLE ExistingCompletionPort, ULONG_PTR CompletionKey, DWORD NumberOfConcurrentThreads)
|
||||
{
|
||||
HANDLE ret;
|
||||
|
||||
ret = ORIG(CreateIoCompletionPort)(FileHandle, ExistingCompletionPort, CompletionKey, NumberOfConcurrentThreads);
|
||||
|
||||
debug("GetQueuedCompletionStatus(0x%08x, 0x%08x, 0x%08x, %d) = 0x%08x",
|
||||
FileHandle, ExistingCompletionPort, CompletionKey, NumberOfConcurrentThreads, ret);
|
||||
|
||||
if (!_zz_ready || !_zz_iswatched(FileHandle) /*|| !_zz_hostwatched(hFile)*/ || _zz_islocked(FileHandle) || !_zz_isactive(FileHandle))
|
||||
return ret;
|
||||
|
||||
if (ret != NULL)
|
||||
{
|
||||
debug("handle %#08x is registered", ret);
|
||||
_zz_register(ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined HAVE_GETQUEUEDCOMPLETIONSTATUS
|
||||
BOOL __stdcall NEW(GetQueuedCompletionStatus)(HANDLE CompletionPort, LPDWORD lpNumberOfBytes, PULONG_PTR lpCompletion, LPOVERLAPPED *lpOverlapped, DWORD dwMilliseconds)
|
||||
{
|
||||
BOOL ret;
|
||||
|
||||
ret = ORIG(GetQueuedCompletionStatus)(CompletionPort, lpNumberOfBytes, lpCompletion, lpOverlapped, dwMilliseconds);
|
||||
|
||||
debug("GetQueuedCompletionStatus(0x%08x, { %d }, %p, %p, %d) = %s",
|
||||
CompletionPort, *lpNumberOfBytes, lpCompletion, lpOverlapped, dwMilliseconds, (ret ? "TRUE" : "FALSE"));
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined HAVE_GETOVERLAPPEDRESULT
|
||||
BOOL __stdcall NEW(GetOverlappedResult)(HANDLE hFile, LPOVERLAPPED lpOverlapped, LPDWORD lpNumberOfBytesTransferred, BOOL bWait)
|
||||
{
|
||||
BOOL ret;
|
||||
|
||||
ret = ORIG(GetOverlappedResult)(hFile, lpOverlapped, lpNumberOfBytesTransferred, bWait);
|
||||
|
||||
debug("GetOverlappedResult(0x%#08x, %p, %p, %s) = %s",
|
||||
hFile, lpOverlapped, lpNumberOfBytesTransferred, (bWait ? "TRUE" : "FALSE"), (ret ? "TRUE" : "FALSE"));
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined HAVE_CREATEFILEMAPPINGA
|
||||
HANDLE __stdcall NEW(CreateFileMappingA)(HANDLE hFile, LPSECURITY_ATTRIBUTES lpAttributes,
|
||||
DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow,
|
||||
@@ -298,11 +358,14 @@ zzuf_table_t table_win32[] =
|
||||
DIVERT(CloseHandle),
|
||||
DIVERT(CreateFileA),
|
||||
DIVERT(CreateFileW),
|
||||
DIVERT(ReadFile),
|
||||
DIVERT(ReadFileEx),
|
||||
DIVERT(CreateIoCompletionPort),
|
||||
DIVERT(GetQueuedCompletionStatus),
|
||||
DIVERT(GetOverlappedResult),
|
||||
DIVERT(CreateFileMappingA),
|
||||
DIVERT(CreateFileMappingW),
|
||||
DIVERT(MapViewOfFile),
|
||||
DIVERT(ReadFile),
|
||||
DIVERT(ReadFileEx),
|
||||
DIVERT_END
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -233,7 +233,7 @@ BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, PVOID impLoad)
|
||||
_zz_init();
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
_zz_fini();
|
||||
//_zz_fini();
|
||||
DeleteCriticalSection(&_zz_pipe_cs);
|
||||
break;
|
||||
}
|
||||
|
||||
+57
-16
@@ -105,12 +105,11 @@ static int modrm_sib_size(uint8_t* code)
|
||||
|
||||
if (modrm == 0x05) /* [(rip) + sdword] */ return 1 + 4;
|
||||
|
||||
/* Does the instruciton have a SIB byte ? */
|
||||
/* Does this instruction have a SIB byte ? */
|
||||
return 1 + (!!(((modrm & 0x7) == 0x4) && ((modrm >> 6) != 0x3))) + modrm_size[modrm >> 6];
|
||||
}
|
||||
|
||||
/* zz_lde is a _very_ simple length disassemble engine.
|
||||
* x64 is not tested and should not work. */
|
||||
/* zz_lde is a _very_ simple length disassemble engine. */
|
||||
static int zz_lde(uint8_t *code)
|
||||
{
|
||||
int insn_size = 0;
|
||||
@@ -130,8 +129,9 @@ static int zz_lde(uint8_t *code)
|
||||
/* Simple instructions should be placed here */
|
||||
switch (opcd)
|
||||
{
|
||||
case 0x68: insn_size += 4; break; /* PUSH Iv */
|
||||
case 0x6a: insn_size += 1; break; /* PUSH Ib */
|
||||
case 0x68: return (insn_size + 4); /* PUSH Iv */
|
||||
case 0x6a: return (insn_size + 1); /* PUSH Ib */
|
||||
case 0x90: return insn_size; /* NOP */
|
||||
default: break;
|
||||
}
|
||||
|
||||
@@ -143,28 +143,25 @@ static int zz_lde(uint8_t *code)
|
||||
{
|
||||
case 0x89: /* mov Ev, Gv */
|
||||
case 0x8b: /* mov Gv, Ev */
|
||||
insn_size += modrm_sib_size(code + insn_size);
|
||||
break;
|
||||
return (insn_size + modrm_sib_size(code + insn_size));
|
||||
|
||||
case 0x80: /* Group#1 Eb, Ib */
|
||||
case 0x82: /* Group#1 Eb, Ib */
|
||||
case 0x83: /* Group#1 Ev, Ib */
|
||||
insn_size += (modrm_sib_size(code + insn_size) + 1);
|
||||
break;
|
||||
return (insn_size + (modrm_sib_size(code + insn_size) + 1));
|
||||
|
||||
case 0x81: /* Group#1 Ev, Iz */
|
||||
insn_size += (modrm_sib_size(code + insn_size) + 4);
|
||||
break;
|
||||
return (insn_size + (modrm_sib_size(code + insn_size) + 4));
|
||||
|
||||
case 0xff:
|
||||
if ((code[insn_size] & 0x38) == 0x30) /* PUSH Ev */
|
||||
insn_size += modrm_sib_size(code + insn_size);
|
||||
return (insn_size + modrm_sib_size(code + insn_size));
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
return insn_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function returns the required size to insert a patch */
|
||||
@@ -260,6 +257,46 @@ static int make_trampoline(uint8_t *code, size_t patch_size, uint8_t **trampolin
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Sometimes Windows APIs are a stub and contain only a JMP to the real function.
|
||||
* To avoid to relocate a JMP, we use the destination address.
|
||||
*/
|
||||
static int relocate_hook(uint8_t **code)
|
||||
{
|
||||
uint8_t *cur_code = *code;
|
||||
|
||||
#ifdef _M_AMD64
|
||||
// we ignore the REX prefix
|
||||
if ((*cur_code & 0xf8) == 0x48)
|
||||
++cur_code;
|
||||
#endif
|
||||
|
||||
/* JMP Jd */
|
||||
if (*cur_code == 0xe9)
|
||||
{
|
||||
*cur_code += (5 + *(uint32_t *)(cur_code + 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* JMP [(rip)+addr] */
|
||||
else if (!memcmp(cur_code, "\xff\x25", 2))
|
||||
{
|
||||
#ifdef _M_AMD64
|
||||
uint8_t **dst_addr = (uint8_t **)(cur_code + 6 + *(uint32_t *)(cur_code + 2));
|
||||
*code = *dst_addr;
|
||||
#elif _M_IX86
|
||||
/* UNTESTED ! */
|
||||
uint8_t **dst_addr = *(uint32_t *)(*cur_code + 2);
|
||||
*code = *dst_addr;
|
||||
#else
|
||||
# error Unsupported architecture !
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* This function allows to hook any API. To do so, it disassembles the beginning of the
|
||||
* targeted function and looks for, at least, 5 bytes (size of JMP Jd).
|
||||
* Then it writes a JMP Jv instruction to make the new_api executed.
|
||||
@@ -273,6 +310,10 @@ static int hook_inline(uint8_t *old_api, uint8_t *new_api, uint8_t **trampoline_
|
||||
uint8_t *trampoline = NULL;
|
||||
size_t trampoline_size = 0;
|
||||
DWORD old_prot;
|
||||
uint8_t *reloc_old_api = old_api;
|
||||
|
||||
while ((relocate_hook(&reloc_old_api)) >= 0)
|
||||
old_api = reloc_old_api;
|
||||
|
||||
*trampoline_api = NULL;
|
||||
|
||||
@@ -344,18 +385,18 @@ static void insert_funcs(void)
|
||||
if ((lib = LoadLibraryA(diversion->lib)) == NULL)
|
||||
{
|
||||
fprintf(stderr, "unable to load %s\n", diversion->lib);
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ((old_api = (uint8_t *)GetProcAddress(lib, diversion->name)) == NULL)
|
||||
{
|
||||
fprintf(stderr, "unable to get pointer to %s\n", diversion->name);
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
if (hook_inline(old_api, diversion->new, &trampoline_api) < 0)
|
||||
{
|
||||
fprintf(stderr, "hook_inline failed while hooking %s!%s\n", diversion->lib, diversion->name);
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
*diversion->old = trampoline_api;
|
||||
}
|
||||
|
||||
+2
-2
@@ -485,7 +485,7 @@ static int dll_inject(PROCESS_INFORMATION *pinfo, char const *lib)
|
||||
if (SuspendThread(thread) == (DWORD)-1) goto _return;
|
||||
|
||||
/* Resolve LoadLibraryA from the target process memory context */
|
||||
rldlib = get_proc_address(process, pid, "LoadLibraryA");
|
||||
if ((rldlib = get_proc_address(process, pid, "LoadLibraryA")) == NULL) goto _return;
|
||||
|
||||
if ((rpl = VirtualAllocEx(process, NULL, pl_len, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) == NULL) goto _return;
|
||||
|
||||
@@ -544,7 +544,7 @@ static void *get_proc_address(void *process, DWORD pid, const char *func)
|
||||
uint32_t exportaddr;
|
||||
uint8_t *base = entry.modBaseAddr;
|
||||
|
||||
if (strcmp("kernel32.dll", entry.szModule))
|
||||
if (stricmp("kernel32.dll", entry.szModule))
|
||||
continue;
|
||||
|
||||
ReadProcessMemory(process, base, &dos, sizeof(dos), &tmp);
|
||||
|
||||
Reference in New Issue
Block a user