www.pudn.com > 29a_fu.zip > 29A-7.018


 
Example code: Invisibility 
------------- 
by yoda (6th July 2k2) 
 
tested on: WinME and Win2000 
 
Intro 
----- 
This is an example how one could hide a process on Windows based 
operation systems from task viewers like ProcDump (G-RoM, Lorian 
& Stone) or ProcessExplorer (SysInternals). 
It could e.g. be used as some kind of dump protection. 
The way to get this done is very different on NT and 9x machines. 
 
Win 95/98/ME 
------------ 
On 9x we reach our goal by simply hooking the target Toolhelp32 
APIs: Process32First/Process32Next. 
If the hook routine decides that the CALLer is querying our 
process we just perform a second Process32Next call on the 
specified TH32 handle. 
 
Additionally we wipe the process from the CTRL+ALT+DEL box by 
using the undocumented but well known RegisterServiceProcess API: 
 
BOOL STDCALL RegisterServiceProcess(DWORD dwProcessID, BOOL bHide); 
 
ProcDump, LordPE, ProcessExplorer are fooled successfully. MS Spy snaps 
the window names of our process but couldn't receive additional 
information except the PID, in case of my system. 
 
Win NT/2k/XP 
------------ 
Here things get trickier. Because a ring3 process has nearly no 
rights we transfer the action to a KMD. 
 
At first we hook NtQuerySystemInformation. Does a thread call 
it and specifies the query class 5 (SystemProcessInformation; thx 
EliCZ) we modify the returned chain of process information structures. 
In fact I don't overwrite the whole structure. I enlarge the 
SYSTEM_PROCESS_INFORMATION.SizeOfBlock structure item of the process 
block being before the block of our process. 
 
This hook isn't realized by a redirection of the API EntryPoint but 
by modifying the ServiceDescriptorTable whose address one can 
get from a structure which is addressed by the 
NtOsKrnl!KeServiceDescriptorTable export: 
 
SSDT STRUCT 
	pSSAT              LPVOID  ?      ; System Service Address Table   ( LPVOID[] ) 
	Obsolete           DWORD   ?      ; or maybe: API ID base 
	dwAPICount         DWORD   ? 
	pSSPT              LPVOID  ?      ; System Service Parameter Table ( BYTE[] ) 
SSDT ENDS  
 
Due to the fact that these Native API IDs differ from every NT OS and 
also from service pack to service pack we need to find out the NT API 
ID of NtQuerySystemInformation. For that purpose we pass the address 
of NtDll!NtQuerySystemInformation to the driver which extracts the 
Native API ID from there.... 
 
NtDll!NtQuerySystemInformation: 
		mov	eax, 97h                   ; EAX == Native API ID 
		lea	edx, [esp+arg_0]           ; EDX -> argument list 
		int	2Eh                        ; perform Native API call 
		retn	10h 
 
The Native API ID is the index into the function address chain we find at 
NtOsKrnl!KeServiceDescriptorTable.SSDT.pSSAT. We simply exchange the 
function address of our target API with the linear address of our 
hook procedure. In our case: pSSAT[ 0x97 ]. 
 
When we're finished with that the user can't see Invisibility.exe anymore 
in the CTRL+ALT+DEL box of NT in the process tab. The next problem is 
that there's also an entry of our process in the window tab of TaskMgr.exe... 
 
TaskMgr.exe internally uses the user32!EnumWindows API to receive the 
window handles and later the windows names so that it can show name/icon 
in the window tab. 
 
Because I didn't wanted to hook every User32.dll of every process separately 
and keep track of every new process being created, I needed to hook the system 
somewhere in the deeper core of NT. 
EnumWindows is just a stub for a non-exported function with some more arguments 
which is also called by User32!EnumChildWindows. This function uses the 
following 3 Native APIs: 
 
Win32k!NtUserBuildHwndList:          - called first 
                                     - called only one time 
                                     - ID: 0x112E on my system 
                                      
Win32k!NtUserInternalGetWindowText:  - called several times 
                                     - ID: 0x11B1 on my system 
                                      
Win32k!NtUserQueryWindow:            - called several times 
                                     - ID: 0x11D2 on my system 
                                      
Hooking NtUserBuildHwndList sounds good for our purposes. NtUserBuildHwndList 
has 7 arguments and its prototype looks something like: 
 
NTSTATUS NTAPI 
NtUserBuildHwndList(                                                   ; my guesses 
	IN  ARGUMENT_1,                                                         
	IN  hParentHwnd, 
	IN  BOOL, 
	IN  ARGUMENT_4, 
	IN  SpaceForHandlesInBufferCount, 
	OUT pOutputBuffer, 
	OUT pbResult 
); 
 
This function isn't exported from win32k.sys. So we need to find its Service- 
DescriptorTable. There is an undocumented non-accessible descriptor. The so 
called ServiceDescriptorTableShadow. I found it some bytes under the address 
being exported as NtOsKrnl!KeServiceDescriptorTable. 
Little memory snippet... 
 
0x0000: SSDT structure for Native API IDs < 0x1000     ; non-shadow SSDT 
0x0010: 00000000 00000000 00000000 00000000            ; table terminator 
0x0020: 00000000 00000000 00000000 00000000 
0x0030: 00000000 00000000 00000000 00000000 
0x0040: 00000000 00000000 00000000 00000000 
0x0050: SSDT structure for Native API IDs <  0x1000    ; KeServiceDescriptorTableShadow ! 
0x0060: SSDT structure for Native API IDs >= 0x1000    ; SSDT for win32k.sys 
0x0070: 00000000 00000000 00000000 00000000            ; table terminator 
 
Now we just need the Native API ID of NtUserBuildHwndList. We've luck. 
IDA says: 
 
[...] 
sub_0_77E0678A	proc near 
		mov	eax, 112Eh                         ; EAX == ID of win32k!NtUserBuildHwndList  !!! 
		lea	edx, [esp+arg_0] 
		int	2Eh 
		retn	1Ch 
sub_0_77E0678A	endp 
 
EnumWindows	proc near 
		xor	eax, eax 
		push	eax 
		push	eax 
		push	[esp+8+arg_4] 
		push	[esp+0Ch+arg_0] 
		push	eax 
		push	eax 
		call	sub_0_77E06607 
		retn	8 
EnumWindows	endp 
[...] 
 
...so we can grab the Native API ID of the API directly from above EnumWindows, 
replace the routine address in the SSDTS.pSSAT[ 0x112E ] and we've hooked the 
routine successfully.  
 
We can use user32!GetWindowThreadProcessId to decide in KernelMode whether one 
of the returned window handles belongs to our process or not because this API 
doesn't call any second API but only the raw NT structures. 
 
After modifying also the output of this API, TaskMgr.exe also doesn't list the 
Invisibility message box caption in the window tab. 
 
ProcDump, ProcessExplorer are tricked too. MS Snap finds/lists the Invisibility 
windows ! 
 
 
Have a look at the source code for more information. 
 
Acknowledgement/Greetz 
---------------------- 
EliCZ           - skilled tips as usual...thx man 
DAEMON          - ditto... 
 
 
E-mail:  LordPE@gmx.net 
WWW:     y0da.cjb.net 
 
yoda