一、窗口模式應用程序(GUI)啟用控制台的方法為:
步驟 方法 1 啟動/關閉控制台 AllocConsole()
FreeConsole()
2 重定向輸入/輸出 freopen("CONIN$","r",stdin)freopen("CONOUT$","w",stdout)
freopen("CONOUT$","w",stderr)
3 控制台輸入/輸出 #include <conio.h>#include <stdio.h>
printf(...)
scanf(...)
system("pause")
二、掛鉤API函數的簡單方法為:
1. DEBUG模式下,函數名值為指令“JMP函數體”的地址。指令格式為 “E9 □□□□”,附帶的參數為四字節表示的轉移偏移量。因此“函數 名值 + *(DWORD*)((DWORD)函數名值 + 1)”為函數體入口地址。“使用轉到 反匯編”的功能計算出函數體入口棧指令長度,得出實際入口地址為“函數名 值 + *(DWORD*)((DWORD)函數名值 + 1) + 入口棧指令長度”;
2. RELEASE模式下,函數名值直接為函數體的入口地址。使用“轉到反匯編 ”的功能計算出函數體除退出指令外的指令長度,得出函數出口地址為“函數 名 + 指令長度”,API函數正是這種模式;
3. 使用“::WriteProcessMemory(::GetCurrentProcess(), API函數出口地 址...)”的方法在API函數上掛鉤以下調用:
序號 說明 指令 參數值 1 調用掛鉤函數 E8 □□□□ 掛鉤函數體實際入口地址 2 退出 C2 □□ 函數參數總長度,用於恢復棧的狀態
三、掛鉤API函數SetLastError,並輸出錯誤描述到控制台的范例
#include <stdio.h>
#include <windows.h>
void hook_SetLastError()//為簡化調用掛鉤函數時的棧操作,掛鉤函數無參數和返回值 。
{
if (::GetLastError())
{
LPVOID lpMsgBuf = 0;
if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS,
0, ::GetLastError(), LANG_USER_DEFAULT, (LPTSTR) &lpMsgBuf, 0, 0))
{
::printf("ERROR: %d %s", ::GetLastError(), (LPCSTR)lpMsgBuf);
::LocalFree(lpMsgBuf);
}
}
}
int __stdcall WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
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);
//此處添加自己的代碼
::WriteProcessMemory(::GetCurrentProcess(), (LPVOID)((unsigned int)::SetLastError + 18),
setup_SetLastError + 5, 3, new SIZE_T);
::system("pause");
return 0;
}