一大早的來到圖書館還把我的本本抗來了,就為了寫一篇部落格。
這個部落格其實說來挺愧疚的,原理搞錯了,卻也實現了預期之外的功能,如題R3下的自身進程守護。
昨天下午和“列寧”交流了一下午,才發現原來我本來的構想就是錯誤的,我本想掛鈎Terminateprocess的函數達到禁止制定進程被結束的,但是意外的把掛鈎的原理搞錯了,程式倒是寫了一堆,就是不能實現功能。把我給急的,後來昨天下午偶遇高人“列寧”,探討了一下午,我終於搞清楚我的錯誤在哪裡,(其實是被探討)我原先的構想是修改引入表中Terminateprocess的地址掛鈎這個API函數的,我以為引入表是所有程式所公用,但是錯了,每個程式有每個程式的引入表,甚至每個動態連結程式庫調用其他函數的時候都有他自己的引入表,所以在本程式修改的引入表只能防止自身的進程使用Terminateprocess的函數結束自身,當然了這個也可以作為自身的進程守護(比如病毒),雖然實在R3的層面下很容易被反HOOK。
於是我又想了一下,如何做到掛鈎其他進程API函數的使用?仔細想了想我就想到兩種,畢竟是菜鳥嘛,也還沒來得及去查閱相關資料。第一,我們可以直接修改動態連結程式庫的Terminateprocess函數的入口地址,自己動手修改之後直接將原動態連結程式庫覆蓋。第二,我們可以向目標進程注入,這個我準備試一試,我自己的想法是用SetWindowsHookEx函數直接向目標進程注入我們的修改該進程引入表的代碼。呵呵未經驗證,菜鳥的個人想法,大牛請不要笑話,發現錯誤也歡迎直接提出。
下面附上My Code片段:
#include "windows.h"<br />#include "stdio.h"<br />#include<tlhelp32.h></p><p>typedef BOOL (WINAPI * PFNTERMINATEPROCESS)(HANDLE,UINT);</p><p>PROC RealTerminateProcess=(PROC)TerminateProcess;</p><p>BOOL WINAPI MyTerminateProcess(HANDLE hProcess,UINT uExitCode)<br />{<br /> MessageBox(NULL,"操作違規!","warning",WM_SHOWWINDOW);<br /> return 0;<br />}</p><p>BOOL SetHook(HMODULE hMod)<br />{<br />DWORD dwOldprotect;<br />MEMORY_BASIC_INFORMATION mbi;<br />IMAGE_DOS_HEADER * pDosHeader=(IMAGE_DOS_HEADER *)hMod;<br />IMAGE_OPTIONAL_HEADER * pOptHeader=(IMAGE_OPTIONAL_HEADER *)((BYTE *)hMod+pDosHeader->e_lfanew+24);<br />IMAGE_IMPORT_DESCRIPTOR * pImportDesc=(IMAGE_IMPORT_DESCRIPTOR *)((BYTE *)hMod+pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);<br />while (pImportDesc->FirstThunk)<br />{<br />//printf("1success");<br />char * pszDllName=(char *)((BYTE *)hMod+pImportDesc->Name);<br />if (strcmp(pszDllName,"KERNEL32.dll")==0)<br />{<br />break;<br />}<br />pImportDesc++;<br />}<br />if (pImportDesc->FirstThunk)<br />{<br />//printf("2success");<br />IMAGE_THUNK_DATA *pThunk=(IMAGE_THUNK_DATA *)((BYTE *)hMod+pImportDesc->FirstThunk);<br />while (pThunk->u1.Function)<br />{<br />//printf("3success");<br />DWORD * lpAddr=(DWORD *)&(pThunk->u1.Function);<br />if (*lpAddr==(DWORD)RealTerminateProcess)<br />{<br />//printf("4success");<br />DWORD * lpNewProc=(DWORD *)MyTerminateProcess;<br />VirtualQuery(lpAddr,&mbi,sizeof(mbi));<br />VirtualProtect(lpAddr,sizeof(DWORD),PAGE_READWRITE,&dwOldprotect); //除保護<br />WriteProcessMemory(GetCurrentProcess(),lpAddr,&lpNewProc,sizeof(DWORD),NULL);<br />VirtualProtect(lpAddr,sizeof(DWORD),dwOldprotect,0); //防寫保護<br />return TRUE;<br />}<br />pThunk++;<br />}<br />}<br />return FALSE;<br />}</p><p>int main()<br />{<br />if(SetHook(GetModuleHandle(NULL)))<br />printf("HOOK成功!");<br />else<br />printf("HOOK失敗!");<br />return 0;<br />}
除此之外,昨天下午和列寧的一番談話中我也受教了,關於函數的呼叫慣例,native API一般都是_stdcall,所以在定義函數類型的時候要注意了,最討厭的地方就是這個錯了編譯不報錯,運行時就會出現錯誤:
下面附上R3下使用NtQueryInformationProcess的用法:
typedef struct<br />{<br />DWORD ExitStatus;<br />DWORD PebBaseAddress;<br />DWORD AffinityMask;<br />DWORD BasePriority;<br />ULONG UniqueProcessId;<br />ULONG InheritedFromUniqueProcessId;<br />} PROCESS_BASIC_INFORMATION;<br />PROCESS_BASIC_INFORMATION pbi;<br />typedef unsigned long(_stdcall*pNtQueryInformationProcess)(HANDLE,DWORD,PVOID,ULONG,PULONG);<br />pNtQueryInformationProcess NtQueryInformationProcess;<br />HINSTANCE hdll=GetModuleHandle("Ntdll.dll");<br />NtQueryInformationProcess=(pNtQueryInformationProcess)GetProcAddress(hdll,"NtQueryInformationProcess");<br />NtQueryInformationProcess(hProcess,0,(PVOID)&pbi,sizeof(PROCESS_BASIC_INFORMATION),NULL);