PDA

View Full Version : DLL Injection with slots... ?!?!?



gilamran
16th October 2010, 22:25
Hi,
I'm quite new to QT so be nice ;-)
I have a DLL that I inject into a QT application (I don't have the source)
I want this DLL to get some signals from the application that it's injected into.

the injection is working very well, and I have access to all the UI, I can even change values of text fields etc.

BUT, I can't connect the DLL slots to the UI's signals.
I've been reading about it a bit, but no one could give a good answer on how to do it.

please please, help!

Thanks
Gil.

squidge
16th October 2010, 22:57
By "can't" what do you mean? Do you get an error message?

gilamran
16th October 2010, 23:00
I did an internal connection (With two text fields in the main APP) and it worked.
Like this:

connect(lineEdit, SIGNAL(textChanged(QString)), lineEdit2, SLOT(setText(QString)));

But when I connect to my own DLL slot function, it didn't work (It didn't get to the slot function)
like this:

connect(lineEdit, SIGNAL(textChanged(QString)), this, SLOT(mySlot()));

As I'm guessing, I can't connect to slots that didn't compile with the main app.... My DLL's slot is not known to the main app...
am I write? what's the work around?

squidge
16th October 2010, 23:27
Are you sure you are using the exact same DLLs and library instance for Qt as the main application?

I don't think the main app needs to know about your slots, as they defined by MOC, and as long as you are using the same version of MOC (and Qt) as the main app, it should find your slot at run time.

If the app you are hooking into using a statically linked version of Qt, then it's a lot more difficult.

tbscope
17th October 2010, 05:19
As squidge already said, signals and slots are handled by MOC.
Thus, make sure that your injected DLL is processed by MOC before linking it (here I mean the actual linking of the DLL, not injecting it).

Lykurg
17th October 2010, 08:27
But when I connect to my own DLL slot function, it didn't work (It didn't get to the slot function)
like this:
connect(lineEdit, SIGNAL(textChanged(QString)), this, SLOT(mySlot()));
What error do you get or how do you know the dll slot isn't called? And this is surly not pointing to the dll!

gilamran
17th October 2010, 09:58
I don't know how to get the error... I just don't see the slot function being called.
In the slot function I have a code that sends a log message. (The log is working great)

Is there a way to see if the connection is ok?

btw: what should I put instead of "this"?

Lykurg
17th October 2010, 10:23
Is there a way to see if the connection is ok?On runtime there will be a warning on the console.


btw: what should I put instead of "this"? A pointer to your "dll", since it should be the slots of the "dll", right?

wysota
17th October 2010, 10:55
Can you show us the header file for the object in the dll declaring the slot you wish to connect to?

squidge
17th October 2010, 10:58
tbh, I would have expected 'this' to work, as you are referring to a class in the same memory space as the application (since you have injected the dll into the application). Giving the dll instance to the connect call doesn't make sense to me, as then it wouldn't know which class to call the metacall methods.

gilamran
17th October 2010, 11:18
On runtime there will be a warning on the console.
I'm unable to debug this... so where can I see the console? (Sorry if it's dumb question)


A pointer to your "dll", since it should be the slots of the "dll", right?
I'm ready to try anything, so where can I get this "dll" pointer from (Sorry again)


can you show us the header file for the object in the dll declaring the slot you wish to connect to?
Sure will, soon. (Currently at work)

Some more info:

I'm using Visual studio
I'm injecting my dll (Using WinJect) into the BasicLayout QT example (Just for the tests)
I'm communicating with the DLL using windows WM_COPYDATA Messages


MANY THANKS for your time and effort!!!

wysota
17th October 2010, 11:28
I'm unfamiliar with how WinJect works and possibly others thought that by "injecting" you meant something else. Is the "injected" dll in the same memory space as the main application or are they two different processes? If the latter then obviously signal/slot connections will not work.

gilamran
17th October 2010, 11:31
yea it's in the same memory space! this is what injection means.
When injected you have access to all the QT objects, widgets, and you can call functions there, like change a some text fields, change data.. everything, if you're not injected... you can't

Lykurg
17th October 2010, 11:31
@squidge: Ok, now I am confused. Seems I have a logical understanding problem. I'll work that out for me :) Thanks.

gilamran
17th October 2010, 11:35
@squidge: Ok, now I am confused. Seems I have a logical understanding problem. I'll work that out for me :) Thanks.

what do you need me to clarify?

Lykurg
17th October 2010, 11:44
I'm unable to debug this... so where can I see the console? If you start your application on the command line and the slot can't be found a warning will be printed (or inside Qt Creator on the application output), but

what do you need me to clarify?
I get the "injecting" wrong (thought you would using QPluginLoader), so your slot should be found. So I am out of ideas right now.

gilamran
17th October 2010, 11:58
Ok, I'll check the command line error.
And I'll post a short code that do what I say, maybe it'll be clear than.

Thanks again!

tbscope
17th October 2010, 12:51
I'm assuming you didn't create a plugin. This means a library exporting certain symbols that you use directly in the application you want to inject.

I assume that you can not change the application code itself directly. If that's not the case, then see the examples and documentation of creating plugins or using libraries.

Consider the following schema:

+-----------------------------------------------------------------------------------------+
| Application |
| |
| +---------------+ +-----------------------------------------+ |
| +---------------+| | Application code, contains objects. | |
| +---------------+|| | | |
| +---------------+||| | mainWindow (a QMainWindow) | |
| | Linked |||+ | | | |
| | libraries ||+ | +-- button (a QPushButton) | |
| | |+ | +-- label (a QLabel) | |
| +---------------+ +-----------------------------------------+ |
| | |
| v |
| +-------------------------------------------------------------------------------------+ |
| | Your injected DLL | |
| | | |
| | +--------------------------+ | |
| | | Class based on QObject | | |
| | | inside DLL | | |
| | | | | |
| | | Contains signals and | | |
| | | slots | | |
| | +--------------------------+ | |
| | | | |
| | v | |
| | +-------------------------------------------------------------------------+ | |
| | | Create an object: | Do this from within a context | | |
| | | | where the application event | | |
| | | MyClass *myclass = new MyClass; | loop is running. | | |
| | +-------------------------------------------------------------------------+ | |
| | | | |
| | v | |
| | +------------------------------------------------+ | |
| | | Example: | | |
| | | Suppose you have installed an application | | |
| | | event filter. | | |
| | | | | |
| | | Also, suppose you intercept the mainWindow | | |
| | | show event. | | |
| | | | | |
| | | From this event, you have a pointer to | | |
| | | mainWindow, let's call it pMainWindow | | |
| | | | | |
| | | Then you can write: | | |
| | | | | |
| | | connect(pMainWindow->button, SIGNAL(...), | | |
| | | myclass, SLOT(...)); | | |
| | | | | |
| | | | | |
| | | In pseudocode: | | |
| | | ---------------------------------------------- | | |
| | | when application started | | |
| | | install eventfilter | | |
| | | | | |
| | | when eventfilter gets called | | |
| | | check the event and the target object | | |
| | | if event = show and object = mainWindow | | |
| | | Create a new MyClass object if none | | |
| | | already exists. | | |
| | | Connect signals and slots | | |
| | | | | |
| | +------------------------------------------------+ | |
| | | |
| +-------------------------------------------------------------------------------------+ |
| |
+-----------------------------------------------------------------------------------------+

You create a dll that reimplements the application event function to install an event filter.
In that event filter, you intercept the show event of a widget (for example). While intercepting that event, create a new QObject based object that contains signals and slots. Connect the slots of that object to the signals of the widget (or a member of that widget).

Make sure that when you build your library, the definitions of all the classes are known (include the correct headers). Also make sure that your code is processed by MOC.

Then inject the library in the program.

How this is exactly done on Windows, I don't know. Maybe you don't need to reimplement the event function of the application in order to install an event filter. That would make it a little bit easier.

EDIT: this is just a brainstorm from me. I do not assume that everything above is 100% correct.

squidge
17th October 2010, 13:38
I think what he means is that the application doesn't know about the DLL and is not loading the DLL.

Instead, he is using Winject to inject the DLL into the applications memory space, the application doesn't know the DLL has been injected. I assume it is being done this way because the source code of the original application isn't available and he wants to modify that application somehow. Maybe get some data from an existing Qt widget or manipulate the data somehow.

Kinda similar to how flaab wanted to grab data from inside a Poker engine in his thread (http://www.qtcentre.org/threads/34627-DEBUG-Debug-or-reverse-engineering-a-QListView-or-QListBox).

gilamran
17th October 2010, 14:44
This is almost the same thing... and we're talking about the same software, FullTiltPoker!
But flaab is asking how to intercept into internal function of QString or somthing like that...
I want my DLL to get signals from this software, like dataChanged, etc.

I'm not building a poker bot like flaab, I'm collecting players statistics.

for this, I need my DLL to be able to "connect" to the software UI signals.
Thanks for clearing me up.

Gil.

squidge
17th October 2010, 16:51
For best results in this case, you should use the same compiler as FTP. I'm going to guess that FTP uses something like Visual Studio 2008 rather than QtCreator (big companies don't like using free software)

gilamran
17th October 2010, 17:56
yea I'm using Visual Studio 2008, How can I tell what's the FTP QT version?

squidge
17th October 2010, 18:14
Is it dynamically linked? (does it refuse to run if the DLLs are missing?)

wysota
17th October 2010, 19:47
Can you inject a dll into a statically linked app (which is probably packed or encrypted too) at all?

tbscope
17th October 2010, 19:52
Can you inject a dll into a statically linked app (which is probably packed or encrypted too) at all?

Short answer: yes
But: it is extremely difficult. It is done in software cracking. You need to alter the assembly source code.

squidge
17th October 2010, 22:44
You can do it without altering the application code at all, if have something that easily identifies the 'target' application (such as the text for the window title or the process name) you can VirtualAllocEx and CreateRemoteThread, then your thread runs in the process space of the application and can do whatever it wishes.

gilamran
17th October 2010, 23:16
You can do it without altering the application code at all, if have something that easily identifies the 'target' application (such as the text for the window title or the process name) you can VirtualAllocEx and CreateRemoteThread, then your thread runs in the process space of the application and can do whatever it wishes.

Hey guys, this is not the issue at all...
It is possible, and this is the working part of my question.
I'll post my code soon (And you can try it too)

Back to the original question:
Can I connect a slot function in my injected dll to the main app?

Thanks

wysota
17th October 2010, 23:33
Until you provide some code of yours (namely the header file for the class you wish to call a slot from) we're stuck so we might as well get a bit offtopic here.

gilamran
18th October 2010, 13:20
Here are the files:
5347
5346
5348
5349

I'm injecting this DLL into the BasicLayout example (Comes with QT, run it to see where I'm going with this) , and do two connections:
1. Line1 with Line2
2. Line1 with mySlot function

I than change Line1 text, and see that Line2 also changes, and any change that I do to Line1 are reflected in Line2 too -> The connection is working!
And I did this connection from my DLL.

In mySlot function I change the Line3 text (We know that I'm able to do it)
so if the 2nd connection was successful we would have seen Line3 also change... but it doesn't... -> The connection didn't work!

I've created MyQWidgetMoc.cpp with moc.exe that comes with QT...

HELP HELP. :confused:
Thanks

wysota
18th October 2010, 13:58
So how do you know your slot was not called? And please don't reply that the text on lineEdit3 didn't change.

gilamran
18th October 2010, 14:12
So how do you know your slot was not called? And please don't reply that the text on lineEdit3 didn't change.

sorry, but the text on lineEdit3 didn't change...
If the 2nd connection was working, the lineEdit3 should have changed to "mySlot CALLED, yey"...
What am I missing!?!?!?

wysota
18th October 2010, 14:18
sorry, but the text on lineEdit3 didn't change...
If the 2nd connection was working, the lineEdit3 should have changed to "mySlot CALLED, yey"...
What am I missing!?!?!?

Debugging your application by changing values of lineedits is not a very professional way of doing things. What if you change the value but the change isn't reflected on the widget? Or if something rewrites the old value?

1. Check the return value of connect()
2. Use qDebug() or your debugger to see whether the slot is called.

gilamran
18th October 2010, 14:37
Check the return value of connect()
The return value is TRUE for both connections


Use qDebug() or your debugger to see whether the slot is called.
I can't use a debugger, because this code is an injected dll, and don't know how to use the qDebug()... (Sorry)

But just to make sure, inside mySlot function I disconnected the first connection, but it wasn't getting disconnected... man! this function is NOT being called!

I've also tried
this->metaObject()->indexOfSlot("mySlot()") and got 4!! the information is there! but not being called... :-(

I'm about to cry! anyone!? :crying:

wysota
18th October 2010, 14:53
The return value is TRUE for both connections
So the connection is successfully made.


I can't use a debugger, because this code is an injected dll,
It doesn't change anything, you can still run the original application under the control of a debugger together with your dll.


and don't know how to use the qDebug()... (Sorry)
So learn to use it.


But just to make sure, inside mySlot function I disconnected the first connection, but it wasn't getting disconnected... man! this function is NOT being called!

I've also tried
this->metaObject()->indexOfSlot("mySlot()") and got 4!! the information is there! but not being called... :-(

I'm about to cry! anyone!? :crying:
Maybe the respective signal is not emitted :)

gilamran
18th October 2010, 15:57
for a better test I did this:
I've opened the BasicLayout project in Visual Studio, added my MyQWidget.cpp/h and moc and connected the fields there...
Inside mySlot function I did a qDebug out, and saw it!!! when I do the connection from inside the app it's working! meaning -> MyQWidget is good for receiving signals! the caller is having a problem! maybe it can't find me in some slots table!?

When a signal is fired, how does QT "know" where to call to?

wysota
18th October 2010, 17:15
the caller is having a problem!
The caller is not having a problem, it is you who has a problem while trying to break into the application.

maybe it can't find me in some slots table!?
Maybe the signal is not emitted (I hate to repeat myself)?


When a signal is fired, how does QT "know" where to call to?
It looks into the connection table for the object emitting the signal.

gilamran
18th October 2010, 18:02
It looks into the connection table for the object emitting the signal.

Where can I see this code? I want to debug it.

wysota
18th October 2010, 18:33
QMetaObject class, as far as I remember. If not, then it's in QObject. But trust me, you won't be able to debug it, it's complicated. If your connect() statement returned true, it means the connection is placed in the connection table. As long as both interested objects are alive, it will stay there (if you don't disconnect the signal manually).

squidge
18th October 2010, 19:22
Post your solution (something loadable into VS or QtC) and we'll have a look at it.

gilamran
18th October 2010, 22:11
The solution is "Qt::DirectConnection"

I did some deep debugging and found that the code is checking if the caller and the sender are from the same thread... OR Qt::AutoConnection! so I did DirectConnection and it's working!!!!!!!!!!!!!!!!!

I want to thank all of you guys, for the time and effort! you are the best!

wysota
18th October 2010, 23:10
Hold on, there is something wrong here. Regardless of what the connection type is (be it AutoConnection or DirectConnection or QueuedConnection), the slot eventually gets called unless the target slot is in a thread that doesn't have an event loop running. So if your slot doesn't get called if you use AutoConnection then it means it runs within a thread without an event loop which in turn implies it is not the main application thread. And accessing widgets from the non-gui thread leads to a crash. I see some contradictions here:
1. since your test app doesn't use worker threads, auto and direct connections should be equivalent
2. your test app doesn't crash so you are not accessing widgets from a worker thread which in turn means the slot should work in the first place
2. if the application you are trying to break into uses threads and that's why the auto connect doesn't work (because your injection code works in the context of one of the worker threads), then accessing any component behind its back will/should likely lead to a crash.

To sum things up - either you are wrong now about direct connections or your solution will be crashing on you like hell soon.

gilamran
19th October 2010, 10:43
ok, ok... we have something here.
I'm comming for managed languages (Java) and I'm used to Garbdge collectors... (Be nice)

The new problem is that the slot is being called only one time.... I'm creating an object of MyQWidget when the DLL is being called, I'm calling the function that does the slot-signal connection, and I'm not releasing the object...
The DLL is still in the Main Application memory space, but MyQWidget is somehwere in memory!? maybe that was the reason that slot was not getting called...

I understand that I'm suppose to have some kind of events loop, that will keep MyQWidget alive, so my slot is available for SIGNALS. How Do I do that?

Am I right?
I guess that now you'll send me to read something (Please do)

Many thanks
Gil

gilamran
19th October 2010, 11:16
(Please read the previous post, first)

I'm trying now to prevent my MyQWidget from terminating (So it can be available for signals) I've changed it to inherit from QDialog (And not just QWidget or QObject)
When the DLL is running for the first time, I'm creating my "dialog" and calling a public function to do the signal connection, and than calling the "exec()" function of the dialog (To keep it alive)
BUT! the main UI is freezing, until I close my Dialog...

Do I have to create the dialog in a different thread? so the main UI will be able to actually send the signal...

Gil.

wysota
19th October 2010, 11:29
If the application is a Qt application (and it is) then there is already an event loop running and you shouldn't need to do anything more. Especially don't try handling anything related to widgets from another thread (in doubt read my previous post again). It doesn't matter if you inherit from QWidget or QDialog, the main event loop is already handling your widget. As for the memory thing, as long as you don't delete the object yourself and as long as its parent doesn't go out of scope, you'll object will remain alive.

gilamran
19th October 2010, 11:43
As far as I can see, I have two options:
1. use exec() -> leads to the main UI waiting for the dialog to close.
2. use show() -> The dialog opens, and closes very fast, no Idea why...

any ideas?

wysota
19th October 2010, 12:03
2. use show() -> The dialog opens, and closes very fast, no Idea why...
You are probably creating it on the stack and not on heap so it gets out of scope and gets deleted by the compiler.

gilamran
19th October 2010, 15:22
That was the problem!!
I've created my QDialog on the heap and now I'm getting all the signals!!! yey!
This might be obvious to some of you, but I come from Java (With garbage collector)

Two things left:
1. When I close the main UI, I can still see it in memory (Probably because it still have a slot in an object that wasn't release...)
So I need a way to know when the window is trying to close, or when the data of the model is being deleted... are there any events/signals that I can listen to and delete myself?

2. Still when I use the QDialog show(), it's openning and closing (very fast), and when I use the exec(), the main UI is stuck till I close it... any idea how to solve this?

Thanks
Gil

wysota
19th October 2010, 15:42
Show us how you create the dialog.

gilamran
19th October 2010, 15:45
#include <windows.h>


INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved)
{
MyQDialog *m_MyQDialog = new MyQDialog();

switch(Reason)
{
case DLL_PROCESS_ATTACH:
m_MyQDialog->connectQWidget();
m_MyQDialog->show();
break;

case DLL_PROCESS_DETACH:
break;

case DLL_THREAD_ATTACH:
break;

case DLL_THREAD_DETACH:
break;
}
return TRUE;
}

wysota
19th October 2010, 19:02
This shouldn't cause your dialog to disappear.

tbscope
19th October 2010, 19:21
At which point in time does DLL_PROCESS_ATTACH happen?

If it happens when the dll gets loaded before the main event loop is running, you're too soon to create the dialog.

Note that the main event loop is the one you want to use to create your dialog.
Try installing a hook into the main application event function. Then, when the application started event happens, create your dialog.

gilamran
19th October 2010, 19:52
I'm injecting my DLL when the application is fully running.
I took the QApplication:instance(), than I checked the applicationFilePath and got the injected exe file path. I guess that this means that My Dialog will be part of the exe application...

It looks like it's going to be inevitable... I will have to debug QT :-(
What's keeping a QDialog alive?

wysota
19th October 2010, 19:58
What's keeping a QDialog alive?
Please define "alive".

gilamran
19th October 2010, 20:50
"alive" means that it's in an events loop.
I did some debugging and got an ASSERT that said: "widgets must be created in the GUI thread"...
now I know that you're going to kill me and tell me that you already told me that it's "accessing widgets from the non-gui thread leads to a crash"... ok well, I did get access to the widgets, and even got my external DLL slot to get called...
but now the thing is that I can't create a dialog from my DLL... is there a way to work around it? (I think that can manage without the dialog)

wysota
19th October 2010, 22:03
Thus far I have an impression that you are doing some random things and expect to find a combination of them that works. This is not a good approach. You should first analyze what the applicaiton you are attaching to is actually doing. Otherwise your code might be called from a completely arbitrary context and it will not be possible to control it. Use a debugger to see whether the application uses threads and find a context where it will be running the main thread and try attaching to that. Otherwise you'll end up in a situation that you are doing something from a worker thread that gets terminated at some point and you won't be able to continue. Maybe you should find a different way to achieve your goal? Is the application dynamically or statically linked?

gilamran
26th October 2010, 15:40
Ok, after some time I've got some progress...
but now I have another question: (Should I open a new thread?)
I investigate the main application UI structure by going to it's children and printing out the widget name, x, y, visible etc.
BUT I have some window (A VERY important one for me) that contains a a very complex UI, but it's not a child of any of the QWidgets... A large portion of the UI is missing...
I found a QWidget with no children... can it be that this is the complex UI that I'm missing? can it be that a complex UI is some kind of external EXE running inside the QWidget?

any ideas?

Thanks

wysota
26th October 2010, 16:06
It's rather a graphics view or a custom widget that paints all its contents by itself.

gilamran
27th October 2010, 00:55
great! it's a graphics view... didn't know they exist... :D

ok, now that I have the graphics view, how can I enum all the items that inherit from QGraphicsTextItem? and print out their text...
yea, I know it's a dumb question, but I have no C++ background.... and I didn't find a way to do it.

Thanks
Gil

wysota
27th October 2010, 10:33
You ask the scene for all items and then you iterate over them checking their type and so on.

gilamran
27th October 2010, 10:36
yea I know.... but my C++ background is 0.
can't get it to work...



foreach (QGraphicsItem *item, scene->items())
{
QGraphicsTextItem *gti = qgraphicsitem_cast<QGraphicsTextItem *>(item);
if (gti)
{
sendmsg("QGraphicsTextItem found");
}
}

wysota
27th October 2010, 10:39
Define "can't get it to work".

gilamran
27th October 2010, 11:56
kaboom, exception

wysota
27th October 2010, 12:00
So use a debugger and fix it.