A forum for reverse engineering, OS internals and malware analysis 

Ask your beginner questions here.
 #8159  by Vrtule
 Sat Aug 20, 2011 8:54 am
I have always used the KeAddSystemServiceTable method to locate the shadow table base address but there are plenty of other ways to do it as well, for example traversing threads (i.e> PsLookupThreadByThreadId) and locating a GUI thread. The address is kept in the thread's KTHREAD.ServiceTable field. Might want to validate this address range too in case it's been altered because some malware do this and redirect to a copied shadow table that contains hooked services. You can also obtain the shadow table address easily from usermode, again many ways really.
Yes, it is possible to obtain address of the shadow table from GUI thread structure. However, as you said, some malware alter that field, so you need to validate it. I haven't seen any malware modifying KeAddSystemServiceTable routine to confuse those getting the address of the shadow table from there. So, KeAddSystemServiceTable seems to me as safer approach.

And yes, it is possible to obain the address from usermode too. For example, you can load ntoskrnl image to memory and search KeAddSystemServiceTable function.

I also noticed that KeServiceDescriptorTable (which is exported) and KeServiceDescriptorTableShadow are located really near each other (in fact, one table follows the other). I am wondering, whether this holds for all versions of Windows kernel. Didanybody examinte this?
 #8164  by GamingMasteR
 Sat Aug 20, 2011 1:59 pm
I also noticed that KeServiceDescriptorTable (which is exported) and KeServiceDescriptorTableShadow are located really near each other (in fact, one table follows the other). I am wondering, whether this holds for all versions of Windows kernel. Didanybody examinte this?
Code: Select all
if (XP)
    KeServiceDescriptorTableShadow := KeServiceDescriptorTable - 0x40
else if (Vista || Seven)
    KeServiceDescriptorTableShadow := KeServiceDescriptorTable + 0x40
 #8165  by EP_X0FF
 Sat Aug 20, 2011 2:04 pm
XP

8055a1e0 804e26a8 00000000 0000011c 80510088 <=sst
8055a1f0 bf999b80 00000000 0000029b bf99a890 <=ssst

7

82b7cb40 82a91d5c 00000000 00000191 82a923a4 <=sst
82b7cb50 9c008000 00000000 00000339 9c00902c <=ssst
 #8248  by Tigzy
 Tue Aug 23, 2011 4:50 pm
Hello

Just to say everything worked ;)
I succeed to Hook these API in SSDT Shadow :
NtUserMessageCall
NtUserPostThreadMessage
NtUserPostMessage
I catch the WM_CLOSE event to know which process needs to be closed, but it works on only few GUIs...
NtUserPostMessage works with iexplore,
NtUserMessageCall works with my process GUI

For all my GUI tested (Hijack this, Taskmgr, ...), there's no message on closed in these APIs.
So anyone knows which API I need to hook to catch these GUI WM_CLOSE events?
 #8266  by Brock
 Thu Aug 25, 2011 8:55 am
@Vrtule

Yes, usermode shadow base acquiring is simple indeed. One method I wrote and used a while back is this (GamingMaster mentioned offsets for some major OS)... Add code for proper offset as needed, if required (Win2k3/Win2k8) but seems generic and okay ;)
Code: Select all

function GetShadowTableBase: DWORD;
var
 hMod: HMODULE;
 iOffs: Integer;
 dwSz: DWORD;
 pBuffer, pBuf: Pointer;
 dwKrnlBase: DWORD;
 pKrnlName: PAnsiChar;
 NtQuerySystemInformation: function(dwClass: ULONG; pBuf: Pointer;
                                     dwSize: ULONG; dwRet: PULONG): Integer; stdcall;
const
 pSDT: PAnsiChar = 'KeServiceDescriptorTable';
 pQSI: PAnsiChar = 'NtQuerySystemInformation';
 NTDLL: PAnsiChar = 'ntdll.dll';
 STATUS_SUCCESS = 0;
begin
 result := 0;
 @NtQuerySystemInformation := GetProcAddress(GetModuleHandleA(NTDLL), pQSI);
 if @NtQuerySystemInformation <> nil then
 begin
 if NtQuerySystemInformation(11, nil, 0, @dwSz) <> STATUS_SUCCESS then
 begin
 pBuffer := VirtualAlloc(nil, dwSz * 2, MEM_COMMIT, PAGE_READWRITE);
 if NtQuerySystemInformation(11, pBuffer, dwSz * 2, @dwSz) = STATUS_SUCCESS then
 begin
 pBuf := Pointer(DWORD(pBuffer) + 12);
 dwKrnlBase := PDWORD(pBuf)^;
 pKrnlName := PAnsiChar(DWORD(pBuf) + PWORD(DWORD(pBuf) + 18)^ + 20);
 if (LOBYTE(LOWORD(GetVersion())) = 6) then
 iOffs := $40
 else
 if (LOBYTE(LOWORD(GetVersion())) = 5) and (HIBYTE(LOWORD(GetVersion())) = 1) then
 iOffs := -$40;
 hMod := LoadLibraryExA(pKrnlName, 0, DONT_RESOLVE_DLL_REFERENCES);
 if hMod > 0 then
 begin
 result := ((DWORD(GetProcAddress(hMod, pSDT)) - hMod) + (dwKrnlBase + DWORD(iOffs)));
 FreeLibrary(hMod);
 end;
 end;
 VirtualFree(pBuffer, 0, MEM_RELEASE);
 end;
 end;
end;

 #8345  by Tigzy
 Tue Aug 30, 2011 8:10 am
Well, thanks to Alex (MP)
The API to hook is NtUserDestroyWindow (quite Obvious as EP_X0FF would say...)

:mrgreen:
Code: Select all
BOOLEAN MyNtUserDestroyWindow (IN HWND hWnd)
{   
   DWORD ProcessId = -1;      
   if (NtUserQueryWindow_callnumber != 0) ProcessId = g_OriginalNtUserQueryWindow (hWnd, QUERY_WINDOW_UNIQUE_PROCESS_ID);    
   
   if (ProcessId != -1)
   {
      //****** Looking for protected process ******
      for (i = 0 ; i < numberOfPIDs ; i++)
      {   
         if (PIDs[i] == ProcessId)
         {                  
            DbgPrint("[NtUserDestroyWindow] PID to Close %d --> ACCESS_DENIED\n", ProcessId);            
            return FALSE;
         }
      }
      //*******************************************
   }
   
   return g_OriginalNtUserDestroyWindow(hWnd);
}
EDIT: Solved!