0

I have a DLL file from which I need the memory address of a class procedure. I am getting the handle to the DLL file, but when I use GetProcAddress, I can't get the address of the procedure. I have tried the following strings for the process name parameter:

"ProcName"
"ProcClass.ProcName"
"ProcClass::ProcName"
"ProcInterface::ProcName"
"ProcInterface.ProcName"

In none of the cases have I gotten the memory address of the procedure. I am mostly certain that the procedure is public.

What is the string format for doing this? Would it be easier to declare a function pointing to the external procedure and get the address later? Like this:

procedure ProcName(); stdcall; far; external 'Example.DLL';

ProcPointer := @ProcName;
mnuzzo
  • 3,529
  • 4
  • 26
  • 29
  • 3
    By the way, you've asked quite a few questions on this topic recently, which is good. However, you haven't accepted many answers. I think you could accept some answers which is a good way to show your appreciation! – David Heffernan Mar 18 '11 at 14:01
  • Did you write this DLL? How do you know it has a class procedure in it and not a regular procedure? – Warren P Mar 19 '11 at 02:58

3 Answers3

6

GetProcAddress only gives you the address for exported functions. Your DLL surely doesn't export the methods of a class!

Use an PE explorer to look for the exported names. For example, use the PE explorer available in GExperts. I've got a "PE Information" menu entry under the GExperts menu.

Cosmin Prund
  • 25,498
  • 2
  • 60
  • 104
  • Dependency walker is the other obvious tool for exports, but this method is not likely to be exported as you say – David Heffernan Mar 18 '11 at 17:00
  • PE Explorer from http://www.heaventools.com is another tool for viewing the exported names. It'll show you function prototypes in Delphi syntax! – Wylder Mar 19 '11 at 15:37
1

You are into reverse engineering territory here.

I think that if I were you I would just step through in the CPU view of the debugger, following a call to the method of interest, and find the entry point address. I'd subtract it from the base address of the DLL and that would be the offset. Then to calculate the address at runtime you just add the offset it to the base address of the DLL in memory at that time. You can find out the base address with calls to LoadLibrary or GetModuleHandle.

Why hard code the offset? Well, since you can't modify your DLL it doesn't seem to be too limiting. If hard coding the offset is not viable then there are other means of locating entry points, but I must admit I'm not the world's greatest expert on that.

Finally, when you implement the replacement method, you will need to replace it with a global function/procedure with an extra parameter, the first parameter, which takes the place of Self.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • @David, can you post code for doing this from a simple class function in a DLL? Since you can't export class members from Delphi (AFAIK, anyway), I'm not sure how you'd get the address of the class function. This is the first of your answers I've felt the urge to downvote, so I'm interested in being proven wrong here. :) – Ken White Mar 18 '11 at 16:06
  • @Ken There's no code. You just step through the debugger and see where it takes you, reading the disassembly. The goal is to find the entry point of the function that you wish to replace. It's probably quite tricky with IDispatch, or whatever this is, and there will likely be a couple of layers of indirection to navigate. – David Heffernan Mar 18 '11 at 16:08
  • @Ken What I'd probably do is generate my own simple IDispatch (if that is indeed what we are talking about) and then see how a method call on one of those is implemented in assembler. I'd then map that onto the real DLL and work out the entry point. Once I've got the entry point address I'd use my code from the previous question to overwrite that code with a JMP to the new code. – David Heffernan Mar 18 '11 at 16:10
  • @Ken I've tried to clarify the answer a little. I'd not explained it well. It's clear in my head, but that doesn't help you. I've explicitly stated that I am talking about stepping in the CPU view of the debugger. – David Heffernan Mar 18 '11 at 16:18
  • @David, that's better. I don't feel I should downvote. Don't feel like I should upvote, either, because I'm not sure any of that is viable for accessing a class function. (The class function would involve locating the class and then a lookup into the class's memory layout, which would be implementation-specific, and would also involve hard-coding an offset which could change for any number of reasons.) – Ken White Mar 18 '11 at 16:24
  • @Ken You need to read up all the previous questions. This is in a DLL that the OP cannot modify. So OP is allowed to assume it cannot change. At least that's my reading of previous questions. It sounds like a duff assignment to me though, that's for sure. – David Heffernan Mar 18 '11 at 16:25
  • @Ken It's kind of the nature of this problem that it is implementation specific and breaks all good practices, assumes knowledge of compiler specifics, private details of class layout etc. It's a reverse engineering hack. That, at least, is my understanding of what OP wants. – David Heffernan Mar 18 '11 at 16:27
  • @David, gotcha. I figured it was a hack of some sort, or you could either build it as a package instead or write a wrapper function that called the class function and then export that wrapper. Thanks for clarifying. I guess it's worth a +1 in that case then. :) Done. – Ken White Mar 18 '11 at 16:32
  • @Ken David's right, I can't change it and as far as I know we're not going to be receiving any updates so a specific offset from the start of the DLL will work. I just tried doing something less of a hack and I found out that the function is more complicated than I first thought and I might have to insert the jump somewhere in the middle :/ – mnuzzo Mar 18 '11 at 17:14
  • @mnuzzo being set the task of hacking at some broken DLL from the outside sounds like a duff assignment to me. Much more fun to work on something that you can see clearly. – David Heffernan Mar 18 '11 at 17:55
  • 1
    @mnuzzo, do you have *any* source code for the DLL? Do you, at least, know what language was used to build it? If you feel the need to add a jump "somewhere in the middle", I'm afraid you've got a rough track ahead, because you'll need to not only jump out of the procedure, but you'll need to jump back in, without messing the stack! If you need to do that, unless you dream in assembler, you should think twice, and maybe three times, if that DLL is worth it. – Cosmin Prund Mar 18 '11 at 17:58
  • @Cosmin D6, same as host app apparently. – David Heffernan Mar 18 '11 at 18:00
  • @mnuzzo Do you understand all the things that can go wrong. If your hook tries to allocate memory that the original DLL is expected to deallocate then you are in trouble, for example. There are hundreds of traps. You could help us by telling precisely what this to be hooked function is meant to do. – David Heffernan Mar 18 '11 at 18:01
  • @mnuzzo, is the D6 DLL using "sharemem"? Is the procedure you want to hook long? The most straight-forward way to fix the DLL is to replace the WHOLE procedure, not just the failing parts. You can do that with a single injected JMP instruction, and with a witty exe-side routine written in Delphi (no assembler). This is trivial if you happen to have the source file for *that class*, even if you don't have the source files for the rest of the DLL. To be bluntly honest, if you need to jump out from the middle of the routine, you'll be in the "If you need to ask, you can't do it" territory. – Cosmin Prund Mar 18 '11 at 18:23
  • I don't have any of the source for the DLL file. I am completely in unknown territory for me. I'll probably use the information from locating the function to recreate what the function is doing since even touching stuff at this low level scares me. Either that or I'll end up doing a DLL hack on the file itself. – mnuzzo Mar 18 '11 at 18:50
  • @David I was asking for the definition of "duff assignment". – mnuzzo Mar 18 '11 at 18:50
  • @David, +1, it's a good answer. Lots of anonymous downvotes to good questions lately. – Cosmin Prund Mar 18 '11 at 20:39
  • @Cosmin I picked up three 2 downvotes in a minute earlier today, one on this Q. It's not a great answer I don't think, but the question isn't really very clear cut. – David Heffernan Mar 18 '11 at 20:43
  • @David, it happened to me a while ago when I down-voted a very bad answer from someone and left a comment. I suspect this user lately looked at my profile and pseudo-randomly selected 4 or 5 questions to down-vote. I felt angry at first and really wanted to pay in kind, although I did not, then learned to down-vote anonymously to bad answers or questions from unknown users, to avoid this kind of *offended user reprisals*, but still be using my power to help StackOverflow attempt to qualify content quality. Of course I'm not your down-voter, your answer's are always between good and excellent – jachguate Mar 19 '11 at 17:32
0

I might be reading this wrong. But it seems to me you wrote the DLL.

You should write a function that is NOT a member of any class, and export it from your DLL. Inside that function, call your class method.

If you didn't write the DLL, you still need to find out what functions it exports, and it is very unlikely any of them were class methods, at least not in Pascal.

If someone wrote a dll in C++ and exported its methods, then you would have to investigate C++ name mangling rules.

Warren P
  • 65,725
  • 40
  • 181
  • 316