text section of MFC in memory changes everytime

248 Views Asked by At

I am trying to implement self integrity check in MFC exe.

Ref : - Tamper Aware and Self Healing Code : Codeproject

I dumped text section

ofstream myfile;
myfile.open ("textsec.bin");
myfile.write((const char*)pCodeStart,dwCodeSize);
myfile.close();

every time its different so hash for it is also different. Please Help

I want to check text i.e. code section in memory should be same as that in file present on disk. So we can be sure that our exe file in memory is not patched. we can use while distributing product exe.

We will get start of code section in memory by

 VOID ImageInformation( HMODULE& hModule, PVOID& pVirtualAddress,
                       PVOID& pCodeStart, SIZE_T& dwCodeSize,
                       PVOID& pCodeEnd )
{
    const UINT PATH_SIZE = 2 * MAX_PATH;
    TCHAR szFilename[ PATH_SIZE ] = { 0 };    

    __try {

        /////////////////////////////////////////////////
        /////////////////////////////////////////////////
        if( 0 == GetModuleFileName( NULL, szFilename, PATH_SIZE ) )
        {
            std::tcerr << _T("Error Retrieving Process Filename");
            std::tcerr << std::endl;
            __leave;
        }

        hModule = GetModuleHandle( szFilename );
        if( NULL == hModule )
        {
            std::tcerr << _T("Error Retrieving Process Module Handle");
            std::tcerr << std::endl;
            __leave;
        }

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////
        PIMAGE_DOS_HEADER pDOSHeader = NULL;
        pDOSHeader = static_cast<PIMAGE_DOS_HEADER>( (PVOID)hModule );
        if( pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE )
        {
            std::tcerr << _T("Error - File is not EXE Format");
            std::tcerr << std::endl;
            __leave;
        }

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////
        PIMAGE_NT_HEADERS pNTHeader = NULL;
        pNTHeader = reinterpret_cast<PIMAGE_NT_HEADERS>(
            (PBYTE)hModule + pDOSHeader->e_lfanew );
        if( pNTHeader->Signature != IMAGE_NT_SIGNATURE )
        {
            std::tcerr << _T("Error - File is not PE Format") << std::endl;
            __leave;
        }

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////
        PIMAGE_FILE_HEADER pFileHeader = NULL;
        pFileHeader = reinterpret_cast<PIMAGE_FILE_HEADER>(
            (PBYTE)&pNTHeader->FileHeader );

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////
        PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
        pOptionalHeader = reinterpret_cast<PIMAGE_OPTIONAL_HEADER>(
            (PBYTE)&pNTHeader->OptionalHeader );

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////
        if( IMAGE_NT_OPTIONAL_HDR32_MAGIC !=
            pNTHeader->OptionalHeader.Magic )
        {
            std::tcerr << _T("Error - File is not 32 bit") << std::endl;
            __leave;
        }

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////
        PIMAGE_SECTION_HEADER pSectionHeader = NULL;
        pSectionHeader = reinterpret_cast<PIMAGE_SECTION_HEADER>(
            (PBYTE)&pNTHeader->OptionalHeader +
            pNTHeader->FileHeader.SizeOfOptionalHeader );

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////
        const CHAR TEXT[] = ".text";
        const CHAR BSSTEXT[] = ".textbss";
        UINT nSectionCount = pNTHeader->FileHeader.NumberOfSections;
        CHAR szSectionName[ IMAGE_SIZEOF_SHORT_NAME + 1 ];
        szSectionName[ IMAGE_SIZEOF_SHORT_NAME ] = '\0';
        for( UINT i = 0; i < nSectionCount; i++ )
        {
            memcpy( szSectionName, pSectionHeader->Name,
                    IMAGE_SIZEOF_SHORT_NAME );

            if( 0 == strncmp( TEXT, szSectionName,
                              IMAGE_SIZEOF_SHORT_NAME ) )
            {
                std::tcout << std::endl;
                break;
            }

            pSectionHeader++;
        }

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////
        if( 0 != strncmp( TEXT, szSectionName, IMAGE_SIZEOF_SHORT_NAME ) )
        {
            std::tcerr << _T("Error - Unable to locate ");
            std::cerr << TEXT;
            std::tcerr << _T(" TEXT") << std::endl;
            __leave;
        }

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////
        pVirtualAddress = (PVOID)(pSectionHeader->VirtualAddress);

        dwCodeSize = pSectionHeader->Misc.VirtualSize;

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////        
        pCodeStart = (PVOID)(((PBYTE)hModule) +
                     (SIZE_T)((PBYTE)pVirtualAddress) );

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////                      
        pCodeEnd = (PVOID)((PBYTE)pCodeStart + dwCodeSize );                      
    }

    __except( EXCEPTION_EXECUTE_HANDLER ) {
        std::tcerr << std::endl << _T("Caught Exception") << std::endl;
    }
}      

Now we can calculate hash of code section

CalculateImageHash( pCodeStart, dwCodeSize, cbCalculatedImageHash );

then we compare with cbExpectedImageHash. cbExpectedImageHash is predefined global

  if( 0 == memcmp( cbExpectedImageHash, cbCalculatedImageHash,
        CryptoPP::SHA224::DIGESTSIZE ) )
    {
        std::tcout << _T("Image is verified.") << std::endl;
    }

In MFC cbCalculatedImageHash is every time different . :( but not in console app.

cbExpectedImageHash and cbCalculatedImageHash are globel .

here is full code of my dialog

// UserAppDlg.cpp : implementation file
//

#include "stdafx.h"
#include "UserApp.h"
#include "UserAppDlg.h"
#include "sha.h"        // SHA
#include "hex.h"        // HexEncoder
#include "files.h"      // FileSink
#include "filters.h"    // StringSink
#include "gzip.h"
using namespace std;
#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CAboutDlg dialog used for App About
// we can add cbExpectedImageHash new values if we get calcualted hash same every
BYTE cbExpectedImageHash[ CryptoPP::SHA224::DIGESTSIZE ] =
{ 
    0xBA, 0x71, 0x29, 0xD8, 0x79, 0x4E, 0xA3, 0x5A, 0x2C, 0xE0
    , 0xC5, 0x3A, 0x68, 0x9E, 0xE8, 0x29, 0x09, 0x44, 0xFA, 0x71
    , 0xAF, 0xDB,0x3E,0x88,0xAD,0x65,0x67,0x78
}; 

BYTE cbCalculatedImageHash[ CryptoPP::SHA224::DIGESTSIZE ] ; 

class CAboutDlg : public CDialog
{
public:
    CAboutDlg();

// Dialog Data
    enum { IDD = IDD_ABOUTBOX };

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()


// CUserAppDlg dialog




CUserAppDlg::CUserAppDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CUserAppDlg::IDD, pParent)
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CUserAppDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CUserAppDlg, CDialog)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()


// CUserAppDlg message handlers
int CUserAppDlg::ImageInformation( HMODULE& hModule, PVOID& pVirtualAddress,
                       PVOID& pCodeStart, SIZE_T& dwCodeSize,
                       PVOID& pCodeEnd )
{
    const UINT PATH_SIZE = 2 * MAX_PATH;
    TCHAR szFilename[ PATH_SIZE ] = { 0 };    

    __try {

        /////////////////////////////////////////////////
        /////////////////////////////////////////////////
        if( 0 == GetModuleFileName( NULL, szFilename, PATH_SIZE ) )
        {
           // std::tcerr << _T("Error Retrieving Process Filename");
           // std::tcerr << std::endl;
            __leave;
        }

        hModule = GetModuleHandle( szFilename );
        if( NULL == hModule )
        {
           // std::tcerr << _T("Error Retrieving Process Module Handle");
           // std::tcerr << std::endl;
            __leave;
        }

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////
        PIMAGE_DOS_HEADER pDOSHeader = NULL;
        pDOSHeader = static_cast<PIMAGE_DOS_HEADER>( (PVOID)hModule );
        if( pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE )
        {
           // std::tcerr << _T("Error - File is not EXE Format");
           // std::tcerr << std::endl;
            __leave;
        }

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////
        PIMAGE_NT_HEADERS pNTHeader = NULL;
        pNTHeader = reinterpret_cast<PIMAGE_NT_HEADERS>(
            (PBYTE)hModule + pDOSHeader->e_lfanew );
        if( pNTHeader->Signature != IMAGE_NT_SIGNATURE )
        {
           // std::tcerr << _T("Error - File is not PE Format") << std::endl;
            __leave;
        }

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////
        PIMAGE_FILE_HEADER pFileHeader = NULL;
        pFileHeader = reinterpret_cast<PIMAGE_FILE_HEADER>(
            (PBYTE)&pNTHeader->FileHeader );

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////
        PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
        pOptionalHeader = reinterpret_cast<PIMAGE_OPTIONAL_HEADER>(
            (PBYTE)&pNTHeader->OptionalHeader );

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////
        if( IMAGE_NT_OPTIONAL_HDR32_MAGIC !=
            pNTHeader->OptionalHeader.Magic )
        {
           // std::tcerr << _T("Error - File is not 32 bit") << std::endl;
            __leave;
        }

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////
        PIMAGE_SECTION_HEADER pSectionHeader = NULL;
        pSectionHeader = reinterpret_cast<PIMAGE_SECTION_HEADER>(
            (PBYTE)&pNTHeader->OptionalHeader +
            pNTHeader->FileHeader.SizeOfOptionalHeader );

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////
        const CHAR TEXT[] = ".text";
        const CHAR BSSTEXT[] = ".textbss";
        UINT nSectionCount = pNTHeader->FileHeader.NumberOfSections;
        CHAR szSectionName[ IMAGE_SIZEOF_SHORT_NAME + 1 ];
        szSectionName[ IMAGE_SIZEOF_SHORT_NAME ] = '\0';
        for( UINT i = 0; i < nSectionCount; i++ )
        {
            memcpy( szSectionName, pSectionHeader->Name,
                    IMAGE_SIZEOF_SHORT_NAME );

            if( 0 == strncmp( TEXT, szSectionName,
                              IMAGE_SIZEOF_SHORT_NAME ) )
            {
               // std::tcout << std::endl;
                break;
            }

            pSectionHeader++;
        }

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////
        if( 0 != strncmp( TEXT, szSectionName, IMAGE_SIZEOF_SHORT_NAME ) )
        {
           // std::tcerr << _T("Error - Unable to locate ");
           // std::cerr << TEXT;
           // std::tcerr << _T(" TEXT") << std::endl;
            __leave;
        }

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////
        pVirtualAddress = (PVOID)(pSectionHeader->VirtualAddress);

        dwCodeSize = pSectionHeader->Misc.VirtualSize;

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////        
        pCodeStart = (PVOID)(((PBYTE)hModule) +
                     (SIZE_T)((PBYTE)pVirtualAddress) );

        /////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////                      
        pCodeEnd = (PVOID)((PBYTE)pCodeStart + dwCodeSize );                      
    }

    __except( EXCEPTION_EXECUTE_HANDLER ) {
       // std::tcerr << std::endl << _T("Caught Exception") << std::endl;
    }
    return 0;
}     

    void CUserAppDlg::CalculateImageHash( PVOID pCodeStart, SIZE_T dwCodeSize,
        PBYTE pcbDigest )
    {
        CryptoPP::SHA224 hash;

        hash.Update( (PBYTE)pCodeStart, dwCodeSize );
        hash.Final( pcbDigest );    
    }  
BOOL CUserAppDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    // Add "About..." menu item to system menu.

    HMODULE hModule = NULL;
    PVOID   pVirtualAddress = NULL;
    PVOID   pCodeStart = NULL;
    PVOID   pCodeEnd = NULL;    
    SIZE_T  dwCodeSize = 0;

     ImageInformation( hModule, pVirtualAddress, pCodeStart,
                      dwCodeSize, pCodeEnd ); 
    ofstream myfile;
    myfile.open ("textsec.bin"); //textsec.bin changes everytime
    myfile.write((const char*)pCodeStart,dwCodeSize);
    myfile.close(); 

    CalculateImageHash( pCodeStart, dwCodeSize, cbCalculatedImageHash );     //cbCalculatedImageHash changes everytime
    myfile.open ("CalculateImageHash.bin");
    myfile.write((const char*)cbCalculatedImageHash,CryptoPP::SHA224::DIGESTSIZE);
    myfile.close();


    // IDM_ABOUTBOX must be in the system command range.
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        CString strAboutMenu;
        strAboutMenu.LoadString(IDS_ABOUTBOX);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // Set the icon for this dialog.  The framework does this automatically
    //  when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE);         // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon

    // TODO: Add extra initialization here

    return TRUE;  // return TRUE  unless you set the focus to a control
}

void CUserAppDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialog::OnSysCommand(nID, lParam);
    }
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CUserAppDlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // device context for painting

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

        // Center icon in client rectangle
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // Draw the icon
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialog::OnPaint();
    }
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CUserAppDlg::OnQueryDragIcon()
{
    return static_cast<HCURSOR>(m_hIcon);
}
0

There are 0 best solutions below