Jump to content

Recommended Posts

Posted
#NoTrayIcon
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <EditConstants.au3>
#include <WinAPIShellEx.au3>

_WinAPI_SetCurrentProcessExplicitAppUserModelID(@ScriptName & TimerInit())
Opt("GUIOnEventMode", 1)
Opt("TrayMenuMode", 3)
Opt("TrayOnEventMode", 1)

Local $iExitItem = TrayCreateItem("Exit Automation Tool")
TrayItemSetOnEvent($iExitItem, "_ExitScript")
TraySetState(1)
TraySetIcon(StringLeft(@AutoItExe, StringInStr(@AutoItExe, "\", 0, -1) - 1) & "\Icons\au3.ico")

TCPStartup()
Global $iWsSocket = websocketConnect() ; Connect to the active "--remote-debugging-port" instance

Global $hMainGUI = GUICreate("Simple CDP chrome automation example", 700, 500, -1, -1, BitOR($WS_OVERLAPPEDWINDOW, $WS_CLIPCHILDREN))
GUISetIcon(StringLeft(@AutoItExe, StringInStr(@AutoItExe, "\", 0, -1) - 1) & "\Icons\au3.ico")
GUISetBkColor(0x1F1F1F)
GUISetOnEvent($GUI_EVENT_CLOSE, "_ExitScript")

Global $idInputQuery = GUICtrlCreateInput("chrome debug feature via websocket", 15, 20, 540, 25)
GUICtrlSetFont(-1, 9.5, 400, 0, "Consolas")
GUICtrlSetColor(-1, 0xE0E0E0)
GUICtrlSetBkColor(-1, 0x2D2D2D)

Global $idBtnSend = GUICtrlCreateButton("Send Query", 565, 19, 120, 27)
GUICtrlSetFont(-1, 9, 600, 0, "Segoe UI")
GUICtrlSetOnEvent($idBtnSend, "_OnSendQuery_Click")

Global $idEditDump = GUICtrlCreateEdit("", 15, 65, 670, 415, BitOR($ES_MULTILINE, $ES_AUTOVSCROLL, $ES_READONLY, $WS_VSCROLL))
GUICtrlSetFont(-1, 9, 400, 0, "Consolas")
GUICtrlSetColor(-1, 0x00FF00) ; Retro terminal green output text  :D
GUICtrlSetBkColor(-1, 0x151515)

GUISetState(@SW_SHOW, $hMainGUI)

_SendWSFrame($iWsSocket, '{"id":1,"method":"Runtime.enable"}')
Sleep(100)
_SendWSFrame($iWsSocket, '{"id":2,"method":"Page.enable"}')

Global $bData, $sCleanText
While Sleep(20)
    $bData = TCPRecv($iWsSocket, 8192, 1)
    If @error Then
        _LogToPanel("!> Connection lost or Chrome process closed.")
        ExitLoop
    EndIf

    If BinaryLen($bData) > 0 Then
        $sCleanText = BinaryToString($bData, 4)
        _LogToPanel("RAW INCOMING PACKET:" & @CRLF & $sCleanText & @CRLF & _
                "--------------------------------------------------")
    EndIf
WEnd

_CleanShutdown()

Func _OnSendQuery_Click()
    Local $sSearchString = GUICtrlRead($idInputQuery)
    If StringStripWS($sSearchString, 8) = "" Then Return

    _LogToPanel("--> Formatting string parameters and steering Chrome engine...")

    ; Format the query text into a valid, safe URL format string
    Local $sTargetUrl = "https://www.google.com/search?q=" & $sSearchString
    $sTargetUrl = StringReplace($sTargetUrl, " ", "+")

    ; Fire the Navigation packet over the active WebSocket channel
    Local $sNavPayload = '{"id":100,"method":"Page.navigate","params":{"url":"' & $sTargetUrl & '"}}'
    _SendWSFrame($iWsSocket, $sNavPayload)
EndFunc   ;==>_OnSendQuery_Click

Func _LogToPanel($sMessage)
    $sMessage = StringReplace($sMessage, Chr(0), "")
    ConsoleWrite(@CRLF & '- ' & @HOUR & ':' & @MIN & ':' & @SEC & '.' & @MSEC & @CRLF & $sMessage)
    Local $sCurrentText = GUICtrlRead($idEditDump)
    GUICtrlSetData($idEditDump, $sMessage & @CRLF & $sCurrentText)
EndFunc   ;==>_LogToPanel

Func _ExitScript()
    ConsoleWrite("-> Disconnecting control panels safely." & @CRLF)
    _CleanShutdown()
EndFunc   ;==>_ExitScript

Func _CleanShutdown()
    TCPCloseSocket($iWsSocket)
    TCPShutdown()
    Exit
EndFunc   ;==>_CleanShutdown

Func websocketConnect($iPort = 9222, $sHost = "127.0.0.1")
    Local $iSocket = TCPConnect(TCPNameToIP($sHost), $iPort)
    If $iSocket = -1 Then Exit MsgBox(16, "Error", "Port " & $iPort & " not open. Did you restart Chrome with the" & @LF & " ""--remote-debugging-port=" & $iPort & """ flag?", 60)

    Local $sRequest = "GET /json/list HTTP/1.1" & @CRLF & "Host: " & $sHost & ":" & $iPort & @CRLF & @CRLF
    TCPSend($iSocket, $sRequest)

    Local $sResponse = ""
    Do
        $sResponse &= TCPRecv($iSocket, 1024)
    Until StringInStr($sResponse, "]")
    TCPCloseSocket($iSocket)

    Local $aUrlParts = StringRegExp($sResponse, '"webSocketDebuggerUrl":\s*"(ws://.*?)"', 1)
    If Not IsArray($aUrlParts) Then Exit MsgBox(16, "Error", "Open a web page tab in Chrome first!")
    Local $sWsTarget = $aUrlParts[0]

    Local $aWsParts = StringRegExp($sWsTarget, "ws://([^/]+)(/devtools/page/.*)", 1)
    Local $sWsHost = $aWsParts[0]
    Local $sWsPath = $aWsParts[1]

    Local $iWsSocket = TCPConnect(TCPNameToIP($sHost), $iPort)
    If $iSocket = -1 Then Return SetError(202, 202, 202)
    Local $sHandshake = "GET " & $sWsPath & " HTTP/1.1" & @CRLF & _
            "Host: " & $sWsHost & @CRLF & _
            "Upgrade: websocket" & @CRLF & _
            "Connection: Upgrade" & @CRLF & _
            "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" & @CRLF & _
            "Sec-WebSocket-Version: 13" & @CRLF & @CRLF
    TCPSend($iWsSocket, $sHandshake)
    Sleep(400)
    TCPRecv($iWsSocket, 4096) ; Clear handshake junk
    Return $iWsSocket
EndFunc   ;==>websocketConnect

Func _SendWSFrame($iSocket, $sPayload)
    Local $iRet, $bText = StringToBinary($sPayload, 4) ; Strict UTF-8 text conversion
    Local $iLen = BinaryLen($bText)

    ; Generate 4 Random Mask Bytes required by Chrome
    Local $bMaskingKey = Binary("0x" & Hex(Random(16, 255, 1), 2) & Hex(Random(16, 255, 1), 2) & Hex(Random(16, 255, 1), 2) & Hex(Random(16, 255, 1), 2))
    Local $aMask[4]
    For $i = 0 To 3
        $aMask[$i] = Int(BinaryMid($bMaskingKey, $i + 1, 1))
    Next

    Local $bHeader
    If $iLen <= 125 Then
        $bHeader = Binary("0x81" & Hex($iLen + 128, 2)) ; Add 128 bit flag to notify payload is masked
    ElseIf $iLen >= 126 And $iLen <= 65535 Then
        $bHeader = Binary("0x81FE" & Hex($iLen, 4))
    EndIf

    ; Mask the payload buffer array byte-by-byte using XOR
    Local $bMaskedPayload = Binary("0x")
    For $i = 1 To $iLen
        Local $iByte = Int(BinaryMid($bText, $i, 1))
        Local $iMaskedByte = BitXOR($iByte, $aMask[Mod($i - 1, 4)])
        $bMaskedPayload &= Hex($iMaskedByte, 2)
    Next

    ; Transmit standard WebSocket client packet structure
    $iRet = TCPSend($iSocket, $bHeader & $bMaskingKey & $bMaskedPayload)
    Return SetError(@error, @extended, $iRet)
EndFunc   ;==>_SendWSFrame

for a feature rich UDF, use AutoIt CDP UDF from @seangriffin 

This is a simple WebSocket thing and call it a day. Just a light example.
But it did do what I needed and thought of sharing it.

You'll need at least chrome.exe --remote-debugging-port=9222 --user-data-dir="C:\ChromeDebugFolder" to be running for this to do anything.

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting  image.gif.922e3a93535f431de08b31ee669cc446.gif
autoit_scripter_blue_userbar.png

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...