Threading issue

c++ / delphi package - dll injection and api hooking
Post Reply
Astaelan
Posts: 22
Joined: Wed Sep 22, 2004 7:08 pm

Threading issue

Post by Astaelan »

Hey madshi, long time since I've been using your code, but I'm back again.

This time with a different problem. As always, your code is great and has come to my rescue saving me countless hours of looking up DLL injection routines and IPC stuff.

However, that leads me to a small problem. I have an application wherein I've injected a DLL, patched some assembly, stubbed out to a function in my DLL. Now at this point I have the data I want to fire into the IPC tunnel, and I do so like this:

Code: Select all

if(!SendIpcMessage("Recv IPC Queue", (char *)g_dwPacketRecvData, g_dwPacketRecvSize, &bDone, sizeof(bDone)))
	TraceOut("Unable to queue recv packet in IPC Queue");
So far so good right?
Now according to the minimal documentation on IPC available, I've been able to piece together that each call to SendIpcMessage uses a new thread to make the call, based on the fact that creating the IPC pipe requires some information on how many threads to allow, and a queue length, neither of which are implemented currently. Too bad, because that queue would solve my current problem.

Basically what's happening is the messages are getting through, rather, the first one does. But then 3 packets come in rapid succession, and I'm crashing out. I've created the pipe to limit to 1 thread as such:

Code: Select all

if(!CreateIpcQueueEx("Recv IPC Queue", (PIPC_CALLBACK_ROUTINE)GetInterceptedPacket, 1, 0x1000))
	MessageBox("Unable to create IPC Queue GetInterceptedPacket");
If I understand correctly, this means that internally it will only allow 1 thread to exist at a time, to ensure the packets come in the correct order. However, my problem is that because it's crashing I'm assuming a second SendIpcMessage call is using the pipe and crashing it out when it's still in use. Should SendIpcMessage return before the callback is finished in the original program? I expect not, because the "answer" needs to be set prior to returning.

So, what I assume is happening in actuality is that my hook prior is also threaded and so a second thread for that hook is called, and trying to use the IPC tunnel.

What my real question is, is how to use CreateGlobalMutex and OpenGlobalMutex. There is very little documentation on how these work, and my understanding of threaded work is limited mostly to .NET. Do I simply create the mutex once in my injected DLL, and use OpenGlobalMutex when I want to open a the thread safe area? How to I release the mutex after?

And an age old question I've always wondered. If I create a static BOOL value, is it thread safe automatically? Can I use it as my own locking mechanism by simply sleeping in a loop until it's no longer set? Or is there still threading issue during the split moment the bool is assigned? My assumption is that since processors are still not TRUELY multitasking and simply task switch, that it should be safe to modify a single bit without special locking mechanisms, am I correct? Sorry if this is a stupid question :)

Back to the grindstone while I wait for a response.
Astaelan
Posts: 22
Joined: Wed Sep 22, 2004 7:08 pm

Post by Astaelan »

Okay, I worked through and tried win32 Mutex's and doesn't seem to make a difference. I get 1 occurance of the IPC message going through properly, then just after that it crashes with an access violation in my program (not the DLL). Unfortunately I can only debug it at the assembly level and that does me no good.

I wanted to also add that when I take out my call to SendIpcMessage, the code works fine with no problems. And I find it strange that it works fine for the first message to get through, and then it dies. Any ideas why this might occur?

I am not certain, due to the internal mechanics of where I'm hooking, but it's my belief that my code is called over and over from the same thread, and not in a multithreaded environment. In otherwords, the code that calls SendIpcMessage should be in a single-threaded model. I realize however, that once called it dispatches a new thread to the callback method. I don't have any code in the callback at all, and I get the problem still.

Hoping someone has an idea, been stuck on this for a few hours and it's slowing me down :)
madshi
Site Admin
Posts: 10764
Joined: Sun Mar 21, 2004 5:25 pm

Re: Threading issue

Post by madshi »

Astaelan wrote:So far so good right?
I guess so.
Astaelan wrote:If I understand correctly, this means that internally it will only allow 1 thread to exist at a time, to ensure the packets come in the correct order.
Right.
Astaelan wrote:However, my problem is that because it's crashing I'm assuming a second SendIpcMessage call is using the pipe and crashing it out when it's still in use.
The IPC mechanism is thread safe and should not crash. Several of my customers are using is without having any problems with it.
Astaelan wrote:Should SendIpcMessage return before the callback is finished in the original program?
Not if you're waiting for a reply.
Astaelan wrote:I expect not, because the "answer" needs to be set prior to returning.
Right.
Astaelan wrote:So, what I assume is happening in actuality is that my hook prior is also threaded and so a second thread for that hook is called, and trying to use the IPC tunnel.
Even if that's the case, it's no problem at all, because SendIpcMessage is totally thread safe.
Astaelan wrote:What my real question is, is how to use CreateGlobalMutex and OpenGlobalMutex. There is very little documentation on how these work
They work just like the normal win32 APIs CreateMutev and OpenMutex work. The only difference is that the "global" mutexes are global... :-) So you can read the win32 documentation about mutexes to understand how they work.
Astaelan wrote:And an age old question I've always wondered. If I create a static BOOL value, is it thread safe automatically? Can I use it as my own locking mechanism by simply sleeping in a loop until it's no longer set? Or is there still threading issue during the split moment the bool is assigned? My assumption is that since processors are still not TRUELY multitasking and simply task switch, that it should be safe to modify a single bit without special locking mechanisms, am I correct? Sorry if this is a stupid question :)
First of all: On a Multi-CPU-PC you do have true multitasking. And a Hyperthreading PC comes quite near. Then how do you define "thread safe"? You can set a BOOL value in a thread without crashing anything. But if another thread is reading the BOOL value at exact the same time, the result is quite unpredictable.

Simply sleeping in a loop until a BOOL is set is not a good idea. I mean how would you do that? "while (!boolVar) ;"? That would bring the CPU usage to 100% all the time while that loop runs. If you add a "Sleep(50)" to the loop, it might work better, but then you have a possible delay of 50ms until the loop notices that the bool has changed. You should better use Events (see CreateEvent or CreateGlobalEvent) for such situations.
Astaelan wrote:I get 1 occurance of the IPC message going through properly, then just after that it crashes with an access violation in my program (not the DLL). Unfortunately I can only debug it at the assembly level and that does me no good.
Try to comment the code in your IPC callback function out. Simply leave the IPC callback function empty. Do the crashes go away then?
Astaelan
Posts: 22
Joined: Wed Sep 22, 2004 7:08 pm

Post by Astaelan »

Thanks for a quick reply, I'm still working on this problem.

To answer you question, no the crashes don't go away. I have a completely empty callback and it crashes. Now, it doesn't actually crash in the callback method, but rather sometime after leaving it.

I decided to try and Destroy the IPC tunnel and recreate it in the callback, and this had a more desireable result, but still doesn't work. Basically, it calls the callback once, but never again. Furthermore, SendIpcMessage doesn't fail. So, SendIpcMessage is called 3 times, but only one callback is ever met. Thought it might be a race condition, so I put a mutex in my callback, and no difference.

Still, with a completely empty callback it crashes. And if I comment out the use of SendIpcMessage, no crashes (of course, no functionality either).

Thanks for clearing up some of my other questions, I was pretty sure I was right, but wanted to clarify. Knowing SendIpcMessage is completely threadsafe is good, I can eliminate the mutex around my calls to it.

Hope you have some other ideas on why it's crashing though... Or maybe a suggestion on how to destroy and recreate the IPC tunnel, since that seems to work to some extent. No crash, but no more than 1 packet makes it through.
madshi
Site Admin
Posts: 10764
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

Are you sure you have used the correct parameters and calling convention for the IPC callback function? I suspect there's something wrong.
Astaelan
Posts: 22
Joined: Wed Sep 22, 2004 7:08 pm

Post by Astaelan »

Here is the definition for my callback in my EXE.

Code: Select all

void GetInterceptedPacket(LPCSTR pIpc, PVOID pMessageBuf, DWORD dwMessageLen, PVOID pAnswerBuf, DWORD dwAnswerLen)
And it's created as such:

Code: Select all

	if(!CreateIpcQueueEx("MyRecvQ", (PIPC_CALLBACK_ROUTINE)GetInterceptedPacket, 1, 256))
		MessageBox("Unable to create IPC Queue GetInterceptedPacket");
It's being created fine. The first packet makes it through.
I put some logging into my DLL, and it's getting 3 packets of which it appears after the first one and before the second one it's crashing out.

The only real notable symptom I've found is that by destroying the IPC queue at the end of the callback, I only get 1 processed callback, but it doesn't crash. If I try to create the IPC queue again in the callback, it doesn't seem to work right. The queue is destroyed but never created properly again, and even packets that come way later don't get processed again.

You'll notice I set a queue of 256 despite it not being implemented, shouldn't matter right?

Is my callback missing something in the definition?

Here is how it's being called from my DLL:

Code: Select all

		if(!SendIpcMessage("MyRecvQ", (PVOID)g_dwPacketRecvData, g_dwPacketRecvSize))
			TraceOut("Unable to queue recv packet in IPC Queue\n");

Any other thoughts?
Astaelan
Posts: 22
Joined: Wed Sep 22, 2004 7:08 pm

Post by Astaelan »

Oh, I forgot to mention, I've tried both with and without passing the "answer" arguments, with no difference. The callback doesn't do anything, completely empty function, and it's not crashing IN the callback, rather sometime after the first time it's used.
madshi
Site Admin
Posts: 10764
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

You forgot WINAPI.
Astaelan
Posts: 22
Joined: Wed Sep 22, 2004 7:08 pm

Post by Astaelan »

Wow, you know, that was the problem. Amazing, something so simple.

I would highly recommend some C++ documentation. I respect the time it takes, but I think it would really appeal to a large audience. Something that simple would have been averted by having a C++ prototype to reference in documentation.

Anyway, much thanks for fixing the issue, brilliant deduction. I hope this thread helps someone in the future.
Post Reply