View Full Version : Protected kernel driver
zdr
December 3rd, 2005, 16:38
Hey all,
I'm quite stuck this problem, hope I'll find answers here...
I got a kernel driver which protects itself from being deleted, It does that by catching a system shutdown event (IRP_MJ_SHUTDOWN) and reverts the changes made to the Service Control Manager.
Normally, to remove a kernel driver I could just delete it by using SCM API or directly altering the registry (HKLM\System\CurrentControlSet\Service\XXX).
If I delete it's entries from the registry and reboot the system (to take effect) it reverts the settings back to normal - which loads the driver again.
I need to figure the best way to remove this driver, I thought of:
1. Writting my custom driver that catches shutdown event and deletes the kernel driver from the SCM. The question is how can I be sure that it will be called AFTER that driver?
2. Patching the driver somehow in user-mode (getting from user-mode to kernel-mode) - could be lead to BSOD. Is this possible in user-mode?
3. Unexcepected shutdown/reboot (by using a button) without letting the OS to handle a shutdown event. Isn't proper solution, could destory the OS.
4. Altering the shutdown notification queue (list of device pointers to be called when the system is shutting down) - IoUnregisterShutdownNotification. It needs to be done in kernel-mode. No idea how can I do this, must be a way to patch the code.
Any other solutions such as registry offline editors, offline delete doesn't fit,
I need to write a program which automates the solution.
Any ideas?
Much thanks.
Kayaker
December 3rd, 2005, 19:31
Hi
One possible solution, though I don't know for certain it would work, would be to use IoAttachDeviceToDeviceStack to attach your driver to the other driver's device object.
"IoAttachDeviceToDeviceStack establishes layering between drivers so that the same IRPs are sent to each driver in the chain.
An intermediate driver can use this routine during initialization to attach its own device object to another driver's device object. Subsequent I/O requests sent to TargetDevice are sent first to the intermediate driver."
When IRP_MJ_SHUTDOWN is sent you get to handle it first. This doesn't do you any good by itself though because the other driver can still check/restore the registry entry when you pass the IRP down to it (which you should do). However, you may be able to use IoSetCompletionRoutine to set a callback which will be called *after* the lower level driver finishes with the IRP.
In other words, you set up as a filter driver, attaching on the top of the device queue stack (though in this case it's to a particular driver), passing requests to lower drivers *down* the stack, but you set up a completion routine to be called on the way back *up* the stack. If all goes well, you have last crack at the registry to delete the service entry you want.
Let us know your progress.
Cheers,
Kayaker
LLXX
December 4th, 2005, 02:09
How about deleting the keys in the registry before the kernal even loads? A simple boot to a DOS kernal or similar might do it...
naides
December 4th, 2005, 08:59
What about booting your computer with one of the Linux versions that run from a CD? (Knoppix for instance) then you have full control of the windows file system and can delete anything you wish.
A little search and you will find registry editors that run in Linux, then modify the WinRegistry without the idiotic controls Windoze or the self protecting driver impose.
zdr
December 4th, 2005, 12:31
Quote:
[Originally Posted by LLXX]How about deleting the keys in the registry before the kernal even loads? A simple boot to a DOS kernal or similar might do it... |
If you read my post you will find that I need to automate this solution so offline editiong isn't a proper nor elegant.
If you got any other ideas, it will be nice.
Anyway, I'm in the middle of writting my own custom driver which alters the registry after shutdown is being called.
LLXX
December 4th, 2005, 20:56
Yes, it is possible to delete the registry keys before the kernal loads, and automate it. This is similar to the "delete-on-reboot" feature that certain "system recovery tools" have. Basically, they modify the system bootup sequence (via swapping out the boot-sector?) so that when the system is restarted, it loads a separate kernal (not the NT kernal) that runs a script to perform tasks such as editing the registry and deleting files. After the script terminates, it restores the original boot sequence and reboots. On this next reboot, the normal route is followed, except for anything that was changed. This reminds me of the "Some files are in use and cannot be removed. You have to reboot the computer to complete the uninstallation. Reboot now?" message.
zdr
December 5th, 2005, 07:36
Hey, I am aware of this issue. (also thought about this)
I've read some information about it on the following link:
http://www.sysinternals.com/Information/NativeApplications.html.
The problem is that the drivers are also loaded during boot.
The question is if there is a way to change the priority of native programs?
Much thanks.
ancev
December 5th, 2005, 07:43
zdr,
this maybe is stupid... but you tried to dleete the file or the registry entries, and then pressing reset, without shutdown? this wouldnt give the driver chace to revert the deletes you did
ancev
zdr
December 5th, 2005, 12:08
I've already tried that, it was my first attempt, it is working. but how can I automate this in sofware?

laola
December 5th, 2005, 12:57
You could examine how e.g. SoftICE performs the HBOOT command

Does the driver protect its own image on the hard disk as well? Modifying its behaviour might prove to be more simple than expected...
Btw, if a driver is loaded, you cannot delete the sys file, but you can create a copy and rename the original one to something else. On reboot, the new file will be loaded instead.
Maximus
December 5th, 2005, 14:09
Don't know if this is still applicable, but on older system and with all the privileges you were able to perform a cold reboot by signalling the PIC.
Try googleing for mmh...
I'd have the code somewhere ...
Code:
cli
@@IsReady: // wait until 8042 is ready
in al,64h // read 8042 status
test al,2h // input buffer full? (pin 1)
jnz @@IsReady
mov al,0FEh // reset (pin 0)
out 64h,al
// bye bye
hope it helps...
(ps: if it still works, remember to perform this after all disk writes are performed... I take no responsibility for losses

)
Pyrae
December 5th, 2005, 19:30
Maximus' method does indeed still work. It's employed by the latest version of some well-known protector mostly used for audio software, for instance.

Kayaker
December 6th, 2005, 01:16
You guys are terrible. You shouldn't be encouraging anyone with nasty code with which to trash their computer, that's Sony's job ;-)
I still think a driver solution is best, but while we're on the other subject, the Softice HBOOT command uses the same technique Maximus and Pyrae mention. Here's a quick analysis of it, maybe someone can fill in the blanks, particulary the OUT commands with ports(?) 670h and 674h, and the LGDT instruction.
Code:
Softice HBOOT command:
Ports 61h and 64h are keyboard controller ports
:BE073B57 6A00 PUSH 00
:BE073B59 E82C8EFEFF CALL BE05C98A
// disconnect from network/remote connections
:BE073B5E E461 IN AL,61
:BE073B60 51 PUSH ECX
:BE073B61 B914000000 MOV ECX,00000014
:BE073B66 E2FE LOOP BE073B66
// pause for 20 instruction cycles - to allow connect?
:BE073B68 59 POP ECX
:BE073B69 0C0C OR AL,0C
:BE073B6B E661 OUT 61,AL
// set some kb controller bits, not sure of significance
:BE073B6D 51 PUSH ECX
:BE073B6E B914000000 MOV ECX,00000014
:BE073B73 E2FE LOOP BE073B73
// pause for 20 cycles
:BE073B75 59 POP ECX
:BE073B76 66BA7406 MOV DX,0674
:BE073B7A B000 MOV AL,00
:BE073B7C EE OUT DX,AL
:BE073B7D 66BA7006 MOV DX,0670
:BE073B81 EE OUT DX,AL
// what the heck are ports 670h and 674h?
:BE073B82 B0FE MOV AL,FE
:BE073B84 E664 OUT 64,AL
// Similar to code Maximus posted, I found the following snippet at
--------------------------------------
// http://my.execpc.com/~geezer/osd/kbd/
; bit b0 of the 8042 'Output Port' drives the CPU reset line
; pulse it low to reset the system
mov al, 0FEh ; 8042 command byte to pulse Output Port pin
out 64h,al
http://heim.ifi.uio.no/~stanisls/helppc/8042.html
Command Fx (Port 64h) :
Pulse Output Port: Bits 0-3 of the 8042 output port can be
pulsed low for 6 ęs; Bits 0-3 of command indicate which
Bits should be pulsed; 0=pulse, 1=don't pulse; pulsing
Bit 0 results in CPU reset since it is connected to system
reset line.
---------------------------------------
:BE073B86 B900006000 MOV ECX,00600000
:BE073B8B E2FE LOOP BE073B8B
// pause
:BE073B8D 66B81000 MOV AX,0010
:BE073B91 0F0115573B07BE LGDT FWORD PTR [BE073B57]
// suggestions as to why LGDT is loading this particular value
// into the GDT, at this particular time?
// FWORD PTR [BE073B57] happens to be the start of the HBOOT procedure
:BE073B98 668ED8 MOV DS,AX
:BE073B9B C3 RET
Kayaker
LLXX
December 6th, 2005, 04:07
The 20-cycle delays are used to ensure that the slower devices on the bus will be given enough time to "digest" a command before it's sent another one. It's a prominent feature of any code that does direct hardware access to slower devices. In the old PC BIOSs, this "IO_Delay" was done with an EB 00 (i.e. null jump); now it seems that 20 cycles are needed for a proper delay.
As for the strange ports... I can't find anything on them.
http://bochs.sourceforge.net/techspec/PORTS.LST
They might be some sort of chipset feature, or more likely to be an alias for 70 - 74 which is the CMOS.
zdr
December 6th, 2005, 04:34
I'm glad to hear about the updates... good to know a way to simulate a shutdown.
Anyway, I've done with the driver, I didn't use the IoAttachDeviceToDeviceStack method, because that specific driver doesn't have any registered, publicly available device name. (in the code they didn't use a standart name, so it is registered as unnamed device)
I also got few BSOD's while playing with it.
I decided to go for the priority trick (loading before that driver).
I will upload the code when i'll get back home.
Another thing that is bugging me is that is that only one device in the stack is allowed to be registered in the shutdown list queue, why is that?!
(If you register anyway, you will get BSOD saying
IRQL_NOT_LESS_OR_EQUAL).
About the shutdown simulation code, it will be nice if anyone post a code that really works. Anyway I will research about this...
Much thanks.
Pyrae
December 6th, 2005, 15:33
Quote:
// suggestions as to why LGDT is loading this particular value
// into the GDT, at this particular time?
// FWORD PTR [BE073B57] happens to be the start of the HBOOT procedure
|
Obviously, the new 'GDT' would not contain any meaningful vectors.
So I'd guess the 'HBOOT' start offset is just an arbitrarily chosen address of some data known to not make up any kind of valid descriptors (maybe just the first label, which came to the coders mind

).
Afaik loading the GDTR with some 'random' pointer is a pretty reliable way to cause a 'triple fault', which might just be a dirtier way to reset the cpu in case the kb controller method didn't do the trick.
regards,
Pyrae
Maximus
December 7th, 2005, 14:22
Triple fault! I remember I read something about it on 386 much time ago -but I have a fairly vague remembrance of that.
Anyway, since we're on the argument, the keyboard controller can also be used (I guess so, since other trick still work) for resetting the CPU *only*. It was the trick used on 286 to switch back to RM from PM (286 weren't able to leave PM -intel architects were surely V.I.P.). Don't know if it can be used for something today, but I think the trick is still there

Kayaker
December 7th, 2005, 18:50
Quote:
[Originally Posted by Pyrae]Afaik loading the GDTR with some 'random' pointer is a pretty reliable way to cause a 'triple fault', which might just be a dirtier way to reset the cpu in case the kb controller method didn't do the trick. |
Good deduction! I've mentioned before that I wrote a driver, IceProbe, which allows me to live trace Softice commands. So naturally I was compelled to trace HBOOT...
Tracing normally, under VMware, the instructions
MOV AL,FE
OUT 64,AL
do just what they're supposed to - cause an immediate unconditional reboot.
If I nop out those instructions and allow the code to proceed to the LGDT instruction I get the VMware message:
"Virtual machine kernel stack fault (hardware reset)
The virtual machine just suffered a stack fault in kernel mode. On a real computer, this would amount to a reset of the processor. It can be caused by an incorrect configuration of the virtual machine, a bug in the OS, or a problem in the VMware software. Press OK to reboot...
When I checked the vmware log file I see in the last few entries:
(if you use the provided debug version of vmware-vmx.exe you get logged debug output)
: vcpu-0| SOUND: ignoring attempt by guest to specify fragment size
: vcpu-0|
Triple fault.
: vcpu-0| Msg_Hint: msg.monitorEvent.cpl0SS (shown)
Bingo, there's the "triple fault"!
The last line is from the message box. The line with the SOUND debug message also confirms what the first part of the HBOOT command is doing. From a reference, Bits 0 and 1 of port 61h control the speaker.
This sequence actually means:
; turn off sound
IN AL,61 // AL returns 30h (binary 110000)
...
OR AL,0C // OR with 0Ch becomes (111100b)
OUT 61,AL // turn off bits 0 and 1
I like a happy ending..
Kayaker
LLXX
December 8th, 2005, 00:17
There's still the question of what those strange ports are...
Code:
:BE073B75 59 POP ECX
:BE073B76 66BA7406 MOV DX,0674
:BE073B7A B000 MOV AL,00
:BE073B7C EE OUT DX,AL
:BE073B7D 66BA7006 MOV DX,0670
:BE073B81 EE OUT DX,AL
VMware doesn't seem to know about these?
Another hypothesis that I have is that 670 and 674 might be somehow related to some debugging hardware...
Kayaker
December 8th, 2005, 02:51
Hi
Yeah, I was kind of avoiding that anomaly, not *really* a happy ending if it's not explained. There's no indication in vmware or elsewhere what those ports might represent. I searched the Sice drivers cpthook and siwvid but there was no other use of those port numbers. Not very informative, but I wrote those instructions into driver code and executed them with BPIO set to the ports, but Sice didn't break. And there was no effect one way or another if I nopped them out of the HBOOT command.
I'm curious now if the IN/OUT commands have to be used exclusively with a *physical* hardware port, or can a piece of software "take over" an unused port number and map it to it's own functions. In effect emulating a user defined piece of hardware and being able to use IN/OUT to communicate with it? I thought perhaps DriverStudio maps some function to those port numbers, and flipping bit 0 triggers it off.
Maximus
December 8th, 2005, 10:10
mmh... port from 0x600->0x6f8 can be a remap for 0x200->0x2f8 ports.
Iwarez
December 8th, 2005, 16:42
According to "Ralf Brown's Interrupt List" those ports (670, 674) reset the display adapter. It's not very detailed though.
Maximus
December 8th, 2005, 17:34
Try to check for 270, 274 ports.
The remapping usually forced to leave the 6xx addresses 'free', for avoiding conflicts.
LLXX
December 8th, 2005, 21:47
Quote:
[Originally Posted by Kayaker]I'm curious now if the IN/OUT commands have to be used exclusively with a *physical* hardware port, or can a piece of software "take over" an unused port number and map it to it's own functions. In effect emulating a user defined piece of hardware and being able to use IN/OUT to communicate with it? I thought perhaps DriverStudio maps some function to those port numbers, and flipping bit 0 triggers it off. |
That is possible, see Intel manual #25366516 (IA-32 Intel(R) Architecture Software Developer's Manual) Chapter 13 for more details. Basically, an I/O instruction can throw a #GP which can be intercepted by the OS, which can then emulate hypothetical hardware.
Maximus
December 9th, 2005, 10:08
The #GP is thrown only in VM86 context, for virtualizing old dos direct IO accesses in complex OSes (i.e. it is needed in dos-boxes). It is not thrown in PM with no VM86 flag, so I guess the problem remain?
(the IOPL-related is not relevant here, I guess).
edit-----
now, i checked the instruction set, 2B 4-15,
if ((pe=1) and ((cpl>iopl) or (vm=1))) then [possible #gp]
Powered by vBulletin® Version 4.2.2 Copyright © 2018 vBulletin Solutions, Inc. All rights reserved.