反調(diào)試專題丨反調(diào)試之最樸實(shí)的招式最致命
反調(diào)試之最樸實(shí)的招式最致命
反調(diào)試手段檢測(cè)花樣層出不窮,今天來(lái)介紹倆種相對(duì)簡(jiǎn)單的手段,但是卻能達(dá)到出其不意的效果。
在系統(tǒng)編程中我們遍歷進(jìn)程,模塊,線程,堆的時(shí)候都需要用到一個(gè)函數(shù):CreateToolhelp32Snapshot,其函數(shù)原型及其解釋如下:
HANDLE CreateToolhelp32Snapshot(
??[in] DWORD dwFlags,
??[in] DWORD th32ProcessID
);
//獲取指定進(jìn)程的快照,以及這些進(jìn)程使用的堆、模塊和線程。
TH32CS_INHERIT:0x80000000
指示快照句柄是可繼承的。
TH32CS_SNAPALL
包括系統(tǒng)中的所有進(jìn)程和線程,以及?th32ProcessID?中指定的進(jìn)程的堆和模塊。?等效于使用?OR 操作 。
TH32CS_SNAPHEAPLIST:0x00000001
包括快照中?th32ProcessID?中指定的進(jìn)程的所有堆。?若要枚舉堆,請(qǐng)參閱?Heap32ListFirst。
TH32CS_SNAPMODULE:0x00000008
包括快照中?th32ProcessID?中指定的進(jìn)程的所有模塊。?若要枚舉模塊,請(qǐng)參閱?Module32First。?如果函數(shù)失敗?且ERROR_BAD_LENGTH,請(qǐng)重試該函數(shù),直到函數(shù)成功。
TH32CS_SNAPMODULE32:0x00000010
64 位 Windows:?在?32 位進(jìn)程中使用此標(biāo)志包括?第?32 個(gè)ProcessID 中指定的進(jìn)程的 32?位模塊,而在?64 位進(jìn)程中使用它包括 64 位模塊。若要從 64 位進(jìn)程包含?在?th32ProcessID 中指定的進(jìn)程的 32?位模塊,請(qǐng)使用?TH32CS_SNAPMODULE32?標(biāo)志。從?64 位進(jìn)程調(diào)用時(shí),在快照中包含?在?th32ProcessID?中指定的進(jìn)程的所有?32 位模塊。此標(biāo)志可以與?TH32CS_SNAPMODULE?或?TH32CS_SNAPALL結(jié)合使用。?如果函數(shù)失敗?且ERROR_BAD_LENGTH,請(qǐng)重試該函數(shù),直到函數(shù)成功。
TH32CS_SNAPPROCESS:0x00000002
在快照中包含系統(tǒng)中的所有進(jìn)程。?若要枚舉進(jìn)程,請(qǐng)參閱?Process32First。
TH32CS_SNAPTHREAD:0x00000004
在快照中包含系統(tǒng)中的所有線程。?若要枚舉線程,請(qǐng)參閱?Thread32First。
接下來(lái)通過(guò)此函數(shù)完成進(jìn)程遍歷:
#include
#include
#include
int main()
{
PROCESSENTRY32 pe32 = { 0 };
pe32.dwSize = sizeof(PROCESSENTRY32);
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
BOOL bRet = Process32First(hSnap, &pe32);
do
{
printf("Process Name:%S\n", pe32.szExeFile);
printf("Process ID:%d\n", pe32.th32ProcessID);
} while (Process32Next(hSnap, &pe32));
CloseHandle(hSnap);
system("pause");
return 0;
}
運(yùn)行效果如下:
?

那么遍歷出進(jìn)程名,就可以開始對(duì)各種調(diào)試器進(jìn)行名稱查找,如果找到,說(shuō)明開啟了調(diào)試器,這里以x32dbg為例:
#include
#include
#include
int main()
{
PROCESSENTRY32 pe32 = { 0 };
pe32.dwSize = sizeof(PROCESSENTRY32);
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
BOOL bRet = Process32First(hSnap, &pe32);
do
{
/*printf("Process Name:%S\n", pe32.szExeFile);
printf("Process ID:%d\n", pe32.th32ProcessID);*/
if (wcsstr(pe32.szExeFile,L"x32dbg.exe") != 0)
{
printf("被調(diào)試");
system("pause");
return 0;
}
} while (Process32Next(hSnap, &pe32));
CloseHandle(hSnap);
printf("一切正常");
system("pause");
return 0;
}
效果如下:
?


同樣的道理,除了可以通過(guò)遍歷進(jìn)程名檢檢查是否有調(diào)試器開啟,還可以遍歷窗口名稱,就像這一塊:
?


這里用到函數(shù)FindWindow,函數(shù)介紹如下:
//檢索頂級(jí)窗口的句柄,該窗口的類名稱和窗口名稱與指定的字符串匹配。此函數(shù)不搜索子窗口。此函數(shù)不執(zhí)行區(qū)分大小寫.
//的搜索。若要搜索子窗口,請(qǐng)從指定的子窗口開始,請(qǐng)使用?FindWindowEx?函數(shù)。
HWND FindWindowA(
??[in, optional] LPCSTR lpClassName,
??[in, optional] LPCSTR lpWindowName
);
[in, optional] lpClassName
類型:?LPCTSTR
類名或上一次對(duì)?RegisterClass?或?RegisterClassEx?函數(shù)的調(diào)用創(chuàng)建的類名或類原子。原子必須位于?lpClassName?的低序單詞中;高階單詞必須為零。
如果?lpClassName?指向字符串,則指定窗口類名。類名可以是向?RegisterClass?或?RegisterClassEx?注冊(cè)的任何名稱,也可以是預(yù)定義控件類名稱中的任何名稱。
如果?lpClassName?為?NULL,它將查找其標(biāo)題與?lpWindowName?參數(shù)匹配的任何窗口。
[in, optional] lpWindowName
類型:?LPCTSTR
窗口名稱?(窗口的標(biāo)題)?。如果此參數(shù)為?NULL,則所有窗口名稱都匹配。
#include
#include
#include
int main()
{
HWND hWnd = NULL;
hWnd = FindWindow(NULL, L"x32dbg");
if (hWnd != NULL)
{
printf("被調(diào)試");
}
else {
printf("一切正常");
}
system("pause");
return 0;
}
?


?
注:這里單純演示手法,在主函數(shù)中進(jìn)行檢測(cè)