您好,登錄后才能下訂單哦!
一、H 0 0 K:
?不知道什么時候開始,我不喜歡叫這些知識為技術,喜歡把這些知識叫做思想。技術只是實現思想的一種行為。
?HOOK這是一個很古老的話題,我見過最早的帖子日期在2004年左右,而我2018年才學習,不變的是思想。
?
二、用戶層:
?windows下用戶層被泛指三環,上層社會,比較高端繁華的地方,讓人向往,確實很棒。
?
三、內核層:
?windows下內核層泛指零環,底層社會,硬件、驅動設備等等協調工作,無時無刻輸送著勞動成果,他們沒有華麗外表封裝自己,但是他們并不丑陋,相反的是他們真的很"偉大"。
?
四、聊聊那些HOOK先關的學問
?那時候的人真聰明,想出各種辦法去繞過、截獲,利用原本的軌道辦一些自己事情,簡單說這就是我理解的Hook。
?為什么放上去一張很Lol的圖呢?這是我第一次理解、見到HOOK的樣子,我仍然覺著他很舒適。以前也總喜歡用工具畫一些精美的圖片,現在除了寫文檔報告,都是用這種草稿圖,感覺更為親切。
?Hook是有目的,有需求點,才去截獲某一個過程,去實現自己的功能又不影響系統正常的運轉。
?Hook手段滿天飛,inlinehook、IAThook、IDThook、Objecthook、SSDThook,很遺憾很遺憾,除了新鮮感,現在的學習完全體會不到那個年代的樂趣,這是我接觸Hook的感觸。
?
Inlinehook: jmp跳轉,個人感覺跳轉的水平決定你的代碼的穩定性。注意會破壞棧頂的5個字節,因為jmp 0x...會占用函數開始前5個字節,先讀取原函數的前5個字節保存,然后在進行替換jmp跳轉,執行jmp以后,要執行保存的原函數機器碼,然后在跳到jmp下一條指令執行。
?
IAThook:
?了解PE的人知道IAT(import address table),脫殼過程中被加密最頻繁的地方,開辟虛擬空間加密、解密IAT。在PE頭中擴展頭里面最后一個數組(數據目錄表)中的第2項(下標1)與第12項(下標11)都可以找到對應IAT的RVA。
?《windows PE權威指南中》導入表的結構又稱雙橋結構,其中一條橋在加載到內存后就會被填充成IAT(FirstThunk),而通過尋找另一條橋INT(OriginalFirstThunk)實現函數綁定。所以單橋無法進行函數綁定。其實INT與IAT在文件中指向的是同一個結構體_IMAGE_THUNK_DATA32這種結構體,但是加載到內存后會把IAT填充成正確的函數地址,可執行程序才能在內存中找IAT調用正確的函數地址。
?說道這里你應該明白什么是IAT:保存加載到內存后正確的函數地址數組。Iathook就很明顯了,替換函數地址,從而該進程或者線程調用函數的時候,去IAT找到的是我們自己的函數地址即可。
籠統的說inthook分為三步,如上圖所示:
?第一步、你要知道應用程序在調用函數的時候會去找IAT,獲取IAT中保存的地址,知道了這些東西以后,你知道去截獲、替換的是什么,就是地址。
?第二步、我們找到IAT,一般情況下我們不去找IAT,我們只需要通過GetProcAddress()或者直接用函數名(函數名編譯器看來就是地址)就可以獲取。然后找到被應用程序調用的函數,如何去找呢?最簡單的辦法逆向看一看它調用了那些函數就行了。
?第三步、替換IAT表中原來函數地址,替換前先保存原地址,備份一下,然后把自己函數地址填充上去即可。
那么替換這些能干一些什么事情呢?看兩張圖
結束進程失敗:
掛起進程失敗:
?360進程用procexp.exe或則任務管理器無法結束無法掛起呢?雖然不一定用iathook,但是用iathook是可以做到的。
?上一篇博客寫的雙進程,先掛起單個進程,就可以破掉雙進程。hook可以保護你不被掛起,不被結束,比起雙進程守護更為穩定實用,同樣復雜程度也要高很多。
改進后的雙進程保護程序:
先來看看這個功能:
?基于mfc窗口,拖拽需要保護的可執行文件。但是這個進程是可以被結束的,利用線程回調檢測被保護的進程狀態,如果被結束,立刻新創建新的進程,然后使用等待函數等待響應,這樣就不會一直循環影響系統性能。
?這里沒有用任何的hook知識,用到了創建快照,3環的進程遍歷,以及創建線程回調。線程回調好處不影響當前進程的操作流程,而且暫停保護功能只需要將線程掛起即可、開啟保護功能只需要將該線程喚醒,大大的節省了代碼量及運行效率。(以下代碼未用這種思路正常關閉線程)
?還是有一些學習價值,所以把代碼貼上來,相關的地方都給了詳細的注釋,這里不再啰嗦。
代碼實現如下:
需要類中聲明、定義的變量及函數:
// This Process True?
BOOL IsCurrentProcessTrue();
// CallbackFunctionHandle
HANDLE m_Handle = NULL;
// DriverObject
HANDLE hDriver = INVALID_HANDLE_VALUE;
// SavePid
static CString g_PathValue;
// GetProcessFileName
static CString g_FilePath;
主要實現代碼:
// The CallBack Function
DWORD WINAPI ThreadPrcCallBack(LPVOID lparameter)
{
ProcessProtectMaster *pDlg = (ProcessProtectMaster*)lparameter;
STARTUPINFO g_si = {};
PROCESS_INFORMATION g_pi = {};
while (true)
{
// 如果遍歷進程發現Pid為假(開啟新的進程)
if (!pDlg->IsCurrentProcessTrue())
{
CreateProcess(pDlg->g_FilePath, NULL, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &g_si, &g_pi);
WaitForSingleObject(g_pi.hProcess, INFINITE);
CloseHandle(g_pi.hProcess);
CloseHandle(g_pi.hThread);
}
}
return 1;
}
// Is Process True?
BOOL ProcessProtectMaster::IsCurrentProcessTrue()
{
HANDLE hProcess = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcess == INVALID_HANDLE_VALUE)
{
AfxMessageBox(L"創建快照失敗");
return FALSE;
}
PROCESSENTRY32W p_32 = { sizeof(PROCESSENTRY32W) };
if (!Process32First(hProcess, &p_32))
{
AfxMessageBox(L"Process32First falure!");
CloseHandle(hProcess);
return FALSE;
}
do{
// 通過進程句柄獲取文件映像路徑
// GetProcessImageFileName(hProcess, Pathbuf, MAX_PATH);
// 強轉CString對比可以用==
CString temp = p_32.szExeFile;
// 如果檢測到有被保護進程則返回為真
if (g_PathValue == temp)
return TRUE;
} while (Process32Next(hProcess, &p_32));
// 沒有檢測到被保護進程為假
return FALSE;
}
// Start Process_Protect
void ProcessProtectMaster::OnBnClickedButton1()
{
HANDLE hProcess = INVALID_HANDLE_VALUE;
// 1. 接收輸入的PID
UpdateData();
// 1.1 把獲取的PID保存在靜態變量中(回調函數會用)
g_FilePath = m_Edit;
// 1.2 獲取文件名
int nPos = g_FilePath.ReverseFind(_T('\\'));
g_PathValue = g_FilePath.Mid(nPos + 1);
// 2. 判斷當前進程是否有效
if (!IsCurrentProcessTrue())
{
AfxMessageBox(L"Process Flase");
return;
}
// 3.顯示開啟保護進程
m_ShowValue.SetWindowTextW(L"已開啟保護");
// 4. 保護當前PID(一直檢測PID,當進程被結束立即打開新的進程)
m_Handle = CreateThread(NULL, NULL, ThreadPrcCallBack, (LPVOID)this, NULL, NULL);
}
// Stop Process_Protect
void ProcessProtectMaster::OnBnClickedButton2()
{
// 取消保護
DWORD nRet = TerminateThread(m_Handle, NULL);
if (nRet)
{
AfxMessageBox(L"進程守護關閉");
m_StatucShow = "未啟用";
// 關閉狀態更新到窗口
UpdateData(FALSE);
}
else
// 獲取回調線程的pid
// DWORD t_Pid = GetThreadId(m_Handle);
// 可以cmd Kill -9 pid
AfxMessageBox(L"請重新嘗試");
}
// The Response File Receive
void ProcessProtectMaster::OnDropFiles(HDROP hDropInfo)
{
// 1.獲得拖拽數目
int DropCount = DragQueryFile(hDropInfo, -1, NULL, 0);
// 2.保存獲取的路徑信息
char wcStr[MAX_PATH] = {};
CString str;
for (int i = 0; i < DropCount; i++)
{
// 3.記得清空字符串
wcStr[0] = 0;
// 4.獲取路徑名
DragQueryFileA(hDropInfo, i, wcStr, MAX_PATH);
str = wcStr;
}
// 直接用控件綁定變量會出現緩沖區過小問題
m_Edit = str;
UpdateData(FALSE);
// 5.釋放內存
DragFinish(hDropInfo);
CDialogEx::OnDropFiles(hDropInfo);
}
關于這兩個功能一個是IAThook,一個是ssdthook。一個三環,一個零環,Hook思想是不分三環還是零環的,零環也同樣有iathook、inlinehook,他并不是三環的專屬。下次博客更新內容是與windows內核一些東西,順帶把hook源碼講解一下與大家分享。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。