I think each of you had the feeling that in one program or another there was a lack of some must have feature. If the program comes with source code, then there are no problems. Anyone can add the necessary functionality. What if the program is closed? Do not despair, this is not a lost case. Now I will tell you how you can add what is missing for the author.
Retreat
OllyDbg debugger again became my victim. After the release of version 2.00, I began to like it more and more, many interesting things appeared. But the author categorically refused to integrate the plugin system into it, and this can be said, the main thing that made the debugger a real working tool.
And at one moment, I realized for myself that it was time to add this opportunity myself.
Let's get started
The first question comes up - how to add your code?
There are two main ways:
- Add a new section, and put all your code in it.
- Put the code in the dll, and then in the free space of the program put a small code call.
There are other more sophisticated options, but I will not consider them.
I chose the second option, because it is more convenient in terms of programming, and I don’t need to copy my code to the exe every time. To load your dll, you can change the entry point to your code, or download a little later. But it is better to load at the very beginning, then we will have access to all APIs before the parent process takes advantage of them.
I did not have to do the patch, I found the already patched one, I changed only the name of the module being loaded.
It was:

It became:

And our code. The trick of the first call is that with one command it pushes the address of the line onto the stack and jumps over it.

Jmp at 00401000 is OEP from Borland C
')
The plugin loading scheme is trivial:
We read from ini the path to the folder with plug-ins, if it is not there, then we take the path by default and check the presence of the folder through the GetFileAttributes. Well, then by mask * .dll, with the help of FindFirstFile / FindNextFile, we list all the files.
Load each through LoadLibrary. And the plugin, in turn, will pull the functions we export. Since in the 1.10 version all functions were exported from exe, we need to do the same export table, with the same ordinals, so that everything is transparent for the plug-ins too. But more about that later.
Since almost all the plugins were controlled from the menu, it was necessary to somehow create and process your branch in the main menu. To process messages, we need to get the address of the window function. And where can I get it? The simple way is to intercept RegisterClass and pull the address from it out of the WNDCLASS-> lpfnWndProc structure field. And of course in his place to write your own.
The second option is to find in the code, and make jmp on yourself. I certainly love perverted methods, but not this time.
I will do any interception of functions directly in the import table, substituting my own handler procedure instead of the API address, and from it already into the API. With this method, everything will be transparent for the debugger itself, and it will think that it works directly with the system.
Do not forget to set the rights to write to this area before any editing of another's memory, otherwise access errors will occur.
This is how the API call before editing looks like:

And a few moments later:

Even repeated re-analysis does not help, so it thinks that there is a call to RegisterClassW, however in both areas below you can make sure that the address 005EEA44 is far from the API address.
So, “where” to process messages, we know, now we need to create, then what to process. To do this, we intercept the AppendMenu in the same way. And in the handler, we expect to add a menu, in front of which we want to insert our menu.
As soon as it appeared, we have a wide choice of menu creation. But I have limited myself so far with the MF_STRING options for displaying a single item, MF_POPUP for drop-down submenus, and MF_SEPARATOR for separators. All menu items added through a slightly outdated InsertMenu. First of all, this is less code, and secondly, Oleg (OllyDbg developer) uses this method himself.
Do not forget at the very end to call the original API AppendMenu for yourself and for the subsequent menu branch for us.
The whole addition will look generalized as follows:
Request from OllyDbg on AppendMenu (Help) -> our CreateMenu () -> Several of our InsertMenu () -> our AppendMenu (Plugins) -> execute the query AppendMenu (Help).
Creating a menu, you need to see in advance which IDs are free, and which will not intersect. In WndProc for the menu, we will catch WM_COMMAND. We filter out only ours by range, for example, using an associative array by ID => processing_address, we transfer control to the correct plugin.
This is how OllyDbg 2.00c versions look like before and after my intervention:

Now the most crucial question is to find the addresses of the functions that should be exported to plugins. Do not expect to find in the release versions of applications debug-information, which could greatly help.
Therefore, let's go the following way, ship to Ida Pro:
- We are looking for text strings that are displayed in case of errors, they can tell us the purpose of functions.
- After squeezing everything out of the lines, it makes sense to find handlers for various menus, they also narrow the search range significantly.
- And finally, an unpleasant and time-consuming method. We load the program into the debugger, and set the breakpoint on the low-level specific (or not) API. And gradually we rise to the upper levels of abstraction, while glancing in parallel with Ida. And so, until we come to the function, when you can clearly define what it does in general. For convenience, we name the functions in Ida, and save the addresses found by ourselves separately.
I wrote all the mini plug-in manager for the day on my knee on Fasm. Then in a couple of weeks I picked up about 30 functions. But at that time it was not compatible with PDK 1.10, which did not prevent me from writing my own to hide the debugger, load characters from the map files generated by IdaPro, and a simple dumper.
A spoon of tar
Probably Oleg paid attention to my idea, and nevertheless made his own PDK in 2.01 alpha 4, which should have killed my project at once. But there are a couple of moments. The new build has become IMHO overloaded and inconvenient, and old plugins are not supported.
At the moment, the plugin manager is completely rewritten from scratch to C ++, with plans for compatibility with all versions. And the interception of several functions here will not get off ...
Well, here you can see how not to write code, even on the knee in one day.
Shoals and so I know, and therefore rewritten from scratch.
Sora on fasmThe updated version will be later when it is finished.
Special thanks to the author OllyDbg and forum participants exel @ b for their active support, and habrovchanam for the amendments.