Bit at a loss hooking a C++ member func with const in Delphi

c++ / delphi package - dll injection and api hooking
Post Reply
sourcerer
Posts: 9
Joined: Sat Mar 19, 2005 5:33 pm

Bit at a loss hooking a C++ member func with const in Delphi

Post by sourcerer »

Hi,
I am a bit at a loss hooking into a function with the following C++ declaration:
public: static void __cdecl Window::CheckTitle(char const *,struct HWND__ *,char const *,int)

I assume the consts need special consideration as they might be passed through the stack, and of course I should add a 'self'

I tried:

procedure CheckTitleCallback(aa:dword; a:dword; var b:dword; c:dword;var d:integer) stdcall;
begin
CheckTitleNext(aa,a,b,c,d);
end;

(all simply assuming pointers are 32 bits, and non consts are vars...was the best I could come up with)

The the Next is properly set, the injection works, but it bombs when the procedure actually gets called.

Any help........GREATLY appreciated.

Kaj
madshi
Site Admin
Posts: 10764
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

It bombs because you're using stdcall, while the C++ declaration uses cdecl.
sourcerer
Posts: 9
Joined: Sat Mar 19, 2005 5:33 pm

Thanks...but

Post by sourcerer »

Wow, hoe do you KNOW that stuff!

I'll try changing that, that's one of the mystery elements to me.

One additional question tho, was my assesment regarding the by value and by reference passing useful, or is that a pointless thing to look at as just 32 bit values are passed regardless?

Thanks again,
Kaj
madshi
Site Admin
Posts: 10764
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

You don't need var and const, if you just want to make it run. If you later want to access the parameters you need to know how, of course, but that's a different topic.
sourcerer
Posts: 9
Joined: Sat Mar 19, 2005 5:33 pm

Works like charm but..

Post by sourcerer »

Okay...as you said, accessing it is a different topic, and now I really start noticing it has been a long time ago I did pointer work in Pascal.

I try to display the pchar but go wrong somewhere...incredible n00b I must say.

procedure CheckTitleCallback(aa:dword; a:pchar; var b:dword; c:pchar;var d:integer) cdecl;
var ch:char;
var td:integer;
var work:pchar;
var pv:longint;
begin
// See if Dumpline works - it does
DumpLine('FindNextFileWCallback ');

// display the pointer value - the address it points to..somehow!
pv := integer(a);
DumpLine(Format('FindNextFileWCallback a=(%d)',[pv]));
// ditto for pointer c
pv := integer(c);
DumpLine(Format('FindNextFileWCallback c=(%d)',[pv]));
// if pointer c ain't nil dump it's first character
if pv<>0 then
begin
ch := c^;
td:=ord(ch);
DumpLine(Format('FindNextFileWCallback c=(%d)',[td]));
end;
// call the original code
CheckTitleNExt(aa,a,b,c,d);
end;

Needless to say it crashes.
Is it because the pointer points to addresses in the address space of the other procedure?
Oddly enough the values for C (the integer(c)) are all low, which kinda makes me suspect that the cast is wrong, but I can't find the way to cast the pointer to an address value.

I hope for some help,
Kaj
madshi
Site Admin
Posts: 10764
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

You should check out each parameter seperately to find out which parameter makes problems and which not. The last parameter is definately not "var", though. Look, in the original declaration it's just "int". Why did you use "var" there?
sourcerer
Posts: 9
Joined: Sat Mar 19, 2005 5:33 pm

Good point yet...

Post by sourcerer »

Ah, yes, the var declaration was an oversight, yet since it wasn't referenced in my code it didn't matter as it was just passed along the way it came in.

I have narrowed the crash down to the following line:

DumpLine(Format('FindNextFileWCallback c=(%d)',[td]));

however I know the crash is not that function itself, because when I type td:=10 in the previous line it works.
I guess that if I exlude the call to DumpLine the "ch := c^; " will be optimized out as the result isn't needed.

I therefore think the "ch := c^;" is the culprit.

Any thoughts on that?

Struggling on,
Kaj
madshi
Site Admin
Posts: 10764
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

Quite probably you're right. Do you have documentation about what those parameters mean? E.g. I know that in some APIs you can use atoms instead of strings. Dereferencing those will crash, too. One example for that is the CreateWindow API.
sourcerer
Posts: 9
Joined: Sat Mar 19, 2005 5:33 pm

Post by sourcerer »

Nope, I have no documentation, I only know the calling format because of the export definition of the function.

Do you know a workaround regarding the pointer dereferencing in CreateWindow?

Obviously the called code has access to those pointers....should I use IPC because the data lies in the memory space of the other process?

Or is the pointer casting invalid? It wouldn't explain the crash, but as I said the values I get for the integers are low, below 1000 even, which seems very odd for an address.

It just occurs to me that perhaps the parameter *can* be a char* but maybe sometimes it's used as something else, and that the calling code just casts it to the proper kind, and the handler treats it accordingly depending on for example the value of the passed integer.

Kaj
madshi
Site Admin
Posts: 10764
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

sourcerer wrote:Obviously the called code has access to those pointers....should I use IPC because the data lies in the memory space of the other process?
You don't seem to understand the underlying basic principles. Your hook callback function is called in the same process context in which the hooked function/API was called. So there is no memory area conflict.
sourcerer wrote:Or is the pointer casting invalid? It wouldn't explain the crash, but as I said the values I get for the integers are low, below 1000 even, which seems very odd for an address.
Addresses below 1000 are definately non dereferencable. That are no strings, but something else. Maybe an index into a string table or whatever.
sourcerer wrote:It just occurs to me that perhaps the parameter *can* be a char* but maybe sometimes it's used as something else, and that the calling code just casts it to the proper kind, and the handler treats it accordingly depending on for example the value of the passed integer.
That's exactly how CreateWindow behaves if you give in an atom ID instead of a class string. That's why I mentioned this example.
sourcerer
Posts: 9
Joined: Sat Mar 19, 2005 5:33 pm

Thanks!

Post by sourcerer »

Thanks for all your help...I figured it out.

The export info for the DLL was all very wrong somehow. The char pointer was actually the string length, and the HWND* was the pointer to the string. Started trying that one as it was the only value that qualified as a pointer, and I was lucky.

But thanks for all your help, I wouldn't have managed.

Kaj
Post Reply