Adding Functions To Any Program Using A DLL: The Codebreakers-Journal, Vol. 1, No. 1 (2004)
Adding Functions To Any Program Using A DLL: The Codebreakers-Journal, Vol. 1, No. 1 (2004)
Adding Functions To Any Program Using A DLL: The Codebreakers-Journal, Vol. 1, No. 1 (2004)
Abstract
Some time ago I have worked on Douby’s ”ReverseMe 1” and added missing functions to the program. After doing this I
looked for a way to make this process easier. It’s very uncomfortable to code with HIEW, especially if you must change the
finished code. Suddenly I got an idea: why not writing a dll? This allows you to use the language you are most familiar with
(ASM, C, C++, Delphi, ...), only few asm-code is needed and it’s not difficult.
I. Introduction
Target: douby’s ReverseMe1
Essay Level: Intermediate
Tools used:
• HIEW
• IDA
• SICE
• a compiler that can create DLLs (VC++, MASM, Delphi, ...)
This is my second essay about ”adding functions”, I hope you enjoy it as much as the first one. Please visit my Homepage.
LIBRARY tstdll
DESCRIPTION "Only a test-dll."
EXPORTS TestProc1
”LIBRARY” is the name of your dll, ”DESCRIPTION” the description (optional) and after ”EXPORTS” you can add all the
functions you want to export.
Functions can be exported by name (this is the default) or by ordinal, a number greater than 0. Using this approach will
make calling easier because you don’t need the whole name but only a number. Another problem with names is that the
compiler will modify them: TestProc1 with one DWORD as parameter would become ”_TestProc1” with C-linkage and
”?TestProc1@@YAXPAUHWND__@@@Z” if your C++ compiler mangles the name. This is not only long but also hard to
remember, so better avoid it. You can also specify the NONAME parameter and no function name will appear in your dll.
That’s what I prefer so your EXPORTS-line should look like this:
EXPORTS
TestProc1 @1 NONAME
TestProc2 @2 NONAME
"@1" means that the function should be exported as ordinal 1.
Now you must tell the Linker that it should create a dll. It’s easy if you use VC++: choose ”New...” and then ”Win32
Dynamic-Link Library” in the Project-Tab. Create a blank file, add the lines above to create a definition file and save it as
”my_dll.def” (”my_dll” is the name of your dll of course). For MASM you must use the following commands (put them
in a batch-file):
Important are the ”/DLL” switch and the name of your DEF-file.
DLLs don’t have a ”WinMain” function but ”DllMain”. Read a good book (Petzold) or look at my code for more, it’s
not difficult. The main purpose is to allocate/free additional memory and/or do some initialization.
2
Copyright c 2004 and published by the CodeBreakers-Journal. Single print or electronic copies for personal use only are permitted. Reproduction and
distribution without permission is prohibited.
The CodeBreakers-Journal, Vol. 1, No. 1 (2004)
It’s possible to use different calling-conventions. __pascal, __fortran, and __syscall are no longer supported in
VC++ 6, so the valid ones are now:
1) 1. STDCALL: used in almost all Win32 Api-function. The parameters are pushed from right to left (reverse order!) and
the called function is responsible for adjusting the stack. C++ functions in VC++ additionally store the ”this” pointer in
ECX (THISCALL).
Short intermezzo: The stack is the memory that is used for local variables and for function-parameters, the pointer
is stored in ESP. Every ”push” and ”pop” will modify it and it’s necessary to keep it consistent. The stack grows
from the highest memory address to the lowest, so if you ”add” something to it the pointer will actually set back
and more stack-memory is available.
2) C: the parameters are pushed from right to left and the caller is responsible for adjusting the stack. This is the default
for C-functions in VC++. The advantage is that you can use variable arguments e.g. sprintf, but it also results in slightly
bigger code.
3) FASTCALL: First the registers ECX and EDX are used, then the stack (Watcom has used more registers...). The called
function must adjust the stack.
Which one should we choose? I suggest to you use ”STDCALL” (__stdcall in VC++) because you don’t have to mess
around with the stack. Define your function like this:
If you use the default (__cdecl) you must adjust the stack. That’s not difficult: sum up the size of every parameter and
do a ”add esp, (sum)” after the call. In the example above it’s DWORD (4) + double (8) = 0Ch so you must write ”add esp, 0Ch”.
After all this technical information let’s return to our code. The last step is to unload the dll. When a program exits all
DLLs (if not needed by other programs) will be removed so it’s not necessary to free it in the middle of your program,
especially if you want to use ”static” variables. On the other hand, don’t leave marks everywhere you have been. :-) Use
”FreeLibrary” to unmap your DLL from memory.
This is the basic code. Somehow we need the addresses of the 3 Api-functions. Use the program ”OpGen” by NeuRaL NoiSE
to get them, it can save a list with all imported functions. Sometimes ”LoadLibraryA” or ”FreeLibrary” aren’t imported. In
that case you must do the following:
3
Copyright c 2004 and published by the CodeBreakers-Journal. Single print or electronic copies for personal use only are permitted. Reproduction and
distribution without permission is prohibited.
The CodeBreakers-Journal, Vol. 1, No. 1 (2004)
”GetModuleHandleA” and ”GetProcAddress” are always imported, I haven’t seen a program without them yet. Now you can
use ”call ebx” to call ”LoadLibraryA”.
LoadLibraryA will load a DLL into memory and increase its reference counter. Another call wouldn’t load the dll a second
time (and waste memory) but only increase the ref-counter. GetModuleHandleA will NOT load the DLL but retrieve the handle
of an already loaded DLL, the ref-counter won’t be increased. Finally a call to FreeLibrary will decrease the ref-counter, if it
has reached 0 the DLL will be unloaded. On program (process) exit Windows removes all libraries from memory unless they
are still used by other programs.
This essay doesn’t show you how to find the place to add code, please read my other big essay how to do it. You will
find a jmp-table which takes care of the command-IDs. It’s interesting that one value is not used, this simplifies many things.
Start ”BRW” or Symantec’s ”ResEdit” to add a new menu-item and give it the ID 40002. Good, my new code will start at
physical offset 0x3B40 (virtual offset 0x403B40). What do we need?
Hmm, ”FreeLibrary” is not imported. I have shown you above what to do in that case.
Here we go! First we must patch the jmp-table (0x1260), the 2nd entry (0x1264) should point to our new code (0x403B40)
so start your Hex-Editor and change: 37 12 40 00 into 40 3B 40 00.
The following code must be entered in HIEW. My FINISH code starts at offset 0x3C00, but you can put it closer to the
other code, this will make all jumps ”short”. If you enter jumps in HIEW (jmp, jne, ...) you must always use the physical
offset. After pressing F9 (Update) you will see to which location the jump actually goes.
4
Copyright c 2004 and published by the CodeBreakers-Journal. Single print or electronic copies for personal use only are permitted. Reproduction and
distribution without permission is prohibited.
The CodeBreakers-Journal, Vol. 1, No. 1 (2004)
While coding the DLL I have found a bug (or feature) with the WM_GETTEXT msg: my buffer has a size of 0x10000 and I
used this value to get the text of the edit-control. What happenend? Nothing! After some trying I found out that you can only
use WORD-values:
5
Copyright c 2004 and published by the CodeBreakers-Journal. Single print or electronic copies for personal use only are permitted. Reproduction and
distribution without permission is prohibited.
The CodeBreakers-Journal, Vol. 1, No. 1 (2004)
As an excercise you can add the missing functions (load, save, exit) to the ReverseMe1. Practice is necessary to get used to
it, reading is not enough. I think with my first essay and this one you have the required knowledge, and you can always send
me a mail if you have problems.
andreas(dot)theDragon(at)gmx(dot)net
6
Copyright c 2004 and published by the CodeBreakers-Journal. Single print or electronic copies for personal use only are permitted. Reproduction and
distribution without permission is prohibited.