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関数呼び出しをインターセプトすることでこれを行うことができます。ユーザーモード レベルでは、これは通常、次の 3 つの場所のいずれかで行われます。

  • 呼び出しサイト- 実行可能ファイルに複数の呼び出しがある場合がありMessageBoxます。無効にするものを見つける必要があります。次に、何もしないコードで呼び出しを上書きできます (つまり、nop命令で上書きします)。
  • IAT - インポート アドレス テーブル。PE ローダーによって埋められた関数ポインターのテーブル。実行は頻繁に (常にではありませんが) ここを通過し、関数ポインターを置き換えると、何もしないルーチンに呼び出しをリダイレクトMessageBoxできます。MessageBox
  • 関数のエントリ ポイント- 関数の開始点MessageBox。これは で見つけることができGetProcAddress、最初の命令は に置き換えられretます。

操作は実行時 (動的) または静的 (バイナリ書き換え/実行可能編集) のいずれかで行われ、最初のオプションがはるかに一般的です。実行時の迂回を実現するのに役立つライブラリは、Microsoft Detours です。

これはすべての可能性の包括的なリストではなく、実行のリダイレクトと迂回の最も一般的な方法です。

于 2012-08-12T19:30:49.660 に答える