496 lines
20 KiB
AutoIt
496 lines
20 KiB
AutoIt
|
;======================================
|
||
|
;~ Author : binhnx
|
||
|
;~ Created : 2014/10/20
|
||
|
;======================================
|
||
|
;~ Modified : BB_19
|
||
|
;~ Last modified : 2017/10/07
|
||
|
;======================================
|
||
|
|
||
|
#include-once
|
||
|
#include <WinAPI.au3>
|
||
|
#include <WinAPIShellEx.au3>
|
||
|
Local $_cHvr_aData[0]
|
||
|
|
||
|
|
||
|
Local Const $_cHvr_HDLLCOMCTL32 = _WinAPI_LoadLibrary('comctl32.dll')
|
||
|
Assert($_cHvr_HDLLCOMCTL32 <> 0, 'This UDF requires comctl32.dll')
|
||
|
Local Const $_cHvr_PDEFSUBCLASSPROC = _WinAPI_GetProcAddress($_cHvr_HDLLCOMCTL32, 'DefSubclassProc')
|
||
|
Local Const $_cHvr_PINTERNALSUBCLASS_DLL = DllCallbackRegister('_cHvr_iProc', 'NONE', 'HWND;UINT;WPARAM;LPARAM;DWORD')
|
||
|
Local Const $_cHvr_PINTERNALSUBCLASS = DllCallbackGetPtr($_cHvr_PINTERNALSUBCLASS_DLL)
|
||
|
|
||
|
OnAutoItExitRegister("_cHvr_Finalize")
|
||
|
Local Const $_cHvr_TSUBCLASSEXE = Call(@AutoItX64 ? '_cHvr_CSCP_X64' : '_cHvr_CSCP_X86')
|
||
|
Local Const $_cHvr_HEXECUTABLEHEAP = DllCall('kernel32.dll', 'HANDLE', 'HeapCreate', 'DWORD', 0x00040000, 'ULONG_PTR', 0, 'ULONG_PTR', 0)[0]
|
||
|
Assert($_cHvr_HEXECUTABLEHEAP <> 0, 'Failed to create executable heap object')
|
||
|
Local Const $_cHvr_PSUBCLASSEXE = _cHvr_ExecutableFromStruct(Call(@AutoItX64 ? '_cHvr_CSCP_X64' : '_cHvr_CSCP_X86'))
|
||
|
|
||
|
|
||
|
Func _cHvr_Register($idCtrl, $fnHovOff = '', $fnHoverOn = '', $fnClick = '', $fnDblClk = '', $HoverData = 0,$ClickData = 0,$fnRightClick = '')
|
||
|
Local $hWnd = GUICtrlGetHandle($idCtrl)
|
||
|
If (Not (IsHWnd($hWnd))) Then Return SetError(1, 0, -1)
|
||
|
Local $nIndex = _cHvr_GetNewIndex($hWnd)
|
||
|
Local $aData[13]
|
||
|
$aData[0] = $hWnd;Control Hwnd
|
||
|
$aData[1] = $idCtrl; Control handle
|
||
|
$aData[3] = $fnHovOff;Hover Off func
|
||
|
$aData[4] = $HoverData;Hover Off Data
|
||
|
$aData[5] = $fnHoverOn;Hover ON func
|
||
|
$aData[6] = $HoverData;Hover ON Data
|
||
|
$aData[7] = $fnRightClick;RClick func
|
||
|
$aData[8] = $ClickData; click data
|
||
|
$aData[9] = $fnClick;Click func
|
||
|
$aData[10] = $ClickData; click data
|
||
|
$aData[11] = $fnDblClk;DB click func
|
||
|
$aData[12] = $ClickData;DB click data
|
||
|
$_cHvr_aData[$nIndex] = $aData
|
||
|
_WinAPI_SetWindowSubclass($hWnd, $_cHvr_PSUBCLASSEXE, $hWnd, $nIndex)
|
||
|
Return $nIndex
|
||
|
EndFunc ;==>_cHvr_Register
|
||
|
|
||
|
Func _cHvr_iProc($hWnd, $uMsg, $wParam, $lParam, $cIndex)
|
||
|
Switch $uMsg
|
||
|
Case 0x0200;Hover
|
||
|
GUISetCursor(2, 1)
|
||
|
_cHvr_cMove($_cHvr_aData[$cIndex], $hWnd, $uMsg, $wParam, $lParam)
|
||
|
Case 0x0201;Leftclick
|
||
|
_cHvr_cDown($_cHvr_aData[$cIndex], $hWnd, $uMsg, $wParam, $lParam)
|
||
|
Case 0x0202
|
||
|
_cHvr_cUp($_cHvr_aData[$cIndex], $hWnd, $uMsg, $wParam, $lParam)
|
||
|
Return False
|
||
|
Case 0x0203;Doubleclick
|
||
|
_cHvr_cDblClk($_cHvr_aData[$cIndex], $hWnd, $uMsg, $wParam, $lParam)
|
||
|
Case 0x0204;Rightclick
|
||
|
_cHvr_cRightClk($_cHvr_aData[$cIndex], $hWnd, $uMsg, $wParam, $lParam)
|
||
|
Case 0x02A3;Hover leave
|
||
|
_cHvr_cLeave($_cHvr_aData[$cIndex], $hWnd, $uMsg, $wParam, $lParam)
|
||
|
Case 0x0082;Deleted
|
||
|
_cHvr_UnRegisterInternal($cIndex, $hWnd)
|
||
|
EndSwitch
|
||
|
Return True
|
||
|
EndFunc ;==>_cHvr_iProc
|
||
|
|
||
|
Func _cHvr_cDown(ByRef $aCtrlData, $hWnd, $uMsg, ByRef $wParam, ByRef $lParam)
|
||
|
_WinAPI_SetCapture($hWnd)
|
||
|
_cHvr_CallFunc($aCtrlData, 9)
|
||
|
EndFunc ;==>_cHvr_cDown
|
||
|
|
||
|
Func _cHvr_cMove(ByRef $aCtrlData, $hWnd, $uMsg, ByRef $wParam, ByRef $lParam)
|
||
|
If (_WinAPI_GetCapture() = $hWnd) Then
|
||
|
Local $bIn = _cHvr_IsInClient($hWnd, $lParam)
|
||
|
If Not $aCtrlData[2] Then
|
||
|
If $bIn Then
|
||
|
$aCtrlData[2] = 1
|
||
|
_cHvr_CallFunc($aCtrlData, 9)
|
||
|
EndIf
|
||
|
Else
|
||
|
If Not $bIn Then
|
||
|
$aCtrlData[2] = 0
|
||
|
_cHvr_CallFunc($aCtrlData, 3)
|
||
|
EndIf
|
||
|
EndIf
|
||
|
ElseIf Not $aCtrlData[2] Then
|
||
|
$aCtrlData[2] = 1
|
||
|
_cHvr_CallFunc($aCtrlData, 5)
|
||
|
Local $tTME = DllStructCreate('DWORD;DWORD;HWND;DWORD')
|
||
|
DllStructSetData($tTME, 1, DllStructGetSize($tTME))
|
||
|
DllStructSetData($tTME, 2, 2) ;$TME_LEAVE
|
||
|
DllStructSetData($tTME, 3, $hWnd)
|
||
|
DllCall('user32.dll', 'BOOL', 'TrackMouseEvent', 'STRUCT*', $tTME)
|
||
|
EndIf
|
||
|
EndFunc ;==>_cHvr_cMove
|
||
|
|
||
|
Func _cHvr_cUp(ByRef $aCtrlData, $hWnd, $uMsg, ByRef $wParam, ByRef $lParam)
|
||
|
Local $lRet = _WinAPI_DefSubclassProc($hWnd, $uMsg, $wParam, $lParam)
|
||
|
If (_WinAPI_GetCapture() = $hWnd) Then
|
||
|
_WinAPI_ReleaseCapture()
|
||
|
If _cHvr_IsInClient($hWnd, $lParam) Then
|
||
|
_cHvr_CallFunc($aCtrlData, 9)
|
||
|
EndIf
|
||
|
EndIf
|
||
|
Return $lRet
|
||
|
EndFunc ;==>_cHvr_cUp
|
||
|
|
||
|
Func _cHvr_cDblClk(ByRef $aCtrlData, $hWnd, $uMsg, ByRef $wParam, ByRef $lParam)
|
||
|
_cHvr_CallFunc($aCtrlData, 11)
|
||
|
EndFunc ;==>_cHvr_cDblClk
|
||
|
|
||
|
Func _cHvr_cRightClk(ByRef $aCtrlData, $hWnd, $uMsg, ByRef $wParam, ByRef $lParam)
|
||
|
_cHvr_CallFunc($aCtrlData, 7)
|
||
|
EndFunc ;==>_cHvr_cDblClk
|
||
|
|
||
|
Func _cHvr_cLeave(ByRef $aCtrlData, $hWnd, $uMsg, ByRef $wParam, ByRef $lParam)
|
||
|
$aCtrlData[2] = 0
|
||
|
_cHvr_CallFunc($aCtrlData, 3)
|
||
|
EndFunc ;==>_cHvr_cLeave
|
||
|
|
||
|
Func _cHvr_CallFunc(ByRef $aCtrlData, $iCallType)
|
||
|
Call($aCtrlData[$iCallType], $aCtrlData[1], $aCtrlData[$iCallType + 1])
|
||
|
EndFunc ;==>_cHvr_CallFunc
|
||
|
|
||
|
Func _cHvr_ArrayPush(ByRef $aStackArr, Const $vSrc1 = Default, Const $vSrc2 = Default, Const $vSrc3 = Default, Const $vSrc4 = Default, Const $vSrc5 = Default)
|
||
|
While (UBound($aStackArr) < ($aStackArr[0] + @NumParams))
|
||
|
ReDim $aStackArr[UBound($aStackArr) * 2]
|
||
|
WEnd
|
||
|
|
||
|
If Not ($vSrc1 = Default) Then
|
||
|
$aStackArr[0] += 1
|
||
|
$aStackArr[$aStackArr[0]] = $vSrc1
|
||
|
EndIf
|
||
|
If Not ($vSrc2 = Default) Then
|
||
|
$aStackArr[0] += 1
|
||
|
$aStackArr[$aStackArr[0]] = $vSrc2
|
||
|
EndIf
|
||
|
If Not ($vSrc3 = Default) Then
|
||
|
$aStackArr[0] += 1
|
||
|
$aStackArr[$aStackArr[0]] = $vSrc3
|
||
|
EndIf
|
||
|
If Not ($vSrc4 = Default) Then
|
||
|
$aStackArr[0] += 1
|
||
|
$aStackArr[$aStackArr[0]] = $vSrc4
|
||
|
EndIf
|
||
|
If Not ($vSrc5 = Default) Then
|
||
|
$aStackArr[0] += 1
|
||
|
$aStackArr[$aStackArr[0]] = $vSrc5
|
||
|
EndIf
|
||
|
EndFunc ;==>_cHvr_ArrayPush
|
||
|
|
||
|
Func _cHvr_IsInClient($hWnd, $lParam)
|
||
|
Local $iX = BitShift(BitShift($lParam, -16), 16)
|
||
|
Local $iY = BitShift($lParam, 16)
|
||
|
Local $aSize = WinGetClientSize($hWnd)
|
||
|
Return Not ($iX < 0 Or $iY < 0 Or $iX > $aSize[0] Or $iY > $aSize[1])
|
||
|
EndFunc ;==>_cHvr_IsInClient
|
||
|
|
||
|
Func _cHvr_CSCP_X86() ;Create Subclass Process x86
|
||
|
; $hWnd HWND size: 4 ESP+4 EBP+8
|
||
|
; $uMsg UINT size: 4 ESP+8 EBP+12
|
||
|
; $wParam WPARAM size: 4 ESP+12 EBP+16
|
||
|
; $lParam LPARAM size: 4 ESP+16 EBP+20
|
||
|
; $uIdSubclass UINT_PTR size: 4 ESP+20 EBP+24
|
||
|
; $dwRefData DWORD_PTR size: 4 ESP+24 EBP+28 Total: 24
|
||
|
|
||
|
; NERVER FORGET ADDING align 1 OR YOU WILL SPEND HOURS TO FIND WHAT CAUSE 0xC0000005 Access Violation
|
||
|
Local $sExe = 'align 1;'
|
||
|
Local $aOpCode[100]
|
||
|
$aOpCode[0] = 0
|
||
|
Local $nAddrOffset[5]
|
||
|
Local $nElemOffset[5]
|
||
|
|
||
|
; Func ; __stdcall
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;'
|
||
|
_cHvr_ArrayPush($aOpCode, 0x55) ;push ebp
|
||
|
_cHvr_ArrayPush($aOpCode, 0x8B, 0xEC) ;mov ebp, esp
|
||
|
|
||
|
; Save un-modified params to nv register
|
||
|
$sExe &= 'BYTE;' ;push ebx
|
||
|
_cHvr_ArrayPush($aOpCode, 0x53) ;53
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;' ;mov ebx, DWORD PTR [ebp+16]
|
||
|
_cHvr_ArrayPush($aOpCode, 0x8B, 0x5D, 16) ;8b 5d 10
|
||
|
$sExe &= 'BYTE;' ;push esi
|
||
|
_cHvr_ArrayPush($aOpCode, 0x56) ;56
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;' ;mov esi, DWORD PTR [ebp+12]
|
||
|
_cHvr_ArrayPush($aOpCode, 0x8B, 0x75, 12) ;8b 75 0c
|
||
|
$sExe &= 'BYTE;' ;push edi
|
||
|
_cHvr_ArrayPush($aOpCode, 0x57) ;57
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;' ;mov ebx, DWORD PTR [ebp+20]
|
||
|
_cHvr_ArrayPush($aOpCode, 0x8B, 0x7D, 20) ;8b 7d 14
|
||
|
|
||
|
; If ($uMsg = 0x0082) Then Goto WndProcInternal ;WM_NCDESTROY
|
||
|
$sExe &= 'BYTE;BYTE;DWORD;' ;cmp esi, 0x82
|
||
|
_cHvr_ArrayPush($aOpCode, 0x81, 0xFE, 0x82) ;81 fe 82 00 00 00
|
||
|
$sExe &= 'BYTE;BYTE;' ;je short WndProcInternal
|
||
|
_cHvr_ArrayPush($aOpCode, 0x74, 0) ;74 BYTE_OFFSET
|
||
|
$nAddrOffset[0] = DllStructGetSize(DllStructCreate($sExe))
|
||
|
$nElemOffset[0] = $aOpCode[0]
|
||
|
|
||
|
; ElseIf ($uMsg = 0x02A3) Then Goto WndProcInternal ;WM_MOUSELEAVE
|
||
|
$sExe &= 'BYTE;BYTE;DWORD;' ;cmp esi, 0x2A3
|
||
|
_cHvr_ArrayPush($aOpCode, 0x81, 0xFE, 0x2A3) ;81 fe a3 02 00 00
|
||
|
$sExe &= 'BYTE;BYTE;' ;je short WndProcInternal
|
||
|
_cHvr_ArrayPush($aOpCode, 0x74, 0) ;74 BYTE_OFFSET
|
||
|
$nAddrOffset[1] = DllStructGetSize(DllStructCreate($sExe))
|
||
|
$nElemOffset[1] = $aOpCode[0]
|
||
|
|
||
|
; ElseIf ($uMsg < 0x200 Or $uMsg > 0x203) Then Goto DefaultWndProc
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;' ;lea eax, DWORD PTR [esi-0x200]
|
||
|
_cHvr_ArrayPush($aOpCode, 0x8D, 0x86, -0x200) ;8d 86 00 02 00 00
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;' ;cmp eax, 3
|
||
|
_cHvr_ArrayPush($aOpCode, 0x83, 0xF8, 3) ;83 f8 03
|
||
|
$sExe &= 'BYTE;BYTE;' ;ja short DefaultWndProc
|
||
|
_cHvr_ArrayPush($aOpCode, 0x77, 0) ;77 BYTE_OFFSET
|
||
|
$nAddrOffset[2] = DllStructGetSize(DllStructCreate($sExe))
|
||
|
$nElemOffset[2] = $aOpCode[0]
|
||
|
|
||
|
; :WndProcInternal (HWND, UINT, WPARAM, LPARAM, DWORD)
|
||
|
$aOpCode[$nElemOffset[0]] = $nAddrOffset[2] - $nAddrOffset[0]
|
||
|
$aOpCode[$nElemOffset[1]] = $nAddrOffset[2] - $nAddrOffset[1]
|
||
|
|
||
|
; Prepare stack
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;' ;mov ecx, DWORD PTR [ebp+28]
|
||
|
_cHvr_ArrayPush($aOpCode, 0x8B, 0x4D, 28) ;8b 4d 1c
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;' ;mov edx, DWORD PTR [ebp+8]
|
||
|
_cHvr_ArrayPush($aOpCode, 0x8B, 0x55, 8) ;8b 55 08
|
||
|
$sExe &= 'BYTE;' ;push ecx
|
||
|
_cHvr_ArrayPush($aOpCode, 0x51) ;51
|
||
|
$sExe &= 'BYTE;' ;push edi
|
||
|
_cHvr_ArrayPush($aOpCode, 0x57) ;57
|
||
|
$sExe &= 'BYTE;' ;push ebx
|
||
|
_cHvr_ArrayPush($aOpCode, 0x53) ;53
|
||
|
$sExe &= 'BYTE;' ;push esi
|
||
|
_cHvr_ArrayPush($aOpCode, 0x56) ;56
|
||
|
$sExe &= 'BYTE;' ;push edx
|
||
|
_cHvr_ArrayPush($aOpCode, 0x52) ;52
|
||
|
|
||
|
; Call
|
||
|
$sExe &= 'BYTE;PTR;' ;mov eax, _cHvr_iProc
|
||
|
_cHvr_ArrayPush($aOpCode, 0xB8, $_cHvr_PINTERNALSUBCLASS)
|
||
|
$sExe &= 'BYTE;BYTE;' ;call near eax
|
||
|
_cHvr_ArrayPush($aOpCode, 0xFF, 0xD0) ;ff 75 8
|
||
|
|
||
|
; If (WndProcInternal() = 0) Then Return
|
||
|
$sExe &= 'BYTE;BYTE;' ;test eax, eax
|
||
|
_cHvr_ArrayPush($aOpCode, 0x85, 0xC0) ;85 c0
|
||
|
$sExe &= 'BYTE;BYTE;' ;jz short Return
|
||
|
_cHvr_ArrayPush($aOpCode, 0x74, 0) ;74 BYTE_OFFSET
|
||
|
$nAddrOffset[3] = DllStructGetSize(DllStructCreate($sExe))
|
||
|
$nElemOffset[3] = $aOpCode[0]
|
||
|
|
||
|
; :DefaultWndProc (HWND, UINT, WPARAM, LPARAM)
|
||
|
$aOpCode[$nElemOffset[2]] = $nAddrOffset[3] - $nAddrOffset[2]
|
||
|
|
||
|
; Prepare stack
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;' ;mov eax, DWORD PTR [ebp+8]
|
||
|
_cHvr_ArrayPush($aOpCode, 0x8B, 0x45, 8)
|
||
|
$sExe &= 'BYTE;' ;push edi
|
||
|
_cHvr_ArrayPush($aOpCode, 0x57) ;57
|
||
|
$sExe &= 'BYTE;' ;push ebx
|
||
|
_cHvr_ArrayPush($aOpCode, 0x53) ;53
|
||
|
$sExe &= 'BYTE;' ;push esi
|
||
|
_cHvr_ArrayPush($aOpCode, 0x56) ;56
|
||
|
$sExe &= 'BYTE;' ;push eax
|
||
|
_cHvr_ArrayPush($aOpCode, 0x50) ;50
|
||
|
|
||
|
;Call
|
||
|
$sExe &= 'BYTE;PTR;' ;mov eax,COMCTL32.DefSubclassProc
|
||
|
_cHvr_ArrayPush($aOpCode, 0xB8, $_cHvr_PDEFSUBCLASSPROC)
|
||
|
$sExe &= 'BYTE;BYTE;' ;call near eax
|
||
|
_cHvr_ArrayPush($aOpCode, 0xFF, 0xD0) ;ff 75 8
|
||
|
$nAddrOffset[4] = DllStructGetSize(DllStructCreate($sExe))
|
||
|
|
||
|
; :Return
|
||
|
$aOpCode[$nElemOffset[3]] = $nAddrOffset[4] - $nAddrOffset[3]
|
||
|
|
||
|
; Restore nv-register
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;'
|
||
|
_cHvr_ArrayPush($aOpCode, 0x5F) ;pop edi
|
||
|
_cHvr_ArrayPush($aOpCode, 0x5E) ;pop esi
|
||
|
_cHvr_ArrayPush($aOpCode, 0x5B) ;pop ebx
|
||
|
|
||
|
|
||
|
; EndFunc
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;WORD'
|
||
|
_cHvr_ArrayPush($aOpCode, 0x5D) ;pop ebp
|
||
|
_cHvr_ArrayPush($aOpCode, 0xC2, 24) ;ret 24
|
||
|
|
||
|
Return _cHvr_PopulateOpcode($sExe, $aOpCode)
|
||
|
EndFunc ;==>_cHvr_CSCP_X86
|
||
|
|
||
|
Func _cHvr_CSCP_X64() ;Create Subclass Process x64
|
||
|
; First four INT and UINT has size = 8 instead of 4 because they are stored in RCX, RDX, R8, R9
|
||
|
; $hWnd HWND size: 8 RCX RSP+8
|
||
|
; $uMsg UINT size: 8 EDX RSP+16
|
||
|
; $wParam WPARAM size: 8 R8 RSP+24
|
||
|
; $lParam LPARAM size: 8 R9 RSP+32
|
||
|
; $uIdSubclass UINT_PTR size: 8 RSP+40
|
||
|
; $dwRefData DWORD_PTR size: 8 RSP+48 Total: 48
|
||
|
Local $sExe = 'align 1;'
|
||
|
Local $aOpCode[100]
|
||
|
$aOpCode[0] = 0
|
||
|
Local $nAddrOffset[5]
|
||
|
Local $nElemOffset[5]
|
||
|
|
||
|
; If ($uMsg = 0x0082) Then Goto WndProcInternal ;WM_NCDESTROY
|
||
|
$sExe &= 'BYTE;BYTE;DWORD;' ;cmp edx, 0x82
|
||
|
_cHvr_ArrayPush($aOpCode, 0x81, 0xFA, 0x82) ;81 fa 82 00 00 00
|
||
|
$sExe &= 'BYTE;BYTE;' ;je short WndProcInternal
|
||
|
_cHvr_ArrayPush($aOpCode, 0x74, 0) ;74 BYTE_OFFSET
|
||
|
$nAddrOffset[0] = DllStructGetSize(DllStructCreate($sExe))
|
||
|
$nElemOffset[0] = $aOpCode[0]
|
||
|
|
||
|
; ElseIf ($uMsg = 0x02A3) Then Goto WndProcInternal ;WM_MOUSELEAVE
|
||
|
$sExe &= 'BYTE;BYTE;DWORD;' ;cmp edx, 0x2A3
|
||
|
_cHvr_ArrayPush($aOpCode, 0x81, 0xFA, 0x2A3) ;81 fa a3 02 00 00
|
||
|
$sExe &= 'BYTE;BYTE;' ;je short WndProcInternal
|
||
|
_cHvr_ArrayPush($aOpCode, 0x74, 0) ;74 BYTE_OFFSET
|
||
|
$nAddrOffset[1] = DllStructGetSize(DllStructCreate($sExe))
|
||
|
$nElemOffset[1] = $aOpCode[0]
|
||
|
|
||
|
; ElseIf ($uMsg < 0x200 Or $uMsg > 0x203) Then Goto DefaultWndProc
|
||
|
$sExe &= 'BYTE;BYTE;DWORD;' ;lea eax, DWORD PTR [rdx-0x200]
|
||
|
_cHvr_ArrayPush($aOpCode, 0x8D, 0x82, -0x200) ;8d 82 00 02 00 00
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;' ;cmp eax, 3
|
||
|
_cHvr_ArrayPush($aOpCode, 0x83, 0xF8, 3) ;83 f8 03
|
||
|
$sExe &= 'BYTE;BYTE;' ;ja short DefaultWndProc
|
||
|
_cHvr_ArrayPush($aOpCode, 0x77, 0) ;77 BYTE_OFFSET
|
||
|
$nAddrOffset[2] = DllStructGetSize(DllStructCreate($sExe))
|
||
|
$nElemOffset[2] = $aOpCode[0]
|
||
|
$aOpCode[$nElemOffset[0]] = $nAddrOffset[2] - $nAddrOffset[0]
|
||
|
$aOpCode[$nElemOffset[1]] = $nAddrOffset[2] - $nAddrOffset[1]
|
||
|
|
||
|
|
||
|
; :WndProcInternal (HWND rsp+8, UINT +16, WPARAM +24, LPARAM +32, DWORD +40)
|
||
|
; $dwRefData = [ESP+48+48(sub rsp, 48)+8(push rdi)] = [ESP+104]
|
||
|
; Save base registers:
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;BYTE;BYTE;' ;mov QWORD PTR [rsp+8], rbx
|
||
|
_cHvr_ArrayPush($aOpCode, 0x48, 0x89, 0x5C, 0x24, 8) ;48 89 5c 24 08
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;BYTE;BYTE;' ;mov QWORD PTR [rsp+16], rbp
|
||
|
_cHvr_ArrayPush($aOpCode, 0x48, 0x89, 0x6C, 0x24, 16) ;48 89 6c 24 10
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;BYTE;BYTE;' ;mov QWORD PTR [rsp+24], rsi
|
||
|
_cHvr_ArrayPush($aOpCode, 0x48, 0x89, 0x74, 0x24, 24) ;48 89 74 24 18
|
||
|
$sExe &= 'BYTE;' ;push rdi
|
||
|
_cHvr_ArrayPush($aOpCode, 0x57) ;57
|
||
|
; Max sub-routine params = 5 (size = 5*8 = 40), + 8 bytes for return value = 48.
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;BYTE;' ;sub rsp, 48
|
||
|
_cHvr_ArrayPush($aOpCode, 0x48, 0x83, 0xEC, 48) ;48 83 ec 30
|
||
|
; rbx, rbp, rsi now at [ESP+8+56], [ESP+16+56], [ESP+24+56]
|
||
|
|
||
|
; Save the parameters:
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;' ;mov rdi, r9
|
||
|
_cHvr_ArrayPush($aOpCode, 0x49, 0x8B, 0xF9) ;49 8b f9
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;' ;mov rsi, r8
|
||
|
_cHvr_ArrayPush($aOpCode, 0x49, 0x8B, 0xF0) ;49 8b f0
|
||
|
$sExe &= 'BYTE;BYTE;' ;mov ebx, edx
|
||
|
_cHvr_ArrayPush($aOpCode, 0x8B, 0xDA) ;8b da
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;' ;mov rbp, rcx
|
||
|
_cHvr_ArrayPush($aOpCode, 0x48, 0x8B, 0xE9) ;48 8b e9
|
||
|
|
||
|
; Prepare additional parameter for internal WndProc
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;BYTE;BYTE;' ;mov rax, QWORD PTR [rsp+104]
|
||
|
_cHvr_ArrayPush($aOpCode, 0x48, 0x8B, 0x44, 0x24, 104) ;48 8b 44 24 68
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;BYTE;BYTE;' ;mov QWORD PTR [rsp+32], Rax]
|
||
|
_cHvr_ArrayPush($aOpCode, 0x48, 0x89, 0x44, 0x24, 32) ;48 89 44 24 20
|
||
|
|
||
|
; Call internal WndProc
|
||
|
$sExe &= 'BYTE;BYTE;PTR;' ;mov rax, QWORD PTR _cHvr_iProc
|
||
|
_cHvr_ArrayPush($aOpCode, 0x48, 0xB8, $_cHvr_PINTERNALSUBCLASS)
|
||
|
;movabs rax, _cHvr_iProc ;48 b8 QWORD_PTR
|
||
|
$sExe &= 'BYTE;BYTE;' ;call rax
|
||
|
_cHvr_ArrayPush($aOpCode, 0xFF, 0xD0) ;ff d0
|
||
|
|
||
|
; If (WndProcInternal() = 0) Then Return
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;' ;cmp edx, 0x2A3
|
||
|
_cHvr_ArrayPush($aOpCode, 0x48, 0x85, 0xC0) ;48 85 c0
|
||
|
$sExe &= 'BYTE;BYTE;' ;je short WndProcInternal
|
||
|
_cHvr_ArrayPush($aOpCode, 0x74, 0)
|
||
|
$nAddrOffset[3] = DllStructGetSize(DllStructCreate($sExe))
|
||
|
$nElemOffset[3] = $aOpCode[0]
|
||
|
|
||
|
; Restore parameters for DefSubclassProc call
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;' ;mov r9, rdi
|
||
|
_cHvr_ArrayPush($aOpCode, 0x4C, 0x8B, 0xCF) ;4c 8b cf
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;' ;mov r8, rsi
|
||
|
_cHvr_ArrayPush($aOpCode, 0x4C, 0x8B, 0xC6) ;4c 8b c6
|
||
|
$sExe &= 'BYTE;BYTE;' ;mov edx, ebx
|
||
|
_cHvr_ArrayPush($aOpCode, 0x8B, 0xD3) ;8b d3
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;' ;mov rcx, rbp
|
||
|
_cHvr_ArrayPush($aOpCode, 0x48, 0x8B, 0xCD) ;48 8b cd
|
||
|
|
||
|
; Restore registers value
|
||
|
$aOpCode[$nElemOffset[3]] = DllStructGetSize(DllStructCreate($sExe)) - $nAddrOffset[3]
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;BYTE;BYTE;' ;mov rbx, QWORD PTR [rsp+64]
|
||
|
_cHvr_ArrayPush($aOpCode, 0x48, 0x8B, 0x5C, 0x24, 64) ;48 8b 5c 24 40
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;BYTE;BYTE;' ;mov rbp, QWORD PTR [rsp+72]
|
||
|
_cHvr_ArrayPush($aOpCode, 0x48, 0x8B, 0x6C, 0x24, 72) ;48 8b 6c 24 48
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;BYTE;BYTE;' ;mov rsi, QWORD PTR [rsp+80]
|
||
|
_cHvr_ArrayPush($aOpCode, 0x48, 0x8B, 0x74, 0x24, 80) ;48 8b 74 24 50
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;BYTE;' ;add rsp, 48
|
||
|
_cHvr_ArrayPush($aOpCode, 0x48, 0x83, 0xc4, 48) ;48 83 c4 30
|
||
|
$sExe &= 'BYTE;' ;pop rdi
|
||
|
_cHvr_ArrayPush($aOpCode, 0x5F) ;5f
|
||
|
$sExe &= 'BYTE;BYTE;BYTE;' ;cmp edx, 0x2A3
|
||
|
_cHvr_ArrayPush($aOpCode, 0x48, 0x85, 0xC0) ;48 85 c0
|
||
|
$sExe &= 'BYTE;BYTE;' ;je short WndProcInternal
|
||
|
_cHvr_ArrayPush($aOpCode, 0x74, 0)
|
||
|
$nAddrOffset[4] = DllStructGetSize(DllStructCreate($sExe))
|
||
|
$nElemOffset[4] = $aOpCode[0]
|
||
|
$aOpCode[$nElemOffset[2]] = DllStructGetSize(DllStructCreate($sExe)) - $nAddrOffset[2]
|
||
|
|
||
|
; :DefaultWndProc (HWND, UINT, WPARAM, LPARAM)
|
||
|
$sExe &= 'BYTE;BYTE;PTR;'
|
||
|
_cHvr_ArrayPush($aOpCode, 0x48, 0xB8, $_cHvr_PDEFSUBCLASSPROC)
|
||
|
$sExe &= 'BYTE;BYTE;'
|
||
|
_cHvr_ArrayPush($aOpCode, 0xFF, 0xE0)
|
||
|
|
||
|
; :Return
|
||
|
$aOpCode[$nElemOffset[4]] = DllStructGetSize(DllStructCreate($sExe)) - $nAddrOffset[4]
|
||
|
$sExe &= 'BYTE;' ;ret 0
|
||
|
_cHvr_ArrayPush($aOpCode, 0xC3)
|
||
|
|
||
|
Return _cHvr_PopulateOpcode($sExe, $aOpCode)
|
||
|
EndFunc ;==>_cHvr_CSCP_X64
|
||
|
|
||
|
Func _cHvr_PopulateOpcode(ByRef $sExe, ByRef $aOpCode)
|
||
|
Local $tExe = DllStructCreate($sExe)
|
||
|
Assert(@error = 0, 'DllStrucCreate Failed With Error = ' & @error)
|
||
|
For $i = 1 To $aOpCode[0]
|
||
|
DllStructSetData($tExe, $i, $aOpCode[$i])
|
||
|
Next
|
||
|
Return $tExe
|
||
|
EndFunc ;==>_cHvr_PopulateOpcode
|
||
|
|
||
|
Func _cHvr_ExecutableFromStruct($tExe)
|
||
|
Local $pExe = DllCall('kernel32.dll', 'PTR', 'HeapAlloc', 'HANDLE', $_cHvr_HEXECUTABLEHEAP, 'DWORD', 8, 'ULONG_PTR', DllStructGetSize($tExe))[0]
|
||
|
Assert($pExe <> 0, 'Allocate memory failed')
|
||
|
DllCall("kernel32.dll", "none", "RtlMoveMemory", "PTR", $pExe, "PTR", DllStructGetPtr($tExe), "ULONG_PTR", DllStructGetSize($tExe))
|
||
|
Assert(@error = 0, 'Failed to copy memory')
|
||
|
Return $pExe
|
||
|
EndFunc ;==>_cHvr_ExecutableFromStruct
|
||
|
|
||
|
Func _cHvr_UnRegisterInternal($cIndex, $hWnd)
|
||
|
_WinAPI_RemoveWindowSubclass($hWnd, $_cHvr_PSUBCLASSEXE, $hWnd)
|
||
|
Local $aData=$_cHvr_aData[$cIndex]
|
||
|
$_cHvr_aData[$cIndex] = 0
|
||
|
Call( "_iControlDelete",$aData[1])
|
||
|
EndFunc ;==>_cHvr_UnRegisterInternal
|
||
|
|
||
|
Func _cHvr_Finalize()
|
||
|
DllCallbackFree($_cHvr_PINTERNALSUBCLASS_DLL)
|
||
|
_WinAPI_FreeLibrary($_cHvr_HDLLCOMCTL32)
|
||
|
If ($_cHvr_HEXECUTABLEHEAP <> 0) Then
|
||
|
If ($_cHvr_PSUBCLASSEXE <> 0) Then
|
||
|
DllCall('kernel32.dll', 'BOOL', 'HeapFree', 'HANDLE', $_cHvr_HEXECUTABLEHEAP, 'DWORD', 0, 'PTR', $_cHvr_PSUBCLASSEXE)
|
||
|
EndIf
|
||
|
DllCall('kernel32.dll', 'BOOL', 'HeapDestroy', 'HANDLE', $_cHvr_HEXECUTABLEHEAP)
|
||
|
EndIf
|
||
|
EndFunc ;==>_cHvr_Finalize
|
||
|
|
||
|
Func Assert($bExpression, $sMsg = '', $sScript = @ScriptName, $sScriptPath = @ScriptFullPath, $iLine = @ScriptLineNumber, $iError = @error, $iExtend = @extended)
|
||
|
If (Not ($bExpression)) Then
|
||
|
MsgBox(BitOR(1, 0x10), 'Assertion Error!', _
|
||
|
@CRLF & 'Script' & @TAB & ': ' & $sScript _
|
||
|
& @CRLF & 'Path' & @TAB & ': ' & $sScriptPath _
|
||
|
& @CRLF & 'Line' & @TAB & ': ' & $iLine _
|
||
|
& @CRLF & 'Error' & @TAB & ': ' & ($iError > 0x7FFF ? Hex($iError) : $iError) _
|
||
|
& ($iExtend <> 0 ? ' (Extended : ' & ($iExtend > 0x7FFF ? Hex($iExtend) : $iExtend) & ')' : '') _
|
||
|
& @CRLF & 'Message' & @TAB & ': ' & $sMsg _
|
||
|
& @CRLF & @CRLF & 'OK: Exit Script' & @TAB & 'Cancel: Continue')
|
||
|
Exit
|
||
|
EndIf
|
||
|
EndFunc ;==>Assert
|
||
|
|
||
|
Func _cHvr_GetNewIndex($hWnd)
|
||
|
;Try to assign index from previously deleted control
|
||
|
For $i = 0 To UBound($_cHvr_aData) - 1 Step +1
|
||
|
If Not IsArray($_cHvr_aData[$i]) Then
|
||
|
Return $i
|
||
|
EndIf
|
||
|
Next
|
||
|
|
||
|
ReDim $_cHvr_aData[UBound($_cHvr_aData) + 1]
|
||
|
Return UBound($_cHvr_aData) - 1
|
||
|
EndFunc ;==>_cHvr_GetNewIndex
|
||
|
|
||
|
Func _WinAPI_GetCapture()
|
||
|
Return DllCall("user32.dll", "HWND", "GetCapture")[0]
|
||
|
EndFunc ;==>_WinAPI_GetCapture
|