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...

No comments:

Post a Comment