A completion routine specifies that more processing is required for the output of that request. For a rootkit, completion routines allow it to modify the output of the request; for example, deleting a filename from a list of files in a specific directory. Setting up a completion routine requires it to first copy the request parameters to the lower driver in the chain. To copy these parameters to the next driver's stack, the rootkit can use the IoCopyCurrentIrpStackLocationToNext API.
Once all the parameters are copied for the next driver, malware can set the completion routine using IoSetCompletionRoutine, and then pass this request to the next driver using IoCallDriver. An example from MSDN is as follows:
IoCopyCurrentIrpStackLocationToNext( Irp );
IoSetCompletionRoutine( Irp, // Irp
MyLegacyFilterPassThroughCompletion, // CompletionRoutine
NULL, // Context
TRUE, // InvokeOnSuccess
TRUE, // InvokeOnError
TRUE); //...