Sunday, September 4, 2011

Hook Specials 28 : Realize hook with VEH

Author:方圆科技
The ways of hook have many methods , They have strengths and weaknesses . Hook of IAT need watch functions like LIABRARY,GETPROCESS . Real realize is trouble. Patch memory and jump to oneself code , That need realize original command on oneself code.....

Now I talk a new thinking , Exception is used to realize hook. You know, When a program happen exception, Exception pass on like this path: 1.debuger  2. Vectorization exception, mean VEH  3.SEH...

If don't use debugger, VEH is first receive exception. Like that We can inset int3 on want to space of hook code, Then through VEH to dispose hook, Realize hook final. Axiom is simple. 

Code:

// Hook.h: interface for the CHook class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_HOOK_H__C0F41F39_4EB7_4129_BFB7_156CB203826F__INCLUDED_)
#define AFX_HOOK_H__C0F41F39_4EB7_4129_BFB7_156CB203826F__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000


#include <list>
using namespace std;

typedef void (*HOOKHANDLEFUN)(EXCEPTION_POINTERS *pExceptionInfo,void *pExtendData);
struct t_HookInfo
{
  DWORD dwAddr;
  HOOKHANDLEFUN pFn;
  BYTE byOldCode;
};


class CHook
{
private:
  static CHook *m_Instance;  //单件模式
protected:
  CHook();                   //保证只生成一个实例
public:
  static CHook* GetInstance();
  t_HookInfo *m_pCurrentBP;
  BOOL m_bSingleFlag;
  EXCEPTION_POINTERS *m_pException;
 
  void SetTF();
  static LONG WINAPI VectoredHandler(PEXCEPTION_POINTERS ExceptionInfo);
  list<t_HookInfo*> m_listHook;
  BOOL AddHook(DWORD dwHookAddr, HOOKHANDLEFUN pFn);
  BOOL RemoveHook(DWORD dwHookAddr);
  BOOL SetBP(t_HookInfo*);
  BOOL UnSetBP(t_HookInfo*);
 
  virtual ~CHook();

};

#endif // !defined(AFX_HOOK_H__C0F41F39_4EB7_4129_BFB7_156CB203826F__INCLUDED_)

Code:
// Hook.cpp: implementation of the CHook class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "HookDll.h"
#include "Hook.h"


#define  TEST
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


#ifdef TEST
#define TESTMSG(str) AfxMessageBox(str)
#else
#define TESTMSG(str)
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#define  BREAKPOINTLEN 2
typedef PVOID (WINAPI *ADDVECTOREDEXCEPTIONHANDLER)(ULONG,PVOID);

CHook* CHook::m_Instance;

CHook::CHook()
{
  //Empty chain table
  m_listHook.empty();
  //Install top exception
  HINSTANCE  hMod = LoadLibrary("kernel32.dll");
  ADDVECTOREDEXCEPTIONHANDLER pfn = (ADDVECTOREDEXCEPTIONHANDLER)
    GetProcAddress(hMod,"AddVectoredExceptionHandler");
  PVOID ret = pfn(1,VectoredHandler);

  m_bSingleFlag = FALSE;
  m_pCurrentBP = NULL;
}

//Function name: GetInstance
//Funtion paramter: Non 
//Function feature: return a class instance
//Return Value:  CHook*

CHook* CHook::GetInstance()
{
  if (!m_Instance)
  {
    m_Instance = new CHook;
  }
  return m_Instance;
}
CHook::~CHook()
{
  list<t_HookInfo*>::iterator it;
 
  for (it = m_listHook.begin(); it!=m_listHook.end(); it++)
  {
    UnSetBP((*it));
    delete (*it);
  }
  m_listHook.empty();
}
//Function name: AddHook
//Funtion paramter: 1.Need hook address 2.Dispose pointer of hook function
//Function feature: Add a HOOKINFO to chain table and install a hook
//Return Value:  succeed return TRUE, Otherwise FALSE
//Notice: The function isn't check validity of paramter address, By caller check
BOOL CHook::AddHook(DWORD dwHookAddr, HOOKHANDLEFUN pFn)
{
  t_HookInfo *pHookInfo = new t_HookInfo;
  if (!pHookInfo)
  {
    return FALSE;
  }
  pHookInfo->dwAddr = dwHookAddr;
  pHookInfo->pFn = pFn;
  m_listHook.push_back(pHookInfo);
  return SetBP(pHookInfo);

}


//Function name: RemoveHook
//Funtion paramter: 1. address of REMOVEHOOK
//Function feature: Delete a hook
//Return Value:  succeed return TRUE, Otherwise FALSE
//Notice: The function isn't check validity of paramter address, By caller check
BOOL CHook::RemoveHook(DWORD dwHookAddr)
{
  list<t_HookInfo*>::iterator it;
 
  for (it = m_listHook.begin(); it!=m_listHook.end(); it++)
  {
    if ((*it)->dwAddr == dwHookAddr)
    {
      UnSetBP(*it);
      delete (*it);
      m_listHook.remove(*it);
      return TRUE;
    }
  }
  return FALSE;
 
}
//Function name: SetBP
//Funtion paramter:1. Information of t_HookInfo hook
//Function feature: Write a INT3
//Return Value:  succeed return TRUE, Otherwise FALSE
//Notice: The function isn't check validity of paramter address, By caller check
BOOL CHook::SetBP(t_HookInfo *pHookInfo)
{
  DWORD dwOldProtect,dwNewProtect = PAGE_EXECUTE_READWRITE;
  if (!pHookInfo)
  {
    return FALSE;
  }
 
  VirtualProtect((void*)pHookInfo->dwAddr,BREAKPOINTLEN,dwNewProtect,&dwOldProtect);
  pHookInfo->byOldCode = *(BYTE*)(pHookInfo->dwAddr);
  *(BYTE*)(pHookInfo->dwAddr) = 0xcc;
  VirtualProtect((void*)pHookInfo->dwAddr,BREAKPOINTLEN,dwOldProtect,&dwNewProtect);
  return TRUE;

}

//Function name: SetBP
//Funtion paramter:1.Information of t_HookInfo hook
//Function feature: Delete break
//Return Value:  succeed return TRUE, Otherwise FALSE
//Notice: The function isn't check validity of paramter address, By caller check
BOOL CHook::UnSetBP(t_HookInfo *pHookInfo)
{
  DWORD dwOldProtect,dwNewProtect = PAGE_EXECUTE_READWRITE;
  if (!pHookInfo)
  {
    return FALSE;
  }
 
  VirtualProtect((void*)pHookInfo->dwAddr,BREAKPOINTLEN,dwNewProtect,&dwOldProtect); 
  *(BYTE*)(pHookInfo->dwAddr) = pHookInfo->byOldCode;
  VirtualProtect((void*)pHookInfo->dwAddr,BREAKPOINTLEN,dwOldProtect,&dwNewProtect);
  return TRUE;
 
}
//Function name: VectoredHandler
//Funtion paramter: Exception information structure pointer
//Function feature: Dispose exception
//Return Value:  Oneself exception return EXCEPTION_CONTINUE_EXECUTION,Otherwise return EXCEPTION_CONTINUE_SEARCH
LONG WINAPI CHook::VectoredHandler(PEXCEPTION_POINTERS ExceptionInfo)
{
  CHook *pHook = CHook::GetInstance();
  //检测是否INT3断点
  if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT)
  {
    CString str;
    str.Format("%-8x",ExceptionInfo->ExceptionRecord->ExceptionAddress);
//    TESTMSG(str);
    list<t_HookInfo*>::iterator it;
    //Check whether oneself break
    for (it = pHook->m_listHook.begin(); it!=pHook->m_listHook.end(); it++)
    {
      if ((*it)->dwAddr ==(DWORD) ExceptionInfo->ExceptionRecord->ExceptionAddress)
      {
        //Log current break, Set step flag, Delete break,
        pHook->m_pException = ExceptionInfo;
        pHook->SetTF();
        pHook->UnSetBP(*it);
        pHook->m_pCurrentBP = *it;
        //Call related function
        (*it)->pFn(ExceptionInfo,NULL);
        return EXCEPTION_CONTINUE_EXECUTION;
      }
    }
    return EXCEPTION_CONTINUE_SEARCH;
  }
  //Dispose step break 
  else if ( ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP )
  {
    //Judge wether step break onself
    if (pHook->m_bSingleFlag && pHook->m_pCurrentBP)
    {
      //Restore break, flag
      pHook->SetBP(pHook->m_pCurrentBP);
      pHook->m_bSingleFlag = FALSE;
      pHook->m_pCurrentBP = NULL;
      return EXCEPTION_CONTINUE_EXECUTION;
    }
    else
    {
      return  EXCEPTION_CONTINUE_SEARCH;
    }
  }

  else
  {
    return  EXCEPTION_CONTINUE_SEARCH;
  }
}


//Function name: SetTF
//Funtion paramter:Non
//Function feature: Set step break
//Return Value:  Non

void CHook::SetTF()
{
 
  if (m_pException)
  {
    m_pException->ContextRecord->EFlags |= 0x100;
    m_bSingleFlag = TRUE;
  }
 
}

Saturday, September 3, 2011

Hook Specials 27 : Find to Check object hook base on cross-reference

Author: sudami
Discuss object hook to check with VXK, While the way is simple base on PDB file analytic , That is unusefulness. Because only write general program to has symbol that is too fat on move and inconveniences, Seach file planed to do it. Happen to dummy wrote a article -- "Find all reference address of some specific address through relocation directives "  last year. some way apply to seach object hook.

Train of thought :
1.Create table 1 to save current Object Function Address of system. Open "\\ObjectTypes" to get RootDirectory, Traverse HashBuckets to get different addr by different object, Save on table 1.

2.Create table 2 to save original Object Function Address of system. Ntosxx of system kernel load to nonpagepool, Search on the range:
①To already export type (eg.IoDeviceObjectType、PsProcessType), Traverse ntosXX'EAT, Get RVA -- uAddr, Then call LookupImageXRef((ULONG)NtosCopy, uAddr, LookupXRefCallback); Search address on LookupXRefCallBack function, if we want to find function module, Feature matched to judge, for example:
      
      
       BOOLEAN
       NTAPI
         LookupXRefCallback(
            PULONG RefAddr
            )
      {
    ULONG tmp, address;
    PBYTE lpAddr = (PBYTE)RefAddr;
    ULONG x, i;
    int  time = 0;


    // If return True, Continue search , 否则Otherwise stop
//    DbgPrint("%08X --> %08X\n", RefAddr, RefAddr[0]);
    __try
    {
        //
        // Because large LoadPeFile called , The same system load to memory.
        // There already align. So (ULONG)RefAddr - (ULONG)NtosCopy;
        // It is RVA,Don't consider ImageBase. Good job; RefAddr is some function address load file to memory oneself, 
        // Such as I want to get A initio original n number bytes
        // Immediate take out from RefAddr
        // sudami 08/09/11 
        //
    tmp = (ULONG)RefAddr - (ULONG)NtosCopy; //RVA
//    DbgPrint("0x%08lx\n", (ULONG)ulKernelBase + tmp );


    //
    // To each RefAddr , From address + 4 of begining disassemble , find to match  code of xx function interior called.
    // There has original function address of IopXX,PspXX,CmpXX....
    // sudami 08/09/11 凌晨
    //

    //
    // coding
    //

    lpAddr+=4;

    switch ( g_nMethod )
    {
    case 1: // IopCreateObjectTypes function


   
            /*++ <IoDeviceObjectType>

        1.    C7 45 D4 B8 00 00 00 mov [ebp+var_2C], 0B8h
        2.    C7 45 E8 4D 57 4A 00 mov [ebp+var_18], offset IopParseDevice
            C6 45 AF 01 mov byte ptr [ebp+var_54+3], 1
        3.    C7 45 E4 9A 71 4C 00 mov [ebp+var_1C], offset IopDeleteDevice
        4.    C7 45 EC 8A 90 4D 00 mov [ebp+var_14], offset IopGetSetSecurityObject
            89 5D F0 mov [ebp+var_10], ebx
            E8 1F 40 F2 FF call ObCreateObjectType

            --*/
            time = 0;
            for(i=0;i<70;i++)
            {
                if ( !MmIsAddressValid( &lpAddr[i]) ){
                    continue ;
                }

                if(lpAddr[i]==0xC7 && lpAddr[i+1]==0x45)
                {
                    time+=1;
                    if (time==1)
                    {
                        x = *((DWORD *)((ULONG)RefAddr+i+3+4));
                        if(x!=0xB8)
                            return FALSE;
                    }
                    if(time==2)
                    {
                        x = *((DWORD *)((ULONG)RefAddr+i+3+4));
                       
                        DbgPrint("IopParseDevice - Orig: 0x%08lx\n", \
                            (ULONG)x + (ULONG)ulKernelBase - (ULONG)pNtH->OptionalHeader.ImageBase);

                        continue ;
                    }

                    if(time==3)
                    {
                        x = *((DWORD *)((ULONG)RefAddr+i+3+4));

                        DbgPrint("IopDeleteDevice - Orig: 0x%08lx\n", \
                            (ULONG)x + (ULONG)ulKernelBase - (ULONG)pNtH->OptionalHeader.ImageBase);

                        continue ;
                    }

                    if(time==4)
                    {
                        x = *((DWORD *)((ULONG)RefAddr+i+3+4));

                        DbgPrint("IopGetSetSecurityObject - Orig: 0x%08lx\n", \
                            (ULONG)x + (ULONG)ulKernelBase - (ULONG)pNtH->OptionalHeader.ImageBase);

                        break ;
                    }
                }
            }
           
            ...

     Like this, Realize to finde address of a part of Object function, Quick and stable seach than force seach.
    
     ② To type of non-export (eg.CmpKeyObjectType、ObpTypeObjectType), The way is verbose , I belive:
       
      
        ; Find pointer of there global variable of non-export, To already export type, such as IoDeviceObjectType, Get address on EAT of ntoskrnl.exe, Exactly point
        ; address of IoDeviceObjectType pointer, rathen than address of IoDeviceObjectType . So, It is no use MJ method to get real address of  CmpKeyObjectType, Must get it that point to address of 
        ; CmpKeyObjectType pointer, So do these to use method of dummy. See below:
        ;
        ; lkd> dd IoDeviceObjectType
        ; 80558ee4 817a9ca0 817a9900 817a9e70 817f0428
        ; | |
        ; | |-- IoDeviceObjectType own address本身的地址
        ; |-- Reference address, Point address of IoDeviceObjectType pointer
        ;
        ; 68 64 8D 48 00 push offset IoDeviceObjectType ; -->在callback函数中要找的引用地址是这样的
        ; ........... That is 80558ee4, rather than 817a9ca0
        ; C7 45 E8 4D 57 4A 00 mov [ebp+ParseProcedure], offset IopParseDevice
        ; 89 5D F0 mov [ebp+QueryNameProcedure], ebx
        ; E8 1F 40 F2 FF call ObCreateObjectType
        ; -- sudami 08/09/12
        ;
        ; Only The question resolved, Can need not Violence search. Traverse to finish all  type, Find address of these point type pointer , Then method of dummy to find quote,
        ; Can find real address of obj again... But I can't find solution now.
       
        ③ Can't find solution. As a result I use violence search, Main code as follow :
       
        // Through a series of read PE to get rva. Calculate some offset and space of memory about PE.
        // Allocate non-page memory
        // Content of file is read on here
        // Get size of file, Apple a memory block to save it
        //DbgPrint("Get size of file, Apple a memory block to save it\n");
        ZwQueryInformationFile (ntFileHandle, &ioStatus, &fsi,
                sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation);

        FileContent =  ExAllocatePool (NonPagedPool, fsi.EndOfFile.LowPart);

        if (FileContent == NULL)
        {
            ntStatus = STATUS_UNSUCCESSFUL;
            ZwClose(ntFileHandle);

            DbgPrint("ExAllocatePool Error\n");
            goto End;
        }

        byteOffset.LowPart = 0;
        byteOffset.HighPart = 0;

        ntStatus = ZwReadFile(ntFileHandle,
            NULL,
            NULL,
            NULL,
            &ioStatus,
            FileContent,
            fsi.EndOfFile.LowPart,
            &byteOffset,
            NULL);

        if (!NT_SUCCESS(ntStatus))
        {
            ZwClose(ntFileHandle);
            ExFreePool(FileContent);

            DbgPrint("ZwReadFile 将要读的内容,读到一片非分页内存失败 Error\n");
            goto End;
        }

        if (fsi.EndOfFile.LowPart <= 0)
        {
            ntStatus = STATUS_NOT_FOUND;
            ZwClose(ntFileHandle);
            ExFreePool(FileContent);
            DbgPrint("NeedSize <= 0 Error\n");
            goto End;
        }

        GetHeaders (FileContent, &pfh, &poh, &psh);
       
        //DbgPrint("psh: %08lx\n", (PVOID)psh);
        //DbgPrint("start search....\n");
        // g_CmpCloseKeyObject_addr
        for (i = 0; i < fsi.EndOfFile.LowPart; i++)         
        {
            if ( (FileContent[i] == 0x8B) && (FileContent[i+1] == 0xFF) && (FileContent[i+2] == 0x55) && (FileContent[i+3] == 0x8B) &&
                (FileContent[i+4] == 0xEC) && (FileContent[i+5] == 0x83) && (FileContent[i+6] == 0x7D) && (FileContent[i+7] == 0x18) &&
                (FileContent[i+8] == 0x01) && (FileContent[i+9] == 0x77) && (FileContent[i+10] == 0x24) && (FileContent[i+11] == 0x56)
                )
            {
                //DbgPrint("文件偏移i: %08lx\n", (PVOID)i);
                sudami_1 = Offset2RVA( i, psh, pfh->NumberOfSections );
                if (sudami_1  == 0) {
                    DbgPrint("sudami_1 == 0 Error\n");
                    goto NotFound;
                }

                if (sudami_1  > SizeOfImage) {
                    DbgPrint("sudami_1 > SizeOfImage Error\n");
                    goto NotFound;
                }

                sudami_1 += ModuleBase;

                if (!MmIsAddressValid((PVOID)sudami_1 )) {
                    DbgPrint("!MmIsAddressValid((PVOID)sudami_1 ) Error\n");
                    goto NotFound;
                }

                g_CmpCloseKeyObject_addr = (DWORD)sudami_1;

                DbgPrint( "CmpCloseKeyObject - Orig:\t0x%08x\n", (ULONG)g_CmpCloseKeyObject_addr );
                break;
            }   
        }
       
       
After all, Check object hook, I can't find simple method.
I belive the thing available, So show it, You may use it...

Friday, September 2, 2011

Hook Specials 26 : Wrote a tool that is used to list MajorFunction

Author:zhuwg
Learn object hook recently,Wrote a tool that is used to list MajorFunction, It can list drvice and driver.

00000000  0.00000000  [majorfunc] DriverEntry: \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\majorfunc 
00000001  0.00006956  [majorfunc] Device Name \Device\devmajorfunc 
00000002  0.00013661  [majorfunc] SymbolicLink:\DosDevices\majorfunc 
00000003  0.00020198  ObReferenceObjectByName ok! 
00000004  0.00023411  \Driver\Atapi->MajorFunction[0]=F9998572 
00000005  0.00025115  \Driver\Atapi->MajorFunction[1]=805041BE 
00000006  0.00025869  \Driver\Atapi->MajorFunction[2]=F9998572 
00000007  0.00026512  \Driver\Atapi->MajorFunction[3]=805041BE 
00000008  0.00027154  \Driver\Atapi->MajorFunction[4]=805041BE 
00000009  0.00027797  \Driver\Atapi->MajorFunction[5]=805041BE 
00000010  0.00028411  \Driver\Atapi->MajorFunction[6]=805041BE 
00000011  0.00029026  \Driver\Atapi->MajorFunction[7]=805041BE 
00000012  0.00029669  \Driver\Atapi->MajorFunction[8]=805041BE 
00000013  0.00030283  \Driver\Atapi->MajorFunction[9]=805041BE 
00000014  0.00030926  \Driver\Atapi->MajorFunction[10]=805041BE 
00000015  0.00031540  \Driver\Atapi->MajorFunction[11]=805041BE 
00000016  0.00032183  \Driver\Atapi->MajorFunction[12]=805041BE 
00000017  0.00032797  \Driver\Atapi->MajorFunction[13]=805041BE 
00000018  0.00033440  \Driver\Atapi->MajorFunction[14]=F9998592 
00000019  0.00034055  \Driver\Atapi->MajorFunction[15]=F99947B4 
00000020  0.00034697  \Driver\Atapi->MajorFunction[16]=805041BE 
00000021  0.00035312  \Driver\Atapi->MajorFunction[17]=805041BE 
00000022  0.00035954  \Driver\Atapi->MajorFunction[18]=805041BE 
00000023  0.00036569  \Driver\Atapi->MajorFunction[19]=805041BE 
00000024  0.00037211  \Driver\Atapi->MajorFunction[20]=805041BE 
00000025  0.00037826  \Driver\Atapi->MajorFunction[21]=805041BE 
00000026  0.00038469  \Driver\Atapi->MajorFunction[22]=F99985BC 
00000027  0.00039083  \Driver\Atapi->MajorFunction[23]=F999F164 
00000028  0.00039726  \Driver\Atapi->MajorFunction[24]=805041BE 
00000029  0.00040340  \Driver\Atapi->MajorFunction[25]=805041BE 
00000030  0.00040983  \Driver\Atapi->MajorFunction[26]=805041BE 
00000031  0.00042687  [atapi] HOOKed Success 
00000032  0.00053359  IoGetDeviceObjectPointer ok 
00000033  0.00056292  \Device\Afd->DriverObject->MajorFunction[0]=F8391D40 
00000034  0.00058024  \Device\Afd->DriverObject->MajorFunction[1]=F8391D40 
00000035  0.00058778  \Device\Afd->DriverObject->MajorFunction[2]=F8391D40 
00000036  0.00059477  \Device\Afd->DriverObject->MajorFunction[3]=F8391D40 
00000037  0.00060147  \Device\Afd->DriverObject->MajorFunction[4]=F8391D40 
00000038  0.00060846  \Device\Afd->DriverObject->MajorFunction[5]=F8391D40 
00000039  0.00061516  \Device\Afd->DriverObject->MajorFunction[6]=F8391D40 
00000040  0.00062187  \Device\Afd->DriverObject->MajorFunction[7]=F8391D40 
00000041  0.00062857  \Device\Afd->DriverObject->MajorFunction[8]=F8391D40 
00000042  0.00063556  \Device\Afd->DriverObject->MajorFunction[9]=F8391D40 
00000043  0.00064226  \Device\Afd->DriverObject->MajorFunction[10]=F8391D40 
00000044  0.00064924  \Device\Afd->DriverObject->MajorFunction[11]=F8391D40 
00000045  0.00065595  \Device\Afd->DriverObject->MajorFunction[12]=F8391D40 
00000046  0.00066265  \Device\Afd->DriverObject->MajorFunction[13]=F8391D40 
00000047  0.00066936  \Device\Afd->DriverObject->MajorFunction[14]=F8391280 
00000048  0.00067634  \Device\Afd->DriverObject->MajorFunction[15]=F8391D40 
00000049  0.00068305  \Device\Afd->DriverObject->MajorFunction[16]=F8391D40 
00000050  0.00069003  \Device\Afd->DriverObject->MajorFunction[17]=F8391D40 
00000051  0.00069674  \Device\Afd->DriverObject->MajorFunction[18]=F8391D40 
00000052  0.00070344  \Device\Afd->DriverObject->MajorFunction[19]=F8391D40 
00000053  0.00071015  \Device\Afd->DriverObject->MajorFunction[20]=F8391D40 
00000054  0.00071713  \Device\Afd->DriverObject->MajorFunction[21]=F8391D40 
00000055  0.00072384  \Device\Afd->DriverObject->MajorFunction[22]=F8391D40 
00000056  0.00073082  \Device\Afd->DriverObject->MajorFunction[23]=F8391D40 
00000057  0.00073752  \Device\Afd->DriverObject->MajorFunction[24]=F8391D40 
00000058  0.00075792  \Device\Afd->DriverObject->MajorFunction[25]=F8391D40 
00000059  0.00076602  \Device\Afd->DriverObject->MajorFunction[26]=F8391D40

Thursday, September 1, 2011

Hook Specials 25 :The Age-Old Art of SSDT Hooking(But Bypass Most ARK Tools...)

Author:wowelf 
Same artile watched the day before yesterday, But it is deleted, So I write now.

    SSDT HOOK is old topic, It is first lesson about ring0 rookit. Let us furbish struture of system service table:
   
Code:
typedef struct _SERVICE_DESCRIPTOR_TABLE_SHADOW
{
  SERVICE_DESCRIPTOR_TABLE  ntoskrnl;  //ntoskrnl.exe
  SERVICE_DESCRIPTOR_TABLE  win32k;    //win32k.sys
  SERVICE_DESCRIPTOR_TABLE  NotUse1;   //未使用
  SERVICE_DESCRIPTOR_TABLE  NotUse2;   //未使用
}SERVICE_DESCRIPTOR_TABLE_SHADOW,*PSERVICE_DESCRIPTOR_TABLE_SHADOW;
     Only ntoskrnl is used on KeServiceDescriptorTable, ntoskrnl and win32k is both used on KeServiceDescriptorTableShadow, But two service tables isn't use NotUse1、NotUse2, And almost check tools of SSDT HOOK both check front two parts, Of course, A little people will use behind two parts.

    Train of thought, Copy ntoskrnl and win32k, Apart move They into NotUse1 and NotUse2, So Table modified and copyed to realize SSDT HOOK, Don't modify original table , So ARK tool can't check .

     Above train of thought has a difiiculty ,That how to let system call to entry NotUse1 and NotUse2 rather than original ntoskrnl and win32k, Good luck, I find a space on KiSystemService:

Code:
inc     large dword ptr fs:638h //<--There record system calls, may replace it
mov     esi, edx
mov     ebx, [edi+0Ch]          //<--edi save ntoskrnl or win32k on service table
xor     ecx, ecx
mov     cl, [eax+ebx]
mov     edi, [edi]
mov     ebx, [edi+eax*4]
sub     esp, ecx
shr     ecx, 2
mov     edi, esp
cmp     esi, ds:_MmUserProbeAddress
//The code on XP, Other windows system has similar code
The way is  inc  large dword ptr fs:638h modify  add edi,0x20, Such original edi point ntoskrnl or win32k to change point to NotUse1 or NotUse2, System-call go directly our copy table.   
     Test result, R.K.U、IceSword both can't test to modifiy code.
    
Code:
BOOLEAN
AddMyServiceTable(
          )
{

  if( !g_bIsMyServiceTableCreated ){
    DbgPrint( "AddMyServiceTable() Create Service table first !\n" );
    return FALSE;
  }


  __asm{
    cli
    mov  eax,cr0
    and  eax,not 10000h
    mov  cr0,eax
  }

  RtlCopyMemory( (PVOID)&KeServiceDescriptorTable->NotUse1,
               (PVOID)&mKeServiceDescriptorTable->ntoskrnl,
           sizeof(SERVICE_DESCRIPTOR_TABLE)*2 );

  RtlCopyMemory( (PVOID)&KeServiceDescriptorTableShadow->NotUse1,
               (PVOID)&mKeServiceDescriptorTableShadow->ntoskrnl,
           sizeof(SERVICE_DESCRIPTOR_TABLE)*2 );

  __asm{
    mov  eax,cr0
    or   eax,10000h
    mov  cr0,eax
    sti
  }

  return TRUE;
}
代码:
BOOLEAN
HookSysCall(
  )
{
  //add edi,20h
  //nop ....
  //
  UCHAR cHackCode[] = { 0x83,0xC7,0x20,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90 };

  KIRQL  oldIrql;

  if( g_bIsHooked )
    return TRUE;

  if( !g_bAddressInited ){
    DbgPrint( "Syscall address not inited\n" );
    return FALSE;
  }

  if( KiSystemService_hack_code_size > sizeof( cHackCode ) ){
    return FALSE;
  }

 
  __asm{
    cli
    mov  eax,cr0
    and  eax,not 10000h
    mov  cr0,eax
  }


  RtlCopyMemory( g_pSysCallOrigCode,(PVOID)KiSystemService_hack_address,KiSystemService_hack_code_size );
 
  KeRaiseIrql( DISPATCH_LEVEL,&oldIrql );

  RtlCopyMemory( (PVOID)KiSystemService_hack_address,cHackCode,KiSystemService_hack_code_size );

  KeLowerIrql( oldIrql );

  __asm{
    mov  eax,cr0
    or   eax,10000h
    mov  cr0,eax
    sti
  }

  g_bIsHooked =  TRUE;

  return TRUE;
}
//----------------------------------------------------------------------------

Hook Specials 24 : HOOK SSDT AND HOOK Shadow SSDT FOR DELPHI

Author:bujin888
Recently many of driver's tutorial  wrote with delphi on forum, Want to show my study results, share for everyone.

code:
unit Driver;

interface

uses
   nt_status,ntoskrnl,ntutils;

const
  DeviceName = '\Device\360safeBoxA';
  DosDeviceName = '\DosDevices\360safeBoxA';
  IOCTL_HOOK_START       = $0022E000;
  IOCTL_HOOK_STOP        = $0022E004;
  IOCTL_PROTECT_PROCESS  = $0022E200;
  IOCTL_PROTECT_HWND     = $0022E201;
  IOCTL_PROTECT_OTHER    = $0022E204;

var
 DosDevName: TUnicodeString;
 TempSafeId:Handle=0;
 TempSafehandle:Handle=0;

function _DriverEntry(pDriverObject: PDriverObject; RegistryPath: PUnicodeString) : NTSTATUS; stdcall;

implementation

uses hooking;

function hookCreate(ADeviceObject: PDeviceObject; AIrp: PIrp): NTSTATUS; stdcall;
begin
  Result := STATUS_SUCCESS;
  AIrp^.IoStatus.Status := Result;
  IoCompleteRequest(AIrp, IO_NO_INCREMENT);
end;

function hookClose(ADeviceObject: PDeviceObject; AIrp: PIrp): NTSTATUS; stdcall;
begin
  Result := STATUS_SUCCESS;
  AIrp^.IoStatus.Status := Result;
  IoCompleteRequest(AIrp, IO_NO_INCREMENT);
end;


function hookDeviceControl(ADeviceObject: PDeviceObject; AIrp:PIrp): NTSTATUS; stdcall;
var
  LStack: PIO_STACK_LOCATION;
  pIOBuffer: Pointer;
  LBufInLen, LBufOutLen,
  LCode, LRet,OutByteCount: ULONG;
begin
   LStack := IoGetCurrentIrpStackLocation(AIrp);
   Result := STATUS_SUCCESS;
   AIrp^.IoStatus.Information := 0;
   LCode := LStack^.Parameters.DeviceIoControl.IoControlCode;
   pIOBuffer := AIrp^.AssociatedIrp.SystemBuffer;

   LBufInLen := LStack^.Parameters.DeviceIoControl.InputBufferLength;
   LBufOutLen := LStack^.Parameters.DeviceIoControl.OutputBufferLength;
   OutByteCount:=0;

 case LCode of
    IOCTL_HOOK_START: begin
      LRet := HookingHook;
      OutByteCount:=4;
      LONG(pIOBuffer^):=LRet;
    end;

    IOCTL_HOOK_STOP: begin
      LRet := HookingUnhook;
      OutByteCount:=4;
      LONG(pIOBuffer^):=LRet;
    end;

    IOCTL_PROTECT_PROCESS: begin
      TempSafeId:=Handle(pIOBuffer^);
      SetSafeId(TempSafeId);
      OutByteCount:=4;
      LONG(pIOBuffer^):=Integer(True);
    end;

    IOCTL_PROTECT_HWND:begin
      TempSafehandle:=Handle(pIOBuffer^);
      SetSafehandle(TempSafehandle);
      OutByteCount:=4;
      LONG(pIOBuffer^):=Integer(True);
    end;

    IOCTL_PROTECT_OTHER: begin
      DoPub;
      OutByteCount:=4;
      LONG(pIOBuffer^):=Integer(True);
    end;
  else
    Result := STATUS_INVALID_DEVICE_REQUEST;
    AIrp^.IoStatus.Information := 0;
  end;

  AIrp^.IoStatus.Status := Result;
  AIrp^.IoStatus.Information := OutByteCount;
  IoCompleteRequest(AIrp, IO_NO_INCREMENT);
end;

procedure DriverUnload(pDriverObject: PDriverObject); stdcall;
begin
  HookingUnhook;
  IoDeleteSymbolicLink(@DosDevName);
  IoDeleteDevice(pDriverObject^.DeviceObject);
end;

function _DriverEntry(pDriverObject: PDriverObject; RegistryPath: PUnicodeString) : NTSTATUS; stdcall;
var
  LDevName: TUnicodeString;
  LDevObj: PDeviceObject;
begin
  RtlInitUnicodeString(LDevName, DeviceName);
  RtlInitUnicodeString(DosDevName, DosDeviceName);

  Result := IoCreateDevice(pDriverObject,0, @LDevName,
                            FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, LDevObj);

  if NT_SUCCESS(Result) then
  begin
    pDriverObject^.MajorFunction[IRP_MJ_CREATE]          := @hookCreate;
    pDriverObject^.MajorFunction[IRP_MJ_CLOSE]           := @hookClose;
    pDriverObject^.MajorFunction[IRP_MJ_DEVICE_CONTROL]  := @hookDeviceControl;
    pDriverObject^.DriverUnload                          := @DriverUnload;

    Result := IoCreateSymbolicLink(@DosDevName, @LDevName);
    if not NT_SUCCESS(Result) then
    begin
        IoDeleteDevice(pDriverObject^.DeviceObject);
    end;
  end;
end;

end.

Code:
unit hooking;

interface

uses
  nt_status,ntoskrnl,ntutils,ssdthook;

type
   TZwOpenProcess = function(ProcessHandle:PHandle; DesiredAccess:TAccessMask;
                             ObjectAttributes:PObjectAttributes;
                             ClientId:PClientId):NTSTATUS; stdcall;
   TNtUserFindWindowEx= Function (hwndParent,hwndChild:Handle;
                                  pstrClassName,pstrWindowName:PUnicodeString;
                                  dwType:LONG):NTSTATUS;stdcall;
var
  HookActive: Boolean=False;
  OldZwOpenProcess:LONG=0;
  OldNtUserFindWindowEx:LONG=0;
  SafeId:Handle=0;
  SafeHandle:Handle=0;

procedure SetSafeId(value:Handle);
procedure SetSafeHandle(value:Handle);
function HookingHook: Integer; stdcall;
function HookingUnhook: Integer; stdcall;
procedure DoPub;
implementation

procedure SetSafeId(value:Handle);
begin
 SafeId:=value;
end;

procedure SetSafeHandle(value:Handle);
begin
 SafeHandle:=value;
end;


function  ZwOpenProcessAddr:Pointer;
begin
 Result:=GetImportFunAddr(@ZwOpenProcess);
end;


function NewNtUserFindWindowEx(hwndParent,hwndChild:Handle;pstrClassName,pstrWindowName:PUnicodeString;dwType:LONG):NTSTATUS;stdcall;
begin
  Result:=TNtUserFindWindowEx(pointer(OldNtUserFindWindowEx))(hwndParent,hwndChild,pstrClassName,pstrWindowName,dwType);
  if Result=SafeHandle then Result:=0;
end;

function NewZwOpenProcess(ProcessHandle:PHandle; DesiredAccess:TAccessMask; ObjectAttributes:PObjectAttributes; ClientId:PClientId):NTSTATUS; stdcall;
var
 Temp:Handle;
begin
 Temp:=ProcessHandle^;
 if Temp=SafeId then
 Result:=0
 else
 Result:=TZwOpenProcess(pointer(OldZwOpenProcess))(ProcessHandle,DesiredAccess,ObjectAttributes, ClientId);
end;


function HookingHook: Integer; stdcall;
var
 uCr0cpu:dword;
begin
  if HookActive then
  begin
    Result:=Integer(False);
    Exit;
  end;

   //关闭写保护
   asm
      cli
      push  eax
      mov   eax, cr0
      mov   [uCr0cpu], eax
      and   eax, not 000010000h
      mov   cr0, eax
      pop   eax
   end;
    OldZwOpenProcess:=InterlockedExchange(SystemServiceName(ZwOpenProcessAddr),LONG(@NewZwOpenProcess));
    OldNtUserFindWindowEx:=InterlockedExchange(ShadowSystemServiceOrd($17a),LONG(@NewNtUserFindWindowEx));
   //  打开写保护
   asm
     push  eax
     mov   eax, [uCr0cpu]
     mov   cr0, eax
     pop   eax
     sti
   end;


  HookActive := True;

  Result := Integer(True);
end;


function HookingUnhook: Integer; stdcall;
var
 uCr0cpu:dword;
begin
  if not HookActive then
  begin
    Result:=Integer(False);
    Exit;
  end;

   //关闭写保护
   asm
      cli
      push  eax
      mov   eax, cr0
      mov   [uCr0cpu], eax
      and   eax, not 000010000h
      mov   cr0, eax
      pop   eax
   end;

  InterlockedExchange(SystemServiceName(ZwOpenProcessAddr),OldZwOpenProcess);
  InterlockedExchange(ShadowSystemServiceOrd($17a),OldNtUserFindWindowEx);
   //  打开写保护
   asm
     push  eax
     mov   eax, [uCr0cpu]
     mov   cr0, eax
     pop   eax
     sti
   end;

  HookActive := False;

  Result := Integer(True);
end;

procedure DoPub;
begin
  DbgPrint('%08x',ShadowSystemServiceOrd(0));
  DbgPrint('%08x',ShadowSystemServiceOrd(0)^);
end;

end.

For prevent some people do wrong with it, Only paste main functions
code:
//  Get a address offunction from export table
function GetImportFunAddr(lpImportAddr: Pointer): Pointer; stdcall;
begin
  Result := PPointer(PPointer(Cardinal(lpImportAddr) + 2)^)^;
end;

//  KeServiceDescriptorTable+ ofsset with function's name calculate
function SystemServiceName(AFunc: Pointer): PLONG; stdcall;
var
  lpKeServiceDescriptorTable: PServiceDescriptorEntry;
begin
  lpKeServiceDescriptorTable := GetImportFunAddr(@KeServiceDescriptorTable);
  Result := PLONG(Cardinal(lpKeServiceDescriptorTable^.ServiceTableBase) + (SizeOf(ULONG) * PULONG(ULONG(AFunc) + 1)^));
end;

//  KeServiceDescriptorTable+ offset of sequence number's name calculate
function SystemServiceOrd(iOrd: ULONG): PLONG; stdcall;
var
  lpKeServiceDescriptorTable: PServiceDescriptorEntry;
begin
  lpKeServiceDescriptorTable := GetImportFunAddr(@KeServiceDescriptorTable);
  Result := PLONG(PLONG(Cardinal(lpKeServiceDescriptorTable^.ServiceTableBase) + (SizeOf(ULONG) * iOrd)));
end;

function FindShadowTable:Pointer;  //XP Vesion
var
 lpKeServiceDescriptorTable:ULONG;
begin
 lpKeServiceDescriptorTable := ULONG(GetImportFunAddr(@KeServiceDescriptorTable));
 Result:=Pointer(lpKeServiceDescriptorTable-$40);
end;

function FindShadowTable2:Pointer;
var
 cPtr, pOpcode:ULONG;
 I:ULONG;
begin
  Result:=nil;
  cPtr:=ULONG(GetImportFunAddr(@KeAddSystemServiceTable));
  I:=cPtr;
  While (I<(cPtr+$1000)) Do
  begin
    if MmIsAddressValid(Pointer(I)) then
    begin
      if word(pointer(I)^)=$888d then
      begin
       Result:=PPointer(I+2)^;
       break
      end;
    end;
    I:=I+1;
  end;
end;

//Offset of sequence number's name
function ShadowSystemServiceOrd(iOrd: ULONG): PLONG; stdcall;
var
  lpKeServiceDescriptorTable:PShadowSrvDescriptorEntry;
begin
  lpKeServiceDescriptorTable :=FindShadowTable2;
  Result := PLONG(Cardinal(lpKeServiceDescriptorTable^.win32kTable.ServiceTableBase) + (SizeOf(ULONG) * iOrd));
end;

Wednesday, August 31, 2011

Hook Specials 23 : Talk two layers hook for SSDT API

Author:HSQ
Hook realy is art, In the fight to survive, Good jobs.
Here, Only talk thing of dispose , Non full code.

Code:

  // Two layers HOOK: 1.First install Inline hook when don't use SSDT HOOK
  ...
  SetInLineHookZwQueryDirectoryFile();
  SetInLineHookZwQuerySystemInformation();
  // Two layers HOOK: 2.Then install outer SSDT HOOK, Like this even if hook  recovered by other tools, Intimal hook work yet.
  InHookSSDTNativeAPI();
  ...
//////////////////////////////////////////////////////////////////////////////
   .....................
////////////////////// Do any thing //////////////////////////////////////////
  // Hide process
  if(NT_SUCCESS(ntStatus))
  {  ZWQUERYSYSTEMINFORMATION TempCheckInSSDTSpace=(ZWQUERYSYSTEMINFORMATION)SYSTEMSERVICE(ZwQuerySystemInformation);
    // Check whether SSDT hook is exist, Avoidance of repetition work; Of cause may repetition work,
    // Don't BSOD, Explain code robust ^-^.
    if(HookSSDTZwQuerySystemInformation!=TempCheckInSSDTSpace)
    {   // When onself ssdt hook is remove, Let's Inline Hook replace it to  continue work
      //if(0x81000000 > (ULONG)TempCheckInSSDTSpace)
      HideFileFromZwQuerySystemInformation(SystemInformationClass,SystemInformation);
      if (TempCheckInSSDTSpace != OldZwQuerySystemInformation)
      {   // If Inline hook already hook to layer space of ssdt, need check KIRQL, Then dusoise
          // for avert BSOD!
        if(DISPATCH_LEVEL >= KeGetCurrentIrql())
        //    Now can't gobbles up CPU times, If Safemon.sys distribute function ,          //maybe system resource use up. SSDT HOOK of SMM can't pass up, Let Inline hook stand up to
        // a kinds of test^-^
          DbgPrint("Rootkit: Hook Inline ZwQuerySystemInformation() Worked ok!\n");
          //
      }
      else
      {
          DbgPrint("Rootkit: Hook Inline ZwQuerySystemInformation() Worked ok!\n");
          //
      }   
    }
    else
    {
      DbgPrint("Rootkit: SSDT HOOK ZwQuerySystemInformation is exist, Inline Hook not need to do any thing any more!\n");
    }
  }
////////////////////// Do any thing //////////////////////////////////////////

Monday, August 29, 2011

Hook Specials 22 : Simple think of recover ssdt hook and FSD hook

Author:cradiator
 I read recover of FSD hook and SSDT hook these days, Past master already is tried of playing, So don't laughing me.

First is SDT hook.

Easy search 360superkiller of reverse by sudami, But mapping size calculate seem like wrong.

Recover paste my think.

1.ZwQuerySystermImformation is transmited 11 number's parameter.
2.Use attach to path to open disk files of ntfs.sys and fastfat.sys.
3.Depend PE format to get mapping base address on file(imageBase).
4.Search to set command of dispath path by condition code .

Disassemble ntfs.sys(fastfat.sys) with IDA, Watch code and opcode:
esi point structure of DriverObject, Opcode is:
c7 46 XX YY YY YY YY

c7 86 XX XX XX XX YY YY YY YY (XX is offset of esi ,YY is real function address)

So can search condition code for segment command:
After get command , Depend above structrue get dispatch index of IRP and original function of dispatch .
computational method of Real index :
Because ntfs.sys real loaded to place that different PE files stored, need relocate :

Come here get original path of dispatch function.

5. Part get with ObReferenceObjectByName,
L"\\FileSystem\\Ntfs"

L"\\FileSystem\\Fastfat"

Correspond to DriverObject.

Contrast address of DriverObject dispatch function and address of read pe file , If different to repair.

--------------------------------------------------------------------------------

SSDT HOOK
1.Identify ntoskrnl.exe or ntkrnlpa.exe is used  by kernel file of driver .
 When memory of computer than 512MB , Windows open PAE with ntkrnlpa.exe, Otherwise use ntoskrnl.exe, There isn't consider multi-core processor.

So we detect PAE whether open to confirm file name of kernel.
When 5 bit of cr4 is set to explain open PAE.
2. When map file of kernel , for example memoryg, Base address is krnlImgBase.
3. ZwQuerySystemInformation transmited 11 number parameter, Get structure array SYSTEM_MODULE_INFORMATION, Traversal array to get krnlBase of system kernel on memory base address .
4.Depend PE format to map to memory file, Get original SSDT.
The way: First get SSDT table address by system export, shave base address to get RVA of SSDT.
Seach section table of kernel file's memory map.
Seach where section is on rva of ssdt.
SSDT of memory mapping file = SSDT RVA  所在节 RVA + 所在节 RawOffset + krnlImgBase

5.Contrast original SSDT and current SSDT, Different to replace.
A question of relocate is must noticed on here.

code: