jugador Posted February 2, 2024 Posted February 2, 2024 RegisterSyncCallback from autohotkey forum by @lexikos https://www.autohotkey.com/boards/viewtopic.php?f=6&t=21223 expandcollapse popup/* RegisterSyncCallback A replacement for RegisterCallback for use with APIs that will call the callback on the wrong thread. Synchronizes with the script's main thread via a window message. This version tries to emulate RegisterCallback as much as possible without using RegisterCallback, so shares most of its limitations, and some enhancements that could be made are not. Other differences from v1 RegisterCallback: - Variadic mode can't be emulated exactly, so is not supported. - A_EventInfo can't be set in v1, so is not supported. - Fast mode is not supported (the option is ignored). - ByRef parameters are allowed (but ByRef is ignored). - Throws instead of returning "" on failure. */ RegisterSyncCallback(FunctionName, Options:="", ParamCount:="") { if !(fn := Func(FunctionName)) || fn.IsBuiltIn throw Exception("Bad function", -1, FunctionName) if (ParamCount == "") ParamCount := fn.MinParams if (ParamCount > fn.MaxParams && !fn.IsVariadic || ParamCount+0 < fn.MinParams) throw Exception("Bad param count", -1, ParamCount) static sHwnd := 0, sMsg, sSendMessageW if !sHwnd { Gui RegisterSyncCallback: +Parent%A_ScriptHwnd% +hwndsHwnd OnMessage(sMsg := 0x8000, Func("RegisterSyncCallback_Msg")) sSendMessageW := DllCall("GetProcAddress", "ptr", DllCall("GetModuleHandle", "str", "user32.dll", "ptr"), "astr", "SendMessageW", "ptr") } if !(pcb := DllCall("GlobalAlloc", "uint", 0, "ptr", 96, "ptr")) throw DllCall("VirtualProtect", "ptr", pcb, "ptr", 96, "uint", 0x40, "uint*", 0) p := pcb if (A_PtrSize = 8) { /* 48 89 4c 24 08 ; mov [rsp+8], rcx 48 89 54'24 10 ; mov [rsp+16], rdx 4c 89 44 24 18 ; mov [rsp+24], r8 4c'89 4c 24 20 ; mov [rsp+32], r9 48 83 ec 28' ; sub rsp, 40 4c 8d 44 24 30 ; lea r8, [rsp+48] (arg 3, ¶ms) 49 b9 .. ; mov r9, .. (arg 4, operand to follow) */ p := NumPut(0x54894808244c8948, p+0) p := NumPut(0x4c182444894c1024, p+0) p := NumPut(0x28ec834820244c89, p+0) p := NumPut( 0xb9493024448d4c, p+0) - 1 lParamPtr := p, p += 8 p := NumPut(0xba, p+0, "char") ; mov edx, nmsg p := NumPut(sMsg, p+0, "int") p := NumPut(0xb9, p+0, "char") ; mov ecx, hwnd p := NumPut(sHwnd, p+0, "int") p := NumPut(0xb848, p+0, "short") ; mov rax, SendMessageW p := NumPut(sSendMessageW, p+0) /* ff d0 ; call rax 48 83 c4 28 ; add rsp, 40 c3 ; ret */ p := NumPut(0x00c328c48348d0ff, p+0) } else ;(A_PtrSize = 4) { p := NumPut(0x68, p+0, "char") ; push ... (lParam data) lParamPtr := p, p += 4 p := NumPut(0x0824448d, p+0, "int") ; lea eax, [esp+8] p := NumPut(0x50, p+0, "char") ; push eax p := NumPut(0x68, p+0, "char") ; push nmsg p := NumPut(sMsg, p+0, "int") p := NumPut(0x68, p+0, "char") ; push hwnd p := NumPut(sHwnd, p+0, "int") p := NumPut(0xb8, p+0, "char") ; mov eax, &SendMessageW p := NumPut(sSendMessageW, p+0, "int") p := NumPut(0xd0ff, p+0, "short") ; call eax p := NumPut(0xc2, p+0, "char") ; ret argsize p := NumPut((InStr(Options, "C") ? 0 : ParamCount*4), p+0, "short") } NumPut(p, lParamPtr+0) ; To be passed as lParam. p := NumPut(&fn, p+0) p := NumPut(ParamCount, p+0, "int") return pcb } RegisterSyncCallback_Msg(wParam, lParam) { if (A_Gui != "RegisterSyncCallback") return fn := Object(NumGet(lParam + 0)) paramCount := NumGet(lParam + A_PtrSize, "int") params := [] Loop % paramCount params.Push(NumGet(wParam + A_PtrSize * (A_Index-1))) return %fn%(params*) } contain machine code which I don't understand. Anyone knowledgeable about using machine code willing to convert it to Autoit
Andreik Posted February 2, 2024 Posted February 2, 2024 I am not familiar with AHK but there are plenty of examples which involves functions that use machine code in AutoIt. Just an example out of many
argumentum Posted February 2, 2024 Posted February 2, 2024 2 hours ago, jugador said: A replacement for RegisterCallback for use with APIs that will call the callback on the wrong thread. have you ever have that happened to you with AutoIt ? Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
jugador Posted February 2, 2024 Author Posted February 2, 2024 (edited) don't know if I translate it correct or not as I am also not familiar with AHK __ExampleA() Func __ExampleA() #cs p := NumPut(0x68, p+0, "char") ; push ... (lParam data) lParamPtr := p, p += 4 p := NumPut(0x0824448d, p+0, "int") ; lea eax, [esp+8] p := NumPut(0x50, p+0, "char") ; push eax p := NumPut(0x68, p+0, "char") ; push nmsg p := NumPut(sMsg, p+0, "int") p := NumPut(0x68, p+0, "char") ; push hwnd p := NumPut(sHwnd, p+0, "int") p := NumPut(0xb8, p+0, "char") ; mov eax, &SendMessageW p := NumPut(sSendMessageW, p+0, "int") p := NumPut(0xd0ff, p+0, "short") ; call eax p := NumPut(0xc2, p+0, "char") ; ret argsize p := NumPut((InStr(Options, "C") ? 0 : ParamCount*4), p+0, "short") #ce $sMsg = '0x8000' ;~ WM_APP $sHwnd = '0x000203B8' ;~ Dummy Gui Hwnd $sSendMessageW = '0x76695539' ;~ ProcAddress SendMessageW $ParamCount = 2 $TParam = $ParamCount*4 $bytecode = '0x' & '68' & '0824448d' & '50' & '68' & StringTrimLeft($sMsg, 2) & '68' & _ StringTrimLeft($sHwnd, 2) & 'b8' & StringTrimLeft($sSendMessageW, 2) & 'd0ff' & 'c2' & $TParam ConsoleWrite($bytecode & @crlf) ConsoleWrite(BinaryLen($bytecode) & @crlf) ;~ BinaryLen = 47 EndFunc what confuse me is if BinaryLen = 47 then why the number of bytes allocate is 96 DllCall("GlobalAlloc", "uint", 0, "ptr", 96, "ptr") Edited February 2, 2024 by jugador
Andreik Posted February 2, 2024 Posted February 2, 2024 You can allocate as much memory you want, it doesn't have to be the same size as the length of the binary data that you want to store.
jugador Posted February 3, 2024 Author Posted February 3, 2024 (edited) Just guess maybe we could solved this type of problem using such function(RegisterSyncCallback) Func __Dummy_Logic() $pcb = DllCall("GlobalAlloc", "uint", 0, "ptr", 96, "ptr")[0] $sMsg = 0x8000 ;~ WM_APP $sHwnd = 0x000203B8 ;~ Dummy Gui Hwnd $sSendMessageW = 0x76695539 ;~ ProcAddress SendMessageW $ParamCount = 2 $TParam = $ParamCount*4 $lParamPtr = $pcb Local $tSTRUCT1 = DllStructCreate("Char[5];uint_ptr", $pcb) DllStructSetData($tSTRUCT1, 1, 0x68) DllStructSetData($tSTRUCT1, 2, $lParamPtr) Local $tSTRUCT2 = DllStructCreate("Int;Char[5];Char[5];Int;Char[5];Int;Char[5];Int;Short;Char[5];Short", $pcb + 4) DllStructSetData($tSTRUCT2, 1, 0x0824448d) DllStructSetData($tSTRUCT2, 2, 0x50) DllStructSetData($tSTRUCT2, 3, 0x68) DllStructSetData($tSTRUCT2, 4, $sMsg) DllStructSetData($tSTRUCT2, 5, 0x68) DllStructSetData($tSTRUCT2, 6, $sHwnd) DllStructSetData($tSTRUCT2, 7, 0xb8) DllStructSetData($tSTRUCT2, 8, $sSendMessageW) DllStructSetData($tSTRUCT2, 9, 0xd0ff) DllStructSetData($tSTRUCT2, 10, 0xc2) DllStructSetData($tSTRUCT2, 11, $TParam) EndFunc Op code out of my reach So it's upto the MVP of Autoit forum to decide to add such function(RegisterSyncCallback) or not Edited February 3, 2024 by jugador
Danyfirex Posted February 4, 2024 Posted February 4, 2024 Hello, I don't think it's going to help much but just convert it for fun. expandcollapse popup#include <winapi.au3> #include <Memory.au3> MsgBox(0, "Main Thread", "GetCurrentThreadId: " & DllCall("kernel32.dll", "handle", "GetCurrentThread")[0]) Local $pCB = _RegisterSyncCallback(_MyFn) ;~ Local $pCB = _DllCallBackRegisterNormal(_MyFn) ;~ DllCallAddress("int", $pCB, "int", 123) DllCall("kernel32.dll", "hwnd", "CreateThread", "ptr", 0, "dword", 0, "long", $pCB, "ptr", 124, "long", 0, "int*", 0) MsgBox(0, "", "Click To Exit") Exit Func _MyFn($arg) MsgBox(0, "_MyFn - Child Thread", "GetCurrentThreadId: " & DllCall("kernel32.dll", "handle", "GetCurrentThread")[0] & @CRLF & "$arg: " & Int($arg)) EndFunc ;==>_MyFn Func _DllCallBackRegisterNormal($Function) Local $hHandle = DllCallbackRegister($Function, "int", "ptr") Return DllCallbackGetPtr($hHandle) EndFunc ;==>_DllCallBackRegisterNormal Func _RegisterSyncCallback($Function, $iOptions = 0, $iParamCount = 0) Local Static $hGUI Local Static $pSendMessage Local Static $iMsg If Not $hGUI Then $hGUI = GUICreate("RegisterSyncCallback_Msg", 300, 200) $iMsg = 0x8000 GUIRegisterMsg($iMsg, RegisterSyncCallback_Msg) $pSendMessage = DllCall("Kernel32.dll", "ptr", "GetProcAddress", "ptr", _WinAPI_GetModuleHandle("user32.dll"), "str", "SendMessageW")[0] ConsoleWrite("$hGUI: " & Hex($hGUI) & @CRLF) ConsoleWrite("$pSendMessage: " & Hex($pSendMessage) & @CRLF) ConsoleWrite("$iMsg: " & Hex($iMsg) & @CRLF) EndIf If @AutoItX64 Then Return MsgBox(0, "Error", "This is a x86 Sample :(") ;add x64 code yourself Local $pRemoteCode = _MemVirtualAlloc(0, 96, $MEM_COMMIT, $PAGE_EXECUTE_READWRITE) If Not $pRemoteCode Then MsgBox(0, "Error", "_MemVirtualAlloc :(") Local $tCodeBuffer = DllStructCreate("byte[96]", $pRemoteCode) Local $hHandle = DllCallbackRegister($Function, "int", "ptr") ;hardcode one parameter Local $sOPCode = "0x68" & SwapEndian($pRemoteCode + 30) & _ "8D4424085068" & SwapEndian($iMsg) & "68" & SwapEndian($hGUI) & _ "B8" & SwapEndian($pSendMessage) & "FFD0C20400" & _ SwapEndian(DllCallbackGetPtr($hHandle)) & "01000000" DllStructSetData($tCodeBuffer, 1, $sOPCode) ConsoleWrite("$tCodeBuffer: " & DllStructGetData($tCodeBuffer, 1) & @CRLF) Return $pRemoteCode EndFunc ;==>_RegisterSyncCallback Func RegisterSyncCallback_Msg($hWnd, $iMsg, $wParam, $lParam) ConsoleWrite(">RegisterSyncCallback_Msg Called" & @CRLF) ConsoleWrite("$hWnd: " & Hex($hWnd) & @CRLF) ConsoleWrite("$iMsg: " & Hex($iMsg) & @CRLF) ConsoleWrite("$wParam: " & Hex($wParam) & @CRLF) ConsoleWrite("$lParam: " & Hex($lParam) & @CRLF) Local $tStruct = DllStructCreate("ptr pFunction", $lParam) Local $tStructParameters = DllStructCreate("ptr NParameters", $lParam + 4) Local $tStructParametersValue = DllStructCreate("ptr Value", $wParam) ConsoleWrite("$tStruct.pFunction: " & $tStruct.pFunction & @CRLF) ConsoleWrite("$tStructParameters.NParameters: " & $tStructParameters.NParameters & @CRLF) ConsoleWrite("$tStructParametersValue.Value: " & $tStructParametersValue.Value & @CRLF) DllCallAddress("int", $tStruct.pFunction, "int", $tStructParametersValue.Value) Return 1 EndFunc ;==>RegisterSyncCallback_Msg Func SwapEndian($hex) Return Hex(BitOR(BitOR(BitOR(BitShift($hex, 24), _ BitAND(BitShift($hex, -8), 0x00FF0000)), _ BitAND(BitShift($hex, 8), 0x0000FF00)), _ BitShift($hex, -24)), 8) EndFunc ;==>SwapEndian Saludos jugador 1 Danysys.com AutoIt... UDFs: VirusTotal API 2.0 UDF - libZPlay UDF - Apps: Guitar Tab Tester - VirusTotal Hash Checker Examples: Text-to-Speech ISpVoice Interface - Get installed applications - Enable/Disable Network connection PrintHookProc - WINTRUST - Mute Microphone Level - Get Connected NetWorks - Create NetWork Connection ShortCut
jugador Posted February 5, 2024 Author Posted February 5, 2024 (edited) @Danyfirex Thanks for the code I do not understand Assembly code so I will not be able to modify the code as per my need. few question: 1) _DllCallBackRegisterNormal create 2 different thread then why no new thread created in case of _RegisterSyncCallback? 2) when use CreateThread in loop _DllCallBackRegisterNormal create 5 different thread but _RegisterSyncCallback run only once why? For $i = 1 to 5 DllCall("kernel32.dll", "hwnd", "CreateThread", "ptr", 0, "dword", 0, "long", $pCB, "ptr", 124, "long", 0, "int*", 0) Next 3) If I want to change this from 1 param to 4 param what change should I made to Assembly code? DllCallbackRegister($Function, "int", "ptr") ;hardcode one parameter test code: expandcollapse popup#include <winapi.au3> #include <Memory.au3> MsgBox(0, "Main Thread", "GetCurrentThreadId: " & DllCall("kernel32.dll", "dword", "GetCurrentThreadId")[0]) Local $pCB = _RegisterSyncCallback(_MyFn) ;Local $pCB = _DllCallBackRegisterNormal(_MyFn) ;~ DllCallAddress("int", $pCB, "int", 123) For $i = 1 to 5 DllCall("kernel32.dll", "hwnd", "CreateThread", "ptr", 0, "dword", 0, "long", $pCB, "ptr", 124, "long", 0, "int*", 0) Next MsgBox(0, "", "Click To Exit") Exit Func _MyFn($arg) MsgBox(0, "_MyFn - Child Thread", "GetCurrentThreadId: " & DllCall("kernel32.dll", "dword", "GetCurrentThreadId")[0] & @CRLF & "$arg: " & Int($arg)) EndFunc ;==>_MyFn Func _DllCallBackRegisterNormal($Function) Local $hHandle = DllCallbackRegister($Function, "int", "ptr") Return DllCallbackGetPtr($hHandle) EndFunc ;==>_DllCallBackRegisterNormal Func _RegisterSyncCallback($Function, $iOptions = 0, $iParamCount = 0) Local Static $hGUI Local Static $pSendMessage Local Static $iMsg If Not $hGUI Then $hGUI = GUICreate("RegisterSyncCallback_Msg", 300, 200) $iMsg = 0x8000 GUIRegisterMsg($iMsg, RegisterSyncCallback_Msg) $pSendMessage = DllCall("Kernel32.dll", "ptr", "GetProcAddress", "ptr", _WinAPI_GetModuleHandle("user32.dll"), "str", "SendMessageW")[0] ConsoleWrite("$hGUI: " & Hex($hGUI) & @CRLF) ConsoleWrite("$pSendMessage: " & Hex($pSendMessage) & @CRLF) ConsoleWrite("$iMsg: " & Hex($iMsg) & @CRLF) EndIf If @AutoItX64 Then Return MsgBox(0, "Error", "This is a x86 Sample :(") ;add x64 code yourself Local $pRemoteCode = _MemVirtualAlloc(0, 96, $MEM_COMMIT, $PAGE_EXECUTE_READWRITE) If Not $pRemoteCode Then MsgBox(0, "Error", "_MemVirtualAlloc :(") Local $tCodeBuffer = DllStructCreate("byte[96]", $pRemoteCode) Local $hHandle = DllCallbackRegister($Function, "int", "ptr") ;hardcode one parameter Local $sOPCode = "0x68" & SwapEndian($pRemoteCode + 30) & _ "8D4424085068" & SwapEndian($iMsg) & "68" & SwapEndian($hGUI) & _ "B8" & SwapEndian($pSendMessage) & "FFD0C20400" & _ SwapEndian(DllCallbackGetPtr($hHandle)) & "01000000" DllStructSetData($tCodeBuffer, 1, $sOPCode) ConsoleWrite("$tCodeBuffer: " & DllStructGetData($tCodeBuffer, 1) & @CRLF) Return $pRemoteCode EndFunc ;==>_RegisterSyncCallback Func RegisterSyncCallback_Msg($hWnd, $iMsg, $wParam, $lParam) ConsoleWrite(">RegisterSyncCallback_Msg Called" & @CRLF) ConsoleWrite("$hWnd: " & Hex($hWnd) & @CRLF) ConsoleWrite("$iMsg: " & Hex($iMsg) & @CRLF) ConsoleWrite("$wParam: " & Hex($wParam) & @CRLF) ConsoleWrite("$lParam: " & Hex($lParam) & @CRLF) Local $tStruct = DllStructCreate("ptr pFunction", $lParam) Local $tStructParameters = DllStructCreate("ptr NParameters", $lParam + 4) Local $tStructParametersValue = DllStructCreate("ptr Value", $wParam) ConsoleWrite("$tStruct.pFunction: " & $tStruct.pFunction & @CRLF) ConsoleWrite("$tStructParameters.NParameters: " & $tStructParameters.NParameters & @CRLF) ConsoleWrite("$tStructParametersValue.Value: " & $tStructParametersValue.Value & @CRLF) DllCallAddress("int", $tStruct.pFunction, "int", $tStructParametersValue.Value) Return 1 EndFunc ;==>RegisterSyncCallback_Msg Func SwapEndian($hex) Return Hex(BitOR(BitOR(BitOR(BitShift($hex, 24), _ BitAND(BitShift($hex, -8), 0x00FF0000)), _ BitAND(BitShift($hex, 8), 0x0000FF00)), _ BitShift($hex, -24)), 8) EndFunc ;==>SwapEndian Edited February 5, 2024 by jugador
Solution Danyfirex Posted February 5, 2024 Solution Posted February 5, 2024 Here a sample for passing two parameters (You would need to make it more dinamically) expandcollapse popup#include <winapi.au3> #include <Memory.au3> MsgBox(0, "Main Thread", "GetCurrentThreadId: " & DllCall("kernel32.dll", "handle", "GetCurrentThread")[0]) Local $pCB = _RegisterSyncCallback(_MyFn, 2) ;~ Local $pCB = _DllCallBackRegisterNormal(_MyFn) Local $tParameters = DllStructCreate("int Value1;int Value2") $tParameters.Value1 = 10 $tParameters.Value2 = 30 ;~ DllCallAddress("int", $pCB, "ptr", DllStructGetPtr($tParameters)) ConsoleWrite("DllStructGetPtr($tParameters): " & DllStructGetPtr($tParameters) & @CRLF) DllCall("kernel32.dll", "hwnd", "CreateThread", "ptr", 0, "dword", 0, "long", $pCB, "ptr", DllStructGetPtr($tParameters), "long", 0, "int*", 0) MsgBox(0, "", "Click To Exit") Exit Func _MyFn($arg1,$arg2) MsgBox(0, "_MyFn - Child Thread", "GetCurrentThreadId: " & DllCall("kernel32.dll", "handle", "GetCurrentThread")[0] & @CRLF & "$arg1: " & Int($arg1) & @CRLF & "$arg2: " & Int($arg2)) EndFunc ;==>_MyFn Func _DllCallBackRegisterNormal($Function) Local $hHandle = DllCallbackRegister($Function, "int", "ptr") Return DllCallbackGetPtr($hHandle) EndFunc ;==>_DllCallBackRegisterNormal Func _RegisterSyncCallback($Function, $iParamCount = 0, $iOptions = 0) Local Static $hGUI Local Static $pSendMessage Local Static $iMsg If Not $hGUI Then $hGUI = GUICreate("RegisterSyncCallback_Msg", 300, 200) $iMsg = 0x8000 GUIRegisterMsg($iMsg, RegisterSyncCallback_Msg) $pSendMessage = DllCall("Kernel32.dll", "ptr", "GetProcAddress", "ptr", _WinAPI_GetModuleHandle("user32.dll"), "str", "SendMessageW")[0] ConsoleWrite("$hGUI: " & Hex($hGUI) & @CRLF) ConsoleWrite("$pSendMessage: " & Hex($pSendMessage) & @CRLF) ConsoleWrite("$iMsg: " & Hex($iMsg) & @CRLF) EndIf If @AutoItX64 Then Return MsgBox(0, "Error", "This is a x86 Sample :(") ;add x64 code yourself Local $pRemoteCode = _MemVirtualAlloc(0, 96, $MEM_COMMIT, $PAGE_EXECUTE_READWRITE) If Not $pRemoteCode Then MsgBox(0, "Error", "_MemVirtualAlloc :(") Local $tCodeBuffer = DllStructCreate("byte[96]", $pRemoteCode) Local $hHandle = DllCallbackRegister($Function, "int", "int;int") ;hardcode one parameter Local $sOPCode = "0x68" & SwapEndian($pRemoteCode + 30) & _ "8D4424085068" & SwapEndian($iMsg) & "68" & SwapEndian($hGUI) & _ "B8" & SwapEndian($pSendMessage) & "FFD0C2" & StringLeft(SwapEndian($iParamCount * 4), 4) & _ SwapEndian(DllCallbackGetPtr($hHandle)) & SwapEndian($iParamCount) DllStructSetData($tCodeBuffer, 1, $sOPCode) ConsoleWrite("$tCodeBuffer: " & DllStructGetData($tCodeBuffer, 1) & @CRLF) Return $pRemoteCode EndFunc ;==>_RegisterSyncCallback Func RegisterSyncCallback_Msg($hWnd, $iMsg, $wParam, $lParam) ConsoleWrite(">RegisterSyncCallback_Msg Called" & @CRLF) ConsoleWrite("$hWnd: " & Hex($hWnd) & @CRLF) ConsoleWrite("$iMsg: " & Hex($iMsg) & @CRLF) ConsoleWrite("$wParam: " & Hex($wParam) & @CRLF) ConsoleWrite("$lParam: " & Hex($lParam) & @CRLF) Local $tStruct = DllStructCreate("ptr pFunction", $lParam) Local $tNParameters = DllStructCreate("ptr NParameters", $lParam + 4) Local $tStructParameters = DllStructCreate("ptr", $wParam) ConsoleWrite("$tStruct.pFunction: " & $tStruct.pFunction & @CRLF) ConsoleWrite("$tNParameters.NParameters: " & $tNParameters.NParameters & @CRLF) Local $aValues[$tNParameters.NParameters] For $i = 0 To $tNParameters.NParameters - 1 $aValues[$i] = DllStructGetData(DllStructCreate("int", DllStructGetData($tStructParameters, 1) + ($i * 4)),1) ConsoleWrite($aValues[$i] & @CRLF) Next DllCallAddress("int", $tStruct.pFunction, "int", $aValues[0],"int",$aValues[1]) Return 1 EndFunc ;==>RegisterSyncCallback_Msg Func SwapEndian($hex) Return Hex(BitOR(BitOR(BitOR(BitShift($hex, 24), _ BitAND(BitShift($hex, -8), 0x00FF0000)), _ BitAND(BitShift($hex, 8), 0x0000FF00)), _ BitShift($hex, -24)), 8) EndFunc ;==>SwapEndian 1: Don't now ask to the owner of the function haha (just don't want to look deeply) 2:I seems to be it needs some code interaction before run the other threads, sleep works For $i = 1 to 5 $tParameters.Value1=$i DllCall("kernel32.dll", "hwnd", "CreateThread", "ptr", 0, "dword", 0, "long", $pCB, "ptr",DllStructGetPtr($tParameters), "long", 0, "int*", 0) Sleep(100) ;need some autoit interaction Next 3: Already added using to struct and checking in the structure parameters but AutoIt does not allow to push parameters as ahk so you need to probably add some if with @NumParams. Saludos jugador 1 Danysys.com AutoIt... UDFs: VirusTotal API 2.0 UDF - libZPlay UDF - Apps: Guitar Tab Tester - VirusTotal Hash Checker Examples: Text-to-Speech ISpVoice Interface - Get installed applications - Enable/Disable Network connection PrintHookProc - WINTRUST - Mute Microphone Level - Get Connected NetWorks - Create NetWork Connection ShortCut
jugador Posted February 6, 2024 Author Posted February 6, 2024 (edited) I tried @trancexx _WinHttpSetStatusCallback example using @Danyfirex _RegisterSyncCallback funcation it worked next is to try @ProgAndy _WinHttpSetStatusCallback code to see if it work without crash Edit: _WinHttpSetStatusCallback code by @ProgAndy run smoothly without crash using @Danyfirex _RegisterSyncCallback funcation for testing try EnumWindows using _RegisterSyncCallback funcation that also worked . again Thanks @Danyfirex for helping me Edited February 6, 2024 by jugador
jugador Posted February 7, 2024 Author Posted February 7, 2024 (edited) @Danyfirex Hopefully one last question to understand code better 1) How you get value 30 ? => ($pRemoteCode + 30) what this 30 define Local $sOPCode = "0x68" & SwapEndian($pRemoteCode + 30) & _ ....... Edited June 2, 2025 by jugador
Danyfirex Posted February 7, 2024 Posted February 7, 2024 (edited) 30 is the number of bytes in the opcode till p := NumPut((InStr(Options, "C") ? 0 : ParamCount*4), p+0, "short") "char" 1 p+4 4 "int" 4 "char" 1 "char" 1 "int" 4 "char" 1 "int" 4 "char" 1 "int" 4 "short" 2 "char" 1 "short" 2 Saludos Edited February 7, 2024 by Danyfirex jugador 1 Danysys.com AutoIt... UDFs: VirusTotal API 2.0 UDF - libZPlay UDF - Apps: Guitar Tab Tester - VirusTotal Hash Checker Examples: Text-to-Speech ISpVoice Interface - Get installed applications - Enable/Disable Network connection PrintHookProc - WINTRUST - Mute Microphone Level - Get Connected NetWorks - Create NetWork Connection ShortCut
argumentum Posted February 7, 2024 Posted February 7, 2024 On 2/6/2024 at 12:20 AM, jugador said: _WinHttpSetStatusCallback code by @ProgAndy run smoothly without crash using @Danyfirex _RegisterSyncCallback post the better code ? for x86 and x64 ? Danyfirex 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
jugador Posted February 7, 2024 Author Posted February 7, 2024 (edited) @argumentum what better code as I know nothing about machine code . I used the code provided by @Danyfirex and to me that's the better code {marked as solved} Edited June 2, 2025 by jugador
Danyfirex Posted February 7, 2024 Posted February 7, 2024 what's the @ProgAndy's code? Saludos jugador 1 Danysys.com AutoIt... UDFs: VirusTotal API 2.0 UDF - libZPlay UDF - Apps: Guitar Tab Tester - VirusTotal Hash Checker Examples: Text-to-Speech ISpVoice Interface - Get installed applications - Enable/Disable Network connection PrintHookProc - WINTRUST - Mute Microphone Level - Get Connected NetWorks - Create NetWork Connection ShortCut
MattyD Posted July 4 Posted July 4 I'm looking back over this - and thought I'd try to explain some of the binary stuff if its helpful. In case its not clear, we're directing callbacks to a bit of pre-compiled code. That routine repackages the callback as a window message, and executes a sendMessage. To make sense of the assembly, we need understand what's going on under the hood with a stdcall . When you make a call in x86, the arguments must be placed on a stack. So take a SendMessage: $iResult = SendMessage($hGUI, $iMsg, $wParam, $lParam) Before we execute a CALL instruction, we first push all the params to our stack so it looks something like this: (Note that the ($hGUI) is technically the "top" of the stack, but I'm showing it this way with the latest push at the bottom.) ESP + 0x0C [ lParam ] ESP + 0x08 [ wParam ] ESP + 0x04 [ iMsg ] ESP + 0x00 [ hGUI ] <-- TOP of Stack And when we execute a CALL, an extra address automatically appears on top of stack. This is to take note of where we executing, so we can resume our routine once the call finishes. + 0x10 [ lParam ] + 0x0C [ wParam ] + 0x08 [ iMsg ] + 0x04 [ hGUI ] ESP [ RET ADD ] ;from EIP OK... So when a callback fires it firsts hits our "SynchronusCallback" pointer. This is that binary code that's dumped into memory. At this point the stack contains our arguments, and somewhere to go once we're done. - CallbackArg2 - CallbackArg1 - Return Address Now breaking down that binary.. The blob is in 3 parts - the executable bit at the start, some data in the middle, and a bunch of left over space. Executed bit: 0x681E003B048D44240850680080000068300B5800B8007D5776FFD0C20800 Data section: (pCallback & iParamCount) 0x00003C0402000000 The machine code calls sendmessage. And now the assembly instructions start to make a bit more sense. (EAX is basically just a register to hold 32bit data here.) 68 1E003B04 : PUSH 0x043B001E - "Push lParam" (A ptr to our "real" Callback address. Lives in the data part of the bin.) 8D 44 24 08 : LEA EAX, [ESP+0x08] - "Get wParam" (Get address where the args start - Already in the stack.) 50 : PUSH EAX - "Push wparam" 68 00800000 : PUSH 0x00008000 - "Push WM_APP" (literal value) 68 300B5800 : PUSH 0x00580B30 - "Push hGui" (hard coded in the bin) B8 007D5776 : MOV EAX, 0x76577D00 - "Get pSendMsg" (Load a ptr to the sendmsg func - again, hard coded in bin) FF D0 : CALL EAX - "Call SendMessage" C2 08 00 : RET 8 - "Return and clear the stck" (8 will clear the 2 Callback args at the beggining) Note the wParam value (our initial callback arguments) is literally a pointer the stack. We pull this out on the AutoIt side using a "int CallbackAg1; int Callback2;" struct or equivalent. Also note the "hard coded" addresses are only baked in when we generate the code at runtime. Now focusing on the "RET 8" line... and teardown. Our stack entering the sendmessage subroutine looks like this. - CallbackArg2 - CallbackArg1 - RetAddress to OSCallback Mgr - lParam (ptr to data bit of the bin) - wParam (Ptr to CallbackArg1 above) - iMsg (Hard Coded) - hGUI (Hard Coded) - RetAddress to Callback With the stdcall convention, functions are responsible for clearing their own args. So after the CALL, our stack should be back to: - CallbackArg2 - CallbackArg1 - RetAddress to OS Callback Mgr And then we execute "RET 8": RetAddress pops back to EIP Then we need to clear our stack so. Hence the "8" bytes (or 2x 32bit arguments). PS: Where does the return value from SendMessage end up? It'll likely be waiting for us in EAX. But we're not interested. argumentum and Danyfirex 2
MattyD Posted July 5 Posted July 5 64 bit is a bit different. This is untested, but from reading up of things. Once the callback fires, we have our parameters already loaded into CPU registers. Where they are live depends of their type: floating-point or ints. We will assume we have Ints to keep things simple. Param 1 - RCX Param 2 - RDX Param 3 - R8 Param 4 - R9 The caller has already allocated some space on the stack for us to dump these values. This is called the "shadow space". There must be 32 bytes there regardless of the parameter count. So to do the dump: MOV [RSP + 0x08], RCX MOV [RSP + 0x10], RDX MOV [RSP + 0x18], R8 MOV [RSP + 0x20], R9 If there are > 4 params, more space will be allocated for us to dump into - but the shadow space specifically refers to that 32-byte area. We'll assume we have < 4 params for now. After the move instructions our stack looks like such: ------Shadow Space ----- RSP + 0x20 [Param 4] RSP + 0x18 [Param 3] RSP + 0x10 [Param 2] RSP + 0x08 [Param 1] RSP [8-Byte Ret Address] <-Top of stack Now we need to setup the sendmessage call. We must allocate shadow space for the subroutine to use. SUB RSP, 40 Note: the return address is 8 bytes. but the stack must be byte-aligned to 16bytes. Hence we allocate 32bytes of shadow space + 8byte pad = 40 bytes (0x28 hex) So our stack is now: RSP + 0x48 [Param 4] RSP + 0x40 [Param 3] RSP + 0x38 [Param 2] RSP + 0x30 [Param 1] RSP + 0x28 [8-Byte Ret Address] ----------------------------------------------- RSP + 0x20 [8-Byte Alignment] ----------- Sendmsg shadow space ------------- RSP + 0x18 RSP + 0x10 RSP + 0x08 RSP + 0x00 And then we setup sendmessage's params. MOV RCX, 0xXXXXXXXXXXXXXXXX ; 1st param: Integer / hGUI MOV RDX, 0x00008000 ; 2nd param: Integer / iMsg ($WM_APP) LEA R8, [RSP + 0x30] ; 3rd param: Pointer / wParam (ptr to parent args) MOV R9, 0xYYYYYYYYYYYYYYYY ; 4th param: Integer / lParam (ptr to our "real" autoit routine) Now we can do the call by copying the grabbing the routine's ptr, and executing CALL MOV RAX, 0xZZZZZZZZZZZZZZZZ CALL RAX Unlike stdcall, we are responsible for clearing the callee's stack. So we should move the stack ptr forward 40 bytes (0x28 hex) to clear what we allocated earlier. Then we can finally return. ADD RSP, 40 RET All together we have: where X = hGUI, Y = pCallback (lparam), Z = pSendMessage MOV [RSP + 0x08], RCX MOV [RSP + 0x10], RDX MOV [RSP + 0x18], R8 MOV [RSP + 0x20], R9 SUB RSP, 40 MOV RCX, 0xXXXXXXXXXXXXXXXX MOX RXD, 0x00008000 LEA R8, [RSP + 0x30] MOV R9, 0xYYYYYYYYYYYYYYYY MOV RAX, 0xZZZZZZZZZZZZZZZZ CALL RAX ADD RSP, 40 RET And if you trust an AI's conversion, here's the machine code: (EDX is basically RDX, but its 32bit. The top bits of RDX are automatically cleared in the register) 48 89 4C 24 08 ; MOV [RSP + 0x08], RCX 48 89 54 24 10 ; MOV [RSP + 0x10], RDX 4C 89 44 24 18 ; MOV [RSP + 0x18], R8 4C 89 4C 24 20 ; MOV [RSP + 0x20], R9 48 83 EC 28 ; SUB RSP, 40 48 B9 XX XX XX XX XX ; MOV RCX, 0xXXXXXXXXXXXXXXXX (hGUI) XX XX XX BA 00 80 00 00 ; MOV EDX, 0x00008000 (iMsg - Optimized) 4C 8D 44 24 30 ; LEA R8, [RSP + 0x30] 49 B9 YY YY YY YY YY ; MOV R9, 0xYYYYYYYYYYYYYYYY (pCallback) YY YY YY 48 B8 ZZ ZZ ZZ ZZ ZZ ; MOV RAX, 0xZZZZZZZZZZZZZZZZ (pSendMessage) ZZ ZZ ZZ FF D0 ; CALL RAX 48 83 C4 28 ; ADD RSP, 40 C3 ; RET Danyfirex 1
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now