Example #1
0
void CNET_Manager::ReportNetHookingMustBeEnableBeforeAppStart()
{
    if (this->bIsNetApplication)
        DynamicMessageBoxInDefaultStation(NULL,_T(".NET hooking must be enable before application starting"),_T("Error"),MB_OK|MB_ICONERROR|MB_TOPMOST);
    else
        DynamicMessageBoxInDefaultStation(NULL,_T("No .NET Module currently loaded"),_T("Error"),MB_OK|MB_ICONERROR|MB_TOPMOST);
}
Example #2
0
//-----------------------------------------------------------------------------
// Name: InitializeApiInfo
// Object: Allocate memory and events associated to pAPIInfo
//         Notice1 : ApiAddress is not reset
//         Notice2 : Must be called only with not hooked or initialized pAPIInfo items
// Parameters :
//          in : API_INFO *pAPIInfo : pointer to APIInfo struct to initialize
//               TCHAR* pszModuleName  : module name
//               TCHAR* pszFunctionName : api name
// Return : 
//-----------------------------------------------------------------------------
BOOL __stdcall InitializeApiInfo(API_INFO *pAPIInfo,TCHAR* pszModuleName,TCHAR* pszFunctionName)
{
    pAPIInfo->MonitoringParamCount = 0;
    pAPIInfo->szModuleName=NULL;
    pAPIInfo->szAPIName=NULL;

    // create an event to signal end of hook
    pAPIInfo->evtEndOfHook=CreateEvent(NULL,FALSE,TRUE,NULL);
    if (!pAPIInfo->evtEndOfHook)
        return FALSE;

    // Initialize PARAMETER_INFOS structs with default values
    for (DWORD cnt=0;cnt<MAX_PARAM;cnt++)
    {
        memset(&pAPIInfo->ParamList[cnt],0,sizeof(PARAMETER_INFOS));
        // by default put all params to unknown
        pAPIInfo->ParamList[cnt].dwType=PARAM_UNKNOWN;
    }

    //////////////////////////////////////
    // copy module name
    //////////////////////////////////////
    pAPIInfo->szModuleName = (TCHAR*)HeapAlloc(ApiOverrideHeap, 0, (_tcslen(pszModuleName) + 1)*sizeof(TCHAR));
    if (!pAPIInfo->szModuleName)
    {
#if 0
        DynamicMessageBoxInDefaultStation(NULL,_T("Memory allocation error"),_T("Error"),MB_OK|MB_ICONERROR|MB_TOPMOST);
#endif
        return FALSE;
    }
    _tcscpy(pAPIInfo->szModuleName, pszModuleName);

    //////////////////////////////////////
    // copy API name
    //////////////////////////////////////
    pAPIInfo->szAPIName = (TCHAR*)HeapAlloc(ApiOverrideHeap, 0, (_tcslen(pszFunctionName) + 1)*sizeof(TCHAR));
    if (!pAPIInfo->szAPIName)
    {
#if 0
        DynamicMessageBoxInDefaultStation(NULL,_T("Memory allocation error"),_T("Error"),MB_OK|MB_ICONERROR|MB_TOPMOST);
#endif
        return FALSE;
    }
    _tcscpy(pAPIInfo->szAPIName, pszFunctionName);

    return TRUE;
}
//-----------------------------------------------------------------------------
// Name: ShowBadRegisterValueMessage
// Object: show error messagebox with register name
// Parameters :
//     in  : TCHAR* pszRegisterName : use on error to display a friendly user message error
//     out : 
//     return : 
//-----------------------------------------------------------------------------
void CRegistersUserInterface::ShowBadRegisterValueMessage(TCHAR* pszRegisterName)
{
    if (!pszRegisterName)
        return;
    TCHAR psz[MAX_PATH];
    _tcscpy(psz,_T("Bad "));
    _tcscat(psz,pszRegisterName);
    _tcscat(psz,_T(" Register Value"));
    DynamicMessageBoxInDefaultStation(this->hWndDialog,psz,_T("Error"),MB_OK|MB_ICONERROR|MB_TOPMOST);
}
//-----------------------------------------------------------------------------
// Name: Init
// Object: vars init. Called at WM_INITDIALOG
// Parameters :
//     in  : 
//     out :
//     return : 
//-----------------------------------------------------------------------------
void CCallStackUserInterface::Init(HWND hWndDialog)
{
    this->hWndDialog=hWndDialog;

    // associate object to window handle
    DynamicSetWindowLongPtr(hWndDialog,GWLP_USERDATA,(LONG)this);


    // parse call stack

    DWORD Cnt=0;
    PBYTE Ebp;
    PBYTE PreviousEbp;
    PBYTE RetAddress;
    BOOL  ShouldLog;
    HMODULE CallingModuleHandle;
    CLinkList CallList(sizeof(CALLSTACK_ITEM_INFO_TEMP));


    // if we have to get call stack 
    CALLSTACK_ITEM_INFO_TEMP CallStackInfo;
    PBYTE PreviousRetAddress;
    BOOL  SnapshotTaked=FALSE;
    API_HANDLER_TLS_DATA* pTlsData;
    CLinkListItem* pItem;
    DWORD CallInstructionSize;

    Ebp=this->CallerEbp;
    RetAddress=0;
    PreviousRetAddress=0;
    pItem=pLinkListTlsData->Tail;

    if(IsBadReadPtr(Ebp,REGISTER_BYTE_SIZE))
    {
        PreviousEbp = 0;
    }
    else
    {
        PreviousEbp=*(PBYTE*)(Ebp);
    }

EbpParsing:
    for(;;) 
    {
        if(pItem)
        {
            pTlsData=(API_HANDLER_TLS_DATA*)pItem->ItemData;
            if (Ebp>=(PBYTE)pTlsData->OriginalRegisters.ebp)
            {
                // assume current log is traced as a return value
                // (check case of no ebp change callee)
                if (PreviousRetAddress)
                {
                    if (pTlsData->pAPIInfo->HookType==HOOK_TYPE_NET)
                    {
                        if ( (PreviousRetAddress<(PBYTE)pTlsData->pAPIInfo->APIAddress)
                            || (PreviousRetAddress>(PBYTE)pTlsData->pAPIInfo->APIAddress+pNetManager->GetNetCompiledFunctionSize((PBYTE)pTlsData->pAPIInfo->APIAddress))
                            )
                        {
                            RetAddress=(PBYTE)pTlsData->pAPIInfo->APIAddress;
                            // avoid infinite loop
                            PreviousRetAddress=(PBYTE)pTlsData->pAPIInfo->APIAddress;
                            // avoid ebp walk
                            goto LogFrame;
                        }
                    }
                    else
                    {
                        // we got no way to get function size (don't check for pdb file).
                        // "hope" that function size is less than 4096 bytes. 
                        // Notice : we can miss a function call (if callee is located between function start and function start + 4096)
                        //          or we can report the same call twice (if function size is more than 4096)
                        if ( (PreviousRetAddress<(PBYTE)pTlsData->pAPIInfo->APIAddress)
                            || (PreviousRetAddress>(PBYTE)pTlsData->pAPIInfo->APIAddress+4096)
                            )
                        {
                            RetAddress=(PBYTE)pTlsData->pAPIInfo->APIAddress;
                            // avoid infinite loop
                            PreviousRetAddress=(PBYTE)pTlsData->pAPIInfo->APIAddress;
                            // avoid ebp walk
                            goto LogFrame;
                        }
                    }
                }
                // log current log ret value
                Ebp=(PBYTE)pTlsData->OriginalRegisters.ebp;
                // fill return address
                RetAddress=pTlsData->OriginalReturnAddress;
                // remove current item
                pItem=pItem->PreviousItem;
                // avoid ebp walk
                goto LogFrame;
            }
        }

        // return address is at current ebp+REGISTER_BYTE_SIZE
        // so get it
        if(IsBadReadPtr(Ebp+REGISTER_BYTE_SIZE,REGISTER_BYTE_SIZE))
            break;
        PreviousRetAddress=RetAddress;
        RetAddress=*(PBYTE*)(Ebp+REGISTER_BYTE_SIZE);
        if (IsBadCodePtr((FARPROC)RetAddress))
            break;
        if(IsBadReadPtr(Ebp,REGISTER_BYTE_SIZE))
            break;

        // get previous ebp (call -1 ebp)
        PreviousEbp=*(PBYTE*)(Ebp);// can throw hardware exception even IsBadReadPtr on application closing

        // if no previous ebp
        if (IsBadReadPtr(PreviousEbp,REGISTER_BYTE_SIZE))
            break;

        // stack coherence checking : 
        // function having PreviousEbp has been called by function having EBP (we walk stack backward)
        // so PreviousEbp MUSTE BE greater or equal to EBP
        // and there if it's equal, we can't guess previous function ebp --> we have to stop
        if (Ebp>=PreviousEbp)
            break; // the stack crawling failure checking at end of for will restore correct ebp

        // update ebp
        Ebp=PreviousEbp;


        if(pItem)
        {
            pTlsData=(API_HANDLER_TLS_DATA*)pItem->ItemData;
            if (Ebp>=(PBYTE)pTlsData->OriginalRegisters.ebp)
            {
                continue;
            }
        }
LogFrame:
        // get pointer to parameters (params are at ebp+2*REGISTER_BYTE_SIZE for func pushing ebp)
        // ebp was already updated to the caller ebp
        // it's interesting to link retAddress with previous ebp parameters, because we get caller function with caller function parameters
        CallStackInfo.ParametersPointer=(PBYTE)(Ebp+2*REGISTER_BYTE_SIZE); 


        // get return address
        CallStackInfo.Address=RetAddress;

        // get address relative address and calling module name
        CallStackInfo.RelativeAddress=0;
        if (!pModulesFilters->GetModuleNameAndRelativeAddressFromCallerAbsoluteAddress(
            CallStackInfo.Address,
            &CallingModuleHandle,
            CallStackInfo.pszModuleName,
            &CallStackInfo.RelativeAddress,
            &ShouldLog,
            FALSE,TRUE
            ))
        {
            // caller address seems to come from a module which don't belong to process, try again taking a snapshot (do it only once)
            // it could be the case in case of injected memory or not rejitted .NET code
            if (!SnapshotTaked)
            {
                SnapshotTaked=TRUE;
                pModulesFilters->GetModuleNameAndRelativeAddressFromCallerAbsoluteAddress(
                    CallStackInfo.Address,
                    &CallingModuleHandle,
                    CallStackInfo.pszModuleName,
                    &CallStackInfo.RelativeAddress,
                    &ShouldLog,
                    TRUE,TRUE
                    );
            }
        }
        CallInstructionSize=CCallInstructionSizeFromReturnAddress::GetCallInstructionSizeFromReturnAddress(RetAddress);

        // adjust return address to call addr
        if (CallStackInfo.RelativeAddress)
            CallStackInfo.Address-=CallInstructionSize;

        if ((ULONG_PTR)CallStackInfo.RelativeAddress>CallInstructionSize)
            CallStackInfo.RelativeAddress-=CallInstructionSize;
        else
            CallStackInfo.RelativeAddress=0;
        // add item to list
        CallList.AddItem(&CallStackInfo);
    }
    // in case stack crawling fails, as we manage a small trace for hooks,
    // use our trace to get previous ebp and start stack walking again
    if (pItem)
    {
        pTlsData=(API_HANDLER_TLS_DATA*)pItem->ItemData;
        Ebp=(PBYTE)pTlsData->OriginalRegisters.ebp;
        goto EbpParsing;
    }


    if (CallList.GetItemsCount()==0)
    {
        DynamicMessageBoxInDefaultStation(this->hWndDialog,_T("Can't get more than return address"),_T("Information"),MB_OK|MB_ICONINFORMATION|MB_TOPMOST);
        this->Close();
        return;
    }

    TCHAR* psz=new TCHAR[(CallList.GetItemsCount()+1)*(MAX_SIZEOF_ONE_STACK_ITEM_REPRESENTATION+30*CallStackEbpRetrievalSize/sizeof(PBYTE))];
    TCHAR pszOneCall[MAX_SIZEOF_ONE_STACK_ITEM_REPRESENTATION];
    TCHAR* pszParams=new TCHAR[30*CallStackEbpRetrievalSize/sizeof(PBYTE)];
    TCHAR* pName;
    CALLSTACK_ITEM_INFO_TEMP* pCallStackInfo;
    DWORD AccessibleMemorySize;

    *psz=0;

    CPE** PeArray=new CPE*[CallList.GetItemsCount()];
    CPE*  pPe;
    TCHAR PeFileName[MAX_PATH];
    TCHAR FunctionName[MAX_PATH];
    DWORD PeArrayUsedSize=0;
    DWORD Cnt2;
    DWORD CallingModuleNameSize;

    // for each item of the list --> for each call
    
    for (pItem=CallList.Head;pItem; pItem=pItem->NextItem)
    {
        pCallStackInfo=(CALLSTACK_ITEM_INFO_TEMP*)pItem->ItemData;


        ////////////////////////////
        // try to get calling function name
        ////////////////////////////
        *FunctionName=0;
        CallingModuleNameSize=(DWORD)_tcslen(pCallStackInfo->pszModuleName);
        if (CallingModuleNameSize>4)
        {
            if (_tcsicmp(&pCallStackInfo->pszModuleName[CallingModuleNameSize-4],_T(".dll"))==0)
            {

                // check if PE of dll has already been parsed
                pPe=NULL;
                for (Cnt2=0;Cnt2<PeArrayUsedSize;Cnt2++)
                {
                    PeArray[Cnt2]->GetFileName(PeFileName);
                    if (_tcsicmp(PeFileName,pCallStackInfo->pszModuleName)==0)
                    {
                        pPe=PeArray[Cnt2];
                        break;
                    }
                }
                if(pPe==NULL)
                {
                    // pe has not been parsed
                    // --> parse it's export table
                    pPe=new CPE(pCallStackInfo->pszModuleName);
                    pPe->Parse(TRUE,FALSE);

                    // add pPe to PeArray
                    PeArray[PeArrayUsedSize]=pPe;
                    PeArrayUsedSize++;
                }


                this->TryToGetDllFunctionName(pPe,
                    (PBYTE)pCallStackInfo->RelativeAddress,
                    FunctionName,
                    MAX_PATH-1
                    );
            }
        }

        // address and module name
        pName=_tcsrchr(pCallStackInfo->pszModuleName,'\\');
        if (pName)
        {
            // end path
            *pName=0;
            // point to module name only
            pName++;

            _stprintf(pszOneCall,_T("0x%p    %s+0x%p    (%s)\r\n"),pCallStackInfo->Address,pName,pCallStackInfo->RelativeAddress,pCallStackInfo->pszModuleName);
        }
        else
            _stprintf(pszOneCall,_T("0x%p    %s+0x%p\r\n"),pCallStackInfo->Address,pCallStackInfo->pszModuleName,pCallStackInfo->RelativeAddress);

        ////////////////////////////
        // add function name
        ////////////////////////////
        if (*FunctionName)
        {
            _tcscat(pszOneCall,_T("\t\tMAY originated from "));
            _tcscat(pszOneCall,FunctionName);
            _tcscat(pszOneCall,_T("("));
        }
        else
            _tcscat(pszOneCall,_T("\t\tOriginated from ??? ("));

        _tcscat(psz,pszOneCall);


        // call stack
        AccessibleMemorySize=CallStackEbpRetrievalSize;
        // reducing size memory checker loop
        while(   IsBadReadPtr(pCallStackInfo->ParametersPointer,AccessibleMemorySize)
            && (AccessibleMemorySize !=0)
            )
        {
            if (AccessibleMemorySize>REGISTER_BYTE_SIZE)// avoid buffer underflow
                AccessibleMemorySize-=REGISTER_BYTE_SIZE;
            else
                AccessibleMemorySize=0;
        }
        // if there's valid data
        if (AccessibleMemorySize)
        {
            for (Cnt=0;Cnt<AccessibleMemorySize/REGISTER_BYTE_SIZE;Cnt++)
            {
                // if not first element
                if (Cnt>0)
                    // add splitter
                    _tcscat(psz,_T(", "));
                // add param content
                //_stprintf(pszParams,_T("Param%u=0x%p"),Cnt+1,*(PBYTE*)&pCallStackInfo->ParametersPointer[Cnt*REGISTER_BYTE_SIZE]);
                _stprintf(pszParams,_T("0x%p"),*(PBYTE*)&pCallStackInfo->ParametersPointer[Cnt*REGISTER_BYTE_SIZE]);
                _tcscat(psz,pszParams);
            }
            _tcscat(psz,_T(")\r\n"));
        }

    }

    // free memory
    for (Cnt2=0;Cnt2<PeArrayUsedSize;Cnt2++)
    {
        delete PeArray[Cnt2];
    }
    delete[] PeArray;

    delete[] pszParams;

    DynamicSendMessage(DynamicGetDlgItem(this->hWndDialog,IDC_EDIT_CALL_STACK),WM_SETTEXT,0,(LPARAM)psz);

    delete[] psz;

}