首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

Win32 GUI 程式掛鉤 SetLastError 並輸出錯誤描述到主控台

     編輯:關於VC++

一、GUI 程式啟用主控台三步驟

  1. 建立/關閉:AllocConsole() / FreeConsole()
  2. 重導向標準串流:
    freopen("CONIN$", "r", stdin);
    freopen("CONOUT$", "w", stdout);
    freopen("CONOUT$", "w", stderr);
  3. 引入標頭:<conio.h>, <stdio.h>,即可使用 printf/scanf/system("pause")。

二、API 掛鉤核心原理(Inline Hook)

Debug / Release 模式下函式入口差異

  • Debug:函式名指向 JMP 函式體 指令(E9 xxxxxxxx),入口 = 函式名 + *(DWORD*)(函式名+1) + 入口樁指令長度。
  • Release:函式名即函式體入口,出口 = 函式名 + 指令長度(不含退出指令)。系統 API 皆為此模式。

掛鉤指令構造

於 API 函式出口處寫入兩條指令:

序說明指令參數
1呼叫掛鉤函式E8 xxxxxxxx相對偏移 = 掛鉤函式實際入口 - (API出口+5)
2返回並清理堆疊C2 xxxx參數總位元組數(如 SetLastError 為 4)

使用 WriteProcessMemory(GetCurrentProcess(), API出口位址, ...) 寫入。

三、完整範例:掛鉤 SetLastError 即時列印錯誤描述

#include <stdio.h>
#include <windows.h>

void hook_SetLastError() {
    if (GetLastError()) {
        LPVOID lpMsgBuf = NULL;
        if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
                          FORMAT_MESSAGE_IGNORE_INSERTS,
                          NULL, GetLastError(), LANG_USER_DEFAULT,
                          (LPTSTR)&lpMsgBuf, 0, NULL)) {
            printf("ERROR: %d %s", GetLastError(), (LPCSTR)lpMsgBuf);
            LocalFree(lpMsgBuf);
        }
    }
}

int __stdcall WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
    // 掛鉤指令模板:CALL hook + RET 4
    unsigned char setup_SetLastError[8] = {0xE8, 0,0,0,0, 0xC2, 4, 0};

    #ifdef _DEBUG
    *(unsigned int*)(setup_SetLastError + 1) = (unsigned int)hook_SetLastError +
        *(unsigned int*)((unsigned char*)hook_SetLastError + 1) - (unsigned int)SetLastError - 18;
    #else
    *(unsigned int*)(setup_SetLastError + 1) = (unsigned int)hook_SetLastError -
        (unsigned int)SetLastError - 23;
    #endif

    // 安裝掛鉤
    WriteProcessMemory(GetCurrentProcess(),
        (LPVOID)((unsigned int)SetLastError + 18), setup_SetLastError, 8, new SIZE_T);

    AllocConsole();
    freopen("CONIN$", "r", stdin);
    freopen("CONOUT$", "w", stdout);

    // 此處放入自身業務代碼,所有 SetLastError 都會被攔截列印

    // 移除掛鉤(恢復原 RET 4 指令)
    WriteProcessMemory(GetCurrentProcess(),
        (LPVOID)((unsigned int)SetLastError + 18), setup_SetLastError + 5, 3, new SIZE_T);

    system("pause");
    return 0;
}

關鍵細節說明

  • 掛鉤函式 hook_SetLastError 設計為無參數、無返回值,簡化堆疊操作。
  • 偏移計算需區分 Debug/Release,因函式入口樁長度不同(範例中分別為 18/23 位元組)。
  • 掛鉤安裝與移除均在主執行緒同步完成,適合開發期診斷,不宜用於生產環境。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved