/* Miranda NG: the free IM client for Microsoft* Windows* Copyright (ñ) 2012-17 Miranda NG project (http://miranda-ng.org), Copyright (c) 2000-12 Miranda 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 "stdafx.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 nullptr; } MUUID* GetPluginInterfaces(const wchar_t* ptszFileName, bool& bIsPlugin) { bIsPlugin = false; HANDLE hFile = CreateFile( ptszFileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr ); if (hFile == INVALID_HANDLE_VALUE) return nullptr; MUUID* pResult = nullptr; BYTE* ptr = nullptr; HANDLE hMap = CreateFileMapping(hFile, nullptr, PAGE_READONLY, 0, 0, nullptr ); __try { __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 == nullptr) __leave; PIMAGE_NT_HEADERS pINTH = { 0 }; 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 = nullptr; 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 (!mir_strcmp(szName, "Load")) bHasLoad = true; if (!mir_strcmp(szName, "MirandaPluginInfoEx")) bHasInfo = true; else if (!mir_strcmp(szName, "Unload")) bHasUnload = true; else if (!mir_strcmp(szName, "MirandaInterfaces")) { bHasMuuids = true; pIds = (MUUID*)&pSecStart[ ptrFuncList[*ptrOrdRVA]]; } // old plugin, skip it else if (!mir_strcmp(szName, "MirandaPluginInterfaces")) __leave; } // 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; *p != miid_last; p++) nLength++; pResult = (MUUID*)mir_alloc( sizeof(MUUID)*nLength); if (pResult) memcpy(pResult, pIds, sizeof(MUUID)*nLength); } __except(EXCEPTION_EXECUTE_HANDLER) {}; } __finally { if (ptr) UnmapViewOfFile(ptr); if (hMap) CloseHandle(hMap); CloseHandle(hFile); }; return pResult; }