Skip to content

Commit

Permalink
Fix crash in 32 bit final build.
Browse files Browse the repository at this point in the history
Fixed a fourth bug that was preventing 32 bit clink from injecting
successfully.  Commit 304e8a3 in Nov 2017 lost the __stdcall calling
convention (the lambda didn't specify __stdcall, and also the function
pointer types lost __stdcall).
  • Loading branch information
chrisant996 committed Oct 23, 2020
1 parent 0fedc93 commit 7de2c4a
Show file tree
Hide file tree
Showing 10 changed files with 68 additions and 68 deletions.
2 changes: 1 addition & 1 deletion clink/app/src/dll/dll.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ static void shutdown_clink()
}

//------------------------------------------------------------------------------
bool initialise_clink(const app_context::desc& app_desc)
INT_PTR WINAPI initialise_clink(const app_context::desc& app_desc)
{
seh_scope seh;

Expand Down
8 changes: 3 additions & 5 deletions clink/app/src/host/host_cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ bool host_cmd::initialise()
DWORD ret = GetEnvironmentVariableW(lpName, lpBuffer, nSize);

void* base = GetModuleHandle(nullptr);
hook_iat(base, nullptr, "GetEnvironmentVariableW", funcptr_t(GetEnvironmentVariableW), 1);
hook_iat(base, nullptr, "GetEnvironmentVariableW", hookptr_t(GetEnvironmentVariableW), 1);

host_cmd::get()->initialise_system();
return ret;
Expand Down Expand Up @@ -503,14 +503,12 @@ bool host_cmd::initialise_system()
app_context::get()->get_binaries_dir(dll_path);

str<560> buffer;
buffer << "\"" << dll_path;
buffer << "\\" CLINK_EXE "\" $*";
buffer << "\"" << dll_path << "\\" << CLINK_EXE << "\" $*";
m_doskey.add_alias("clink", buffer.c_str());

// Add an alias to operate on the command history.
buffer.clear();
buffer << "\"" << dll_path;
buffer << "\\" CLINK_EXE "\" history $*";
buffer << "\"" << dll_path << "\\" << CLINK_EXE << "\" history $*";
m_doskey.add_alias("history", buffer.c_str());
}

Expand Down
2 changes: 1 addition & 1 deletion clink/app/src/loader/inject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ int inject(int argc, char** argv)
void* our_dll_base = vm().get_alloc_base("");
uintptr_t init_func = uintptr_t(remote_dll_base);
init_func += uintptr_t(initialise_clink) - uintptr_t(our_dll_base);
ret |= (process(target_pid).remote_call((void*)init_func, app_desc) != nullptr);
ret |= (process(target_pid).remote_call((process::funcptr_t)init_func, app_desc) != nullptr);

return ret;
}
4 changes: 2 additions & 2 deletions clink/app/src/utils/hook_setter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ hook_setter::hook_desc* hook_setter::add_desc(
hook_type type,
void* module,
const char* name,
funcptr_t hook)
hookptr_t hook)
{
if (m_desc_count >= sizeof_array(m_descs))
return nullptr;
Expand All @@ -62,7 +62,7 @@ hook_setter::hook_desc* hook_setter::add_desc(
//------------------------------------------------------------------------------
bool hook_setter::commit_iat(void* self, const hook_desc& desc)
{
funcptr_t addr = hook_iat(desc.module, nullptr, desc.name, desc.hook, 1);
hookptr_t addr = hook_iat(desc.module, nullptr, desc.name, desc.hook, 1);
if (addr == nullptr)
{
LOG("Unable to hook %s in IAT at base %p", desc.name, desc.module);
Expand Down
10 changes: 5 additions & 5 deletions clink/app/src/utils/hook_setter.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
class hook_setter
{
public:
typedef void (__stdcall *funcptr_t)();
typedef void (__stdcall *hookptr_t)();

hook_setter();
template <typename RET,
Expand All @@ -30,11 +30,11 @@ class hook_setter
{
void* module;
const char* name;
funcptr_t hook;
hookptr_t hook;
hook_type type;
};

hook_desc* add_desc(hook_type type, void* module, const char* name, funcptr_t hook);
hook_desc* add_desc(hook_type type, void* module, const char* name, hookptr_t hook);
bool commit_iat(void* self, const hook_desc& desc);
bool commit_jmp(void* self, const hook_desc& desc);
hook_desc m_descs[4];
Expand All @@ -45,12 +45,12 @@ class hook_setter
template <typename RET, typename... ARGS>
bool hook_setter::add_iat(void* module, const char* name, RET (__stdcall *hook)(ARGS...))
{
return (add_desc(hook_type_iat_by_name, module, name, funcptr_t(hook)) != nullptr);
return (add_desc(hook_type_iat_by_name, module, name, hookptr_t(hook)) != nullptr);
}

//------------------------------------------------------------------------------
template <typename RET, typename... ARGS>
bool hook_setter::add_jmp(void* module, const char* name, RET (__stdcall *hook)(ARGS...))
{
return (add_desc(hook_type_jmp, module, name, funcptr_t(hook)) != nullptr);
return (add_desc(hook_type_jmp, module, name, hookptr_t(hook)) != nullptr);
}
6 changes: 3 additions & 3 deletions clink/process/include/process/hook.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#pragma once

typedef void (__stdcall *funcptr_t)();
typedef void (__stdcall *hookptr_t)();

funcptr_t hook_iat(void* base, const char* dll, const char* func_name, funcptr_t hook, int find_by_name);
funcptr_t hook_jmp(void* module, const char* func_name, funcptr_t hook);
hookptr_t hook_iat(void* base, const char* dll, const char* func_name, hookptr_t hook, int find_by_name);
hookptr_t hook_jmp(void* module, const char* func_name, hookptr_t hook);
2 changes: 1 addition & 1 deletion clink/process/include/process/pe.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
class pe_info
{
public:
typedef void (__stdcall *funcptr_t)();
typedef FARPROC funcptr_t;
pe_info(void* base);
funcptr_t* get_import_by_name(const char* dll, const char* func_name) const;
funcptr_t* get_import_by_addr(const char* dll, funcptr_t func_addr) const;
Expand Down
7 changes: 4 additions & 3 deletions clink/process/include/process/process.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,20 @@ class process
{
public:
enum arch { arch_unknown, arch_x86, arch_x64 };
typedef FARPROC funcptr_t;

process(int pid=-1);
int get_pid() const;
bool get_file_name(str_base& out) const;
arch get_arch() const;
int get_parent_pid() const;
void* inject_module(const char* dll);
template <typename T> void* remote_call(void* function, T const& param);
template <typename T> void* remote_call(funcptr_t function, T const& param);
void pause();
void unpause();

private:
void* remote_call(void* function, const void* param, int param_size);
void* remote_call(funcptr_t function, const void* param, int param_size);
void pause(bool suspend);
int m_pid;

Expand All @@ -46,7 +47,7 @@ inline int process::get_pid() const

//------------------------------------------------------------------------------
template <typename T>
void* process::remote_call(void* function, T const& param)
void* process::remote_call(funcptr_t function, T const& param)
{
return remote_call(function, &param, sizeof(param));
}
Expand Down
40 changes: 20 additions & 20 deletions clink/process/src/hook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include <core/log.h>

//------------------------------------------------------------------------------
static void write_addr(funcptr_t* where, funcptr_t to_write)
static void write_addr(hookptr_t* where, hookptr_t to_write)
{
vm vm;
vm::region region = { vm.get_page(where), 1 };
Expand All @@ -24,44 +24,44 @@ static void write_addr(funcptr_t* where, funcptr_t to_write)
}

//------------------------------------------------------------------------------
static funcptr_t get_proc_addr(const char* dll, const char* func_name)
static hookptr_t get_proc_addr(const char* dll, const char* func_name)
{
if (void* base = LoadLibraryA(dll))
return pe_info(base).get_export(func_name);
return (hookptr_t)pe_info(base).get_export(func_name);

LOG("Failed to load library '%s'", dll);
return nullptr;
}

//------------------------------------------------------------------------------
funcptr_t hook_iat(
hookptr_t hook_iat(
void* base,
const char* dll,
const char* func_name,
funcptr_t hook,
hookptr_t hook,
int find_by_name
)
{
LOG("Attempting to hook IAT for module %p", base);
LOG("Target is %s,%s (by_name=%d)", dll, func_name, find_by_name);

funcptr_t* import;
hookptr_t* import;

// Find entry and replace it.
pe_info pe(base);
if (find_by_name)
import = pe.get_import_by_name(nullptr, func_name);
import = (hookptr_t*)pe.get_import_by_name(nullptr, func_name);
else
{
// Get the address of the function we're going to hook.
funcptr_t func_addr = get_proc_addr(dll, func_name);
hookptr_t func_addr = get_proc_addr(dll, func_name);
if (func_addr == nullptr)
{
LOG("Failed to find function '%s' in '%s'", func_name, dll);
return nullptr;
}

import = pe.get_import_by_addr(nullptr, func_addr);
import = (hookptr_t*)pe.get_import_by_addr(nullptr, (pe_info::funcptr_t)func_addr);
}

if (import == nullptr)
Expand All @@ -72,7 +72,7 @@ funcptr_t hook_iat(

LOG("Found import at %p (value = %p)", import, *import);

funcptr_t prev_addr = *import;
hookptr_t prev_addr = *import;
write_addr(import, hook);

vm().flush_icache();
Expand All @@ -86,15 +86,15 @@ static char* alloc_trampoline(void* hint)
size_t page_size = vm::get_page_size();

vm vm;
funcptr_t trampoline = nullptr;
hookptr_t trampoline = nullptr;
while (trampoline == nullptr)
{
void* vm_alloc_base = vm.get_alloc_base(hint);
vm_alloc_base = vm_alloc_base ? vm_alloc_base : hint;

char* tramp_page = (char*)vm_alloc_base - alloc_granularity;

trampoline = funcptr_t(VirtualAlloc(tramp_page, page_size,
trampoline = hookptr_t(VirtualAlloc(tramp_page, page_size,
MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE));

hint = tramp_page;
Expand Down Expand Up @@ -138,7 +138,7 @@ static char* write_rel_jmp(char* write, const void* dest)
}

//------------------------------------------------------------------------------
static char* write_trampoline_out(void* const dest, void* const to_hook, funcptr_t const hook)
static char* write_trampoline_out(void* const dest, void* const to_hook, hookptr_t const hook)
{
const int rel_jmp_size = 5;
int offset = 0;
Expand Down Expand Up @@ -209,7 +209,7 @@ static char* write_trampoline_out(void* const dest, void* const to_hook, funcptr
struct {
char a[2];
char b[4];
char c[sizeof(funcptr_t)];
char c[sizeof(hookptr_t)];
} inst;

*(short*)inst.a = 0x25ff;
Expand All @@ -220,7 +220,7 @@ static char* write_trampoline_out(void* const dest, void* const to_hook, funcptr
#endif

*(int*)inst.b = rel_addr;
*(funcptr_t*)inst.c = hook;
*(hookptr_t*)inst.c = hook;

if (!vm().write(write, &inst, sizeof(inst)))
{
Expand Down Expand Up @@ -341,7 +341,7 @@ void* follow_jump(void* addr)
}

//------------------------------------------------------------------------------
static funcptr_t hook_jmp_impl(funcptr_t to_hook, funcptr_t hook)
static hookptr_t hook_jmp_impl(hookptr_t to_hook, hookptr_t hook)
{
LOG("Attempting to hook at %p with %p", to_hook, hook);

Expand Down Expand Up @@ -387,18 +387,18 @@ static funcptr_t hook_jmp_impl(funcptr_t to_hook, funcptr_t hook)
}

vm.set_access(target_region, prev_access);
return funcptr_t(trampoline);
return hookptr_t(trampoline);
}

//------------------------------------------------------------------------------
funcptr_t hook_jmp(void* module, const char* func_name, funcptr_t hook)
hookptr_t hook_jmp(void* module, const char* func_name, hookptr_t hook)
{
char module_name[96];
module_name[0] = '\0';
GetModuleFileName(HMODULE(module), module_name, sizeof_array(module_name));

// Get the address of the function we're going to hook.
funcptr_t func_addr = pe_info(module).get_export(func_name);
hookptr_t func_addr = (hookptr_t)pe_info(module).get_export(func_name);
if (func_addr == nullptr)
{
LOG("Failed to find function '%s' in '%s'", func_name, module_name);
Expand All @@ -409,7 +409,7 @@ funcptr_t hook_jmp(void* module, const char* func_name, funcptr_t hook)
LOG("Target is %s, %s @ %p", module_name, func_name, func_addr);

// Install the hook.
funcptr_t trampoline = hook_jmp_impl(func_addr, hook);
hookptr_t trampoline = hook_jmp_impl(func_addr, hook);
if (trampoline == nullptr)
{
LOG("Jump hook failed.");
Expand Down
55 changes: 28 additions & 27 deletions clink/process/src/process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,47 +144,48 @@ void* process::inject_module(const char* dll_path)
// LoadLibraryW hooked then we'd get a potentially invalid address if we
// were to just use &LoadLibraryW.
pe_info kernel32(LoadLibrary("kernel32.dll"));
void* thread_proc = (void*)kernel32.get_export("LoadLibraryW");
pe_info::funcptr_t func = kernel32.get_export("LoadLibraryW");

wstr<280> wpath(dll_path);
return remote_call(thread_proc, wpath.data(), wpath.length() * sizeof(wchar_t));
return remote_call(func, wpath.data(), wpath.length() * sizeof(wchar_t));
}

//------------------------------------------------------------------------------
void* process::remote_call(void* function, const void* param, int param_size)
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4200)
#endif
struct thunk_data
{
void* (WINAPI* func)(void*);
void* out;
char in[];
};
#if defined(_MSC_VER)
# pragma warning(pop)
#endif

//------------------------------------------------------------------------------
static DWORD WINAPI stdcall_thunk(thunk_data& data)
{
data.out = data.func(data.in);
return 0;
}

//------------------------------------------------------------------------------
void* process::remote_call(pe_info::funcptr_t function, const void* param, int param_size)
{
// Open the process so we can operate on it.
handle process_handle = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_CREATE_THREAD,
FALSE, m_pid);
if (!process_handle)
return nullptr;

#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4200)
#endif
struct thunk_data
{
void* (*func)(void*);
void* out;
char in[];
};
#if defined(_MSC_VER)
# pragma warning(pop)
#endif

const auto& thunk = [] (thunk_data& data) -> DWORD {
data.out = data.func(data.in);
return 0;
};

auto* stdcall_thunk = static_cast<DWORD (__stdcall*)(thunk_data&)>(thunk);
// Scanning for 0xc3 works on 64 bit, but not on 32 bit. I gave up and just
// imposed a max size of 64 bytes, since the emited code is around 40 bytes.
static int thunk_size;
// TODO: 0xc3 is incorrect for 32 bit. Currently it's getting lucky that a
// 0xc3 occurs reasonably soon after the actual lambda code, but it ends up
// copying quite a few more bytes than it meant/needed to.
if (!thunk_size)
for (const auto* c = (unsigned char*)stdcall_thunk; ++thunk_size, *c++ != 0xc3;);
for (const auto* c = (unsigned char*)stdcall_thunk; thunk_size < 64 && ++thunk_size, *c++ != 0xc3;);

vm vm(m_pid);
vm::region region = vm.alloc(1, vm::access_write);
Expand Down

0 comments on commit 7de2c4a

Please sign in to comment.