summaryrefslogtreecommitdiff
path: root/src/modules
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2012-07-16 18:28:49 +0000
committerGeorge Hazan <george.hazan@gmail.com>2012-07-16 18:28:49 +0000
commitf7e482e4333df76b198b16c7685c2304007fbe79 (patch)
treedbc5bbd793cba9d4a7ce9c7440664318c53a0d02 /src/modules
parent5b0a53a6d3f1b8d70b34631d96d3815d0a334dd3 (diff)
dynamic dll checker
git-svn-id: http://svn.miranda-ng.org/main/trunk@989 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'src/modules')
-rw-r--r--src/modules/plugins/dll_sniffer.cpp150
-rw-r--r--src/modules/plugins/newplugins.cpp151
-rw-r--r--src/modules/plugins/pluginopts.cpp2
-rw-r--r--src/modules/plugins/plugins.h7
4 files changed, 220 insertions, 90 deletions
diff --git a/src/modules/plugins/dll_sniffer.cpp b/src/modules/plugins/dll_sniffer.cpp
new file mode 100644
index 0000000000..469cebf931
--- /dev/null
+++ b/src/modules/plugins/dll_sniffer.cpp
@@ -0,0 +1,150 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2010 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "..\..\core\commonheaders.h"
+#include "plugins.h"
+
+static IMAGE_SECTION_HEADER *getSectionByRVA(IMAGE_SECTION_HEADER *pISH, int nSections, IMAGE_DATA_DIRECTORY *pIDD)
+{
+ for (int i=0; i < nSections; i++, pISH++)
+ if (pIDD->VirtualAddress >= pISH->VirtualAddress && pIDD->VirtualAddress + pIDD->Size <= pISH->VirtualAddress + pISH->SizeOfRawData )
+ return pISH;
+
+ return NULL;
+}
+
+MUUID* GetPluginInterfaces(const TCHAR* ptszFileName, bool& bIsPlugin)
+{
+ bIsPlugin = false;
+
+ HANDLE hFile = CreateFile( ptszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
+ if (hFile == INVALID_HANDLE_VALUE)
+ return NULL;
+
+ MUUID* pResult = NULL;
+ BYTE* ptr = NULL;
+ HANDLE hMap = CreateFileMapping( hFile, NULL, PAGE_WRITECOPY, 0, 0, NULL );
+
+ __try
+ {
+ if ( !hMap )
+ __leave;
+
+ DWORD dwHSize = 0, filesize = GetFileSize( hFile, &dwHSize );
+ if ( !filesize || filesize == INVALID_FILE_SIZE || dwHSize)
+ __leave;
+
+ if ( filesize < sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS) )
+ __leave;
+
+ ptr = (BYTE*)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
+ if (ptr == NULL)
+ __leave;
+
+ PIMAGE_NT_HEADERS pINTH;
+ PIMAGE_DOS_HEADER pIDH = (PIMAGE_DOS_HEADER)ptr;
+ if ( pIDH->e_magic == IMAGE_DOS_SIGNATURE )
+ pINTH = (PIMAGE_NT_HEADERS)(ptr + pIDH->e_lfanew);
+ else
+ __leave;
+
+ if ((PBYTE)pINTH + sizeof(IMAGE_NT_HEADERS) >= ptr + filesize )
+ __leave;
+ if ( pINTH->Signature != IMAGE_NT_SIGNATURE )
+ __leave;
+
+ int nSections = pINTH->FileHeader.NumberOfSections;
+ if ( !nSections )
+ __leave;
+
+ INT_PTR base;
+ PIMAGE_DATA_DIRECTORY pIDD;
+ if ( pINTH->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 &&
+ pINTH->FileHeader.SizeOfOptionalHeader >= sizeof(IMAGE_OPTIONAL_HEADER32) &&
+ pINTH->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
+ {
+ pIDD = (PIMAGE_DATA_DIRECTORY)( (PBYTE)pINTH + offsetof( IMAGE_NT_HEADERS32, OptionalHeader.DataDirectory ));
+ base = *(DWORD*)((PBYTE)pINTH + offsetof(IMAGE_NT_HEADERS32, OptionalHeader.ImageBase));
+ }
+ else if ( pINTH->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64 &&
+ pINTH->FileHeader.SizeOfOptionalHeader >= sizeof(IMAGE_OPTIONAL_HEADER64) &&
+ pINTH->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
+ {
+ pIDD = (PIMAGE_DATA_DIRECTORY)( (PBYTE)pINTH + offsetof( IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory ));
+ base = *(ULONGLONG*)((PBYTE)pINTH + offsetof(IMAGE_NT_HEADERS64, OptionalHeader.ImageBase ));
+ }
+ else __leave;
+
+ // Export information entry
+ DWORD expvaddr = pIDD[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
+ DWORD expsize = pIDD[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
+ if (expsize < sizeof(IMAGE_EXPORT_DIRECTORY)) __leave;
+
+ BYTE* pImage = ptr + pIDH->e_lfanew + pINTH->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_NT_HEADERS) - sizeof(IMAGE_OPTIONAL_HEADER);
+ IMAGE_SECTION_HEADER *pExp = getSectionByRVA((IMAGE_SECTION_HEADER *)pImage, nSections, pIDD);
+ if ( !pExp) __leave;
+
+ BYTE *pSecStart = ptr + pExp->PointerToRawData - pExp->VirtualAddress;
+ IMAGE_EXPORT_DIRECTORY *pED = (PIMAGE_EXPORT_DIRECTORY)&pSecStart[expvaddr];
+ DWORD *ptrRVA = (DWORD*)&pSecStart[pED->AddressOfNames];
+ WORD *ptrOrdRVA = (WORD*)&pSecStart[pED->AddressOfNameOrdinals];
+ DWORD *ptrFuncList = (DWORD*)&pSecStart[pED->AddressOfFunctions];
+
+ MUUID* pIds;
+ bool bHasLoad = false, bHasUnload = false, bHasInfo = false, bHasMuuids = false;
+ for (size_t i=0; i < pED->NumberOfNames; i++, ptrRVA++, ptrOrdRVA++) {
+ char *szName = (char*)&pSecStart[*ptrRVA];
+ if ( !lstrcmpA(szName, "Load"))
+ bHasLoad = true;
+ if ( !lstrcmpA(szName, "MirandaPluginInfoEx"))
+ bHasInfo = true;
+ else if ( !lstrcmpA(szName, "Unload"))
+ bHasUnload = true;
+ else if ( !lstrcmpA(szName, "MirandaInterfaces")) {
+ bHasMuuids = true;
+ pIds = (MUUID*)&pSecStart[ ptrFuncList[*ptrOrdRVA]];
+ }
+ }
+
+ // a plugin might have no interfaces
+ if (bHasLoad && bHasUnload && bHasInfo)
+ bIsPlugin = true;
+
+ if (!bHasLoad || !bHasMuuids || !bHasUnload)
+ __leave;
+
+ int nLength = 1; // one for MIID_LAST
+ for (MUUID* p = pIds; !equalUUID(*p, miid_last); p++)
+ nLength++;
+
+ pResult = (MUUID*)mir_alloc( sizeof(MUUID)*nLength);
+ if (pResult)
+ memcpy(pResult, pIds, sizeof(MUUID)*nLength);
+ }
+ __finally
+ {
+ UnmapViewOfFile(ptr);
+ CloseHandle(hFile);
+ };
+
+ return pResult;
+}
diff --git a/src/modules/plugins/newplugins.cpp b/src/modules/plugins/newplugins.cpp
index 9712f01d07..3c27b63f22 100644
--- a/src/modules/plugins/newplugins.cpp
+++ b/src/modules/plugins/newplugins.cpp
@@ -91,14 +91,24 @@ int equalUUID(const MUUID& u1, const MUUID& u2)
return memcmp(&u1, &u2, sizeof(MUUID))?0:1;
}
+bool hasMuuid(const MUUID* p, const MUUID& uuid)
+{
+ if (p == NULL)
+ return false;
+
+ for (int i=0; !equalUUID(miid_last, p[i]); i++)
+ if ( equalUUID(uuid, p[i]))
+ return true;
+
+ return false;
+}
+
+
bool hasMuuid(const BASIC_PLUGIN_INFO& bpi, const MUUID& uuid)
{
- if (bpi.Interfaces) {
- MUUID *piface = bpi.Interfaces();
- for (int i=0; !equalUUID(miid_last, piface[i]); i++)
- if ( equalUUID(uuid, piface[i]))
- return true;
- }
+ if (bpi.Interfaces)
+ return hasMuuid(bpi.Interfaces, uuid);
+
return false;
}
@@ -162,13 +172,8 @@ MUUID miid_clist = MIID_CLIST;
MUUID miid_database = MIID_DATABASE;
MUUID miid_servicemode = MIID_SERVICEMODE;
-static bool validInterfaceList(Miranda_Plugin_Interfaces ifaceProc)
+static bool validInterfaceList(MUUID *piface)
{
- // we don't need'em anymore in the common case
- if (ifaceProc == NULL)
- return true;
-
- MUUID *piface = ifaceProc();
if (piface == NULL)
return false;
@@ -256,7 +261,7 @@ int checkAPI(TCHAR* plugin, BASIC_PLUGIN_INFO* bpi, DWORD mirandaVersion, int ch
bpi->Load = (Miranda_Plugin_Load) GetProcAddress(h, "Load");
bpi->Unload = (Miranda_Plugin_Unload) GetProcAddress(h, "Unload");
bpi->InfoEx = (Miranda_Plugin_InfoEx) GetProcAddress(h, "MirandaPluginInfoEx");
- bpi->Interfaces = (Miranda_Plugin_Interfaces) GetProcAddress(h, "MirandaPluginInterfaces");
+ bpi->Interfaces = (MUUID*) GetProcAddress(h, "MirandaInterfaces");
// if they were present
if ( !bpi->Load || !bpi->Unload || !bpi->InfoEx) {
@@ -367,42 +372,6 @@ static int valid_library_name(TCHAR *name)
return 0;
}
-// returns true if the given file matches dbx_*.dll, which is used to LoadLibrary()
-static int validguess_db_name(TCHAR *name)
-{
- int rc = 0;
- // this is ONLY SAFE because name -> ffd.cFileName == MAX_PATH
- TCHAR x = name[4];
- name[4] = 0;
- rc = lstrcmpi(name, _T("dbx_")) == 0 || lstrcmpi(name, _T("dbrw")) == 0;
- name[4] = x;
- return rc;
-}
-
-// returns true if the given file matches clist_*.dll
-static int validguess_clist_name(TCHAR *name)
-{
- int rc = 0;
- // argh evil
- TCHAR x = name[6];
- name[6] = 0;
- rc = lstrcmpi(name, _T("clist_")) == 0;
- name[6] = x;
- return rc;
-}
-
-// returns true if the given file matches svc_*.dll
-static int validguess_servicemode_name(TCHAR *name)
-{
- int rc = 0;
- // argh evil
- TCHAR x = name[4];
- name[4] = 0;
- rc = lstrcmpi(name, _T("svc_")) == 0;
- name[4] = x;
- return rc;
-}
-
void enumPlugins(SCAN_PLUGINS_CALLBACK cb, WPARAM wParam, LPARAM lParam)
{
// get miranda's exe path
@@ -456,16 +425,27 @@ static INT_PTR PluginsEnum(WPARAM, LPARAM lParam)
pluginEntry* OpenPlugin(TCHAR *tszFileName, TCHAR *dir, TCHAR *path)
{
- BASIC_PLUGIN_INFO bpi;
pluginEntry* p = (pluginEntry*)HeapAlloc(hPluginListHeap, HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, sizeof(pluginEntry));
_tcsncpy(p->pluginname, tszFileName, SIZEOF(p->pluginname));
- TCHAR buf[MAX_PATH];
- mir_sntprintf(buf, SIZEOF(buf), _T("%s\\%s\\%s"), path, dir, tszFileName);
+ // add it to the list anyway
+ pluginList.insert(p);
+
+ TCHAR tszFullPath[MAX_PATH];
+ mir_sntprintf(tszFullPath, SIZEOF(tszFullPath), _T("%s\\%s\\%s"), path, dir, tszFileName);
+
+ // map dll into the memory and check its exports
+ bool bIsPlugin = false;
+ mir_ptr<MUUID> pIds( GetPluginInterfaces(tszFullPath, bIsPlugin));
+ if ( !bIsPlugin) {
+ p->pclass |= PCLASS_FAILED; // piece of shit
+ return p;
+ }
- // plugin name suggests its a db module, load it right now
- if ( validguess_db_name(tszFileName)) {
- if (checkAPI(buf, &bpi, mirandaVersion, CHECKAPI_DB)) {
+ // plugin declared that it's a database. load it asap!
+ if ( hasMuuid(pIds, miid_database)) {
+ BASIC_PLUGIN_INFO bpi;
+ if (checkAPI(tszFullPath, &bpi, mirandaVersion, CHECKAPI_DB)) {
// db plugin is valid
p->pclass |= (PCLASS_DB | PCLASS_BASICAPI);
// copy the dblink stuff
@@ -478,14 +458,18 @@ pluginEntry* OpenPlugin(TCHAR *tszFileName, TCHAR *dir, TCHAR *path)
// didn't have basic APIs or DB exports - failed.
p->pclass |= PCLASS_FAILED;
}
- else if ( validguess_clist_name(tszFileName)) {
+ // plugin declared that it's a contact list. mark it for the future load
+ else if ( hasMuuid(pIds, miid_clist)) {
// keep a note of this plugin for later
if (pluginListUI != NULL) p->nextclass = pluginListUI;
pluginListUI = p;
p->pclass |= PCLASS_CLIST;
}
- else if ( validguess_servicemode_name(tszFileName)) {
- if (checkAPI(buf, &bpi, mirandaVersion, CHECKAPI_NONE)) {
+ // plugin declared that it's a service mode plugin.
+ // load it for a profile manager's window
+ else if ( hasMuuid(pIds, miid_servicemode)) {
+ BASIC_PLUGIN_INFO bpi;
+ if (checkAPI(tszFullPath, &bpi, mirandaVersion, CHECKAPI_NONE)) {
p->pclass |= (PCLASS_OK | PCLASS_BASICAPI);
p->bpi = bpi;
if ( hasMuuid(bpi, miid_servicemode)) {
@@ -499,28 +483,9 @@ pluginEntry* OpenPlugin(TCHAR *tszFileName, TCHAR *dir, TCHAR *path)
// didn't have basic APIs or DB exports - failed.
p->pclass |= PCLASS_FAILED;
}
-
- // add it to the list
- pluginList.insert(p);
return p;
}
-// called in the first pass to create pluginEntry* structures and validate database plugins
-static BOOL scanPluginsDir(WIN32_FIND_DATA *fd, TCHAR *path, WPARAM, LPARAM)
-{
- pluginEntry* p = OpenPlugin(fd->cFileName, _T("Plugins"), path);
- if ( !(p->pclass & PCLASS_FAILED)) {
- if (pluginList_freeimg == NULL && lstrcmpi(fd->cFileName, _T("advaimg.dll")) == 0)
- pluginList_freeimg = p;
-
- if (pluginList_crshdmp == NULL && lstrcmpi(fd->cFileName, _T("svc_crshdmp.dll")) == 0) {
- pluginList_crshdmp = p;
- p->pclass |= PCLASS_LAST;
- }
- }
-
- return TRUE;
-}
void SetPluginOnWhiteList(const TCHAR* pluginname, int allow)
{
@@ -572,7 +537,7 @@ bool TryLoadPlugin(pluginEntry *p, bool bDynamic)
p->pclass |= PCLASS_OK | PCLASS_BASICAPI;
if (p->bpi.Interfaces) {
- MUUID *piface = bpi.Interfaces();
+ MUUID *piface = bpi.Interfaces;
for (int i=0; !equalUUID(miid_last, piface[i]); i++) {
int idx = getDefaultPluginIdx( piface[i] );
if (idx != -1 && pluginDefault[idx].pImpl) {
@@ -591,7 +556,7 @@ bool TryLoadPlugin(pluginEntry *p, bool bDynamic)
p->pclass |= PCLASS_LOADED;
if (p->bpi.Interfaces) {
- MUUID *piface = bpi.Interfaces();
+ MUUID *piface = bpi.Interfaces;
for (int i=0; !equalUUID(miid_last, piface[i]); i++) {
int idx = getDefaultPluginIdx( piface[i] );
if (idx != -1)
@@ -744,7 +709,6 @@ void UnloadNewPlugins(void)
} }
/////////////////////////////////////////////////////////////////////////////////////////
-//
// Loads all plugins
int LoadNewPluginsModule(void)
@@ -827,6 +791,22 @@ int LoadNewPluginsModule(void)
// Plugins module initialization
// called before anything real is loaded, incl. database
+static BOOL scanPluginsDir(WIN32_FIND_DATA *fd, TCHAR *path, WPARAM, LPARAM)
+{
+ pluginEntry* p = OpenPlugin(fd->cFileName, _T("Plugins"), path);
+ if ( !(p->pclass & PCLASS_FAILED)) {
+ if (pluginList_freeimg == NULL && lstrcmpi(fd->cFileName, _T("advaimg.dll")) == 0)
+ pluginList_freeimg = p;
+
+ if (pluginList_crshdmp == NULL && lstrcmpi(fd->cFileName, _T("svc_crshdmp.dll")) == 0) {
+ pluginList_crshdmp = p;
+ p->pclass |= PCLASS_LAST;
+ }
+ }
+
+ return TRUE;
+}
+
int LoadNewPluginsModuleInfos(void)
{
bModuleInitialized = TRUE;
@@ -855,14 +835,13 @@ int LoadNewPluginsModuleInfos(void)
void UnloadNewPluginsModule(void)
{
- int i;
-
- if ( !bModuleInitialized) return;
+ if ( !bModuleInitialized)
+ return;
UnloadPluginOptions();
// unload everything but the DB
- for (i = pluginList.getCount()-1; i >= 0; i--) {
+ for (int i = pluginList.getCount()-1; i >= 0; i--) {
pluginEntry* p = pluginList[i];
if ( !(p->pclass & PCLASS_DB) && p != pluginList_crshdmp)
Plugin_Uninit(p);
@@ -872,8 +851,8 @@ void UnloadNewPluginsModule(void)
Plugin_Uninit(pluginList_crshdmp);
// unload the DB
- for (i = pluginList.getCount()-1; i >= 0; i--) {
- pluginEntry* p = pluginList[i];
+ for (int k = pluginList.getCount()-1; k >= 0; k--) {
+ pluginEntry* p = pluginList[k];
Plugin_Uninit(p);
}
diff --git a/src/modules/plugins/pluginopts.cpp b/src/modules/plugins/pluginopts.cpp
index 45d8080d98..0b0f8ab821 100644
--- a/src/modules/plugins/pluginopts.cpp
+++ b/src/modules/plugins/pluginopts.cpp
@@ -89,7 +89,7 @@ static BOOL dialogListPlugins(WIN32_FIND_DATA* fd, TCHAR* path, WPARAM, LPARAM l
dat->flags = 0;
if (pi.Interfaces) {
- MUUID *piface = pi.Interfaces();
+ MUUID *piface = pi.Interfaces;
for (int i=0; !equalUUID(miid_last, piface[i]); i++) {
int idx = getDefaultPluginIdx( piface[i] );
if (idx != -1 ) {
diff --git a/src/modules/plugins/plugins.h b/src/modules/plugins/plugins.h
index 6cfa8595c7..64118a45ed 100644
--- a/src/modules/plugins/plugins.h
+++ b/src/modules/plugins/plugins.h
@@ -17,8 +17,6 @@ typedef PLUGININFOEX * (__cdecl * Miranda_Plugin_InfoEx) (DWORD mirandaVersion);
typedef DATABASELINK * (__cdecl * Database_Plugin_Info) (void * reserved);
// prototype for clists
typedef int (__cdecl * CList_Initialise) (void);
-// Interface support
-typedef MUUID * (__cdecl * Miranda_Plugin_Interfaces) (void);
// can all be NULL
struct BASIC_PLUGIN_INFO
@@ -27,10 +25,10 @@ struct BASIC_PLUGIN_INFO
Miranda_Plugin_Load Load;
Miranda_Plugin_Unload Unload;
Miranda_Plugin_InfoEx InfoEx;
- Miranda_Plugin_Interfaces Interfaces;
Database_Plugin_Info DbInfo;
CList_Initialise clistlink;
PLUGININFOEX * pluginInfo; // must be freed if hInst = = NULL then its a copy
+ MUUID *Interfaces; // array of supported interfaces
DATABASELINK * dblink; // only valid during module being in memory
};
@@ -66,6 +64,7 @@ void SetPluginOnWhiteList(const TCHAR* pluginname, int allow);
int getDefaultPluginIdx(const MUUID& muuid);
bool hasMuuid(const BASIC_PLUGIN_INFO&, const MUUID&);
+bool hasMuuid(const MUUID* pFirst, const MUUID&);
int equalUUID(const MUUID& u1, const MUUID& u2);
int checkAPI(TCHAR* plugin, BASIC_PLUGIN_INFO* bpi, DWORD mirandaVersion, int checkTypeAPI);
@@ -88,3 +87,5 @@ struct MuuidReplacement
extern MuuidReplacement pluginDefault[];
bool LoadCorePlugin( MuuidReplacement& );
+
+MUUID* GetPluginInterfaces(const TCHAR* ptszFileName, bool& bIsPlugin); \ No newline at end of file