[Question] Internal commans handling

Discuss and announce Total Commander plugins, addons and other useful tools here, both their usage and their development.

Moderators: Hacker, petermad, Stefan2, white

User avatar
m^2
Power Member
Power Member
Posts: 1413
Joined: 2006-07-12, 10:02 UTC
Location: Poland
Contact:

[Question] Internal commans handling

Post by *m^2 »

2 Ghisler:
How does TC handle internal commands?
It's possible to make TC do something with finding a window of TTOTAL_CMD class and sending a WM_COPYDATA message to it.

During work on universal plugin interface, I managed to take over TTOTAL_CMD's WindowProc. And, surprise, it doesn't get any WM_COPYDATA messages.

Could you please tell what's happening with them?
User avatar
majkinetor !
Power Member
Power Member
Posts: 1580
Joined: 2006-01-18, 07:56 UTC
Contact:

Post by *majkinetor ! »

Do you receive msg for calling comamnd (1075) ?

Anyway your code is probably wrong as I can catch WM_COPYDATA

Check out the screenshot:

Image: http://img265.imageshack.us/img265/1817/clipse5.png

I recorder this with TC open and using Favmenu to set the folder.
Habemus majkam!
User avatar
m^2
Power Member
Power Member
Posts: 1413
Joined: 2006-07-12, 10:02 UTC
Location: Poland
Contact:

Post by *m^2 »

No, I don't.
This program uses hooks to get messages, right?
I don't, they are too slow.
Hooks react before the WindowProc is called. I'm not 100% sure my code is correct. But I get quite a lot of messages, just not these important...
User avatar
majkinetor !
Power Member
Power Member
Posts: 1580
Joined: 2006-01-18, 07:56 UTC
Contact:

Post by *majkinetor ! »

I don't, they are too slow.
Well, this sounds like it is slow as hell...
Hooks are not too slow, they are just slower then subclassing.

Can you show relevant parts of your code ? Explain what you did ?
Bla bla...

Also, keep in mind that some other control may subclassed after you. So, it is removing messages from your quieue. You never know how subclass hierarachy is deep. You can easily have X > Y > Z > TotalCMD and your code being Y. Don't know how this can be detected atm.


Winispector probably use hooks. Otherwise, the only solution to monitor all programs AFAIK is being driver, and I doubt Winspector has driver part.
Habemus majkam!
User avatar
Hacker
Moderator
Moderator
Posts: 13142
Joined: 2003-02-06, 14:56 UTC
Location: Bratislava, Slovakia

Post by *Hacker »

[mod]Moved to the Plugins and addons forum.

Hacker (Moderator)[/mod]
Mal angenommen, du drückst Strg+F, wählst die FTP-Verbindung (mit gespeichertem Passwort), klickst aber nicht auf Verbinden, sondern fällst tot um.
User avatar
m^2
Power Member
Power Member
Posts: 1413
Joined: 2006-07-12, 10:02 UTC
Location: Poland
Contact:

Post by *m^2 »

majkinetor ! wrote:Winispector probably use hooks. Otherwise, the only solution to monitor all programs AFAIK is being driver, and I doubt Winspector has driver part.
There's at least one more way.
majkinetor ! wrote:Can you show relevant parts of your code ? Explain what you did ?
Bla bla...
Code injection. At the begining of each function I want to take over I write

Code: Select all

mov eax, replacement_function_addr
jmp eax
.

I use it to get RegisterClass, what gives me the address of TTOTAL_CMD's WindowProc.
Then I just do the same trick again...and I'm ready.

Of course, while writing these jumps, I remember what was there before, so I can restore the original code whenever I want to.
majkinetor ! wrote: Also, keep in mind that some other control may subclassed after you. So, it is removing messages from your quieue. You never know how subclass hierarachy is deep. You can easily have X > Y > Z > TotalCMD and your code being Y. Don't know how this can be detected atm.
Subclassing..I didn't think about it. It may be the problem. I'll take a closer look.
Hacker wrote:Moved to the Plugins and addons forum.

Hacker (Moderator)
I think that TotalCommander forum is a better place for this topic, it's not about the interface, but about TC's internals.
User avatar
majkinetor !
Power Member
Power Member
Posts: 1580
Joined: 2006-01-18, 07:56 UTC
Contact:

Post by *majkinetor ! »

Code injection.
I didn't know you used this way. Its amazing how you made it work.

So, you say that you change code for the func by overwriting the start of the function with your asm code ? But how do you call original function then as its start is deleted ? Did you do something like:

Code: Select all


originalCode = Redirect(@TC_Function, @replacement_function )


replacement_function()
{
  ...  
  Restore(@TC_Function, @originalCode)
  TC_Function()
  Redirect(@TC_Function, @replacement_function)
}
I use it to get RegisterClass, what gives me the address of TTOTAL_CMD's WindowProc.
I don't understand this.
I usualy call GetWindowLong to find out WindowProc adr.
Habemus majkam!
User avatar
m^2
Power Member
Power Member
Posts: 1413
Joined: 2006-07-12, 10:02 UTC
Location: Poland
Contact:

Post by *m^2 »

majkinetor ! wrote: So, you say that you change code for the func by overwriting the start of the function with your asm code ? But how do you call original function then as its start is deleted ? Did you do something like:

Code: Select all


originalCode = Redirect(@TC_Function, @replacement_function )


replacement_function()
{
  ...  
  Restore(@TC_Function, @originalCode)
  TC_Function()
  Redirect(@TC_Function, @replacement_function)
}
That's exactly what I do.
majkinetor ! wrote:
I use it to get RegisterClass, what gives me the address of TTOTAL_CMD's WindowProc.
I don't understand this.
I usualy call GetWindowLong to find out WindowProc adr.
But to call GetWindowLong, there must be a window. I can obtain this address and do the modification before there's any window of this class created.
User avatar
majkinetor !
Power Member
Power Member
Posts: 1580
Joined: 2006-01-18, 07:56 UTC
Contact:

Post by *majkinetor ! »

. I can obtain this address and do the modification before there's any window of this class created.
So, how do you use RegisterClass to get proc adr ?

That's exactly what I do.
I beleive this code may crash the TC in some situations.
You should probably redirect and restore in critical sections. Anyway, amazing if it works correctly. I know there are Delphi modules for redirection, but they have disasemblers integrated AFAIK so they detect where to "stop deleting" original code as you can bump in the middle of instruction the way you do. Something may eventualy jump in the middle of your process of "fixing" and call the function you are "fixing".

If it works without problems, and you didn't use any 3th party modules for redirection, I must say I am impressed.

I suspect that Ghisler will hunt you until he burns you to death, for doing such nasty and dirty hacks to his only child.
Habemus majkam!
User avatar
m^2
Power Member
Power Member
Posts: 1413
Joined: 2006-07-12, 10:02 UTC
Location: Poland
Contact:

Post by *m^2 »

majkinetor ! wrote:
. I can obtain this address and do the modification before there's any window of this class created.
So, how do you use RegisterClass to get proc adr ?
Every time TC registers a class, it calls my function. This function checks if the class name is "TTOTAL_CMD".
- If it's not, it does what you wrote above: restores the original RegisterClass, calls it and places a jump to itself on it again.
- If it is, reads the WndProc address ( from WNDCLASS given as a parameter ), places a jump there, releases RegisterClass and calls it (does not overtake it again, as it's not needed anymore).
majkinetor ! wrote:
That's exactly what I do.
I beleive this code may crash the TC in some situations.
You should probably redirect and restore in critical sections.
You're definitely right, thank you.
User avatar
majkinetor !
Power Member
Power Member
Posts: 1580
Joined: 2006-01-18, 07:56 UTC
Contact:

Post by *majkinetor ! »

Will this redirected RegisterClass for entire system, not only TC ? RegsterClass is shared by all processes in the system IMO.

Well... its cool.

I have here little firewall (~50K) that is using this technique to redirect OpenSocket API. I just think it used hooks for some reason, possible to because OpenSocket isn't shared. I know its hard to turn it of without reseting computer (or I don't know to use it). Maybe you can do the same, and create little firewall as a FS plugin. Nothing fancy, just basic monitoring needs. :D
Habemus majkam!
User avatar
m^2
Power Member
Power Member
Posts: 1413
Joined: 2006-07-12, 10:02 UTC
Location: Poland
Contact:

Post by *m^2 »

majkinetor ! wrote:Will this redirected RegisterClass for entire system, not only TC ? RegsterClass is shared by all processes in the system IMO.

Well... its cool.

I have here little firewall (~50K) that is using this technique to redirect OpenSocket API. I just think it used hooks for some reason, possible to because OpenSocket isn't shared. I know its hard to turn it of without reseting computer (or I don't know to use it). Maybe you can do the same, and create little firewall as a FS plugin. Nothing fancy, just basic monitoring needs. :D
I saw some results from it and there ware nothing but TC windows, so it's rather not shared. I'll do more tests tomorrow.
User avatar
m^2
Power Member
Power Member
Posts: 1413
Joined: 2006-07-12, 10:02 UTC
Location: Poland
Contact:

Post by *m^2 »

I did no tests, but it won't work. I make a jump. So I'd need to place the replacement function at the same virtual address in every process. So I'm lucky that it's not shared :D
User avatar
majkinetor !
Power Member
Power Member
Posts: 1580
Joined: 2006-01-18, 07:56 UTC
Contact:

Post by *majkinetor ! »

Nothing special - you make a global hook, which loads your dll in every app, then you do your fixing thingie the same way as in TC.
Habemus majkam!
User avatar
m^2
Power Member
Power Member
Posts: 1413
Joined: 2006-07-12, 10:02 UTC
Location: Poland
Contact:

Post by *m^2 »

majkinetor ! wrote:Nothing special - you make a global hook, which loads your dll in every app, then you do your fixing thingie the same way as in TC.
But there's no way to ensure that my dll will get the same address in all processes.

I've been thinking about this Delphi module you mentioned and I think that finding ret was not the main purpose of disassemblation - if don't have enough space, you'll do nothing. But if you have the routine disassembled, you can assemble it again to work in a different part of memory (actually probably the only thing that has to be changed in the binary representation are jumps ). Why relocation is better than these jumps I do? I can't make it fully thread safe, this code may miss some calls. Example?

Code: Select all

Thread 1                   | Thread 2
-----------------------------------------------------
call the "orig." function  |                                // Thread 1 thinks it's the original function,
                                                            // but there's a jump
jump
enter the critical section |
restore the orig. code     |
call the orig. function    | call the orig. function       // there's just the orig code => 
                                                           // Thread 2 has no critical section to enter
place the jump again       |
leave the critical section |
The only way to prevent it is stopping all running threads instead of entering the critical section. But what if the function waits for some input from another thread or so? Unacceptable.
Post Reply