Chapter 5 Monitoring Native API Call
Translation: kendiv (fcczj@263.net)
Update: Tuesday, April 12, 2005
Disclaimer: Please indicate the source and guarantee the integrity of the article, and all rights to the translation.
Manage handle
Special note is that the API function call is logged only when the condition statement containing the spywritefilter () function is only included in the internal version of the spywritefilter (). This behavior is to reduce useless information in the HOOK protocol. For example, a mobile mouse will trigger a series of NTReadFile () function calls. Other sources and physical experiments that generate useless information are similar: For example, when you measure a certain physical effect in an experimental environment, the measurement method itself will also affect the physical effect to be measured, which will result in measurement results. distortion". This also occurs when recording the API. Note: The NTDeviceIocontrolFile () function is also included in the format string array in Listing 5-6. However, the client of the SPY device uses the Device I / O Control call to read the API Hook protocol. This means that the client will discover its own NTDeviceiocontrolFile () call in the protocol data. According to the frequency of the IOCTL transaction, the data you expect may be inundated in its own function call record (the translation: here means, if the client is frequently used IOCTL, then in the record IOCTL function call, only a small amount It is what we expect, and most of them are generated by the client), and the SPY device uses the ID of the thread that installs the API Hook and ignores the API call from the thread to solve this problem.
SPYWRITEFILTER () is ignored for all API calls that generate handles and the generated handle is not recorded. If the SPY device discovers that a handle has been turned off or returned to the system, then any function sequence that uses the handle will be ignored. More effective is that if the API call contains a handle created by a system or other process that exists before starting the API Hook protocol (this handset is very long), the API call will be disabled. Of course, the client can prohibit or allow this filtering through IOCTL. You can test this filtering mechanism using a simple client program that will introduce this chapter. You will be surprised that this simple "noise filter" function is powerful.
In Listing 5-6, functions generating handle are: ntcreatefile (), ntcreateKey (), NTPENFILE (), NTOPENKEY (), NTOpenProcess (), and ntopenthread (). The format string of all these functions contains a% control, which is used to indicate the "handle (registration)" in Table 5-2. For functions of closing or release handle: ntclose (), and NTDeleteKey (), all of which contain one%-control, corresponding to "handle (revocation registration)" in Table 5-2 in the format string. Other functions are just a simple use of handle (these functions do not create the release of these handles), including% in their format strings! . Basically, the handle is in the context of the process, used to uniquely identify the number of an object. When an API function generates a new handle, the client must usually pass an Object_attributes structure to store the handle and other things. For the object's name, it should be accessible. Later, this name will no longer be needed because the system can use the object handle to find the properties of its corresponding object in the handle table. This is not good news for API SPY users, because it must replace the symbol name in a large number of protocol items. Therefore, my SPY device will register all object names and their corresponding handle and the ID of the handle owner process, and will update this list whenever a new handle appears. When a registered handle / process pair occurs later, the API recorder will retrieve its corresponding original symbol name from the list and join the protocol added. The registered handle is valid before being turned off by an API function. If an API call you can generate a new handle, the registered handle will be no longer in the registered state. For Windows 2000, my frequent observation system sometimes returns the same handle value, although there is no call to turn off the handle in the agreement before this. I don't remember whether there is similar situation in Windows NT 4.0. A registered handle, if the different object properties appear again, it is displayed by some way to turn off, so the registration of this handle must be revoked. Otherwise, the Handle Directory of the SPY device will eventually enter the overflow state.
SpyWRITEFILTER () is called by SpyhookPrtocol () is a basic component of the handle tracking mechanism. Any Hook's API function will pass through the function when called. Listing 5-8 shows the implementation of the function.
Bool SpyWriteFilter (pspy_protocol psp,
PBYTE PBFORMAT,
Pvoid PParameters,
DWORD DPARAMETERS)
{
Phandle phobject = NULL;
Handle hObject = null;
POBJECT_ATTRIBUTES POA = NULL;
PDWORD PDNEXT;
DWORD I, J;
PDNEXT = PParameters;
i = j = 0;
While (PBFormat [i])
{
While (pbformat [i] && (pbformat [i]! = ')) i ;
IF (PBFORMAT [I] && PBFORMAT [ i])
{
J ; switch (PBFORMAT [i ])
{
Case 'b':
Case 'a':
Case 'W':
Case 'u':
Case 'n':
Case 'L':
Case 's':
Case 'I':
Case 'C':
Case 'd':
Case 'P':
{
Break;
}
Case 'o':
{
IF (POA == Null)
{
POA = (POBJECT_ATTRIBUTES) * PDNEXT;
}
Break;
}
Case ' ':
{
IF (phobject == null)
{
PhoBject = (PHANDLE) * PDNEXT;
}
Break;
}
Case '!':
Case '-':
{
IF (HOBJECT == NULL)
{
HOBJECT = (Handle) * pdnext;
}
Break;
}
DEFAULT:
{
J -;
Break;
}
}
PDNEXT ;
}
}
Return // Number of Arguments OK
(j == dparameters)
&&&&
// no Handles Involved
(((PhoBject == Null) && (HOBJECT == NULL))
||
// new handle, successfully registered
((PhoBject! = NULL) &&
SpyHandleregister (psp, psgetcurrentprocessid (),
* PhoBject, Object_name (PoA))))))))))
||
// Registered Handle
SpyHandleslot (PSP, PsgetCurrentProcessid (), HOBJECT)
||
// filter disabled
(! gfspyhookfilter);
}
Listing 5-8. SPYWRITEFILTER () will remove unregistered API calls from the protocol
SpyWriteFilter () mainly looks for the% O (object attribute),% (new handle),%! (Open handle) and% - (closed handle), by scanning protocol format strings, and close the handle) The combination takes special actions as follows:
l If there is no handle, all API calls will be recorded. This involves the API function that does not include the format control ID% ,%! And% - in all format strings.
l If the format string contains% , this indicates that the API function will allocate a new handle, and will use the Help function spyHandleRegister () to register the handle and the first% O item in the format string. The name is associated. If such a name does not exist, the handle will be registered in an empty string. If registration is successful, this API call will be recorded.
l If the format string contains%! or%, the called function will use or close a handle. In this case, SpyWriteFilter () will use the SpyHandLot () function to query the index of the handle to test whether the handle is registered. If the test is successful, the API call will be recorded. l For all other situations, the function call is recorded only when the filtering mechanism is turned off. Whether the filtering mechanism is turned on by the global logical variable gfrspyhookfilter.
The handle directory is part of the SPY_PROTOCOL structure, which is included in the global device_context structure of the SPY device (W2k_spy.sys), which gives the list 5-9 gives its definitions and the definition of the SPY_HEADER sub-structure. After these definitions are the source code for four handle management functions (SpyHandLot (), SpyHandleName (), SpyHandleunRegister (), and SpyHandleRegister ()). The handle is registered by adding the value of the handle to the end of the AhobJets [] array. At the same time, the process ID of the handle will be saved to the AWNAMES [] array, and the object name will be copied into the awnames [] buffer, and the start offset address of the name will be saved to the adnames [] array. When logging out of a handle, the process is similar to the above, which may require other elements in an array to ensure that there is no "empty cave" in the array. Listing 5-9 Top defined constants define the size of the handle directory: It can store up to 4,096 handles, the size of the name is limited to 1,048,576 Unicode characters (2MB), and the protocol buffer is 1MB.
#define spy_handles 0x00001000 // Max Number of Handles
#define spy_name_buffer 0x00100000 // Object Name Buffer Size
#define spy_data_buffer 0x00100000 // Protocol Data Buffer Size
/ / -------------------------------------------------------------------------------------------- -----------------
Typedef struct _sspy_header
{
Large_integer Listart; // Start Time
DWORD DREAD; // Read Data Index
DWORD DWRITE; / / WRITE DATA INDEX
DWORD DCALLS; / / API USAGE COUNT
DWORD DHANDLES; // Handle Count
DWORD DNAME; // Object Name Index
}
SPY_HEADER, * pspy_header, ** ppspy_header;
#define spy_header_ sizeof (Spy_Header)
/ / -------------------------------------------------------------------------------------------- -----------------
Typedef struct _sspy_protocol
{
Spy_header sh; // protocol header
Handle ahprocesses [spy_handles]; // process id array
Handle ahobjects [spy_handles]; // Handle Array
DWORD adnames [spy_handles]; // name offsetsword frs [spy_name_buffer]; // name strings
Byte abdata [spy_data_buffer]; // Protocol Data
}
Spy_protocol, * pspy_protocol, ** PPSPY_PROTOCOL;
#DEFINE SPY_PROTOCOL_ SIZEOF (SPY_PROTOCOL)
/ / =========================================================================================================================================================================================== ==================
// Handle Management
/ / =========================================================================================================================================================================================== ==================
DWORD SpyHandLot (PSPY_PROTOCOL PSP,
Handle HProcess,
Handle hobject)
{
DWORD DSLOT = 0;
IF (HOBJECT! = NULL)
{
While ((DSLOT
&&&&
((psp-> ahprocesses [dslot]! = hprocess) ||
(PSP-> Ahobjects [DSLOT]! = HOBJECT)) DSLOT ;
DSLOT = (DSLOT
}
Return dslot;
}
/ / -------------------------------------------------------------------------------------------- -----------------
DWORD SpyHandleName (PSPY_PROTOCOL PSP,
Handle HProcess,
Handle Hobject,
PWORD PWNAME,
DWORD DNAME)
{
Word W;
DWORD I;
DWORD DSLOT = SPYHANDLOT (PSP, HProcess, HObject);
IF ((PWNAME! = null) && DName)
{
i = 0;
IF (dslot)
{
While ((i 1
{
PWNAME [i ] = W;
}
}
PWNAME [I] = 0;
}
Return dslot;
}
/ / -------------------------------------------------------------------------------------------- -----------------
DWord SpyHandleunRegister (pspy_protocol psp,
Handle HProcess,
Handle Hobject,
PWORD PWNAME,
DWORD DNAME)
{
DWORD I, J;
DWORD DSLOT = SPYHANDLENAME (PSP, HProcess, HOBJECT,
PWNAME, DNAME;
IF (dslot)
{
IF (dslot == psp-> sh.dhandles)
{
// Remove Last Name Entry
PSP-> sh.dname = psp-> adnames [dslot-1];
}
Else
{
I = psp-> adnames [dslot-1];
J = PSP-> adnames [dslot];
// shift left all remaining name entries
While (j
{
PSP-> AWNAMES [i ] = PSP-> AWNAMES [J ];
}
J - = (psp-> sh.dname = i);
// shift left all remaining handles and name offsets
For (i = dslot; i
{
PSP-> ahprocesses [i-1] = psp-> ahprocesses [i];
PSP-> Ahobjects [i-1] = psp-> ahobjects [i];
PSP-> adnames [i-1] = psp-> adnames [i] - j;
}
}
PSP-> Sh.dhandles -
}
Return dslot;
}
/ / -------------------------------------------------------------------------------------------- -----------------
DWord SpyHandleregister (PSPY_PROTOCOL PSP,
Handle HProcess,
Handle Hobject,
Punicode_String Puname)
{
PWORD PWNAME;
DWORD DNAME;
DWORD I;
DWORD DSLOT = 0;
IF (HOBJECT! = NULL)
{
// Unregister Old Handle with Same Value
SpyHandleunRegister (PSP, HProcess, Hobject, NULL, 0);
IF (psp-> sh.dhandles == SPY_HANDLES)
{
// unregister Oldest Handle if overflow
SpyHandleunRegister (PSP, PSP-> AhProcesses [0], PSP-> Ahobjects [0], NULL, 0);
}
PWNAME = (Puname! = null) && spyMemoryTestAddress (PUNAME)
Puname-> buffer
: Null;
DNAME = ((pwname! = null) && spymemorytestaddress (PWNAME)
? puname-> length / word_
: 0);
IF (DNAME 1 <= SPY_NAME_BUFFER - PSP-> Sh.dname)
{
// Append Object to End of List
PSP-> ahprocesses [psp-> sh.dhandles] = HPROCESS
PSP-> ahobjects [psp-> sh.dhandles] = hobject;
PSP-> adnames [psp-> sh.dhandles] = psp-> sh.dname;
For (i = 0; i { PSP-> awnames [psp-> sh.dname ] = PWNAME [i]; } PSP-> AWNAMES [PSP-> Sh.dname ] = 0; PSP-> Sh.DHandles ; Dslot = psp-> sh.dhandles; } } Return dslot; } Listing 5-9. Handle management related structure and functions …….………..to be continued………………