SourceForge.net Logo







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)

TheirCorp Home Page