Process-wide API spying - an ultimate hack 摘要翻译(三)
在已運(yùn)行進(jìn)程注入間諜DLL
主體代碼(文字說明放在代碼的注釋中):
void inject(DWORD threadid,BYTE*remotebuff, HMODULE hMod, DWORD
entrypoint,HANDLE processhandle,HANDLE eventhandle);
void loadandinject(DWORD procid)
{
??? BYTE array[256];
??? char buff[1024];
??? DWORD byteswritten,dw,threadid;
??? //按照J(rèn)effrey Richter提出的方法在目標(biāo)進(jìn)程加載spydll.dll
??? HANDLE processhandle=OpenProcess(PROCESS_ALL_ACCESS,0,procid);
??? BYTE* writebuff=(BYTE*)VirtualAllocEx(processhandle,0,4096,MEM_RESERVE,PAGE_EXECUTE_READWRITE);
??? writebuff=(BYTE*)VirtualAllocEx(processhandle,writebuff,4096,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
??? DWORD funcptr=(DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
??? strcpy(buff,"spydll.dll");
??? WriteProcessMemory(processhandle,writebuff,buff,256,&byteswritten);
??? CreateRemoteThread(processhandle,0,0,(LPTHREAD_START_ROUTINE)funcptr,writebuff,0,&threadid);
??? //在目標(biāo)進(jìn)程中找到spydll.dll的模塊句柄
??? HANDLE snap= CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,procid);
??? MODULEENTRY32 mod;
??? mod.dwSize=sizeof(MODULEENTRY32);
??? Module32First(snap,&mod);
??? HMODULE hMod=0;
??? while(Module32Next(snap,&mod))
??? {
??????? if(!strcmp(mod.szModule,"spydll.dll"))
??????? {
??????????? hMod=mod.hModule;
??????????? break;
??????? }
??? }
??? CloseHandle(snap);
??? //獲取spydll.dll在目標(biāo)進(jìn)程中的入口點(diǎn)
??? ReadProcessMemory(processhandle,(void*)hMod,buff,1024,&dw);
??? IMAGE_DOS_HEADER * dosheader=(IMAGE_DOS_HEADER *)buff;
??? IMAGE_OPTIONAL_HEADER * opthdr =(IMAGE_OPTIONAL_HEADER *)((BYTE*)buff+dosheader->e_lfanew+24);
??? DWORD entry=(DWORD)hMod+opthdr->AddressOfEntryPoint;
??? //創(chuàng)建一個自我復(fù)位的Event,其初始狀態(tài)為沒有信號狀態(tài)
??? HANDLE eventhandle=CreateEvent(0,0,0,"spyevent");
??? //讓目標(biāo)進(jìn)程已經(jīng)運(yùn)行的線程調(diào)用掛鉤DLL文件的入口點(diǎn)函數(shù)
??? snap= CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0);
??? THREADENTRY32 th;
??? th.dwSize=sizeof(THREADENTRY32);
??? Thread32First(snap,&th);
??? while(Thread32Next(snap,&th))
??? {
??????? if(th.th32OwnerProcessID==procid)
??????????? inject(th.th32ThreadID,writebuff,hMod,entry,processhandle,eventhandle);
??? }
??? CloseHandle(eventhandle);
}
inject和前面篇幅的函數(shù)一樣,也是機(jī)器碼寫的。但這里的情況更加復(fù)雜一些,因?yàn)楸仨毟淖兡繕?biāo)線程的執(zhí)行體上下文,讓它調(diào)用我們硬編碼以調(diào)用spydll.dll的入口點(diǎn),以下是它的匯編偽碼:
??? push eax
??? push ebx
??? push ecx
??? push edx
??? pushf
??? push 0
??? push value_of_DLL_THREAD_ATTACH
??? push hMod
??? call dword ptr[_imp_Dllentrypoint]
??? push eventnameptr
??? push 0
??? push value_of_EVENT_ALL_ACCESS
??? call dword ptr[_imp_OpenEvent]
??? push eax
??? push eax
??? call dword ptr[_imp_SetEvent]
??? call dword ptr[_imp_CloseHandle]
??? popf
??? pop edx
??? pop ecx
??? pop ebx
??? pop eax
??? jmp dword ptr[retaddressptr]
inject具體代碼如下:
void inject(DWORD threadid,BYTE* remotebuff,HMODULE hMod,DWORD entrypoint,HANDLE processhandle,HANDLE eventhandle)
{
??? DWORD arg1=(DWORD)hMod,arg2=DLL_THREAD_ATTACH,arg3=0;
??? typedef HANDLE (__stdcall*func)(DWORD,BOOL,DWORD);
??? func OpenThread=(func)GetProcAddress(GetModuleHandle("KERNEL32.dll"),"OpenThread");
??? HANDLE threadhandle=OpenThread(THREAD_SUSPEND_RESUME| THREAD_GET_CONTEXT|THREAD_SET_CONTEXT,0,threadid);
??? SuspendThread(threadhandle);
??? CONTEXT Context;
??? Context.ContextFlags=CONTEXT_CONTROL;
??? GetThreadContext(threadhandle,&Context);
??? DWORD retaddress= Context.Eip;
??? //we are going to do the tough job of filling the array with the machine codes
??? BYTE array[256];
??? //copy all necessary data into the array
??? DWORD *openeventptr=(DWORD *)&array[100];
??? openeventptr[0]=(DWORD )&OpenEvent;
??? openeventptr=(DWORD *)&remotebuff[100];
??? DWORD*seteventptr=(DWORD *)&array[104];
??? seteventptr[0]=(DWORD )&SetEvent;
??? seteventptr=(DWORD *)&remotebuff[104];
??? DWORD* closehandleptr=(DWORD *)&array[108];
??? closehandleptr[0]=(DWORD )&CloseHandle;
??? closehandleptr=(DWORD *)&remotebuff[108];
??? DWORD* entrypointptr=(DWORD *)&array[112];
??? entrypointptr[0]=entrypoint;
??? entrypointptr=(DWORD *)&remotebuff[112];
??? DWORD* retaddressptr=(DWORD *)&array[116];
??? retaddressptr[0]=retaddress;
??? retaddressptr=(DWORD *)&remotebuff[116];
??? strcpy((char*)&array[120],"spyevent");
??? char*eventnameptr=(char*)&remotebuff[120];
??? //now we are filling the array with actual machine instructions
??? //push registers and flags
??? array[0]=0x50;?? //push eax
??? array[1]=0x53;?? //push ebx
??? array[2]=0x51;?? //push ecx
??? array[3]=0x52;?? //push edx
??? array[4]=0x9C;?? //pushf
??? //push entrypoint arguments
??? array[5]=0x68;?? //push 0
??? memmove(&array[6],&arg3,4);
??? array[10]=0x68;? //push value_of_DLL_THREAD_ATTACH
??? memmove(&array[11],&arg2,4);
??? array[15]=0x68;? //push hMod
??? memmove(&array[16],&arg1,4);
??? //call entrypoint
??? array[20]=0xFF;? //call dword ptr[_imp_Dllentrypoint]
??? array[21]=0x15;
??? memmove(&array[22],&entrypointptr,4);
??? //push OpenEvent arguments
??? array[26]=0x68;? //push eventnameptr
??? memmove(&array[27],&eventnameptr,4);
??? array[31]=0x68;? //push 0
??? int a=0;
??? memmove(&array[32],&a,4);
??? array[36]=0x68;? //push value_of_EVENT_ALL_ACCESS
??? a=EVENT_ALL_ACCESS;
??? memmove(&array[37],&a,4);
??? //call OpenEvent
??? array[41]=0xFF;? //call dword ptr[_imp_OpenEvent]
??? array[42]=0x15;
??? memmove(&array[43],&openeventptr,4);
???
??? // push eax
??? array[47]=0x50;
??? // push eax
??? array[48]=0x50;
??? //call SetEvent
??? array[49]=0xFF;
??? array[50]=0x15;
??? memmove(&array[51],&seteventptr,4);
??? //call CloseHandle
??? array[55]=0xFF;
??? array[56]=0x15;
??? memmove(&array[57],&closehandleptr,4);
??? //restore registers and flags
??? array[61]=0x9D;?? //popf
??? array[62]=0x5A;?? //pop edx
??? array[63]=0x59;?? //pop ecx
??? array[64]=0x5B;?? //pop ebx
??? array[65]=0x58;?? //pop eax
??? //jmp dword ptr[retaddressptr]
??? array[66]=0xFF;
??? array[67]=0x25;
??? memmove(&array[68],&retaddressptr,4);
??? // we have finished filling the array, thanks God
??? DWORD byteswritten;
??? WriteProcessMemory(processhandle,(void *)remotebuff,(void*)array,256,&byteswritten);
??? Context.Eip=(DWORD)&remotebuff[0];
??? SetThreadContext(threadhandle,&Context);
??? ResumeThread(threadhandle);
??? //在改變目標(biāo)線程的執(zhí)行體上下文后,inject函數(shù)為等待目標(biāo)線程置位同步的Event,所以直到目標(biāo)線程已經(jīng)恢復(fù)到原來的執(zhí)行體上下文前,Inject函數(shù)都不能對其他的線程進(jìn)行更改操作
??? //此外這里使用的同步技術(shù)還可以用于檢測線程死鎖
??? WaitForSingleObject(eventhandle,INFINITE);
??? CloseHandle(threadhandle);
}
注意:如果我們需要把spydll.dll注入到我們自己創(chuàng)建的進(jìn)程,最好的辦法是在spydll.dll剛被加載的時候改寫目標(biāo)函數(shù)的地址(此時的fdwReason=DLL_PROCESS_ATTACH),因?yàn)檫@個時候我們的進(jìn)程還只有一個線程(主線程)在運(yùn)行。但如果要把spydll.dll注入到已經(jīng)運(yùn)行的進(jìn)程,就需要在每一個目標(biāo)線程中調(diào)用spydll.dll的入口函數(shù),以分配函數(shù)替換需要的存貯空間,否則就會導(dǎo)致調(diào)用Prolog()函數(shù)時因?yàn)闆]有分配存貯空間而出錯。另外一方面,我們要Hook的目標(biāo)函數(shù)的地址將被我們的spydll.dll輸出,所以我們可以通過spydll.dll的輸出函數(shù)表獲取目標(biāo)函數(shù)在注入進(jìn)程中的地址。
由于對已運(yùn)行進(jìn)程的注入很復(fù)雜,除了實(shí)驗(yàn)用途以外,建議使用自己創(chuàng)建進(jìn)程的方式來注入。
總結(jié)
以上是生活随笔為你收集整理的Process-wide API spying - an ultimate hack 摘要翻译(三)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 几个java小问题代码(大神不喜勿喷)
- 下一篇: matlab中求矩阵的迹,求Matlab