0

我有一个获取 MFC 应用程序句柄的 Win32 应用程序。我的目标是强制 MFC 程序不显示 ASSERT 错误消息框。

基本上,我制作了一个原型,允许我的 Win32 应用程序强制 MFC 应用程序显示一个消息框,只是为了检查这个想法是否可行。现在我需要强制 MFC 应用程序不显示此类 ASSERT 错误消息框。

那可能吗?

4

2 回答 2

1

令我非常遗憾的是我错过了那个代码。但是,您仍然可以手动完成。

  1. 下载并安装CFF 资源管理器
  2. 用它打开你的exe文件
  3. 在部分资源管理器中选择导入目录。
  4. 在导入的dll列表中选择USER32.dll
  5. 选择 MessageBoxA 或 MessageBoxW。编辑 OFT 列。在那里写一些“无害”功能的OFT。我以 GetWindowRect 为例。

在此处输入图像描述

如果您仍然希望应用程序执行此操作,我有一个功能非常相似的代码。它只是将您的 dll 嵌入到导入表中。您既可以编辑它以达到想要的结果,也可以使用它将 MessageBoxW 调用重定向到您的处理程序。

#include <windows.h>
#include <tchar.h>
#include "stdafx.h"
#include <stdio.h>

DWORD MapFile(HANDLE &FileMapping, LPVOID &FileBegin, const _TCHAR *exeName) {
    HANDLE File = CreateFile(exeName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
                                    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    if (File == INVALID_HANDLE_VALUE) {
        return GetLastError();
    }   

    FileMapping = CreateFileMapping(File, NULL, PAGE_READWRITE, 0, 0, NULL);
    CloseHandle(File);

    if (!FileMapping) {
        return GetLastError();
    }

    FileBegin = MapViewOfFile(FileMapping, FILE_MAP_WRITE, 0, 0, 0);
    if (!FileBegin) {
        CloseHandle(FileMapping);
        return GetLastError();
    }

    return 0;
}

DWORD RewriteImportTable(const HANDLE FileMapping, const LPVOID FileBegin, const _TCHAR *dllName, const _TCHAR *funcName, DWORD &finalResult) {

    IMAGE_DOS_HEADER* dos_header;
    IMAGE_FILE_HEADER* file_header;
    IMAGE_OPTIONAL_HEADER* optional_header;
    IMAGE_SECTION_HEADER* section_header;

    // Counting PE-header offset
    dos_header = (IMAGE_DOS_HEADER*) FileBegin;
    DWORD PEOffset = dos_header->e_lfanew;
    file_header = (IMAGE_FILE_HEADER*) ((DWORD)FileBegin + PEOffset); // file_header must reference "PE\0"

    // Checking if we work with PE
    _TCHAR* PEString = "PE\0";
    if (_tcscmp(PEString, (const _TCHAR*) file_header) != 0) {
        printf("This file is not Portable Executable!\n");
        return 666;
    }

    file_header = (IMAGE_FILE_HEADER *)((DWORD)file_header + sizeof(DWORD)); // Ignoring PE
    optional_header = (IMAGE_OPTIONAL_HEADER *)((DWORD)file_header + sizeof(IMAGE_FILE_HEADER));

    // Finding import section
    DWORD ImportRVA = optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
    int sectNum = -1;

    // Finding import table
    section_header = (IMAGE_SECTION_HEADER*) ((DWORD) optional_header + sizeof(IMAGE_OPTIONAL_HEADER));

    for (int i = 0; i < (file_header->NumberOfSections); i++) {
        if (ImportRVA < (section_header->VirtualAddress)) {
            section_header--;
            sectNum = i-1;
            break;  
        }
        section_header++;
    }

    if (sectNum == -1) {
        printf("This program uses no external libraries! (strange)\n");
        return 666;
    }

    // Getting address of section folowing import section
    section_header++;
    DWORD SectionNextToImportBegin = (DWORD)FileBegin + section_header->PointerToRawData;
    section_header--;

    // Getting the address of the import table
    LPVOID ImportSectionBegin = (LPVOID) ((DWORD)FileBegin + section_header->PointerToRawData);

    // Counting the import table offset in the import section
    LPVOID ImportTable = (LPVOID)((DWORD)ImportSectionBegin + (ImportRVA - section_header->VirtualAddress));

    IMAGE_IMPORT_DESCRIPTOR *DLLInfo = (IMAGE_IMPORT_DESCRIPTOR*) ImportTable;
    LPVOID DLLName;
    DWORD DLLCounter = 0;

    while (DLLInfo->Name != NULL) {
        DLLCounter++;
        DLLName = (LPVOID) ((DWORD)ImportSectionBegin + ((DWORD)DLLInfo->Name - section_header->VirtualAddress));
        DLLInfo++;
    }

    printf("Number of imported libraries: %d\n", DLLCounter);

    // Counting the size of the future import table
    DWORD newImportTableSize = sizeof(IMAGE_IMPORT_DESCRIPTOR) * (DLLCounter + 2);

    // Finding the end of the import section
    LPVOID pos = (LPVOID) (SectionNextToImportBegin - 1);

    DWORD maxFree = 0;
    DWORD prevPtr;
    LPVOID freePtr = NULL;

    // Searching for the free place
    while (pos >= ImportSectionBegin) {
        if (*(BYTE*)pos == 0) {
            prevPtr = (DWORD) pos;

            while (*(BYTE*)pos == 0) {
                pos = (LPVOID) ((DWORD)pos - 1);
            }

            if (((DWORD)prevPtr - (DWORD)pos) > maxFree) {
                maxFree = ((DWORD)prevPtr - (DWORD)pos);
                freePtr = (LPVOID) ((DWORD)pos + 1);
            }
        }
        pos = (LPVOID) ((DWORD)pos - 1);
    }

    // Modifying pointer: it can refer the tailing zero of some stucture
    freePtr = (LPVOID) ((LPDWORD)freePtr + 1);
    maxFree -= 4;

    // Checking if we have enough space in the import section
    if (maxFree < newImportTableSize) {
        printf("Not enough free space in Import Section\n");
        return 666;
    }

    printf("Injecting new library...\n");

    // Copying old import table on the new place
    memcpy(freePtr, ImportTable, sizeof(IMAGE_IMPORT_DESCRIPTOR) * DLLCounter);

    // Saving everithing we need on the old place
    typedef struct {
        DWORD ZeroDword;
        DWORD IAT;
        DWORD IATEnd;
    } MeanStruct;

    MeanStruct patch;
    patch.ZeroDword = NULL; // this is \0 for dll name
    patch.IAT = ImportRVA + _tcslen(dllName) + sizeof(MeanStruct); // RVA to where list of functions begins
    patch.IATEnd = NULL;

    WORD Hint = 0;

    IMAGE_IMPORT_BY_NAME myName;
    myName.Hint = 0x00;
    myName.Name[0] = 0x00;

    LPDWORD zeroPtr = (LPDWORD) ImportTable;
    memcpy(zeroPtr, dllName, _tcslen(dllName));
    zeroPtr = (LPDWORD) ((DWORD)zeroPtr + strlen(dllName));
    memcpy(zeroPtr, &patch, sizeof(patch));
    zeroPtr = (LPDWORD) ((DWORD)zeroPtr + sizeof(patch));

    finalResult = (DWORD)zeroPtr - (DWORD)ImportSectionBegin + section_header->VirtualAddress;

    memcpy(zeroPtr, &Hint, sizeof(WORD));
    zeroPtr = (LPDWORD) ((DWORD)zeroPtr + sizeof(WORD));
    memcpy(zeroPtr, funcName, strlen(funcName) + 1); // we have no need to write \0 into the end - this is already free space
    zeroPtr = (LPDWORD) ((DWORD)zeroPtr + strlen(funcName) + 1);
    memcpy(zeroPtr, &myName, sizeof(IMAGE_IMPORT_BY_NAME));

    // filling info about dll
    IMAGE_IMPORT_DESCRIPTOR myDLL;

    // counting RVA for IMAGE_IMPORT_BY_NAME: 
    DWORD IIBN_Table = ImportRVA + strlen(dllName) + sizeof(DWORD);

    // function name pointer
    myDLL.Characteristics = IIBN_Table;
    myDLL.TimeDateStamp = NULL;
    myDLL.ForwarderChain = NULL;
    // dll name pointer
    myDLL.Name = ImportRVA;
    myDLL.FirstThunk = IIBN_Table;

    // writting dll info into the new import table
    LPVOID oldFreePtr = freePtr;
    freePtr = (LPVOID) ((DWORD)freePtr + sizeof(IMAGE_IMPORT_DESCRIPTOR) * DLLCounter);
    memcpy(freePtr, &myDLL, sizeof(IMAGE_IMPORT_DESCRIPTOR));

    // creating list tail
    myDLL.Characteristics = NULL;
    myDLL.TimeDateStamp = NULL;
    myDLL.ForwarderChain = NULL;
    myDLL.Name = NULL;
    myDLL.FirstThunk = NULL;

    // writing list tail
    freePtr = (LPVOID) ((DWORD)freePtr + sizeof(IMAGE_IMPORT_DESCRIPTOR));
    memcpy(freePtr, &myDLL, sizeof(IMAGE_IMPORT_DESCRIPTOR));

    // setting new import table rva
    DWORD newImportTableRVA = (DWORD)oldFreePtr - (DWORD)ImportSectionBegin + section_header->VirtualAddress;

    // changing DataDirectory
    optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = newImportTableRVA;
    optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (DLLCounter + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);

    // clearing non-actual values
    optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
    optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;

    optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0;
    optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0;

    return 0;
}

int _tmain(int argc, _TCHAR *argv[]) {

    if (argc != 4) {
        printf("Invalid arguments number!!!\n");
        return 0;
    }

    HANDLE FileMapping;
    LPVOID FileBegin;
    DWORD FileMappingResult = MapFile(FileMapping, FileBegin, argv[1]);
    if (0 != FileMappingResult) {
        printf("Error of file mapping (%d)\n", FileMappingResult);
        if (NULL != FileMapping) CloseHandle(FileMapping);
        return FileMappingResult;
    }

    DWORD functionAddr;
    DWORD RewriteImportTableResult = RewriteImportTable(FileMapping, FileBegin, argv[2], argv[3], functionAddr);
    if (0 != RewriteImportTableResult) {
        UnmapViewOfFile(FileBegin);
        CloseHandle(FileMapping);
        return 666;
    }

    printf("Library successfully injected!\n");
    printf("Address of injected function: %X", functionAddr);

    UnmapViewOfFile(FileBegin);
    CloseHandle(FileMapping);

    return 0;
}
于 2012-08-12T19:29:34.763 回答
1

您可以通过拦截MessageBoxA/MessageBoxW函数调用来做到这一点。在用户模式级别,这通常在以下三个位置之一完成:

  • 调用站点- 您的可执行文件中可能有多个调用MessageBox。您需要找到要禁用的那个。然后你可以用什么都不做的代码覆盖调用(即用nop指令覆盖)。
  • IAT - 导入地址表;由 PE 加载器填充的函数指针表。执行经常(但不总是)流经此处,替换函数指针MessageBox可以允许将MessageBox调用重定向到一些什么都不做的例程。
  • 函数入口点-MessageBox函数的开始。这可以通过GetProcAddress将第一条指令替换为ret.

操作在运行时(动态)或静态(二进制重写/可执行编辑)完成,第一个选项更为常见。可以帮助您实现运行时绕行的库是 Microsoft Detours。

这不是所有可能性的完整列表,而是执行重定向和绕行的最常见方法。

于 2012-08-12T19:30:49.660 回答