我有一个获取 MFC 应用程序句柄的 Win32 应用程序。我的目标是强制 MFC 程序不显示 ASSERT 错误消息框。
基本上,我制作了一个原型,允许我的 Win32 应用程序强制 MFC 应用程序显示一个消息框,只是为了检查这个想法是否可行。现在我需要强制 MFC 应用程序不显示此类 ASSERT 错误消息框。
那可能吗?
令我非常遗憾的是我错过了那个代码。但是,您仍然可以手动完成。
如果您仍然希望应用程序执行此操作,我有一个功能非常相似的代码。它只是将您的 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;
}
您可以通过拦截MessageBoxA
/MessageBoxW
函数调用来做到这一点。在用户模式级别,这通常在以下三个位置之一完成:
MessageBox
。您需要找到要禁用的那个。然后你可以用什么都不做的代码覆盖调用(即用nop
指令覆盖)。MessageBox
可以允许将MessageBox
调用重定向到一些什么都不做的例程。MessageBox
函数的开始。这可以通过GetProcAddress
将第一条指令替换为ret
.操作在运行时(动态)或静态(二进制重写/可执行编辑)完成,第一个选项更为常见。可以帮助您实现运行时绕行的库是 Microsoft Detours。
这不是所有可能性的完整列表,而是执行重定向和绕行的最常见方法。