I have a third-party console application. I need run it from my application but I cannot run it as a separate process (because I need to work with its dependencies: fill Import tables manually, setup hooks etc.). So probably I should call main function of this executable manually. Here is how I'm trying to do this:
Load this EXE using auto hMod = LoadLibrary("console_app.exe")
Fill Import table of this exe manually
Get entry point of this EXE and call it
And I'm stuck with the last step.
Here is how I'm trying to call entry point:
void runMain(HINSTANCE hInst)
{
typedef BOOL(WINAPI *PfnMain)(int, char*[]);
auto imageNtHeaders = ImageNtHeader(hInst);
auto pfnMain = (PfnMain)(DWORD_PTR)(imageNtHeaders->OptionalHeader.AddressOfEntryPoint + (DWORD_PTR)hInst);
char* args[] = { R"(<console_app_path>)", R"(arg1)", R"(arg2)" };
pfnMain(3, args);
}
It works. But it works as if there is no arguments.
Where am I wrong? How can I run an executable inside my process with arguments? Thanks.
UPDATE:
I've investigated how my particular third-party exe gets cmd arguments and found that:
It doesn't import GetCommandLine at all and do not call it
After call _initterm call argc and argv arguments are available through cs:argc and cs:argv (see pictures below)
CMD arguments that I pass to my main console app are transferred to
child EXE too.
Can you explain, please, what _initterm actually do and where CMD arguments are actually stored?
You're calling the entry point of the application, not int main(int, char**). Now you may have read that the entry point of a C++ program is int main(int, char**) but that's just a C++ perspective.
The Win32 perspective is different; the entry point is a int (*)(void);. The Visual Studio linker looks for int mainCRTStartup(void); and uses that, unless you specify another entry point with /ENTRY. The default implementation of mainCRTStartup calls GetCommandLine() to fill in argv[] before calling main(argc,argv). There are also other things in mainCRTStartup which you might want to happen: run global ctors, initialize the CRT state, ...
Of course, that's assuming the other program was compiled with Visual C++, but whatever language it's been written in, it must be calling GetCommandLine.
Now, for your problem, here's an interesting observation: GetCommandLine() returns a writeable pointer. You can overwrite the existing command line. Of course, if you control the import tables, you decide what GetCommandLine means. (Remember, as usual there are A and W variants).
One warning: the MSVCRT isn't designed to be initialized twice, neither the static version nor the DLL one. So practically speaking you can't use it, and that will hurt.
[edit]
Your update shows a call to _initterm. That's a MSVCRT function, as I already hinted. Specifically,
/***
*crtexe.c - Initialization for console EXE using CRT DLL
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
...
/*
* routine in DLL to do initialization (in this case, C++ constructors)
*/
extern int __cdecl _initterm_e(_PIFV *, _PIFV *);
extern void __cdecl _initterm(_PVFV *, _PVFV *);
The MSVCRT DLL calls GetCommandLine() on behalf of the EXE.
the entrypoint of executable (EP) have no arguments - so you and can not direct call it with arguments.
usual application got arguments by parsing command line. [w]mainCRTStartup do this - if you have console application linked to c/c++ runtime - this is real EP .
so if you Fill Import table of this exe manually - set exception for GetCommandLineA and GetCommandLineW functions - redirect it to self implementation and return your custom command line.
but if app used not static linked CRT it can import __getmainargs or __wgetmainargs or even _acmdln, or _wcmdln from msvcrt.dll - so already task become complex.
and you assume that relocs exits in EXE, you not handle TLS if it exist, you not handle application manifest, possible dl redirections, etc.
but I cannot run it as a separate process
this is not true. you can and must run it as separate process - this is the best solution.
exec your app by CreateProcess with CREATE_SUSPENDED flag. here you free easy set any CommandLine which you need. you not need manually and not fully correct load EXE but system do this task for you.
after process is created you need inject self DLL to it by using QueueUserAPC (but not CreateRemoteThread !!) and finally call ResumeThread
as result your DLL will be loaded and executed in first EXE thread, just before application EP - and here you can do all needed tasks
Related
I have a solution with two DLLs. The first one is the "main" DLL. It happens to be an ODBC driver, but I think that is not important for this question.
The second DLL contains all the UI logic for the first one. As the UI is not always needed, I want to use the /DELAYLOAD feature which explicitly says:
The delayed loading of a DLL can be specified during the build of
either a .EXE or .DLL project.
The main DLL's project correctly references the UI ones. If I don't use /DELAYLOAD, everythin works just fine. The two DLLs will be installed into the same directory, so I thought loading one DLL from within the other should be easy. But apparently, it's not.
As soon as the first function from the UI DLL is called, the application (any ODBC client in my case) crashes.
GetLastError() yields 126 which apparently means that the target DLL could not be found in any of the search paths.
And indeed, according to this answer LoadLibrary() does have a look into the directory of the calling executable, but not into the one of the currently executed DLL. I'm assuming /DELAYLOAD is also just using LoadLibrary() under the hood, is that correct?
If I copy the executable into the installation directory of my driver, it works just fine, which proves my assumption that it just doesn't look in the current DLL's directory.
Appart from that, I was also able to make it run by calling
LoadLibrary(L"C:\\absolute\\path\\to\\UI.dll");
just before the first function of the UI DLL is loaded.
I was also able to determine this path programmatically using
wchar_t buffer[512];
GetModuleFileName(hThisDLL, buffer, sizeof(buffer));
But then I would have to cover every single UI call with this logic. So I wouldn't see much advantage anymore that /DELAYLOAD has over the "old-school" way of using LoadLibrary() and GetProcAddress().
Question
Is there a simple way to make /DELAYLOAD find the target DLL from another DLL in the same directory?
There is. My suggestion would be to create a delay-load-failure hook function.
https://learn.microsoft.com/en-us/cpp/build/reference/failure-hooks?view=vs-2019
Basically, you write a function inside your main DLL that gets notified in the event of a delay load failure. In that function, when the given code indicates failure, you try manually calling LoadLibrary with of a path consisting of the folder in which your main DLL resides plus the name of the DLL that failed to load
How you get the your main DLL from within your main DLL is up to you. There are many ways.
Something like this:
FARPROC WINAPI delayHook(unsigned dliNotify, PDelayLoadInfo pdli)
{
FARPROC fpRet = NULL;
switch (dliNotify)
{
case dliStartProcessing:
break;
case dliNotePreLoadLibrary:
break;
case dliNotePreGetProcAddress:
break;
case dliFailLoadLib:
{
std::string newPath = GetMyModulePath();
newPath += "\\";
newPath += pdli->szDll;
fpRet = reinterpret_cast<FARPROC>(::LoadLibrary(csDir));
}
break;
case dliFailGetProc:
break;
case dliNoteEndProcessing:
break;
default:
break;
}
return fpRet;
}
//
// Set access to our delay load hook.
//
PfnDliHook __pfnDliFailureHook2 = delayHook;
Background
I'm developing a C++ windows DLL module that exports a single function
__declspec(dllexport) void Run()
Motivation
I would like to implement some sort of accessing rights to my function. I wish to prevent unauthorized modules from activating my DLL proc.
I don't need a robust/bullet proof mechanism. I only like to "defend" this proc from other modules running under my own app.
Approach
Get the calling module name and decide based on the name if access is granted.
Question
Would this approach suffice?
if so, how do I get the name of the calling module?
if so, how do I get the name of the calling module?
get return address by call _ReturnAddress
get base address of the image that contains this return address -
RtlPcToFileHeader
finally call GetModuleFileName function
so code can be like this
HMODULE hmod;
if (RtlPcToFileHeader(_ReturnAddress(), (void**)&hmod))
{
WCHAR sz[MAX_PATH];
if (GetModuleFileName(hmod, sz, MAX_PATH))
{
DbgPrint("%p %S\n", hmod, sz);
}
}
about - are this work in XP ? yes, but with one note. _ReturnAddress is CL intrinsic - so not depended from os version (for say gcc exist __builtin_return_address (0) ) GetModuleFileName also very old api function and exist in win2000, xp, everywhere. about RtlPcToFileHeader
- it exported (and implemented) in ntdll.dll in all windows versions from xp to latest. also begin from win2003 it also exported from kernel32.dll but implementation here - simply jump to ntdll.RtlPcToFileHeader - so if want use this on xp also - link with ntdll.lib and place it before kernel32.lib in libs order or can get it it runtime by GetProcAddress(GetModuleHandle(L"ntdll"), "RtlPcToFileHeader");
or even if somebody afraid that RtlPcToFileHeader will be removed from ntdll (this is of course no) can use this
GetProcAddress(GetModuleHandle(g_xp ? L"ntdll" : L"kernel32"), "RtlPcToFileHeader");
I'm trying to create a dll that contains a VCL data module - the idea being that various applications can all load the same dll and use the same database code.
The data module itself is tested ok as part of an application - I've copied the form over to my dll project.
So in the dll entry point method, I need to initialize the data module:
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
//if I don't call this, I get an exception on initializing the data module
CoInitialize(NULL);
//initialize a standard VCL form; seems to works fine
//I'm not using Application->CreateForm as I don't want the form to appear straight away
if(!MyForm) MyForm = new TMyForm(Application);
//this doesn't work - the thread seems to hang in the TDataModule base constructor?
//I've also tried Application->CreateForm; same result
if(!MyDataModule) MyDataModule = new TMyDataModule(Application);
}
I've also seen something about how I need to call Application->Initialize before creating the form but this doesn't seem to make any difference.
Any ideas?
Thanks
You really should not be doing very much work in your DllEntryPoint() at all. Certainly not calling CoInitialize(), anyway. It is not the DLL's responsibility to call that when loaded. It is the calling app's responsibility before loading the DLL.
You should either:
export an additional function to initialize your DLL and then have the app it after loading the DLL (same for uninitialing the DLL before unloading it)
don't create your TForm/TDataModule until the first time the DLL actually needs them.
move your TForm/TDataModule into their own worker thread inside the DLL. In this case, you would then call CoIniitalize().
And in all cases, don't relay on the DLL's Application object to manage the lifetime of your TForm/TDataModule. Free them yourself instead before the DLL is unloaded.
I have a need to create a Tcl extension that calls a managed .NET DLL/Class Library. Currently, the structure of my application is Tcl > DLL Wrapper (C++ CLR) > .NET Class Library (VB.NET), where ">" represents a function call.
My VB.NET DLL just takes a value and returns it back, keeping it simple for now. In the end, this will do some more advanced stuff that makes use of some .NET functionality.
Public Class TestClass
Public Function TestFunction(ByVal param As Integer) As Integer
Return param
End Function
End Class
My Tcl Extension (C++ CLR) creates an object of the type above
int TestCmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
// Check the number of arguments
if (objc != 2) {
Tcl_WrongNumArgs(interp, 0, objv, "arg");
return TCL_ERROR;
}
int param, result;
if (Tcl_GetIntFromObj(interp, objv[1], ¶m) != TCL_OK)
return TCL_ERROR;
SimpleLibrary::TestClass^ myclass = gcnew SimpleLibrary::TestClass(); //System.IO.FileNotFoundException
result = myclass->TestFunction(param);
Tcl_SetObjResult(interp, Tcl_NewIntObj(result));
return TCL_OK;
}
And finally, my Tcl script loads the extension and calls the function.
load SimpleTclExtension.dll
TestCmd 2
If my VB.NET DLL is in the same directory as my extension DLL, the extension crashes when it instantiates a TestClass object. I've noticed if the VB.NET DLL is relocated to C:\Tcl\bin, the extension will find it, and TestCmd can be called just fine. The problem is that this will eventually need to be deployed across a number of PCs, and it's preferred not to mingle my application's files with another application's.
It seems like there should be some configuration settings that will fix this problem, but I'm not sure where. Any help is greatly appreciated.
Firstly, depending on just what kind of Tcl application you are using you may want to look at Eagle which is a implementation of Tcl in CLR.
I think you are bumping into .Net's desire to only load assemblies from your application's directory or its immediate subdirectories. The application here is the tclsh/wish executable which is why moving the .Net assembly makes it load. This is something you can fix with suitable manifests or calls to the API to permit assembly loading from alternate locations. In this case I think you will need to run some initialization code in your Tcl extension when it gets loaded into the Tcl interpreter to init the CLR and add the extensions location as a suitable place to load assemblies from. It has been a while since I was looking at this so I forgot the details but I think you want to look at the AppDomain object and check the assembly loading path properties associated with that or its child objects. Try AppDomain.RelativeSearchPath
To be more specific, Eagle includes Garuda which is a Tcl extension built specifically to allow calling .Net from Tcl
I've successfully loaded a C++ plugin using a custom plugin loader class. Each plugin has an extern "C" create_instance function that returns a new instance using "new".
A plugin is an abstract class with a few non-virtual functions and several protected variables(std::vector refList being one of them).
The plugin_loader class successfully loads and even calls a virtual method on the loaded class (namely "std::string plugin::getName()".
The main function creates an instance of "host" which contains a vector of reference counted smart pointers, refptr, to the class "plugin". Then, main creates an instance of plugin_loader which actually does the dlopen/dlsym, and creates an instance of refptr passing create_instance() to it. Finally, it passes the created refptr back to host's addPlugin function. host::addPlugin successfully calls several functions on the passed plugin instance and finally adds it to a vector<refptr<plugin> >.
The main function then subscribes to several Apple events and calls RunApplicationEventLoop(). The event callback decodes the result and then calls a function in host, host::sendToPlugin, that identifies the plugin the event is intended for and then calls the handler in the plugin. It's at this point that things stop working.
host::sendToPlugin reads the result and determines the plugin to send the event off to.
I'm using an extremely basic plugin created as a debugging plugin that returns static values for every non-void function.
Any call on any virtual function in plugin in the vector causes a bad access exception. I've tried replacing the refptrs with regular pointers and also boost::shared_ptrs and I keep getting the same exception. I know that the plugin instance is valid as I can examine the instance in Xcode's debugger and even view the items in the plugin's refList.
I think it might be a threading problem because the plugins were created in the main thread while the callback is operating in a seperate thread. I think things are still running in the main thread judging by the backtrace when the program hits the error but I don't know Apple's implementation of RunApplicationEventLoop so I can't be sure.
Any ideas as to why this is happening?
class plugin
{
public:
virtual std::string getName();
protected:
std::vector<std::string> refList;
};
and the pluginLoader class:
template<typename T> class pluginLoader
{
public: pluginLoader(std::string path);
// initializes private mPath string with path to dylib
bool open();
// opens the dylib and looks up the createInstance function. Returns true if successful, false otherwise
T * create_instance();
// Returns a new instance of T, NULL if unsuccessful
};
class host
{
public:
addPlugin(int id, plugin * plug);
sendToPlugin(); // this is the problem method
static host * me;
private:
std::vector<plugin *> plugins; // or vector<shared_ptr<plugin> > or vector<refptr<plugin> >
};
apple event code from host.cpp;
host * host::me;
pascal OSErr HandleSpeechDoneAppleEvent(const AppleEvent *theAEevt, AppleEvent *reply, SRefCon refcon) {
// this is all boilerplate taken straight from an apple sample except for the host::me->ae_callback line
OSErr status = 0;
Result result = 0;
// get the result
if (!status) {
host::me->ae_callback(result);
}
return status;
}
void host::ae_callback(Result result) {
OSErr err;
// again, boilerplate apple code
// grab information from result
if (!err)
sendToPlugin();
}
void host::sendToPlugin() {
// calling *any* method in plugin results in failure regardless of what I do
}
EDIT: This is being run on OSX 10.5.8 and I'm using GCC 4.0 with Xcode. This is not designed to be a cross platform app.
EDIT: To be clear, the plugin works up until the Apple-supplied event loop calls my callback function. When the callback function calls back into host is when things stop working. This is the problem I'm having, everything else up to that point works.
Without seeing all of your code it isn't going to be easy to work out exactly what is going wrong. Some things to look at:
Make sure that the linker isn't throwing anything away. On gcc try the compile options -Wl -E -- we use this on Linux, but don't seem to have found a need for it on the Macs.
Make sure that you're not accidentally unloading the dynamic library before you've finished with it. RAII doesn't work for unloading dynamic libraries unless you also stop exceptions at the dynamic library border.
You may want to examine our plug in library which works on Linux, Macs and Windows. The dynamic loading code (along with a load of other library stuff) is available at http://svn.felspar.com/public/fost-base/trunk/
We don't use the dlsym mechanism -- it's kind of hard to use properly (and portably). Instead we create a library of plugins by name and put what are basically factories in there. You can examine how this works by looking at the way that .so's with test suites can be dynamically loaded. An example loader is at http://svn.felspar.com/public/fost-base/trunk/fost-base/Cpp/fost-ftest/ftest.cpp and the test suite registration is in http://svn.felspar.com/public/fost-base/trunk/fost-base/Cpp/fost-test/testsuite.cpp The threadsafe_store holds the factories by name and the suite constructor registers the factory.
I completely missed the fact that I was calling dlclose in my plugin_loader's dtor and for some reason the plugins were getting destructed between the RunApplicatoinEventLoop call and the call to sendToPlugin. I removed dlclose and things work now.