久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

API攔截——實(shí)現(xiàn)Ring3全局HOOK

 guoliyan1 2012-04-10

API攔截——實(shí)現(xiàn)Ring3全局HOOK

 

API攔截——實(shí)現(xiàn)Ring3全局HOOK

首先來解釋一下這次的目標(biāo)。由于windows的copy-on-write機(jī)制(Ring0下可以用CR0寄存器關(guān)掉它),Ring3下的HOOK只對(duì)當(dāng)前進(jìn)程有效,,其他進(jìn)程的API還是正常的。這就是說我們必須枚舉進(jìn)程,,然后對(duì)每個(gè)Ring3進(jìn)程執(zhí)行一遍HOOK操作,。

但是,系統(tǒng)中總有新進(jìn)程產(chǎn)生,,對(duì)于這些新進(jìn)程我們?cè)趺刺幚砟??最容易想到的就是設(shè)置一個(gè)TIMER,,每隔一段時(shí)間就枚舉一遍進(jìn)程然后把新的掛鉤。但仔細(xì)一想就知道不行,,TEMER過快嚴(yán)重影響系統(tǒng)效率,慢了又起不到作用,,況且windows不是一個(gè)實(shí)時(shí)操作系統(tǒng),,沒人能保證到時(shí)間TEMER就被激活。如果我們能監(jiān)控進(jìn)程創(chuàng)建,,并在他們真正運(yùn)行之前就執(zhí)行掛鉤操作,,就可以完美的解決問題。
但是如何做到這一點(diǎn)呢,?我們知道Ring3的進(jìn)程都有一個(gè)“父進(jìn)程”也就是說新進(jìn)程都是由老進(jìn)程創(chuàng)建的(驅(qū)動(dòng)很少創(chuàng)建進(jìn)程),。知道這一點(diǎn)就好辦了,我們要做的只是截獲進(jìn)程創(chuàng)建,。你肯定會(huì)說“這么簡單,,HOOK NtCreateProcess就可以了!”但是這不是最簡單的做法,。為什么這么說呢,,首先在NtCreateProcess函數(shù)被調(diào)用時(shí)進(jìn)程并沒有真正被創(chuàng)建,我們無法執(zhí)行HOOK操作,,而當(dāng)NtCreateProcess返回時(shí),,進(jìn)程又已經(jīng)開始運(yùn)行,HOOK時(shí)存在線程同步的問題(我用OD在NtCreateProcess設(shè)下INT3斷點(diǎn),,卻攔不到,,不只是為什么?),。
所以我選的函數(shù)是NtResumeThread,。我們知道,當(dāng)新進(jìn)程被創(chuàng)建時(shí),,OS會(huì)為其創(chuàng)建一個(gè)住線程,,而在這之后會(huì)調(diào)用NtResumeThread時(shí)期開始運(yùn)行,這時(shí)初始化完畢,,DLL都已經(jīng)被載入,,但進(jìn)程卻沒有開始運(yùn)行這時(shí)我們最好的機(jī)會(huì)(HAHA,天助我也HAHAHA…),。
NTSTATUS NtResumeThread(
IN HANDLE ThreadHandle,
OUT PULONG PreviousSuspendCount OPTIONAL
);
思路是這樣但是怎么實(shí)現(xiàn)呢,?來看一下函數(shù)的定義:
我們關(guān)心的是第一個(gè)參數(shù),它存儲(chǔ)的是新進(jìn)程主線程的句柄,,我們可以通過調(diào)用ThreadInformationClass=0,,ThreadInformationLength=28的NtQueryInformationThread函數(shù)來獲得該縣城所屬進(jìn)程的PID,,然后只要HOOK它就可以了。
話雖如此,,可是如果把HOOK的代碼都放到遠(yuǎn)程去未免太麻煩了,。開始我想的是用遠(yuǎn)程進(jìn)程調(diào)用CreateRemoteThread來回調(diào)HOOK進(jìn)程。但仔細(xì)想想就會(huì)發(fā)現(xiàn),,我們?cè)诒镜豀OOK時(shí)有足夠的權(quán)限,,可是如果遠(yuǎn)程進(jìn)程是GUEST權(quán)限的呢?回調(diào)時(shí)由于權(quán)限不夠就會(huì)出錯(cuò),。翻了翻《windows核心編程》后恍然大悟:可以使用windows的事件對(duì)象來實(shí)現(xiàn),。用到的API有:OpenEvent,CreateEvent,,SetEvent,,ResetEvent。在HOOK每一個(gè)進(jìn)程的時(shí)候,,用CreateEvent創(chuàng)建一個(gè)不可繼承,、自動(dòng)重置的Event對(duì)象,然后創(chuàng)建一個(gè)線程用WaitForSingleObject函數(shù)等待改Event,。當(dāng)攔截到新進(jìn)程創(chuàng)建時(shí),,遠(yuǎn)程線程調(diào)用SetEvent來激活Event,然后同樣調(diào)用WaitForSingleObject函數(shù)等待,。這時(shí)本地的WaitForSingleObject會(huì)返回,, 然后再進(jìn)行相關(guān)的處理,然后調(diào)用SetEvent來讓遠(yuǎn)程hook函數(shù)繼續(xù)運(yùn)行,。這樣有個(gè)問題就是本題怎樣知道新進(jìn)程PID,?我的解決辦法是遠(yuǎn)程調(diào)用SetEvent前先把PID寫在HOOK函數(shù)開頭的特定偏移位置,然后本地用ReadProcessMemory來讀取,。限于篇幅講得不太具體,,如果不懂最好去看一看《windows核心編程》。
好了,,理論就講道這里,,來看看代碼,GO?。m然是在去年的5期文章的基礎(chǔ)上改的,,不過改動(dòng)較大,所以關(guān)鍵代碼已提上來了,。)
首先是hook函數(shù),,主要功能是對(duì)指定進(jìn)程的指定API進(jìn)行hook操作
int HookNamedApi(PDLLINFO pDllInfo, char *ApiName, DWORD HookProc,HANDLE ObjectProcessHandle)
{
DWORD dw, NamedApiAddress,NewFunc;//變量初始化
MEMORY_BASIC_INFORMATION mbi;
static EventInfo myEventInfo;
static Num=0x676e696b;

NamedApiAddress = (DWORD)GetProcAddress(pDllInfo->hModule, ApiName);//目標(biāo)api地址,每個(gè)進(jìn)程的api地址都是一樣的,只要找本進(jìn)程的就可以了,。
if(NamedApiAddress == NULL)
{
printf(“Error:GetProcAddress in hook_api”);//錯(cuò)誤處理
return 0;
}

if(!VirtualQueryEx(ObjectProcessHandle,(void*)NamedApiAddress,&mbi,sizeof(MEMORY_BASIC_INFORMATION)))//獲取目標(biāo)api所在內(nèi)存信息
{
printf(“Error:VirtualQueryEx in hook_api”);
return 0;
}

if(!VirtualProtectEx(ObjectProcessHandle,mbi.BaseAddress,mbi.RegionSize,PAGE_EXECUTE_READWRITE,&dw))//分配寫和執(zhí)行權(quán)限,,因?yàn)槲覀円獙?duì)目標(biāo)API開頭進(jìn)行寫操作
{
printf(“Error:VirtualProtectEx in hook_api”);
return 0;
}
LPVOID WriteAddress=VirtualAllocEx(ObjectProcessHandle,0,1000,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);//分配內(nèi)存,寫入hook函數(shù)

//計(jì)算備份函數(shù)COPY的位置
NewFunc = NamedApiAddress – (DWORD)pDllInfo->modinfo.lpBaseOfDll + (DWORD)pDllInfo->lpNewBaseOfDll;
//修改原函數(shù)入口處內(nèi)容
if(strcmp(ApiName,”NtResumeThread”)==0)//如果是hook NtResumeThread函數(shù)要做一些處理
{
DWORD my_CreateEventA=(DWORD)GetProcAddress(GetModuleHandle(“kernel32.dll”),”CreateEventA”);
HANDLE EventFar;
__asm//這里不用匯編vc總說類型不對(duì),,偷個(gè)懶^_^
{
pushad
push 00000000h
push Num
push 0x676e696b
push esp//構(gòu)造Event名
push 0
push 0
push 0
call my_CreateEventA
mov EventFar,eax
add esp,12
popad
}
*(PDWORD)((DWORD)FarStartUp+9)=(DWORD)GetProcAddress(GetModuleHandle(“kernel32.dll”),”O(jiān)penEventA”);//遠(yuǎn)程函數(shù)的API地址都是動(dòng)態(tài)寫入的,。這里說一句,以前是寫入遠(yuǎn)程后用WriteProcessMemory來改,,后來想到這樣太慢(轉(zhuǎn)到Ring0要1000個(gè)CPU時(shí)間的哦)于是改在本地完成,,但我們對(duì)代碼段進(jìn)行了寫操作,默認(rèn)是不允許的,,所以要用PE修改工具來給.text段加上可寫屬性
LPVOID StartUpAddr=VirtualAllocEx(ObjectProcessHandle,0,500,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);//分配內(nèi)存,寫入StartUp函數(shù),,因?yàn)槲覀冇肊vent來解決,,所以要在遠(yuǎn)程打開該Event對(duì)象
WriteProcessMemory(ObjectProcessHandle,StartUpAddr,(LPVOID)FarStartUp,500,0);//寫入函數(shù)
printf(“%x\n”,(DWORD)StartUpAddr);//調(diào)試信息
HANDLEFarThread=CreateRemoteThread(ObjectProcessHandle,0,0, (PTHREAD_START_ROUTINE)StartUpAddr,(PVOID)Num,0,0);//創(chuàng)建遠(yuǎn)程線程
WaitForSingleObject(FarThread,-1);//等待遠(yuǎn)程初始化完畢
CloseHandle(FarThread);
DWORD ReadBuf;
ReadProcessMemory(ObjectProcessHandle,(LPVOID)((DWORD)StartUpAddr+21),&ReadBuf,4,0);//讀出遠(yuǎn)程的Event句柄數(shù)值,后面寫入HOOK函數(shù)
VirtualFreeEx(ObjectProcessHandle,StartUpAddr,500,MEM_RELEASE);//釋放內(nèi)存
*(PDWORD)(HookProc+WRITEBASE+7)=ReadBuf;//寫入句柄
myEventInfo.EventFar=EventFar;
myEventInfo.ObjectProcessHandle=ObjectProcessHandle;
myEventInfo.WriteAddress=(DWORD)WriteAddress;//線程參數(shù)
CreateThread(0,0,(unsigned long (__stdcall *)(void *))my_EventProcess_Thread,&myEventInfo,0,0);//創(chuàng)建本地等待線程
Num++;//每個(gè)進(jìn)程用不同的Event,,所以名稱不一樣
}
*(PDWORD)(HookProc+WRITEBASE)=NewFunc;
*(PDWORD)(HookProc+WRITEBASE+14)=(DWORD)GetProcAddress(GetModuleHandle(“kernel32.dll”),”GetCurrentProcessId”);
*(PDWORD)(HookProc+WRITEBASE+21)=(DWORD)GetProcAddress(GetModuleHandle(“kernel32.dll”),”SetEvent”);
*(PDWORD)(HookProc+WRITEBASE+28)=(DWORD)GetProcAddress(GetModuleHandle(“kernel32.dll”),”WaitForSingleObject”);
*(PDWORD)(HookProc+WRITEBASE+35)=(DWORD)GetProcAddress(GetModuleHandle(“ntdll.dll”),”NtQueryInformationThread”);
*(PDWORD)(HookProc+WRITEBASE+42)=(DWORD)GetProcAddress(GetModuleHandle(“kernel32.dll”),”ResetEvent”);//初始化HOOK函數(shù),,寫入API地址

WriteProcessMemory(ObjectProcessHandle,WriteAddress,(void *)HookProc,1000,0);//寫入HOOK函數(shù)
*(PDWORD)(&HookCode[0]+1)=(DWORD)WriteAddress;
WriteProcessMemory(ObjectProcessHandle,(LPVOID)NamedApiAddress,&HookCode,7,0);//修改目標(biāo)API首字節(jié),使其跳轉(zhuǎn)到我們的HOOK函數(shù)
printf(“func:%x\n”,WriteAddress);//調(diào)試信息
return 1;
}
接下來是遠(yuǎn)程的初始化函數(shù),用來打開Event
void FarStartUp(int Num){//Event名稱的后半段,,我創(chuàng)建的Event名稱都是形如”kingXXXX”
int myOpenEvent=0×10020000;//API函數(shù)地址,,動(dòng)態(tài)寫入,這條代碼編譯后是類似于這樣的匯編碼:mov [ebp+XX],XXXX,,修改時(shí)只要把XXXX換成API地址就可以了
__asm call GetMyAddr;//這個(gè)是用來取得本函數(shù)的地址用的,,不知道的話可以上網(wǎng)查查
DWORD myEventHandle=0×00220000;//本地從這里讀出句柄代碼,HOOK函數(shù)中的代碼類似
DWORD FuncAddr;
__asm
{
jmp run//正式運(yùn)行時(shí)跳過
GetMyAddr:
pop eax
mov FuncAddr,eax
push eax
ret
run:
push 00000000
push Num
push 0x676e696b
push esp
push 0
push EVENT_ALL_ACCESS
call myOpenEvent//構(gòu)造字符串,,并打開句柄
mov myEventHandle,eax
}
*(PDWORD)(FuncAddr+3)=myEventHandle;//往開頭寫入
return;
}
這時(shí)上面說到過的等待線程,,每HOOK一個(gè)進(jìn)程就有一個(gè)對(duì)應(yīng)的這個(gè)線程,這里本來應(yīng)該加一個(gè)垃圾回收機(jī)制,,即當(dāng)本線程對(duì)應(yīng)的進(jìn)程已經(jīng)不存在了的時(shí)候,,線程自我銷毀。不過還沒來得及寫^_^
void __stdcall my_EventProcess_Thread(PVOID InEventInfo)
{
EventInfo myEventInfo;
PEventInfo Info=(PEventInfo)InEventInfo;
myEventInfo.EventFar=Info->EventFar;//保存句柄和進(jìn)程信息
myEventInfo.ObjectProcessHandle=Info->ObjectProcessHandle;
myEventInfo.WriteAddress=Info->WriteAddress;//這個(gè)是HOOK函數(shù)句柄
while(true)//循環(huán)等待
{
WaitForSingleObject(myEventInfo.EventFar,-1);
DWORD ReadBuf=0;//當(dāng)對(duì)應(yīng)進(jìn)程創(chuàng)建后WaitForSingleObject返回,,執(zhí)行到這里
ReadProcessMemory(myEventInfo.ObjectProcessHandle,(LPVOID)(myEventInfo.WriteAddress+67),&ReadBuf,4,0);//從遠(yuǎn)程讀出新進(jìn)程的PID,,在HOOK函數(shù)調(diào)用SetEvent之前會(huì)在遠(yuǎn)程寫入。
HANDLE ObjectProcessHandle=OpenProcess(PROCESS_ALL_ACCESS,1,ReadBuf);//打開目標(biāo)進(jìn)程
HookProcess(ObjectProcessHandle);//執(zhí)行HOOK操作,,本來應(yīng)改檢查一下該進(jìn)程是否已經(jīng)被HOOK,,還沒來得及寫
SetEvent(myEventInfo.EventFar);//恢復(fù)遠(yuǎn)程Hook函數(shù)運(yùn)行
ResetEvent(myEventInfo.EventFar);//本來是自動(dòng)重置的Event,不過為了保險(xiǎn)在重置一下
}
return;
}
下面是精華了哦,,重點(diǎn)仔細(xì)看啊,。
DWORD __stdcall Hook_NtResumeThread(
HANDLE ThreadHandle,
PULONG PreviousSuspendCount OPTIONAL)
{

int OldNtResumeThread;//原NtQueryDirectoryFile函數(shù)
int EventHandle; //Event句柄,由FarStartUp函數(shù)打開
int my_GetCurrentProcessId;
int my_SetEnent;
int my_WaitForSingleObject;
int my_NtQueryInformationThread;//存放個(gè)API的指的變量
int my_ResetEvent;
__asm
{
mov OldNtResumeThread,00112244h
mov EventHandle,00225588h
mov my_GetCurrentProcessId,22447799h
mov my_SetEnent,55662244h
mov my_WaitForSingleObject,55889966h
mov my_NtQueryInformationThread,77554411h
mov my_ResetEvent,55661188h//hook時(shí)寫入
pushad//保護(hù)堆棧
}
__asm call GetAddr;//同F(xiàn)arStartUp函數(shù)
int FarRead;
__asm mov FarRead,22550011h;
DWORD myAddr;
__asm
{
jmp start
GetAddr:
pop eax
mov myAddr,eax
push eax
ret
start:
}
DWORD myStatus;//存儲(chǔ)返回變量
BYTE SystemInfo[60];//存放NtQueryInformationThread返回信息的緩沖
int infoaddr=(DWORD)&SystemInfo;//緩沖地址
int CurrentProcess;
__asm
{
push 0
push 28//這里必須是28,,則函數(shù)不執(zhí)行,,這個(gè)值是我從10到100瓊琚出來的,,辛苦啊555。,。,。
push infoaddr
push 0
push ThreadHandle
call my_NtQueryInformationThread//調(diào)用NtQueryInformationThread獲得線程所屬進(jìn)程的PID
mov myStatus,eax
}
DWORD *)(SystemInfo+8);
__asm
{
call my_GetCurrentProcessId//獲得本進(jìn)程PID
mov CurrentProcess,eax
}
if(id==(DWORD)CurrentProcess)//如果是對(duì)當(dāng)前進(jìn)程操作就直接返回,免得傳回本地浪費(fèi)時(shí)間降低效率
{
__asm
{
push PreviousSuspendCount
push ThreadHandle
call OldNtResumeThread
mov myStatus,eax
popad//對(duì)應(yīng)開頭的pushad,,用來保護(hù)堆棧,,下同
}
return myStatus;
}
if(myStatus==0)//如果NtQueryInformationThread執(zhí)行不成功就直接返回,漏hook總比程序死掉好,,嘿嘿
{
*(PDWORD)(myAddr+3)=id;//把目標(biāo)PID寫道函數(shù)開頭
__asm
{
push EventHandle
call my_SetEnent//恢復(fù)本地對(duì)應(yīng)線程運(yùn)行
push -1
push EventHandle
call my_WaitForSingleObject//等待本地HOOK操作完成
push EventHandle
call my_ResetEvent
}
}
__asm
{
push PreviousSuspendCount
push ThreadHandle
call OldNtResumeThread//調(diào)用原NtResumeThread函數(shù),,到這里,新進(jìn)程正式開始運(yùn)行
mov myStatus,eax
popad//保護(hù)堆棧
}
return myStatus;//這個(gè)是用來擺平vc++編譯器的,,沒實(shí)際意義^_^
}
小結(jié):
最后來總結(jié)一下思路把,,程序分為本地(HOOK程序)和遠(yuǎn)程(被HOOK程序)。
最近Ring0的木馬大行其道,,不過Ring0的東西寫起來太費(fèi)時(shí)搞不好就BSOD,,光是弄DDK就花了我一個(gè)禮拜,555…所以我們的Ring3HOOK還是很有市場的,,快加到你的愛馬里吧,,只要在開頭加一個(gè)枚舉進(jìn)程,所有的Ring3進(jìn)程就統(tǒng)統(tǒng)地被掛上了,,再配合以前的隱藏文件……嘿嘿

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多