Import Monitor
This project is for monitoring calls to implicitly imported
DLL
functions. Programs don't need to be altered or specially compiled
for this. It works by creating a DLL which exports all of the
functions a program (or DLL) uses from the DLL whose calls are to
be monitored.
This method can catch resource and memory leaks in any program
(so far it only monitors implicitly loaded DLLs).
This has already produced six monitoring DLLs (which did
nothing
but pass on the parameters), so it's a valid concept. It might not
be possible to monitor "Ole32" and other COM-based DLLs with
PowerBASIC programs.
Presently, this process is assisted by several small programs:
"MakeMon", "FixMon" and "FixProg". These could easily be combined
and given a GUI.
Since the name of the original DLL appears inside the program
file's import section, it is changed to that of the monitoring DLL.
Then, when the program tries to call the original DLL, it
calls
the corresponding function in the monitoring DLL instead.
The monitoring DLL can check, store or change the parameters
being passed, before calling the corresponding function in the
original DLL. When that call is done, it can check, store or
change the return value before it returns control to the program.
An example:
1) MyProgram imports "HeapAlloc" from "Kernel32.DLL"
2) MyProgram is altered internally to import "HeapAlloc" (and
all other required imports from
Kernel32.DLL) from the
monitoring DLL named "Kernelzz.DLL"
instead.
3) MyProgram is started
4) MyProgram calls "HeapAlloc" in "Kernelzz.DLL".
5) "HeapAlloc" in "Kernelzz.DLL", checks, or stores or modifies the
values of the: heap-block handle, the
allocation control flags
and the number of bytes requested.
6) "HeapAlloc" in "Kernelzz.DLL" calls "HeapAlloc" in
Kernel32.DLL",
passing the original (or modified)
values it received from
MyProgram.
7) "HeapAlloc" in Kernel32.DLL" returns a value to
"HeapAlloc" in
"Kernelzz.DLL"
8) "HeapAlloc" in "Kernelzz.DLL" checks, or stores or
modifies the
return value.
9) "HeapAlloc" in "Kernelzz.DLL" returns control to MyProgram
How it's done:
1) Manually prepare a file with the declarations for all of a
single DLL's exports (seven of these
files have already been
prepared).
This must be named by taking
the DLL's name, adding "Mon" and
the extension ".bi". Thus, for
"Kernel32.DLL", the file name
would be "Kernel32" + "Mon" + ".bi" =
"Kernel32Mon.bi".
For the current parser, each declare
must be in a single line,
so you can't use PBEdit to prepare them
(it splits long lines).
The parser expects keywords to be in mixed case.
You can ensure
this by:
Setting PBEdit's syntax options to
"Mixed case", then...
Putting the declares into a PBEdit
window, then...
Cutting all the code from the window,
then...
Pasting the code back into the window
You should do that before joining any
split lines, because
PBEdit may split them again and waste
your effort.
To prepare the file's contents:
a) Ensure all keywords are in mixed case
(as mentioned above)
b) Remove all: "Declare "
c) Remove all: "Lib "LibName""
d) Remove all: "Optional "
e) Replace all: ")" with ") Export"
f) Replace all: " As Any" with " As Long"
g) Join all split lines
h) You should remove lines which are
blank or contain anything other
than declares
For example, the lines:
Declare Function ImportFun Lib "SomeLib.DLL" Alias "ImportFunction"
(ByVal pName As Asciiz Ptr, _
ByVal n As Dword, ByVal r As Any) As Long
Declare Sub ImportSub Lib "SomeLib.DLL" Alias "ImportSub" (ByVal pName
As Asciiz Ptr, _
ByVal n As Dword, ByVal r As Any)
...should be changed to:
Function ImportFun Alias "ImportFunction" (ByVal pName As Asciiz Ptr,
ByVal n As Dword, ByVal r As Long) Export As Long
Sub ImportSub Alias "ImportSub" (ByVal pName As Asciiz Ptr, ByVal n As
Dword, ByVal r As Long) Export
----------------------------------------------------------
2) Generate the source code:
a) Load the "MakeMon" project
b) De-REM one of the $Dll (DLL-name)
equates, or add one of
your own.
c) Be sure a copy of the template
"MonTemp.prj" is present
d) Compile and run "MakeMon"
This will create a file with a name
derived from the DLL's name.
To do this, it replaces the last two
letters of the DLL's name
with "zz". Thus, generating source code
from "Kernel32Mon.bi"
yields "Kernelzz.prj".
Notes:
The names of the exports have the case
of their first letters
toggled to avoid compile errors.
Underscores are converted to
tildes (~) and vice versa.
If the monitoring DLL's name conflicts
with others, you'll need
to make some changes. This name is
automatically set on the
"#Compile" line.
----------------------------------------------------------
3) Ensure the generated code will compile:
At this point, it's likely to have a few
errors that prevent it
from compiling. For instance, sometimes
there will be duplicate
exports that are normally conditionally
compiled, but weren't
removed during the file's preparation.
Be sure you have #Included the original
declarations for the
DLL you intend to monitor.
You might also have to correct a few
syntax errors.
----------------------------------------------------------
4) Add any monitoring code you want to the DLL's code. For
example:
a) Start a new log file at
"%DLL_PROCESS_ATTACH"
b) Monitor getting and releasing of DC
handles
c) Monitor creating and deleting of GDI
objects
d) Monitor allocating and deallocating
memory
e) Count the number of times certain
exports are called
f) Check the data being passed for
problem values
g) Change the data being passed
h) Add event hooks to a program
i) Print final results to a log file and
close it at
"%DLL_PROCESS_DETACH"
j) Anything else you can think of...
----------------------------------------------------------
5) Compile the DLL:
----------------------------------------------------------
6) Fix the names of the DLL's exports:
(The names were made to be slightly
different than the
originals to avoid compiler errors about
"duplicate name
definitions")
De-REM or add a $Dll equate in the
"FixMon" project, and
run it.
----------------------------------------------------------
7) Make a backup copy of the program file to be monitored:
It's easier than trying to repair the
alterations.
----------------------------------------------------------
8) Change the names of the original DLLs in the program's
import
section to match those of the monitoring
DLLs in the program
file to be monitored.
This can be done with "FixProg" by
dropping the program onto
it in Windows Explorer. You need to
REM-out Data statements
for the DLLs you don't want to monitor.
It generates a log
file of its results.
----------------------------------------------------------
9) Put copies of all the monitoring DLLs into the program's
folder, "C:\Windows\", or
"C:\Windows\System\".
----------------------------------------------------------
10) You're ready to run the program
ImportMon Files:
MakeMon.prj
FixMon.prj
FixProg.prj
MonTemp.prj (DLL template)
As for the rest:
The "...Mon.bi" files are declares
The "...zz.prj" files are ready-to-compile DLLs
The ".DLL" files are do-nothing monitor DLLs that you can try
out on a program to confirm that a specific program can be
monitored.
The DLLs presently covered are:
Advapi32.DLL
GDI32.DLL
Kernel32.DLL
Shell32.DLL
User32.DLL
WinMM.DLL (untested)
WinINet.DLL
The Import Monitor source code is in the "importmon" folder of the CVS directory
Browse CVS
Website Home
Project Summary Page at SourceForge.net
This project is sponsored by TheirCorp
(formerly TheirWare Corporation)