I have the following code that needs to be ported from windows to boost:
BOOL Class::fn_GetModulePath(WCHAR szPath[MAX_PATH])
{
BOOL bReturn = FALSE;
dll::library_handle hDll = dll::load_shared_library((const char*)DC_DLL_FILENAME);
//HMODULE hDll = LoadLibrary(DC_DLL_FILENAME);
if (hDll)
{
// This function needs replacing
DWORD dwResult = GetModuleFileName(hDll,szPath,MAX_PATH);
dll::close_shared_library(hDll);
//FreeLibrary(hDll);
if (dwResult)
{
int iLen = (int) wcslen(szPath);
if (iLen)
{
for (int i = iLen; i >= 0; i--)
{
if(szPath[i] == '\\')
{
szPath[i+1] = 0;
break;
}
}
}
bReturn = TRUE;
}
}
return bReturn;
}
How would I go about implementing the GetModuleFileName function using Boost?
Any help appreciated!
boost::dll::shared_library class has a method location which returns the full path to the library.
For the whole program, there is boost::dll::program_location global function.
In addition, it is possible to find the executable or library location by symbol address and by source location:
boost::dll::symbol_location
boost::dll::this_line_location
The latter can only be used by a module to find its own location.
You can use Boost.Dll like so:
shared_library lib(DC_DLL_FILENAME);
filesystem::path full_path = lib.location();
If you're trying to get the path to the currently running code, that is boost::dll::this_line_location().
Related
My goal is to understand stack unwinding in 64-bit PE32+ executable format in Windows, or how the following API can calculate addresses of a function prologue, body, epilogue, etc.:
CONTEXT context = {0};
RtlCaptureContext(&context);
DWORD64 ImgBase = 0;
RUNTIME_FUNCTION* pRTFn = RtlLookupFunctionEntry(context.Rip, &ImgBase, NULL);
_tprintf(L"Prologue=0x%p\n", (void*)(ImgBase + pRTFn->BeginAddress));
I know that the information on the offsets of all non-leaf functions used by the linker is included in the PE32+ header in the exceptions directory. So I tried to write my own function to parse it. I got to this point where I got stumped:
//INFO -- must be compiled as x64 only!
void GetFunctionTable(BYTE* lpBaseAddress, size_t szImageSz)
{
if(lpBaseAddress)
{
if(szImageSz > sizeof(IMAGE_DOS_HEADER))
{
IMAGE_DOS_HEADER* pDOSHeader = (IMAGE_DOS_HEADER*)lpBaseAddress;
if(pDOSHeader->e_magic == IMAGE_DOS_SIGNATURE)
{
IMAGE_NT_HEADERS* pNtHeader = (IMAGE_NT_HEADERS*)((BYTE*)pDOSHeader + pDOSHeader->e_lfanew);
PIMAGE_DATA_DIRECTORY pDataDirectories = NULL;
if(pNtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
{
//64-bit image only
IMAGE_NT_HEADERS64* pHdr64 = (IMAGE_NT_HEADERS64*)pNtHeader;
IMAGE_OPTIONAL_HEADER64* pIOH64 = &pHdr64->OptionalHeader;
pDataDirectories = pIOH64->DataDirectory;
IMAGE_DATA_DIRECTORY* pExceptDir = &pDataDirectories[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
if(pExceptDir->VirtualAddress &&
pExceptDir->Size)
{
IMAGE_RUNTIME_FUNCTION_ENTRY* pRFs = (IMAGE_RUNTIME_FUNCTION_ENTRY*)
GetPtrFromRVA64(pExceptDir->VirtualAddress, pNtHeader, lpBaseAddress);
//'pRFs' = should point to an array of RUNTIME_FUNCTION structs
// but in my case it points to an empty region of memory with all zeros.
}
}
}
}
}
}
with the following helper functions:
PIMAGE_SECTION_HEADER GetEnclosingSectionHeader64(DWORD_PTR rva, PIMAGE_NT_HEADERS64 pNTHeader)
{
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
unsigned int i;
for ( i=0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++ )
{
if ( (rva >= section->VirtualAddress) &&
(rva < (section->VirtualAddress + section->Misc.VirtualSize)))
return section;
}
return 0;
}
LPVOID GetPtrFromRVA64(DWORD rva, const void* pNTHeader, const void* imageBase)
{
PIMAGE_SECTION_HEADER pSectionHdr;
INT_PTR delta;
pSectionHdr = GetEnclosingSectionHeader64( rva, (PIMAGE_NT_HEADERS64)pNTHeader );
if ( !pSectionHdr )
return 0;
delta = (INT_PTR)(pSectionHdr->VirtualAddress - pSectionHdr->PointerToRawData);
return (PVOID) ( (BYTE*)imageBase + rva - delta );
}
So I'm testing it on the self executable:
HMODULE hMod = ::GetModuleHandle(NULL);
MODULEINFO mi = {0};
if(::GetModuleInformation(::GetCurrentProcess(), hMod, &mi, sizeof(mi)))
{
GetFunctionTable((BYTE*)hMod, mi.SizeOfImage);
}
But the problem is that inside my GetFunctionTable when I try to look up the function table mapped in memory in the IMAGE_DIRECTORY_ENTRY_EXCEPTION directory, I'm getting a pointer (i.e. IMAGE_RUNTIME_FUNCTION_ENTRY*) to an empty region of memory. I must be not translating the rva address correctly.
So anyone who knows how PE32+ header is mapped in memory, can please show what am I doing wrong there?
I am using Leadtools 17.5. If I statically link the Leadtools Dlls into my 64 bit C++ Application and then call L_SetLicenseBuffer everything works fine and the return value is zero. But for security reasons, the final product is not allowed to add those DLLs into the System32 folder and is also not allowed to change the system path, and since multiple applications are using the tools I want to install them in a common folder (C:\Program Files\Common Files\LeadTools\17.5 for example) and use AddDllDirectory to add the path to the DLL search path. So I decided to load the DLLs dynamically at the run-time. So I created a definition for the function like this:
typedef L_INT (EXT_FUNCTION* TL_SetLicenseBuffer)(L_UCHAR* pLicenseBuffer, L_SSIZE_T nSize, L_TCHAR* pszDeveloperKey);
typedef L_BOOL (EXT_FUNCTION* TL_IsSupportLocked)(L_UINT uType);
then created a function pointer like this:
TL_SetLicenseBuffer pfSetLicenseBuffer = NULL;
TL_IsSupportLocked pfIsSupportLocked = NULL;
then add the paths to where the DLLs are to the DLL search path:
AddDllDirectory(LEAD_DLL_PATH);
AddDllDirectory(LEAD_FILTER_PATH);
and set the default directory search path for DLLs to be the user defined:
SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_USER_DIRS);
then load the DLL and get the address of the functions I need:
HINSTANCE hKrn = LoadLibrary(L"ltkrnx.dll");
pfSetLicenseBuffer = (TL_SetLicenseBuffer)GetProcAddress(hKrn, "L_SetLicenseBuffer");
pfIsSupportLocked = (TL_IsSupportLocked)GetProcAddress(hKrn, "L_IsSupportLocked");
now if I use the function pointer with the same parameters as before, the function fails and returns -13 and any subsequent call to for example to pfIsSupportLocked shows the nag dialog:
retCode = pfSetLicenseBuffer(pLicenseData, LicSize, pKeyStr); // retCode is -13
pfIsSupportLocked(L_SUPPORT_DOCUMENT); // Shows nag dialog
Does anyone know how I can fix this?
Thank you
Sam
The first thing you need to do is check the debugger output and make sure that the DLL you are expecting to get loaded is the one getting loaded by verifying the path. It is possible that you have multiple versions of LTKRNX.DLL in your search path. I have tested your code here and it returned SUCCESS:
typedef L_INT (EXT_FUNCTION* TL_SetLicenseBuffer)(L_UCHAR* pLicenseBuffer, L_SSIZE_T nSize, L_TCHAR* pszDeveloperKey);
typedef L_BOOL (EXT_FUNCTION* TL_IsSupportLocked)(L_UINT uType);
HINSTANCE hKrn = LoadLibrary(L"ltkrnx.dll");
TL_SetLicenseBuffer pfSetLicenseBuffer = NULL;
TL_IsSupportLocked pfIsSupportLocked = NULL;
pfSetLicenseBuffer = (TL_SetLicenseBuffer)GetProcAddress(hKrn, "L_SetLicenseBuffer");
pfIsSupportLocked = (TL_IsSupportLocked)GetProcAddress(hKrn, "L_IsSupportLocked");
L_INT retCode = pfSetLicenseBuffer(szLICAnsi, _countof(szLICAnsi), pKeyStr);
if(retCode == SUCCESS)
bRet = pfIsSupportLocked(L_SUPPORT_DOCUMENT);
else
printf("Problem!");
Also what PaulMcKenzie suggested is another way to verify that your calls to LoadLibrary are working correctly. If you still cannot figure it out, you can contact our Technical Support to assist you with this issue at support#leadtools.com
I was not able to make the dynamic loading to work at all, but I was able to use Delay loading to work.What I had to do was to go back to linking the extracted .Lib files to my application and then tell compiler to load the associated DLLs with delay, which gave me a chance to create Notification Hooks to __pfnDliNotifyHook2 and __pfnDliFailureHook2 and that way I could use LoadLibrary to load the delayed loaded Dlls from correct location.But that only fixed half the problem because some of these Dlls are dependent on other DLLs and when I used the full path to load the DLL that I wanted, it could not find the secondary DLLs (which were located in the same directory as the one I was loading) and that would cause LoadLibrary to fail. The solution was to keep track of those dependencies and pre-load them. I am including some of the code to fix the issue for anyone whom might run into similar situation later on.P. S. I am using Embarcadero's C++ Builder, so Some of the objects like the Strings, TStringList and Exception may not be exactly what everyone is familiar with, but the concept should work in VC++ as well.
#include <map>
struct TDllDependency
{
TStringList* Dependency;
HMODULE hDll;
__fastcall TDllDependency(void)
{
hDll = NULL;
Dependency = new TStringList();
}
virtual __fastcall ~TDllDependency(void)
{
delete Dependency;
}
};
class TDllModList : public std::map<System::String, TDllDependency>
{
public:
void __fastcall CheckDependency(const System::String& aName);
};
//---------------------------------------------------------------------------
System::String __fastcall GetLtDllPath(void)
{
wchar_t* pfPath = NULL;
System::String dllPath;
SHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, KF_FLAG_DEFAULT, NULL, &pfPath);
if (NULL != pfPath)
{
dllPath = IncludeTrailingBackslash(pfPath) + L"LeadTools\\17.5\\";
::CoTaskMemFree(pfPath);
}
return dllPath;
}
System::String mDllPath(GetLtDllPath());
TDllModList DllModList;
void __fastcall InitDllDepends()
{
DllModList.clear();
#if defined(_WIN64)
DllModList[L"ltimgefxx.dll"].Dependency->CommaText = L"ltdisx.dll,ltimgutlx.dll";
DllModList[L"ltefxx.dll"].Dependency->CommaText = L"ltdisx.dll,ltimgutlx.dll";
DllModList[L"ltimgcorx.dll"].Dependency->CommaText = L"ltdisx.dll,ltimgutlx.dll";
DllModList[L"ltdlgimgefxx.dll"].Dependency->CommaText = L"ltdisx.dll,ltdlgkrnx.dll,ltdlgcomx.dll,ltdlgctrlx.dll,ltdlgutlx.dll,ltimgefxx.dll,ltimgsfxx.dll,ltimgcorx.dll,ltimgclrx.dll";
DllModList[L"ltdlgutlx.dll"].Dependency->CommaText = L"ltdisx.dll,ltfilx.dll,ltdlgkrnx.dll,ltimgclrx.dll,ltimgcorx.dll,ltimgefxx.dll,ltimgsfxx.dll";
DllModList[L"ltdlgctrlx.dll"].Dependency->CommaText = L"ltdlgutlx.dll,ltdlgkrnx.dll,ltdisx.dll,ltfilx.dll,ltimgefxx.dll";
DllModList[L"ltdlgcomx.dll"].Dependency->CommaText = L"ltdlgkrnx.dll,ltdlgctrlx.dll,ltdlgutlx.dll";
#elif defined(__WIN32__)
DllModList[L"ltimgefxu.dll"].Dependency->CommaText = L"ltdisu.dll,ltimgutlu.dll";
DllModList[L"ltefxu.dll"].Dependency->CommaText = L"ltdisu.dll,ltimgutlu.dll";
DllModList[L"ltimgcoru.dll"].Dependency->CommaText = L"ltdisu.dll,ltimgutlu.dll";
DllModList[L"ltdlgimgefxu.dll"].Dependency->CommaText = L"ltdisu.dll,ltdlgkrnu.dll,ltdlgcomu.dll,ltdlgctrlu.dll,ltdlgutlu.dll,ltimgefxu.dll,ltimgsfxu.dll,ltimgcoru.dll,ltimgclru.dll";
DllModList[L"ltdlgutlu.dll"].Dependency->CommaText = L"ltdisu.dll,ltfilu.dll,ltdlgkrnu.dll,ltimgclru.dll,ltimgcoru.dll,ltimgefxu.dll,ltimgsfxu.dll";
DllModList[L"ltdlgctrlu.dll"].Dependency->CommaText = L"ltdlgutlu.dll,ltdlgkrnu.dll,ltdisu.dll,ltfilu.dll,ltimgefxu.dll";
DllModList[L"ltdlgcomu.dll"].Dependency->CommaText = L"ltdlgkrnu.dll,ltdlgctrlu.dll,ltdlgutlu.dll";
#endif
};
HMODULE SafeLoadLeadDll(const System::String tName)
{
System::String tPath;
HMODULE retVal = NULL;
DllModList.CheckDependency(tName);
tPath = mDllPath + tName;
if(FileExists(tPath))
retVal = ::LoadLibrary(tPath.c_str());
return retVal;
}
FARPROC WINAPI MyDliNotifyHook(unsigned dliNotify, PDelayLoadInfo pdli)
{
FARPROC retVal = NULL;
System::String tStr(pdli->szDll);
tStr = tStr.LowerCase();
if(dliNotePreLoadLibrary == dliNotify)
{
TDllModList::iterator i = DllModList.find(tStr);
if(DllModList.end() == i)
{
retVal = (FARPROC)SafeLoadLeadDll(tStr);
DllModList[tStr].hDll = (HMODULE)retVal;
}
else if(NULL == i->second.hDll)
{
i->second.hDll = SafeLoadLeadDll(tStr);
retVal = (FARPROC)i->second.hDll;
}
else
retVal = (FARPROC)i->second.hDll;
}
else if(dliFailLoadLib == dliNotify)
{
tStr = L"Compleatly falied to load " + tStr;
::OutputDebugString(tStr.c_str());
}
return retVal;
}
FARPROC WINAPI MyDliFailureHook(unsigned dliNotify, PDelayLoadInfo pdli)
{
FARPROC retVal = NULL;
if(dliNotePreLoadLibrary == dliNotify)
{
System::String tMsg = pdli->szDll;
tMsg = L"Failed to load \"" + tMsg + L"\".\n" + SysErrorMessage(::GetLastError());
throw Exception(tMsg);
}
return retVal;
}
extern "C" PfnDliHook __pfnDliNotifyHook2 = MyDliNotifyHook;
extern "C" PfnDliHook __pfnDliFailureHook2 = MyDliFailureHook;
void __fastcall TDllModList::CheckDependency(const System::String& aName)
{
TDllModList::iterator i = find(aName);
if(end() != i)
{
int len = i->second.Dependency->Count;
int j;
System::String tPath;
for(j = 0; j < len; j++)
{
if(end() == find(i->second.Dependency->Strings[j]))
{
CheckDependency(i->second.Dependency->Strings[j]);
tPath = mDllPath + i->second.Dependency->Strings[j];
(*this)[i->second.Dependency->Strings[j]].hDll = ::LoadLibrary(tPath.c_str());
}
}
}
}
//---------------------------------------------------------------------------
And of course InitDllDepends(); should be called at the beginning of WinMain to set things up correctly.
I'd like to ask, how could I locate a specific (exported) function inside a DLL. For example I'd like to locate ReadProcessMemory inside Kernel32. I wouldn't like to rely on Import table, I'd like to locate different APIs based on their addresses what I get with a custom function.
I tried to make a small research on VA, RVA & File offsets, but I didn't succeed. Here's an example which I tried, but it isn't working (returns 0 in all cases):
DWORD Rva2Offset(DWORD dwRva, UINT_PTR uiBaseAddress)
{
WORD wIndex = 0;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
PIMAGE_NT_HEADERS pNtHeaders = NULL;
pNtHeaders = (PIMAGE_NT_HEADERS) (uiBaseAddress + ((PIMAGE_DOS_HEADER) uiBaseAddress)->e_lfanew);
pSectionHeader = (PIMAGE_SECTION_HEADER) ((UINT_PTR) (&pNtHeaders->OptionalHeader) + pNtHeaders->FileHeader.SizeOfOptionalHeader);
if (dwRva < pSectionHeader[0].PointerToRawData)
return dwRva;
for (wIndex = 0; wIndex < pNtHeaders->FileHeader.NumberOfSections; wIndex++)
{
if (dwRva >= pSectionHeader[wIndex].VirtualAddress && dwRva < (pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].SizeOfRawData))
return (dwRva - pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].PointerToRawData);
}
return 0;
}
Could you help me how could I accomplish this simple task?
Thank you.
P.s.: I'm not sticking to the function above, both if you can point out what's the problem, or give a better source would be awesome.
This gives you the relative virtual address
uintptr_t baseAddr = (uintptr_t)GetModuleHandle("nameOfExe.exe");
uintptr_t relativeAddr = functionAddress - baseAddr;
This converts relative virtual address to File offset:
DWORD RVAToFileOffset(IMAGE_NT_HEADERS32* pNtHdr, DWORD dwRVA)
{
int i;
WORD wSections;
PIMAGE_SECTION_HEADER pSectionHdr;
pSectionHdr = IMAGE_FIRST_SECTION(pNtHdr);
wSections = pNtHdr->FileHeader.NumberOfSections;
for (i = 0; i < wSections; i++)
{
if (pSectionHdr->VirtualAddress <= dwRVA)
if ((pSectionHdr->VirtualAddress + pSectionHdr->Misc.VirtualSize) > dwRVA)
{
dwRVA -= pSectionHdr->VirtualAddress;
dwRVA += pSectionHdr->PointerToRawData;
return (dwRVA);
}
pSectionHdr++;
}
return (-1);
}
I need to register a .NET COM dll from a C++ program that is using it. For .NET versions older then .NET 4 this is explained in How to run regasm.exe from a C++ program?. Following is the minimal code (no checks) that provides the path to an older version of the CLR.
CComBSTR mscoreeName("mscoree.dll");
HINSTANCE hMscoree = CoLoadLibrary(mscoreeName, FALSE);
typedef HRESULT (WINAPI *LPFNGETCORSYSDIR)(LPWSTR, DWORD, DWORD*);
LPFNGETCORSYSDIR lpfunc = (LPFNGETCORSYSDIR)GetProcAddress(hMscoree,_T("GetCORSystemDirectory"));
DWORD bufferSize = 256;
DWORD bufferUsed;
LPWSTR pwzBuffer = new WCHAR[bufferSize];
(*lpfunc)(pwzBuffer, bufferSize, &bufferUsed);
However since I use .NET 4 the method GetCORSystemDirectory is superseded by the ICLRRuntimeInfo::GetRuntimeDirectory which is not an entry point in mscoree.dll (checked with depends). According the documentation on MSDN the method is included as a resource in MSCorEE.dll.
Question is how to get access to this method from C++?
Besides that I'm wondering if there is no easier way...
The problem with the way of working in the question is in finding the correct location of RegAsm. Thanks to the comment of Hans Passant to use RegistrationService.RegisterAssembly I changed the ClassLibrary into a self-registering executable.
static void Main(string[] args)
{
if (args.Length != 1)
{
ShowHelpMessage();
return;
}
if (args[0].CompareTo("/register") == 0)
{
Assembly currAssembly = Assembly.GetExecutingAssembly();
var rs = new RegistrationServices();
if (rs.RegisterAssembly(currAssembly, AssemblyRegistrationFlags.SetCodeBase))
{
Console.WriteLine("Succesfully registered " + currAssembly.GetName());
} else
{
Console.WriteLine("Failed to register " + currAssembly.GetName());
}
return;
}
if (args[0].CompareTo("/remove") == 0)
{
Assembly currAssembly = Assembly.GetExecutingAssembly();
var rs = new RegistrationServices();
if (rs.UnregisterAssembly(currAssembly))
{
Console.WriteLine("Succesfully removed " + currAssembly.GetName());
}
else
{
Console.WriteLine("Failed to remove " + currAssembly.GetName());
}
return;
}
ShowHelpMessage();
}
Is there an equivalent to the Java File method isDirectory() in MFC? I tried using this :
static bool isDirectory(CString &path) {
return GetFileAttributes(path) & FILE_ATTRIBUTE_DIRECTORY;
}
but it doesn't seem to work.
CFileFind::IsDirectory()
http://msdn.microsoft.com/en-us/library/scx99850(VS.80).aspx
EDIT:
#include <afxwin.h>
#include <iostream>
using namespace std;
CFileFind finder;
fileName += _T("c:\\aDirName");
if (finder.FindFile(fileName))
{
if (finder.FindNextFIle())
{
if (finder.IsDirectory())
{
// Do directory stuff...
}
}
}
If you change filename to have wildcards, you can do a
while(finder.findNextFile()) {...
to get all matching files.
Sorry for possibly "inconsistency" of answer to question but may be you'll see it useful because anytime I need something like this in Windows I am NOT using MFC but regular Windows API:
//not completely tested but after some debug I'm sure it'll work
bool IsDirectory(LPCTSTR sDirName)
{
//First define special structure defined in windows
WIN32_FIND_DATA findFileData; ZeroMemory(&findFileData, sizeof(WIN32_FIND_DATA));
//after that call WinAPI function finding file\directory
//(don't forget to close handle after all!)
HANDLE hf = ::FindFirstFile(sDirName, &findFileData);
if (hf == INVALID_HANDLE_VALUE) //also predefined value - 0xFFFFFFFF
return false;
//closing handle!
::FindClose(hf);
// true if directory flag in on
return (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
}
MFC solution as requested:
a_FSItem path ot the item to test (examine the CFile::GetStatus() for the needed requirements).
CFileStatus t_aFSItemStat;
CFile::GetStatus( a_FSItem, t_aFSItemStat );
if ( ( t_aFSItemStat.m_attribute & CFile::directory )
return true;
return false;
if you wish to include a volume root as a valid directory just add it to the test
t_aFSItemStat.m_attribute & CFile::volume
Its not MFC, but I use this:
bool IsValidFolder(LPCTSTR pszPath)
{
const DWORD dwAttr = ::GetFileAttributes(pszPath);
if(dwAttr != 0xFFFFFFFF)
{
if((FILE_ATTRIBUTE_DIRECTORY & dwAttr) &&
0 != _tcscmp(_T("."), pszPath) &&
0 != _tcscmp(_T(".."), pszPath))
{
return true;
}
}
return false;
}