Windows NT 4.0 source code leak
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

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