2010-03-11 22:16:41 -08:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif /* HAVE_CONFIG_H */
|
|
|
|
|
2008-02-27 13:01:30 -08:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
2012-02-17 12:48:11 -08:00
|
|
|
#ifndef WIN32_LEAN_AND_MEAN
|
|
|
|
# define WIN32_LEAN_AND_MEAN
|
|
|
|
#endif
|
2011-09-14 00:44:09 -07:00
|
|
|
#include <windows.h>
|
2012-02-17 12:48:11 -08:00
|
|
|
#undef WIN32_LEAN_AND_MEAN
|
|
|
|
|
2014-07-13 01:59:40 -07:00
|
|
|
#include <psapi.h> /* EnumProcessModules(Ex) */
|
2011-09-14 00:44:09 -07:00
|
|
|
|
2012-08-19 01:59:51 -07:00
|
|
|
#include "Evil.h"
|
2012-10-05 13:09:47 -07:00
|
|
|
#include "evil_private.h"
|
2008-04-26 09:27:46 -07:00
|
|
|
|
|
|
|
#include "dlfcn.h"
|
|
|
|
|
2008-02-27 13:01:30 -08:00
|
|
|
|
2015-04-26 07:36:08 -07:00
|
|
|
static char *_dl_err = NULL;
|
|
|
|
static int _dl_err_viewed = 0;
|
2008-02-27 13:01:30 -08:00
|
|
|
|
|
|
|
static void
|
2015-04-26 07:36:08 -07:00
|
|
|
_dl_get_last_error(char *desc)
|
2008-02-27 13:01:30 -08:00
|
|
|
{
|
2015-04-26 07:36:08 -07:00
|
|
|
char *str;
|
2009-08-27 01:19:06 -07:00
|
|
|
size_t l1;
|
|
|
|
size_t l2;
|
2008-02-27 13:01:30 -08:00
|
|
|
|
2008-06-08 14:39:49 -07:00
|
|
|
str = evil_last_error_get();
|
2008-02-27 13:01:30 -08:00
|
|
|
|
|
|
|
l1 = strlen(desc);
|
2008-06-08 14:39:49 -07:00
|
|
|
l2 = strlen(str);
|
2008-02-27 13:01:30 -08:00
|
|
|
|
2015-04-26 07:36:08 -07:00
|
|
|
if (_dl_err)
|
|
|
|
free(_dl_err);
|
2008-02-27 13:01:30 -08:00
|
|
|
|
2015-04-26 07:36:08 -07:00
|
|
|
_dl_err = (char *)malloc(sizeof(char) * (l1 + l2 + 1));
|
|
|
|
if (!_dl_err)
|
|
|
|
_dl_err = strdup("not enough resource");
|
2008-02-27 13:01:30 -08:00
|
|
|
else
|
|
|
|
{
|
2015-04-26 07:36:08 -07:00
|
|
|
memcpy(_dl_err, desc, l1);
|
|
|
|
memcpy(_dl_err + l1, str, l2);
|
|
|
|
_dl_err[l1 + l2] = '\0';
|
2008-02-27 13:01:30 -08:00
|
|
|
}
|
2008-06-08 14:39:49 -07:00
|
|
|
free(str);
|
2015-04-26 07:36:08 -07:00
|
|
|
_dl_err_viewed = 0;
|
2008-02-27 13:01:30 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void *
|
2012-10-05 13:09:47 -07:00
|
|
|
dlopen(const char* path, int mode EVIL_UNUSED)
|
2008-02-27 13:01:30 -08:00
|
|
|
{
|
|
|
|
HMODULE module = NULL;
|
|
|
|
|
|
|
|
if (!path)
|
|
|
|
{
|
|
|
|
module = GetModuleHandle(NULL);
|
|
|
|
if (!module)
|
2015-04-26 07:36:08 -07:00
|
|
|
_dl_get_last_error("GetModuleHandle returned: ");
|
2008-02-27 13:01:30 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-08-27 01:19:06 -07:00
|
|
|
char *new_path;
|
|
|
|
size_t l;
|
|
|
|
unsigned int i;
|
2008-02-27 13:01:30 -08:00
|
|
|
|
|
|
|
/* according to MSDN, we must change the slash to backslash */
|
|
|
|
l = strlen(path);
|
|
|
|
new_path = (char *)malloc(sizeof(char) * (l + 1));
|
|
|
|
if (!new_path)
|
|
|
|
{
|
2015-04-26 07:36:08 -07:00
|
|
|
if (_dl_err)
|
|
|
|
free(_dl_err);
|
|
|
|
_dl_err = strdup("not enough resource");
|
|
|
|
_dl_err_viewed = 0;
|
2008-02-27 13:01:30 -08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
for (i = 0; i <= l; i++)
|
|
|
|
{
|
|
|
|
if (path[i] == '/')
|
|
|
|
new_path[i] = '\\';
|
|
|
|
else
|
|
|
|
new_path[i] = path[i];
|
|
|
|
}
|
2008-06-08 14:39:49 -07:00
|
|
|
#ifdef UNICODE
|
2008-02-27 13:01:30 -08:00
|
|
|
{
|
|
|
|
wchar_t *wpath;
|
|
|
|
|
2008-04-26 09:27:46 -07:00
|
|
|
wpath = evil_char_to_wchar(new_path);
|
2008-03-13 10:46:53 -07:00
|
|
|
module = LoadLibrary(wpath);
|
2008-02-27 13:01:30 -08:00
|
|
|
free(wpath);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
module = LoadLibraryEx(new_path, NULL,
|
|
|
|
LOAD_WITH_ALTERED_SEARCH_PATH);
|
2008-06-08 14:39:49 -07:00
|
|
|
#endif /* ! UNICODE */
|
2008-02-27 13:01:30 -08:00
|
|
|
if (!module)
|
2015-04-26 07:36:08 -07:00
|
|
|
_dl_get_last_error("LoadLibraryEx returned: ");
|
2008-02-27 13:01:30 -08:00
|
|
|
|
|
|
|
free(new_path);
|
|
|
|
}
|
|
|
|
|
|
|
|
return module;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
dlclose(void* handle)
|
|
|
|
{
|
|
|
|
if (FreeLibrary(handle))
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
{
|
2015-04-26 07:36:08 -07:00
|
|
|
_dl_get_last_error("FreeLibrary returned: ");
|
2008-02-27 13:01:30 -08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void *
|
|
|
|
dlsym(void *handle, const char *symbol)
|
|
|
|
{
|
2011-09-14 00:44:09 -07:00
|
|
|
FARPROC fp = NULL;
|
|
|
|
LPCTSTR new_symbol;
|
2008-02-27 13:01:30 -08:00
|
|
|
|
2011-09-14 00:44:09 -07:00
|
|
|
if (!symbol || !*symbol) return NULL;
|
2008-02-27 13:01:30 -08:00
|
|
|
|
2011-09-14 00:44:09 -07:00
|
|
|
#ifdef UNICODE
|
|
|
|
new_symbol = evil_char_to_wchar(symbol);
|
2008-02-27 13:01:30 -08:00
|
|
|
#else
|
2011-09-14 00:44:09 -07:00
|
|
|
new_symbol = symbol;
|
|
|
|
#endif /* UNICODE */
|
|
|
|
|
|
|
|
if (handle == RTLD_DEFAULT)
|
|
|
|
{
|
|
|
|
HMODULE modules[1024];
|
|
|
|
DWORD needed;
|
|
|
|
DWORD i;
|
|
|
|
|
|
|
|
/* TODO: use EnumProcessModulesEx() on Windows >= Vista */
|
|
|
|
if (!EnumProcessModules(GetCurrentProcess(),
|
|
|
|
modules, sizeof(modules), &needed))
|
2015-04-26 07:38:10 -07:00
|
|
|
{
|
|
|
|
#ifdef UNICODE
|
|
|
|
_dl_get_last_error("EnumProcessModules returned: ");
|
|
|
|
free((void *)new_symbol);
|
|
|
|
#endif /* UNICODE */
|
|
|
|
return NULL;
|
|
|
|
}
|
2011-09-14 00:44:09 -07:00
|
|
|
|
2015-04-26 07:36:08 -07:00
|
|
|
for (i = 0; i < (needed / sizeof(HMODULE)); i++)
|
2011-09-14 00:44:09 -07:00
|
|
|
{
|
|
|
|
fp = GetProcAddress(modules[i], new_symbol);
|
|
|
|
if (fp) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
fp = GetProcAddress(handle, new_symbol);
|
|
|
|
|
|
|
|
#ifdef UNICODE
|
2011-10-05 14:06:08 -07:00
|
|
|
free((void *)new_symbol);
|
2011-09-14 00:44:09 -07:00
|
|
|
#endif /* UNICODE */
|
|
|
|
|
2008-02-27 13:01:30 -08:00
|
|
|
if (!fp)
|
2015-04-26 07:36:08 -07:00
|
|
|
_dl_get_last_error("GetProcAddress returned: ");
|
2008-02-27 13:01:30 -08:00
|
|
|
|
|
|
|
return fp;
|
|
|
|
}
|
|
|
|
|
2015-04-29 01:50:11 -07:00
|
|
|
char *
|
|
|
|
dlerror (void)
|
|
|
|
{
|
|
|
|
if (!_dl_err_viewed)
|
|
|
|
{
|
|
|
|
_dl_err_viewed = 1;
|
|
|
|
return _dl_err;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (_dl_err)
|
|
|
|
free(_dl_err);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef _GNU_SOURCE
|
|
|
|
|
|
|
|
static char _dli_fname[MAX_PATH];
|
|
|
|
static char _dli_sname[MAX_PATH]; /* a symbol should have at most 255 char */
|
|
|
|
|
|
|
|
static int
|
|
|
|
_dladdr_comp(const void *p1, const void *p2)
|
|
|
|
{
|
|
|
|
return ( *(int *)p1 - *(int *)p2);
|
|
|
|
}
|
|
|
|
|
2008-04-28 07:34:55 -07:00
|
|
|
int
|
2012-10-05 13:09:47 -07:00
|
|
|
dladdr (const void *addr EVIL_UNUSED, Dl_info *info)
|
2008-04-28 07:34:55 -07:00
|
|
|
{
|
2015-04-29 01:50:11 -07:00
|
|
|
TCHAR tpath[PATH_MAX];
|
2009-09-26 14:36:01 -07:00
|
|
|
MEMORY_BASIC_INFORMATION mbi;
|
2015-04-29 01:50:11 -07:00
|
|
|
unsigned char *base;
|
|
|
|
char *path;
|
2009-08-27 01:19:06 -07:00
|
|
|
size_t length;
|
2015-04-29 01:50:11 -07:00
|
|
|
|
|
|
|
IMAGE_NT_HEADERS *nth;
|
|
|
|
IMAGE_EXPORT_DIRECTORY *ied;
|
|
|
|
DWORD *addresses;
|
|
|
|
WORD *ordinals;
|
|
|
|
DWORD *names;
|
|
|
|
DWORD *tmp;
|
|
|
|
DWORD res;
|
|
|
|
DWORD rva_addr;
|
|
|
|
DWORD i;
|
2008-04-28 07:34:55 -07:00
|
|
|
|
2010-01-19 05:46:45 -08:00
|
|
|
if (!info)
|
|
|
|
return 0;
|
2008-04-28 07:34:55 -07:00
|
|
|
|
2015-04-29 01:50:11 -07:00
|
|
|
info->dli_fname = NULL;
|
|
|
|
info->dli_fbase = NULL;
|
|
|
|
info->dli_sname = NULL;
|
|
|
|
info->dli_saddr = NULL;
|
|
|
|
|
|
|
|
/* Get the name and base address of the module */
|
|
|
|
|
|
|
|
if (!VirtualQuery(addr, &mbi, sizeof(mbi)))
|
|
|
|
{
|
|
|
|
_dl_get_last_error("VirtualQuery returned: ");
|
|
|
|
return 0;
|
|
|
|
}
|
2009-09-26 14:36:01 -07:00
|
|
|
|
2010-01-19 05:46:45 -08:00
|
|
|
if (mbi.State != MEM_COMMIT)
|
|
|
|
return 0;
|
2009-09-26 14:36:01 -07:00
|
|
|
|
2010-01-19 05:46:45 -08:00
|
|
|
if (!mbi.AllocationBase)
|
|
|
|
return 0;
|
2009-09-26 14:36:01 -07:00
|
|
|
|
2015-04-29 01:50:11 -07:00
|
|
|
base = (unsigned char *)mbi.AllocationBase;
|
2008-04-28 07:34:55 -07:00
|
|
|
|
2015-04-29 01:50:11 -07:00
|
|
|
if (!GetModuleFileName((HMODULE)base, (LPTSTR)&tpath, PATH_MAX))
|
|
|
|
{
|
|
|
|
_dl_get_last_error("GetModuleFileName returned: ");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
# ifdef UNICODE
|
2008-04-28 07:34:55 -07:00
|
|
|
path = evil_wchar_to_char(tpath);
|
2015-04-29 01:50:11 -07:00
|
|
|
# else
|
2008-04-28 07:34:55 -07:00
|
|
|
path = tpath;
|
2015-04-29 01:50:11 -07:00
|
|
|
# endif /* ! UNICODE */
|
2008-04-28 07:34:55 -07:00
|
|
|
|
2015-04-29 01:50:11 -07:00
|
|
|
length = strlen(path);
|
2008-04-28 07:34:55 -07:00
|
|
|
if (length >= PATH_MAX)
|
|
|
|
{
|
|
|
|
length = PATH_MAX - 1;
|
|
|
|
path[PATH_MAX - 1] = '\0';
|
|
|
|
}
|
|
|
|
|
2015-04-29 01:50:11 -07:00
|
|
|
memcpy(_dli_fname, path, length + 1);
|
|
|
|
info->dli_fname = (const char *)_dli_fname;
|
|
|
|
info->dli_fbase = base;
|
2008-05-09 16:16:42 -07:00
|
|
|
|
2015-04-29 01:50:11 -07:00
|
|
|
# ifdef UNICODE
|
|
|
|
free(path);
|
|
|
|
# endif /* ! UNICODE */
|
2008-04-28 07:34:55 -07:00
|
|
|
|
2015-04-29 01:50:11 -07:00
|
|
|
/* get the name and the address of the required symbol */
|
2008-04-28 07:34:55 -07:00
|
|
|
|
2015-04-29 01:50:11 -07:00
|
|
|
if (((IMAGE_DOS_HEADER *)base)->e_magic != IMAGE_DOS_SIGNATURE)
|
|
|
|
{
|
|
|
|
SetLastError(1276);
|
|
|
|
return 0;
|
|
|
|
}
|
2008-04-28 07:34:55 -07:00
|
|
|
|
2015-04-29 01:50:11 -07:00
|
|
|
nth = (IMAGE_NT_HEADERS *)(base + ((IMAGE_DOS_HEADER *)base)->e_lfanew);
|
|
|
|
if (nth->Signature != IMAGE_NT_SIGNATURE)
|
2008-02-27 13:01:30 -08:00
|
|
|
{
|
2015-04-29 01:50:11 -07:00
|
|
|
SetLastError(1276);
|
|
|
|
return 0;
|
2008-02-27 13:01:30 -08:00
|
|
|
}
|
2015-04-29 01:50:11 -07:00
|
|
|
|
|
|
|
/* no exported symbols ? it's an EXE and we exit without error */
|
|
|
|
if (nth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == 0)
|
2008-02-27 13:01:30 -08:00
|
|
|
{
|
2015-04-29 01:50:11 -07:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we assume now that the PE file is well-formed, so checks only when needed */
|
|
|
|
ied = (IMAGE_EXPORT_DIRECTORY *)(base + nth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
|
|
|
|
addresses = (DWORD *)(base + ied->AddressOfFunctions);
|
|
|
|
ordinals = (WORD *)(base + ied->AddressOfNameOrdinals);
|
|
|
|
names = (DWORD *)(base + ied->AddressOfNames);
|
|
|
|
|
|
|
|
/* the addresses are not ordered, so we need to order them */
|
|
|
|
tmp = malloc(ied->NumberOfFunctions * sizeof(DWORD));
|
|
|
|
if (!tmp)
|
|
|
|
{
|
|
|
|
SetLastError(8);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(tmp, addresses, ied->NumberOfFunctions * sizeof(DWORD));
|
|
|
|
qsort(tmp, ied->NumberOfFunctions, sizeof(DWORD), _dladdr_comp);
|
|
|
|
rva_addr = (unsigned char *)addr - base;
|
|
|
|
res = (DWORD)(-1);
|
|
|
|
for (i = 0; i < ied->NumberOfFunctions; i++)
|
|
|
|
{
|
|
|
|
if (tmp[i] < rva_addr)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
res = tmp[i];
|
|
|
|
break;
|
2008-02-27 13:01:30 -08:00
|
|
|
}
|
2015-04-29 01:50:11 -07:00
|
|
|
|
|
|
|
/* if rva_addr is too high, we store the latest address */
|
|
|
|
if (res == (DWORD)(-1))
|
|
|
|
res = tmp[ied->NumberOfFunctions - 1];
|
|
|
|
|
|
|
|
free(tmp);
|
|
|
|
|
|
|
|
for (i = 0; i < ied->NumberOfNames; i++)
|
|
|
|
{
|
|
|
|
if (addresses[ordinals[i]] == res)
|
|
|
|
{
|
|
|
|
char *name;
|
|
|
|
|
|
|
|
name = (char *)(base + names[i]);
|
|
|
|
length = strlen(name);
|
|
|
|
if (length >= PATH_MAX)
|
|
|
|
{
|
|
|
|
length = PATH_MAX - 1;
|
|
|
|
name[PATH_MAX - 1] = '\0';
|
|
|
|
}
|
|
|
|
memcpy(_dli_sname, name, length + 1);
|
|
|
|
info->dli_sname = (const char *)_dli_sname;
|
|
|
|
info->dli_saddr = base + res;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2008-02-27 13:01:30 -08:00
|
|
|
}
|
2015-04-29 01:50:11 -07:00
|
|
|
|
|
|
|
#endif /* _GNU_SOURCE */
|