mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
253 lines
11 KiB
253 lines
11 KiB
|
|
Windows API Profile Logger
|
|
|
|
LOGGER
|
|
|
|
by BobDay 08/23/92
|
|
|
|
|
|
1.0 General Information
|
|
2.0 How to use Logger
|
|
3.0 Debugging Scenarios with Logger
|
|
4.0 How Logger Works
|
|
5.0 Source code for Logger
|
|
|
|
|
|
1.0 General Information
|
|
|
|
LOGGER is a tool that records all API calls and parameters that a
|
|
Windows application program makes. It records these calls in the
|
|
order that they are made by the application.
|
|
|
|
2.0 How to use Logger
|
|
|
|
1. Copy LOGGER onto your machine:
|
|
|
|
net use p: \\popcorn\public
|
|
copy p:\bobday\logger\z*.dll .
|
|
copy p:\bobday\logger\z*.dll .\z*.exe (see description below)
|
|
copy p:\bobday\logger\logger.* .
|
|
copy p:\bobday\logger\apfcnvrt.exe .
|
|
|
|
Some applications (WinWord 1.1, Excel 2.1) require that z*.dll have
|
|
the extension of .EXE, to match those of KERNEL,USER, and GDI.
|
|
|
|
I usually copy these things into the current directory, put they could
|
|
also be put anywhere accessable by the PATH environment variable.
|
|
|
|
2. Run APFCNVRT on the application:
|
|
|
|
APFCNVRT WIN myapp.exe
|
|
APFCNVRT WIN mydll.dll
|
|
|
|
Run APFCNVRT with WIN as the 1st parameter and the filename as the
|
|
second for all .exe's and .dll's that you wish logged.
|
|
|
|
3. Create a LOGGER section in WIN.INI (C:\NT\WINDOWS\WIN.INI)
|
|
|
|
The section should have two values:
|
|
|
|
[LOGGER]
|
|
dbgport=0
|
|
mousehack=0
|
|
|
|
"dbgport" is used to control where logging output should go.
|
|
0 = log to disk (into a file called OUTPUT.LOG)
|
|
1 = log to debug port (via OutputDebugString)
|
|
2 = log to nowhere (no logging) This is useful, see #5 below
|
|
The default value is 0.
|
|
|
|
"mousehack" is used in conjunction with SGA and Win 3.0/Win 3.1.
|
|
It should be set to 0. The default value is 1, so you MUST set
|
|
it to 0. If you do not have it set to 0 and you attempt to run
|
|
in the WOW environment, LOGGER will GP Fault.
|
|
|
|
4. Run the application as normal.
|
|
|
|
It will run slower due to logging, and will create two output files:
|
|
OUTPUT.LOG and OUTPUT.DAT. OUTPUT.LOG is a log of all of the API
|
|
call made by the application. OUTPUT.DAT is any large data that
|
|
would not fit onto nice log lines. OUTPUT.DAT is binary data, whereas
|
|
OUTPUT.LOG is readable.
|
|
|
|
Both files are created in the current directory.
|
|
|
|
5. You can change the location where logging output is going while
|
|
the application is running. You can use this to selectively log
|
|
just a portion of the application run.
|
|
|
|
a. Start with "dbgport=2" in your logger section of WIN.INI
|
|
b. Start the application and get it to a nice paused position
|
|
where you want to start logging from.
|
|
c. Break into the debugger and edit the symbol "_cDbg" (command
|
|
for debugger).
|
|
|
|
Samples: (WDEB386) (NTSD)
|
|
eb _cDbg 1 !bde.es _cDbg
|
|
Symbol is #0397:061E
|
|
eb 397:61E 1
|
|
^ ^
|
|
| |
|
|
Both of these samples change the debugging port to 1 (output
|
|
to the debugger).
|
|
d. Make the application perform the section which you wish to log.
|
|
e. Break into the debugger and set the debug port back to 2.
|
|
|
|
When you are done, you will have output which happened only during
|
|
the time when debug port was not 2.
|
|
|
|
6. Run APFCNVRT on the application to disconnect LOGGER:
|
|
|
|
APFCNVRT UNDO myapp.exe
|
|
APFCNVRT UNDO mydll.dll
|
|
|
|
Run APFCNVRT with UNDO as the 1st parameter and the filename as the
|
|
second for all .exe's and .dll's that you did in step 2.
|
|
|
|
You may delete the .exe's and .dll's copied in the 1st step.
|
|
|
|
3.0 Debugging Scenarios with LOGGER
|
|
|
|
If your application dies mysteriously, or GP's during certain
|
|
operations:
|
|
|
|
Do a stack trace and see if the bug is obvious.
|
|
|
|
Otherwise, connect logger and set the "dbgport" option to 1.
|
|
Run the application and watch until the application dies.
|
|
Examine the last API executed to determine whether valid parameters
|
|
are being passed.
|
|
|
|
Possibly run the application again, inserting breakpoints to
|
|
determine what caused the application or the system to become
|
|
confused. A good starting breakpoint would be at the API that
|
|
is performed last.
|
|
|
|
If you application runs fine, but has errors (things don't work
|
|
right) doing certain operations:
|
|
|
|
Run the application, watching the debugger as it runs, look for
|
|
error messages from WOW32 at log level 2. These are failures.
|
|
|
|
If the error is not obvious from that process, then connect
|
|
logger and set the "dbgport" option to 0. Run the application and
|
|
make it perform the operations that are wrong.
|
|
|
|
Then exit the application and examine the OUTPUT.LOG file for
|
|
APIs which are failing. Try to narrow down the search by doing
|
|
as little as possible with the application besides the part that
|
|
is malfunctioning. Also, look through the OUTPUT.LOG file for
|
|
WM_KEYDOWN, WM_KEYUP messages or WM_LBUTTONDOWN, WM_LBUTTONUP,
|
|
WM_RBUTTONDOWN, etc. messages. Find those messages that you
|
|
know you did just before the operation that is malfunctioning.
|
|
This should narrow down the search quite a bit.
|
|
|
|
You may also want to create a log of the application running on
|
|
Win 3.1 (remember to edit your \windows\win.ini file too).
|
|
Comparing the two OUTPUT.LOG files will give you an idea about what
|
|
is occuring differently under WOW vs. under Win 3.1.
|
|
|
|
4.0 How LOGGER works
|
|
|
|
LOGGER consists of 3 main pieces:
|
|
|
|
1. APFCNVRT.EXE
|
|
2. Thunk DLLs - ZSER, ZERNEL, ZDI
|
|
3. LOGGER.DLL
|
|
|
|
LOGGER and its associated pieces make up a mechanism that can be
|
|
used to record all of the API calls made by a Windows application.
|
|
Logger does this by installing a set of thunks in-between the application
|
|
and the real Windows APIs. The thunks record the API name and
|
|
information into a log and make the real API call for the application.
|
|
|
|
APFCNVRT is a tool that edits the application program to use the thunks,
|
|
rather than the real Windows APIs. It does this by editing the imported
|
|
names table in the application program's .exe header. It replaces the
|
|
API in GDI.EXE with equivalent thunks in the ZDI.DLL. It replaces the
|
|
API in USER.EXE with those in ZSER.DLL, and KERNEL.EXE with ZERNEL.DLL.
|
|
|
|
Suppose, for example, an application is using the API RectInRegion. That
|
|
API is really know in the system as "GDI.181", an API in GDI.EXE whose
|
|
ordinal number is 181. Using APFCNVRT, we change the application to
|
|
reference "ZDI.181" instead, where "ZDI.181" happens to be an exported
|
|
function from the ZDI.DLL whose ordinal number is 181. In this case,
|
|
"ZDI.181" is a function called zRectInRegion, which is the thunk for the
|
|
RectInRegion API.
|
|
|
|
All of the thunk DLLs (ZSER.DLL, ZERNEL.DLL, and ZDI.DLL) are filled
|
|
with these thunks. For API FiddleFoo, there will be a function zFiddleFoo
|
|
in one of the thunk DLLs. The letter z was prepended to all of the thunk
|
|
function names so that they can easily be distinguished from the real
|
|
function, yet the real functions name is still known.
|
|
|
|
Each of the thunk functions perform a well ordered process:
|
|
|
|
1. Receive all of the parameters from the application program in the
|
|
same manner that real API would (C/Pascal calling convention).
|
|
2. Log the API as having been called and all of the input parameters.
|
|
3. Perform necessary parameter subsitutions.
|
|
4. Perform the real API.
|
|
5. Log the API as having returned, the return value and all of the
|
|
output parameters
|
|
6. Return the return value to the application in the same manner that
|
|
the real API would (C/Pascal calling convention).
|
|
|
|
In this manner, there is some information logged before the API call is
|
|
made, and some information logged after the API call has returned. This
|
|
is helpful in discovering whether the system is failing during the API
|
|
call, or after it.
|
|
|
|
The parameter substitution step is necessary so that we can catch
|
|
functions which have callbacks. For example, before calling the
|
|
EnumFonts API, we replace the applications supplied callback address
|
|
with our own callback address. The function at this address will log
|
|
the parameters which are passed to the application in the same way that
|
|
the API thunks do.
|
|
|
|
There are callback functions for all of the APIs that need them:
|
|
Window Procs for RegisterClass, Font Procs for EnumFonts, Hook Procs
|
|
for SetWindowsHook, etc.
|
|
|
|
The callback functions all look the same:
|
|
|
|
1. Receive all of the parameters (C/Pascal).
|
|
2. Log the callback as having been started and all of the input
|
|
parameters.
|
|
3. Make the real callback to the applications originally supplied
|
|
callback address.
|
|
4. Log the callback as having been finished and all of the output
|
|
parameters.
|
|
5. Return the return value to the system in the same manner (C/Pascal).
|
|
|
|
All of these logging calls go through the Logging DLL, LOGGER.DLL.
|
|
LOGGER.DLL has 2 entry points, LogIn, and LogOut. The only difference
|
|
between LogIn and LogOut is that LogIn is used for logging input
|
|
parameters and LogOut is used for logging output parameters. Both
|
|
functions take a variable number of parameters, but operate differently
|
|
than the standard C function printf.
|
|
|
|
A sample call to LogIn would look like this:
|
|
|
|
LogIn( "APICALL:RectVisible HDC+LPRECT+", param1, param2 );
|
|
|
|
Instead of having %d's, %s's, %x's in the format string, LogIn and LogOut
|
|
take the type names. Each parameter is logged according to its type.
|
|
The "+" character is a seperator between parameters and there must be a
|
|
trailing one.
|
|
|
|
The line which gets logged from this LogIn call would look like this:
|
|
|
|
01|APICALL:RectVisible 2056 { 0002 0003 0195 018f }
|
|
|
|
The "{ 0002 0003 0195 018f }" is the logging of the rectangle pointed
|
|
to by the LPRECT parameter, param2. LOGGER knows the type LPRECT and
|
|
knows that if there is a valid pointer passed, it should dump it as a RECT
|
|
structure. Similar operations are performed for other parameters, knowing
|
|
their parameter type.
|
|
|
|
|
|
5.0 Source code for Logger
|
|
|
|
Source code for Logger is on \\brillig\ntct\slm\src\sga\logger
|
|
and \\brillig\ntct\slm\src\wrapper\win31x
|