Chapter III Writing Kernel Mode Drivers
Translation: kendiv (fcczj@263.net)
Update:
Thursday, February 10, 2005
Disclaimer: Please indicate the source and guarantee the integrity of the article, and all rights to the translation.
Table 3-4 lists the functions defined in List 3-8, and also gives a short introduction. Some of these functions, such as W2KServiceStart () and W2KServiceControl () and SC Manager's native API functions - StartService () and controlservice () are more similar. There is nothing inconsistency, and you can find calls to these native functions at the core location of these outsourcing functions. The main difference between the outer bag function and the native function is that the operation object of StartService () and ControlService () is a service handle, and W2KServiceOpen () and W2KServiceClose () are the name of the service. These names will call W2KServiceOpen () and W2KServiceClose () internally to the corresponding handle, W2KServiceOpen () and W2KServiceClose () will call OpenService () and ClosServiceHandle ().
Name
Describe
W2KServiceAdd adds a service / driver W2KServiceClose to the system to turn off a service handle W2KServiceConnect Connect to the Service Control Manager W2KServiceContinue Continue to perform a pause service / driver W2KServiceControl stop, suspend, continue, query or notify a loaded service / driver W2KServicedisconnect Disconnect and Service Control Manager Connection W2KServiceLoad Loading and Start (Optional) A Service / Driver W2KServiceLoadex Loading and Start (Optional) A Service / Driver (Auto Generate Name) W2KServiceManager Open / Close a temporary service Control Manager Handle W2KServiceOpen Gets a handle of a loaded service / driver W2KServicePAUS Pauses a running service / driver W2KServiceRemove removes a service / driver W2KServiceStart starts a loaded service / driver W2KServiceStop stop one Service / Driver W2KServiceUnLoad stop and uninstall a service / driver W2KServiceunloadEx stop and uninstall a service / driver (automatic generation name)
Table 3-4. Outsourcing function of the SC manager provided by W2K_LIB.dll
Typical usage of functions in Table 3-4 must follow the following guidelines:
l Use W2KServiceLoad () or W2KServiceLoadex () to load a service. The latter function automatically generates the display name of the service according to the path and version information of the executable. The logical variable fstart is used to determine if the service is automatically executed after successfully loaded the service. In the case of success, the function returns a manager handle for subsequent calls. If the service has been loaded or the service has started running, the FSTART is TRUE, calling the function will not return any errors. However, if an error occurs, if necessary, an error-in service will be automatically uninstalled.
l Using W2KServiceunload () and W2KServiceUnLoadEx () to uninstall a service, this requires the manager handle returned to W2KServiceLoad () or W2KServiceLoadex (). W2KServiceUnLoadEx () will automatically generate service names based on the path to the executable. If you have closed the manager handle, use W2KServiceConnect () or take a new manager handle or simply pass a NULL (this means using a temporary manager handle). The manager handle is automatically turned off by W2KServiceUnLoad (). If the service already deletes the flag, it will not return any errors, but do not immediately delete the service because the open device handle has existence. l Use W2KServiceStart (), W2KServiceStop (), W2KServicePause (), or W2KServiceContinue () to control a service. These functions also need to use the manager handle returned by W2KServiceLoad () or W2KServiceLoadex (). If you provide a manager handle that is a NULL, use a temporary manager handle. If the specified service is already required, no error will be returned.
l Call W2KServiceDisconnect () to close a manager handle. You can call W2KServiceConnect () at any time to get a manager handle.
W2KServiceLoadex () is a very powerful function. It will build all parameters required to automatically load a service, but you want to provide the path to executable files. The service name required by the CreateService () function of the SC Manager will be born from the executable file name (the extension of the file). In order to build a newly created service, W2KServiceLoadex () will try to read the FileDescription string from the file version information. If the version information is not included in the executable, or the FileDescription string is not available, the default service name will be used.
Unlike W2KServiceLoad (), W2KServiceLoadex () supports environment variables in the path. In other words, if the path string contains such a substrings such as% systemroot% or% temp%, they are replaced by the current value of the corresponding system variable. W2KServiceUnLoadEx () is a good partner for W2KServiceLoadex (), which will extract the name of the service from the supplied path, similar to the previously mentioned expansion process, and pass the extracted service name to W2KServiceunload (). These two functions are the ideal partners that need to load / uninstall third-party devices, simply provide the full path of these drivers. A sample program is included in the disc of this book.
Tools for console mode ----- w2k_load.exe are a generic kernel driver load / unloader that provides a simple command line interface for W2KServiceLoadex () and W2KServiceunloadEx (). Its source code can be found in the / src / w2k_load directory of the book CD. Listing 3-9 gives related code, which is only a schematic implementation. Because a lot of work is done by W2KServiceLoadex () and W2KServiceUnLoadEx () and W2KServiceUnLoadEx ().
/ / =========================================================================================================================================================================================== ================== // Global Strings
/ / =========================================================================================================================================================================================== ==================
Word awusage [] =
L "/ r / n"
L "usage:" SW (main_module) L "
L "" SW (main_module) L "
L "" SW (main_module) l "
Word awunload [] = l "/ unload";
Word awok [] = l "ok / r / n";
Word awerror [] = l "Error / R / N";
/ / =========================================================================================================================================================================================== ==================
// Command Handlers
/ / =========================================================================================================================================================================================== ================= Bool WinAPI DriverLoad (PWORD PWPATH)
{
SC_HANDLE HMANAGER;
BOOL fok = false;
_printf (l "/ r / nloading /"% s / "...", pwpath);
IF ((HManager = W2KServiceLoadex (PWPATH, TRUE))! = NULL)
{
W2KServicedisconnect (HManager);
Fok = true;
}
_printf (fok? awok: awrror);
Return fok;
}
/ / -------------------------------------------------------------------------------------------- -----------------
Bool WinApi Driverunload (PWORD PWPATH)
{
BOOL fok = false;
_printf (l "/ r / nunlineing /"% s / "...", pwpath);
Fok = W2KServiceunloadex (PWPATH, NULL);
_printf (fok? awok: awrror);
Return fok;
}
/ / =========================================================================================================================================================================================== ==================
// main program
/ / =========================================================================================================================================================================================== ==================
DWORD Main (DWORD ARGC, PTBYTE * Argv, PTByte * Argp)
{
_printf (atabout);
IF (argc == 2)
{
DriverLoad (Argv [1]);
Else
{
IF ((ARGC == 3) && (! lstrcmpi (argv [2], awhloyad))
{
Driverunload (Argv [1]);
}
Else
{
_Printf (awusage, awhload, awnunload);
}
}
Return 0;
}
/ / =========================================================================================================================================================================================== ==================
// end of program
/ / =========================================================================================================================================================================================== ==================
Listing 3-9. Load / Uninstall Device Drive
Table 3-4 The remaining library functions in Table 3- work at a lower level, they are used inside W2K_LIB.DLL. Of course, if you like, you can also call them from your program. From the list 3-8, they can be easily available.
Enumeration service and driver
Sometimes it is necessary to know that the system is currently loading that service or driver, and what states are now in. To achieve this, the SC manager provides another powerful function called EnumServiceStatus (). This function requires a manager handle and an array of ENUM_SERVICE_STATUS, which will contain information about currently loaded services or drivers. This list can be filtered according to the type and status of service / drive. If the buffer provided by the caller cannot accommodate all items one time, the function can be repeatedly called until all items are obtained.
However, it is difficult to calculate the required buffer size because the buffer must provide additional space for those unknown strings, which are referenced by the member of Enum_Service_Status. Fortunately, EnumServiceStatus () will return the number of bytes required for the remaining project, so the determined buffer size can be obtained by repeatedly attempting. Listing 3-10 gives the definition of Service_Status and Enum_Service_Status structures. These declarations are located in Win32 header file Winsvc.h.
Typedef struct _service_status
{
DWORD DWSERVICEPE;
DWORD DWCURRENTATE;
DWORD DWCONTROLACCEPTED;
DWORD dwin32exitcode;
DWORD DWSERVICESPECIFICEXITCODE;
DWORD dwcheckpoint;
DWORD dwaithint;
} Service_status, * lpservice_status; typedef struct _ENUM_SERVICE_STATUS
{
LPTSTR LPSERVICENAME;
LPTSTR LPDISPLAYNAME;
Service_status serviceArstatus;
} ENUM_SERVICE_STATUS;
Listing 3-10 Service_Status and Enum_Service_Status definition
Listing 3-11 The W2KServiceList () function given is another good stuff from the W2k_lib.dll tool library. It has omitted the aforementioned action and returns a structure available at any time, which contains all requests and a pair of extended structures. This function will return a pointer to the W2K_Services structure, which is defined in W2K_Lib.h, which gives the definition thereof at the top of the list 3-11. The w2k_services structure also contains four additional members with an ENUM_SERVICE_STATUS structure array. DENTRIES indicates how much item is copied to the status array, and DBYTES indicates the size of the returned W2K_Services structure. DDisPlayName and DServiceName are set to the maximum length of LPDisplayName and LPServiceName strings in AESS [], respectively. These values will provide great convenience, especially when you write a console mode, output a service / driver list on the screen, and require the name column to use the appropriate alignment.
To provide an exact system snapshot, W2KServiceList () is trying to get all items by calling EnumServiceStatus () once. To this end, the function first provides a buffer having a length of 0, which usually causes to return ERROR_MORE_DATA error code. In this case, enumServiceStatus () will return the required buffer size and then assign the appropriate buffer according to this size and then call EnumServiceStatus () again. At this point, EnumServiceStatus () should return success. However, this has a small probability event - another project between EnumServiceStatus () can be added to the list twice. Therefore, this process will be repeated in a loop until all everything is correct or an error returned by a non-error_more_data.
/ / -------------------------------------------------------------------------------------------- -----------------
Typedef struct _w2k_services
{
DWORD DENTRIES; // Number of Entries In Ass []
DWORD DBYTES; // Overalll Number of Bytes
DWORD DDISPLAYNAME; // Maximum Display Name Length
DWORD DSERVICENAME; // Maximum Service Name Length
ENUM_SERVICE_STATUS AESS []; // Service / Driver Status Array
}
W2k_services, * pw2k_services, ** PPW2K_Services;
#define w2k_services_ sizeof (w2k_services)
#define w2k_services __ (_ n) /
(W2K_SERVICES_ ((_n) * enum_service_status_))
/ / -------------------------------------------------------------------------------------------- ----------------- PW2K_SERVICES WINAPI W2KSERVICELIST (Bool FDRIVER,
Bool fwin32,
Bool Factive,
Bool finactive)
{
SC_HANDLE HMANAGER;
DWORD DTYPE, DSTATE, DBYTES, DRESUME, DNAME, I;
PW2K_SERVICES PWS = NULL;
IF ((pws = w2kmemorycreate)! = null)
{
PWS-> DENTRIES = 0;
PWS-> DBYTES = 0;
PWS-> ddisplayName = 0;
PWS-> DSERVICENAME = 0;
IF (FDRIVER || FWIN32) && (Factive || Finactive))
{
IF ((HManager = W2KServiceConnect ())! = null)
{
DTYPE = (FDRIVER? Service_Driver: 0) |
(fwin32? service_win32: 0);
DSTATE = (Factive && Finactive
? Service_state_all
: (Factive
? Service_active
: Service_inactive));
DBYTES = PWS-> DBYTES;
While (pws! = null)
{
PWS-> DENTRIES = 0;
PWS-> DBYTES = DBYTES;
PWS-> ddisplayName = 0;
PWS-> DSERVICENAME = 0;
DRESUME = 0;
IF (ENUMSERVicesSTATUS (HManager, Dtype, Dstate,
PWS-> Ass, PWS-> DBYTES,
& DBYTES, & PWS-> DENTRIES,
& DRESUME))
Break;
DBYTES = PWS-> DBYTES;
PWS = W2kMemoryDestroy (PWS);
IF (getLastError ()! = error_more_data) Break;
PWS = W2kmemoryCreate (W2K_Services_ DBYTES);
}
W2KServicedisconnect (HManager);
}
Else
{
PWS = W2kMemoryDestroy (PWS);
}
}
IF (Pws! = null)
{
For (i = 0; i
{
DNAME = LSTRLEN (PWS-> Ass [i] .lpdisplayName);
PWS-> DDISPLAYNAME = Max (PWS-> DDISPLAYNAME, DNAME);
DNAME = lstrlen (PWS-> Ass [i] .lpServiceName);
PWS-> DServiceName = max (PWS-> DServiceName, DNAME);
}
}
}
Return Pws;}
Listing 3-11. Enumeration Service / Driver
W2KServiceList () requires four logical types of parameters to determine the contents of the list you want to return. With FDRIVER and FWIN32 parameters, you can choose whether to include drivers or services, respectively. If these two parameters are True, the returned list will also include drivers and services. The Factive and FinActive logo are used to control the status filter that is added to the list. . The FINACTIVE parameter selects the remaining modules, that is, these modules have been loaded but have stopped running. If all four parameters are false, the W2K_Services structure returned by the function will contain an empty state array. The sample code in the disc contains a simple service / drive browser, which is designed to Win32 console mode and depend on W2KServiceList () in W2K_LIB.dll. It uses the DDisPlayName and DServiceName members in the W2K_Services structure (see Listing 3-11) to select the appropriate horizontal alignment for all names. You can find the source code for this tool in the CD / SRC / W2K_SVC directory. Its executable corresponds to /bin/w2k_svc.exe in the disc. The column 3-4 lists the kernel drivers (using command options / drivers / active) on all activities listed on my machine.
In the next chapter, we will begin to develop a kernel driver that can actually work, which detects the memory used by the kernel and the basic memory management data structure of Crack. This project will be accompanied by you to read Chapters 4, 5 and 6, in each chapter, the driver will be enhanced. Finally, a universal Windows 2000 Kernel SPY will be obtained.