Jump to content

CallByName on COM Object exceptions


Recommended Posts

I tried to implement the code in this topic:

Firstly, i have no idea how these lines of code work but meanwhile i noticed that:

; Everytime autoit wants to call a method, get or set a property in a object it needs to go to
; IDispatch::GetIDsFromNames. This is our version of that function, note that by defining this ourselves
; we can fool autoit to believe that the object supports a lot of different properties/methods.
Func __IDispatch_GetIDsFromNames($pSelf, $riid, $rgszNames, $cNames, $lcid, $rgDispId)
...
EndFunc

The problem is i ran into is that some object calls didn't go through IDispatch::GetIDsFromNames.
Here is the code to replicate what i'm mentioning:

Spoiler
;Au3CallByName, Bilgus
Global $Au3_CallByName = 0
Global $hKernel32 = DllOpen("Kernel32.dll")
OnAutoItExitRegister(__CallByNameCleanup)


Func __CallByNameCleanup()
    Au3_CallByName_Init(False) ;Unload
    DllClose($hKernel32)
EndFunc   ;==>__CallByNameCleanup

; Takes a pointer to the v-table in a class and replaces specified member Id in it to a new one.
Func __HookVTableEntry($pVtable, $iVtableOffset, $pHook, ByRef $pOldRet)
    ;;https://www.autoitscript.com/forum/topic/107678-hooking-into-the-idispatch-interface/
    Local Const $PAGE_READWRITE = 0x04
    Local $tpVtable = DllStructCreate("ptr", $pVtable)
    Local $szPtr = DllStructGetSize($tpVtable)
    Local $pFirstEntry, $pEntry, $tEntry, $aCall, $flOldProtect, $bStatus

    ; Dereference the vtable pointer
    $pFirstEntry = DllStructGetData($tpVtable, 1)
    $pEntry = $pFirstEntry + ($iVtableOffset * $szPtr) ;vtable is a big array of pointers 

    ; Make the memory free for all. Yay!
    $aCall = DllCall($hKernel32, "int", "VirtualProtect", "ptr", $pEntry, "long", $szPtr, "dword", $PAGE_READWRITE, "dword*", 0)

    If @error Or Not $aCall[0] Then
        ConsoleWriteError("Error: Failed To hook vTable" & @CRLF)
        Return False
    EndIf
    $flOldProtect = $aCall[4]

    $tEntry = DllStructCreate("ptr", $pEntry)
    $pOldRet = DllStructGetData($tEntry, 1)
    If $pOldRet <> $pHook Then
        DllStructSetData($tEntry, 1, $pHook)
        $bStatus = True
    Else ;Already Hooked
        ConsoleWriteError("Error: vTable is already hooked" & @CRLF)
        $bStatus = False
    EndIf

    ;put the memory protect back how we found it
    DllCall($hKernel32, "int", "VirtualProtect", "ptr", $pEntry, "long", $szPtr, "dword", $flOldProtect, "dword*", 0)
    Return $bStatus
EndFunc   ;==>__HookVTableEntry

; Everytime autoit wants to call a method, get or set a property in a object it needs to go to
; IDispatch::GetIDsFromNames. This is our version of that function, note that by defining this ourselves
; we can fool autoit to believe that the object supports a lot of different properties/methods.
Func __IDispatch_GetIDsFromNames($pSelf, $riid, $rgszNames, $cNames, $lcid, $rgDispId)
    Local Const $DISP_E_UNKNOWNNAME = 0x80020006, $DISPID_UNKNOWN = -1
    Local Static $pGIFN = __Pointer_GetIDsFromNames()
    Local $hRes

    ;Call the original GetIDsFromNames
    $hRes = DllCallAddress("LRESULT", $pGIFN, "ptr", $pSelf, "ptr", $riid, _
            "struct*", $rgszNames, "dword", $cNames, "dword", $lcid, "ptr", $rgDispId)
    If @error Then
        ConsoleWriteError("Error: GetIDsFromNames: " & @error & @CRLF)
        Return $DISP_E_UNKNOWNNAME
    EndIf

    ; Autoit didnt find the name now its our turn
    If $DISPID_UNKNOWN = DllStructGetData(DllStructCreate("long[" & $cNames & "]", $rgDispId), 1, 1) Then
        ;$rgszNames is a pointer to an array[$cNames] of names -- Autoit only asks for one member $cNames = 1
        Local $tName = DllStructCreate("wchar[64]", DllStructGetData(DllStructCreate("ptr[" & $cNames & "]", $rgszNames), 1, 1))
        Local $sName = DllStructGetData($tName, 1)
        ConsoleWrite($sName & @CRLF)

        ;We just prepend CBN_CB_ to the function name and try to call it
        $hRes = Call("CBN_CB_" & $sName, $sName, $pGIFN, $pSelf, $riid, $rgszNames, $cNames, $lcid, $rgDispId)
        If Not @error And $hRes <> Default Then Return $hRes ; User handled the function

        ;Call the original GetIDsFromNames
        $hRes = DllCallAddress("LRESULT", $pGIFN, "ptr", $pSelf, "ptr", $riid, _
                "struct*", $rgszNames, "dword", $cNames, "dword", $lcid, "ptr", $rgDispId)
        If @error Then
            ConsoleWrite("Error: GetIDsFromNames: " & @error & @CRLF)
            Return $DISP_E_UNKNOWNNAME
        EndIf
    EndIf
    Return $hRes[0]
EndFunc   ;==>__IDispatch_GetIDsFromNames

Func __Pointer_GetIDsFromNames($ptr = 0)
    ;Stores pointer to the original 'GetIDsFromNames'
    Local Static $pOldGIFN = $ptr
    If $ptr <> 0 Then $pOldGIFN = $ptr
    Return $pOldGIFN
EndFunc   ;==>__Pointer_GetIDsFromNames

Func Au3_CallByName_Init($bHook = True, $classname = "shell.application")
    Local Const $iOffset_GetIDsFromNames = 5 ;vtable index

    Local Static $IDispatch_GetIDsFromNames_Callback = 0
    Local $oObject, $pObject, $pHook, $pOldGIFN

    If $bHook Then
        If $IDispatch_GetIDsFromNames_Callback = 0 Then
            $IDispatch_GetIDsFromNames_Callback = DllCallbackRegister("__IDispatch_GetIDsFromNames", _
                                                                      "LRESULT", "ptr;ptr;ptr;dword;dword;ptr")
        EndIf
        $pHook = DllCallbackGetPtr($IDispatch_GetIDsFromNames_Callback)
    Else
        $pHook = __Pointer_GetIDsFromNames()
        If $pHook <= 0 Then Return ;Already Unloaded
    EndIf

    $oObject = ObjCreate($classname)
    $pObject = DllStructSetData(DllStructCreate("ptr"), 1, $oObject)

    If __HookVTableEntry($pObject, $iOffset_GetIDsFromNames, $pHook, $pOldGIFN) Then
        __Pointer_GetIDsFromNames($pOldGIFN) ;Save the original pointer to GetIDsFromNames
        If Not $bHook Then
            DllCallbackFree($IDispatch_GetIDsFromNames_Callback)
            $IDispatch_GetIDsFromNames_Callback = 0
        EndIf
    Else
        ;Error
    EndIf

    $oObject = 0
EndFunc   ;==>Au3_CallByName_Init

;|||||||||===========|||||||||
;||||||||| CallBacks |||||||||
Func CBN_CB_Au3_CallByName($sName, $pGIFN, $pSelf, $riid, $rgszNames, $cNames, $lcid, $rgDispId)
    Local Const $DISP_E_UNKNOWNNAME = 0x80020006
    ConsoleWrite(">Call By Name: " & $sName &  " -> " & $Au3_CallByName & @crlf)
    Local Static $tpMember = DllStructCreate("ptr")
    If $Au3_CallByName Then
        Local $hRes, $tMember

        ;ConsoleWrite("CallByName: " & $Au3_CallByName & @CRLF)
        $tMember = DllStructCreate("wchar[" & StringLen($Au3_CallByName) + 1 & "]")
        DllStructSetData($tMember, 1, $Au3_CallByName)
        DllStructSetData($tpMember, 1, DllStructGetPtr($tMember))
        $rgszNames = $tpMember
        $Au3_CallByName = 0

        ;Call the original GetIDsFromNames
        $hRes = DllCallAddress("LRESULT", $pGIFN, "ptr", $pSelf, "ptr", $riid, _
                "struct*", $rgszNames, "dword", $cNames, "dword", $lcid, "ptr", $rgDispId)
        If @error Then
            ConsoleWrite("Error: Call By Name: " & @error & @CRLF)
            Return $DISP_E_UNKNOWNNAME
        EndIf
        Return $hRes[0]
    EndIf
    Return Default ;Default handler
EndFunc

;||||||||| CallBacks |||||||||
;|||||||||===========|||||||||

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;TESTS;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


Au3_CallByName_Init() 

#include <MsgBoxConstants.au3>
#include <Word.au3>

; Create application object
Local $oWord = _Word_Create()
If @error Then Exit MsgBox($MB_SYSTEMMODAL, "Word UDF: _Word_DocTableWrite Example", _
        "Error creating a new Word application object." & @CRLF & "@error = " & @error & ", @extended = " & @extended)
; Open the test document
Local $oDoc = __Word_DocOpen($oWord, @ScriptDir & "\doc.doc", Default, Default, True)
If @error Then Exit MsgBox($MB_SYSTEMMODAL, "Word UDF: _Word_DocTableWrite Example", _
        "Error opening '.\Extras\Test.doc'." & @CRLF & "@error = " & @error & ", @extended = " & @extended)

Func __Word_DocOpen($oAppl, $sFilePath, $bConfirmConversions = Default, $iFormat = Default, $bReadOnly = Default, $bRevert = Default, $bAddToRecentFiles = Default, $sOpenPassword = Default, $sWritePassword = Default)
    If $bConfirmConversions = Default Then $bConfirmConversions = False
    If $iFormat = Default Then $iFormat = $WdOpenFormatAuto
    If $bReadOnly = Default Then $bReadOnly = False
    If $bRevert = Default Then $bRevert = False
    If $bAddToRecentFiles = Default Then $bAddToRecentFiles = False
    If $sOpenPassword = Default Then $sOpenPassword = ""
    If $sWritePassword = Default Then $sWritePassword = ""
    If Not IsObj($oAppl) Then Return SetError(1, 0, 0)
    If StringLeft($sFilePath, "HTTP") = 0 And Not FileExists($sFilePath) Then Return SetError(2, 0, 0)
    If StringInStr($sFilePath, "\") = 0 Then $sFilePath = @ScriptDir & "\" & $sFilePath

    $Au3_CallByName = 'Documents'
    Local $oDoc = $oAppl.Au3_CallByName

    $Au3_CallByName = 'Open'
    ;~ $oDoc = $oDoc.Open($sFilePath, $bConfirmConversions, $bReadOnly, $bAddToRecentFiles, $sOpenPassword, "", $bRevert, $sWritePassword, "", $iFormat) ;this works
    $oDoc = $oDoc.Au3_CallByName($sFilePath, $bConfirmConversions, $bReadOnly, $bAddToRecentFiles, $sOpenPassword, "", $bRevert, $sWritePassword, "", $iFormat)
    If @error Or Not IsObj($oDoc) Then Return SetError(3, @error, 0)
    ; If a read-write document was opened read-only then return an error
    If $bReadOnly = False And $oDoc.Readonly = True Then Return SetError(0, 1, $oDoc)
    Return $oDoc
EndFunc   ;==>_Word_DocOpen

 

I followed the example in the topic and tried to do the same thing with method .Documents (line 193) and .Open (line 194) but didn't get the same result because .Documents was being passed through __IDispatch_GetIDsFromNames while .Open didn't.

$Au3_CallByName = 'Documents'
Local $oDoc = $oAppl.Au3_CallByName
$Au3_CallByName = 'Open'
$oDoc = $oDoc.Au3_CallByName($sFilePath, $bConfirmConversions, $bReadOnly, $bAddToRecentFiles, $sOpenPassword, "", $bRevert, $sWritePassword, "", $iFormat)

Console outputs:

==> The requested action with this object has failed.:
$oDoc = $oDoc.Au3_CallByName($sFilePath, $bConfirmConversions, $bReadOnly, $bAddToRecentFiles, $sOpenPassword, "", $bRevert, $sWritePassword, "", $iFormat)
$oDoc = $oDoc^ ERROR

Is there any workarounds to solve this?

Thank you!

Edited by sylremo
Link to comment
Share on other sites

Hi @Bilgus, thank you for your quick response

5 hours ago, Bilgus said:

Have you tried hooking the word object instead?

Yes, i tried but it made no differences.

I came up with another example

Spoiler
#RequireAdmin

Global $Au3_CallByName = 0
Global $hKernel32 = DllOpen("Kernel32.dll")
OnAutoItExitRegister(__CallByNameCleanup)

Global $g___oJSON_Init

Global $sOJsonLibrary = FileRead(@ScriptDir & '\JSON.js')

Global $iError = 0

Au3_CallByName_Init(True, 'HTMLFILE')
$g___oJSON_Obj = ObjCreate("HTMLFILE")

If @error Then
    $iError = 1 
Else
    ;~ ConsoleWrite('IsObj($g___oJSON_Obj.parentwindow) -> ' & IsObj($g___oJSON_Obj.parentwindow) & @CRLF)
    ;~ For $i = 1 To 7
    ;~     ConsoleWrite($i & ' -> ' & ObjName($g___oJSON_Obj, $i) & @CRLF)
    ;~ Next
    $g___oJSON_Obj.parentwindow.execScript($sOJsonLibrary)
    If @error Then
        $iError = 2 
    Else
        $g___oJSON_Init = $g___oJSON_Obj.parentwindow.eval('JSON')
        If @error Then
            $iError = 3
        EndIf
    EndIf
EndIf

$JSON = $g___oJSON_Init.parse('{"title":"text"}')

MsgBox(4096, $iError, $JSON.title)

Func __CallByNameCleanup()
    Au3_CallByName_Init(False)     ;Unload
    DllClose($hKernel32)
EndFunc   ;==>__CallByNameCleanup

Func __HookVTableEntry($pVtable, $iVtableOffset, $pHook, ByRef $pOldRet)
    ;;https://www.autoitscript.com/forum/topic/107678-hooking-into-the-idispatch-interface/
    Local Const $PAGE_READWRITE = 0x04
    Local $tpVtable = DllStructCreate("ptr", $pVtable)
    Local $szPtr = DllStructGetSize($tpVtable)
    Local $pFirstEntry, $pEntry, $tEntry, $aCall, $flOldProtect, $bStatus

    ; Dereference the vtable pointer
    $pFirstEntry = DllStructGetData($tpVtable, 1)
    $pEntry = $pFirstEntry + ($iVtableOffset * $szPtr)     ;vtable is a big array of pointers

    ; Make the memory free for all. Yay!
    $aCall = DllCall($hKernel32, "int", "VirtualProtect", "ptr", $pEntry, "long", $szPtr, "dword", $PAGE_READWRITE, "dword*", 0)

    If @error Or Not $aCall[0] Then
        ConsoleWriteError("Error: Failed To hook vTable" & @CRLF)
        Return False
    EndIf
    $flOldProtect = $aCall[4]

    $tEntry = DllStructCreate("ptr", $pEntry)
    $pOldRet = DllStructGetData($tEntry, 1)
    If $pOldRet <> $pHook Then
        DllStructSetData($tEntry, 1, $pHook)
        $bStatus = True
    Else     ;Already Hooked
        ConsoleWriteError("Error: vTable is already hooked" & @CRLF)
        $bStatus = False
    EndIf

    ;put the memory protect back how we found it
    DllCall($hKernel32, "int", "VirtualProtect", "ptr", $pEntry, "long", $szPtr, "dword", $flOldProtect, "dword*", 0)
    Return $bStatus
EndFunc   ;==>__HookVTableEntry

Func __IDispatch_GetIDsFromNames($pSelf, $riid, $rgszNames, $cNames, $lcid, $rgDispId)
    Local Const $DISP_E_UNKNOWNNAME = 0x80020006, $DISPID_UNKNOWN = -1
    Local Static $pGIFN = __Pointer_GetIDsFromNames()
    Local $hRes

    ;Call the original GetIDsFromNames
    $hRes = DllCallAddress("LRESULT", $pGIFN, "ptr", $pSelf, "ptr", $riid, _
            "struct*", $rgszNames, "dword", $cNames, "dword", $lcid, "ptr", $rgDispId)
    If @error Then
        ConsoleWriteError("Error: GetIDsFromNames: " & @error & @CRLF)
        Return $DISP_E_UNKNOWNNAME
    EndIf

; Autoit didnt find the name now its our turn
;~ If $DISPID_UNKNOWN = DllStructGetData(DllStructCreate("long[" & $cNames & "]", $rgDispId), 1, 1) Then
    ;$rgszNames is a pointer to an array[$cNames] of names -- Autoit only asks for one member $cNames = 1
    Local $tName = DllStructCreate("wchar[64]", DllStructGetData(DllStructCreate("ptr[" & $cNames & "]", $rgszNames), 1, 1))
    Local $sName = DllStructGetData($tName, 1)
    ConsoleWrite('__IDispatch_GetIDsFromNames triggered: ' & $sName & @CRLF)

    ;We just prepend CBN_CB_ to the function name and try to call it
    $hRes = Call("CBN_CB_" & $sName, $sName, $pGIFN, $pSelf, $riid, $rgszNames, $cNames, $lcid, $rgDispId)
    If Not @error And $hRes <> Default Then Return $hRes         ; User handled the function

    ;Call the original GetIDsFromNames
    $hRes = DllCallAddress("LRESULT", $pGIFN, "ptr", $pSelf, "ptr", $riid, _
            "struct*", $rgszNames, "dword", $cNames, "dword", $lcid, "ptr", $rgDispId)
    If @error Then
        ConsoleWrite("Error: GetIDsFromNames: " & @error & @CRLF)
        Return $DISP_E_UNKNOWNNAME
    EndIf
;~ EndIf
    Return $hRes[0]
EndFunc   ;==>__IDispatch_GetIDsFromNames

Func __Pointer_GetIDsFromNames($ptr = 0)
    ;Stores pointer to the original 'GetIDsFromNames'
    Local Static $pOldGIFN = $ptr
    If $ptr <> 0 Then $pOldGIFN = $ptr
    Return $pOldGIFN
EndFunc   ;==>__Pointer_GetIDsFromNames

Func Au3_CallByName_Init($bHook = True, $classname = "shell.application")
    Local Const $iOffset_GetIDsFromNames = 5     ;vtable index

    Local Static $IDispatch_GetIDsFromNames_Callback = 0
    Local $oObject, $pObject, $pHook, $pOldGIFN

    If $bHook Then
        If $IDispatch_GetIDsFromNames_Callback = 0 Then
            $IDispatch_GetIDsFromNames_Callback = DllCallbackRegister("__IDispatch_GetIDsFromNames", _
                    "LRESULT", "ptr;ptr;ptr;dword;dword;ptr")
        EndIf
        $pHook = DllCallbackGetPtr($IDispatch_GetIDsFromNames_Callback)
    Else
        $pHook = __Pointer_GetIDsFromNames()
        If $pHook <= 0 Then Return         ;Already Unloaded
    EndIf

    $oObject = ObjCreate($classname)
    $pObject = DllStructSetData(DllStructCreate("ptr"), 1, $oObject)

    If __HookVTableEntry($pObject, $iOffset_GetIDsFromNames, $pHook, $pOldGIFN) Then
        __Pointer_GetIDsFromNames($pOldGIFN)         ;Save the original pointer to GetIDsFromNames
        If Not $bHook Then
            DllCallbackFree($IDispatch_GetIDsFromNames_Callback)
            $IDispatch_GetIDsFromNames_Callback = 0
        EndIf
    Else
        ;Error
    EndIf

    $oObject = 0
EndFunc   ;==>Au3_CallByName_Init

Func CBN_CB_Au3_CallByName($sName, $pGIFN, $pSelf, $riid, $rgszNames, $cNames, $lcid, $rgDispId)
    Local Const $DISP_E_UNKNOWNNAME = 0x80020006
    ;~ ConsoleWrite(">Call By Name: " & $sName & " -> " & $Au3_CallByName & @CRLF)
    Local Static $tpMember = DllStructCreate("ptr")
    ;~ If $Au3_CallByName Then
        Local $hRes, $tMember

        ;ConsoleWrite("CallByName: " & $Au3_CallByName & @CRLF)
        $tMember = DllStructCreate("wchar[" & StringLen($sName) + 1 & "]")
        DllStructSetData($tMember, 1, $sName)
        DllStructSetData($tpMember, 1, DllStructGetPtr($tMember))
        $rgszNames = $tpMember
        ;~ $Au3_CallByName = 0

        ;Call the original GetIDsFromNames
        $hRes = DllCallAddress("LRESULT", $pGIFN, "ptr", $pSelf, "ptr", $riid, _
                "struct*", $rgszNames, "dword", $cNames, "dword", $lcid, "ptr", $rgDispId)
        If @error Then
            ConsoleWrite("Error: Call By Name: " & @error & @CRLF)
            Return $DISP_E_UNKNOWNNAME
        EndIf
        Return $hRes[0]
    ;~ EndIf
    Return Default     ;Default handler
EndFunc   ;==>CBN_CB_Au3_CallByName

And here is the uglified version of the js file

Spoiler
function xml2json(e){return xml2jsonRecurse(e=cleanXML(e),0)}function xml2jsonRecurse(e){for(var r,n,t,a,s,l={};e.match(/<[^\/][^>]*>/);)r=(s=e.match(/<[^\/][^>]*>/)[0]).substring(1,s.length-1),-1==(n=e.indexOf(s.replace("<","</")))&&(r=s.match(/[^<][\w+$]*/)[0],-1==(n=e.indexOf("</"+r))&&(n=e.indexOf("<\\/"+r))),a=(t=e.substring(s.length,n)).match(/<[^\/][^>]*>/)?xml2json(t):t,void 0===l[r]?l[r]=a:Array.isArray(l[r])?l[r].push(a):l[r]=[l[r],a],e=e.substring(2*s.length+1+t.length);return l}function cleanXML(e){return e=replaceAttributes(e=replaceAloneValues(e=replaceSelfClosingTags(e=(e=(e=(e=(e=e.replace(/<!--[\s\S]*?-->/g,"")).replace(/\n|\t|\r/g,"")).replace(/ {1,}<|\t{1,}</g,"<")).replace(/> {1,}|>\t{1,}/g,">")).replace(/<\?[^>]*\?>/g,""))))}function replaceSelfClosingTags(e){var r=e.match(/<[^/][^>]*\/>/g);if(r)for(var n=0;n<r.length;n++){var t=r[n],a=t.substring(0,t.length-2);a+=">";var s=t.match(/[^<][\w+$]*/)[0],l="</"+s+">",i="<"+s+">",c=a.match(/(\S+)=["']?((?:.(?!["']?\s+(?:\S+)=|[>"']))+.)["']?/g);if(c)for(var g=0;g<c.length;g++){var u=c[g],f=u.substring(0,u.indexOf("="));i+="<"+f+">"+u.substring(u.indexOf('"')+1,u.lastIndexOf('"'))+"</"+f+">"}i+=l,e=e.replace(t,i)}return e}function replaceAloneValues(e){var r=e.match(/<[^\/][^>][^<]+\s+.[^<]+[=][^<]+>{1}([^<]+)/g);if(r)for(var n=0;n<r.length;n++){var t=r[n],a=t.substring(0,t.indexOf(">")+1)+"<_@ttribute>"+t.substring(t.indexOf(">")+1)+"</_@ttribute>";e=e.replace(t,a)}return e}function replaceAttributes(e){var r=e.match(/<[^\/][^>][^<]+\s+.[^<]+[=][^<]+>/g);if(r)for(var n=0;n<r.length;n++){var t=r[n],a="<"+t.match(/[^<][\w+$]*/)[0]+">",s=t.match(/(\S+)=["']?((?:.(?!["']?\s+(?:\S+)=|[>"']))+.)["']?/g);if(s)for(var l=0;l<s.length;l++){var i=s[l],c=i.substring(0,i.indexOf("="));a+="<"+c+">"+i.substring(i.indexOf('"')+1,i.lastIndexOf('"'))+"</"+c+">"}e=e.replace(t,a)}return e};function buildParamlist(t){var e=" p0";t=t||1;for(var r=1;r<t;r++)e=e+" , p"+r;return e}Object.prototype.propAdd=function(prop,val){eval("this."+prop+"="+val)},Object.prototype.methAdd=function(meth,def){eval("this."+meth+"= new "+def)},Object.prototype.jsFunAdd=function(funname,numParams,objectTypeName){var x=buildParamlist(numParams);return objectTypeName=objectTypeName||"Object",eval(objectTypeName+".prototype."+funname+" = function("+x+") { return "+funname+"("+x+"); }")},Object.prototype.protoAdd=function(methName,jsFunction,objectTypeName){objectTypeName=objectTypeName||"Object",eval(objectTypeName+".prototype."+methName+"="+jsFunction)},Object.keys||(Object.keys=function(){"use strict";var o=Object.prototype.hasOwnProperty,a=!{toString:null}.propertyIsEnumerable("toString"),u=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],i=u.length;return function(t){if("object"!=typeof t&&("function"!=typeof t||null===t))throw new TypeError("Object.keys called on non-object");var e,r,n=[];for(e in t)o.call(t,e)&&n.push(e);if(a)for(r=0;r<i;r++)o.call(t,u[r])&&n.push(u[r]);return n}}()),Object.prototype.objGet=function(s){return eval(s)},Array.prototype.index=function(t){return this[t]},Object.prototype.index=function(t){return this[t]},Array.prototype.item=function(t){return this[t]},Object.prototype.item=function(t){return this[t]},Object.prototype.keys=function(){if("object"==typeof this)return Object.keys(this)},Object.prototype.keys=function(t){return (typeof t=="object"?Object.keys(t):Object.keys(this))},Object.prototype.arrayAdd=function(t,e){this[t]=e},Object.prototype.arrayDel=function(t){this.splice(t,1)},Object.prototype.isArray=function(){return this.constructor==Array},Object.prototype.type=function(){return typeof this},Object.prototype.type=function(t){if("undefined"==typeof t){return typeof this}else{return typeof t}};var JSON=new Object;function jsonPath(obj,expr,arg,basename){var P={resultType:arg&&arg.resultType||"VALUE",result:[],normalize:function(t){var r=[];return t.replace(/[\['](\??\(.*?\))[\]']/g,function(t,e){return"[#"+(r.push(e)-1)+"]"}).replace(/'?\.'?|\['?/g,";").replace(/;;;|;;/g,";..;").replace(/;$|'?\]|'$/g,"").replace(/#([0-9]+)/g,function(t,e){return r[e]})},asPath:function(t){for(var e=t.split(";"),r=("undefined"==typeof basename?"$":basename),n=1,o=e.length;n<o;n++)r+=/^[0-9*]+$/.test(e[n])?"["+e[n]+"]":"."+e[n];return r},store:function(t,e){return t&&(P.result[P.result.length]="PATH"==P.resultType?P.asPath(t):e),!!t},trace:function(t,e,r){if(t){var n=t.split(";"),o=n.shift();if(n=n.join(";"),e&&e.hasOwnProperty(o))P.trace(n,e[o],r+";"+o);else if("*"===o)P.walk(o,n,e,r,function(t,e,r,n,o){P.trace(t+";"+r,n,o)});else if(".."===o)P.trace(n,e,r),P.walk(o,n,e,r,function(t,e,r,n,o){"object"==typeof n[t]&&P.trace("..;"+r,n[t],o+";"+t)});else if(/,/.test(o))for(var a=o.split(/'?,'?/),u=0,i=a.length;u<i;u++)P.trace(a[u]+";"+n,e,r);else/^\(.*?\)$/.test(o)?P.trace(P.eval(o,e,r.substr(r.lastIndexOf(";")+1))+";"+n,e,r):/^\?\(.*?\)$/.test(o)?P.walk(o,n,e,r,function(t,e,r,n,o){P.eval(e.replace(/^\?\((.*?)\)$/,"$1"),n[t],t)&&P.trace(t+";"+r,n,o)}):/^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/.test(o)&&P.slice(o,n,e,r)}else P.store(r,e)},walk:function(t,e,r,n,o){if(r instanceof Array)for(var a=0,u=r.length;a<u;a++)a in r&&o(a,t,e,r,n);else if("object"==typeof r)for(var i in r)r.hasOwnProperty(i)&&o(i,t,e,r,n)},slice:function(t,e,r,n){if(r instanceof Array){var o=r.length,a=0,u=o,i=1;t.replace(/^(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)$/g,function(t,e,r,n){a=parseInt(e||a),u=parseInt(r||u),i=parseInt(n||i)}),a=a<0?Math.max(0,a+o):Math.min(o,a),u=u<0?Math.max(0,u+o):Math.min(o,u);for(var p=a;p<u;p+=i)P.trace(p+";"+e,r,n)}},eval:function(x,_v,_vname){try{return $&&_v&&eval(x.replace(/@/g,"_v"))}catch(t){throw new SyntaxError("jsonPath: "+t.message+": "+x.replace(/@/g,"_v").replace(/\^/g,"_a"))}}},$=obj;if(expr&&obj&&("VALUE"==P.resultType||"PATH"==P.resultType))return P.trace(P.normalize(expr).replace(/^\$;/,""),obj,"$"),!!P.result.length&&P.result}function oLiteral(t){this.literal=t}function protectDoubleQuotes(t){return t.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}JSON.jsonPath=function(t,e,r,basename){return jsonPath(t,e,r,basename)},"object"!=typeof JSON&&(JSON={}),function(){"use strict";function f(t){return t<10?"0"+t:t}var cx,escapable,gap,indent,meta,rep;function quote(t){return escapable.lastIndex=0,escapable.test(t)?'"'+t.replace(escapable,function(t){var e=meta[t];return"string"==typeof e?e:"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+t+'"'}function str(t,e){var r,n,o,a,u,i=gap,p=e[t];switch(p&&"object"==typeof p&&"function"==typeof p.toJSON&&(p=p.toJSON(t)),"function"==typeof rep&&(p=rep.call(e,t,p)),typeof p){case"string":return quote(p);case"number":return isFinite(p)?String(p):"null";case"boolean":case"null":return String(p);case"object":if(!p)return"null";if(gap+=indent,u=[],"[object Array]"===Object.prototype.toString.apply(p)){for(a=p.length,r=0;r<a;r+=1)u[r]=str(r,p)||"null";return o=0===u.length?"[]":gap?"[\n"+gap+u.join(",\n"+gap)+"\n"+i+"]":"["+u.join(",")+"]",gap=i,o}if(rep&&"object"==typeof rep)for(a=rep.length,r=0;r<a;r+=1)"string"==typeof rep[r]&&(o=str(n=rep[r],p))&&u.push(quote(n)+(gap?": ":":")+o);else for(n in p)Object.prototype.hasOwnProperty.call(p,n)&&(o=str(n,p))&&u.push(quote(n)+(gap?": ":":")+o);return o=0===u.length?"{}":gap?"{\n"+gap+u.join(",\n"+gap)+"\n"+i+"}":"{"+u.join(",")+"}",gap=i,o}}"function"!=typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()}),"function"!=typeof JSON.stringify&&(escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},JSON.stringify=function(t,e,r){var n;if(indent=gap="","number"==typeof r)for(n=0;n<r;n+=1)indent+=" ";else"string"==typeof r&&(indent=r);if((rep=e)&&"function"!=typeof e&&("object"!=typeof e||"number"!=typeof e.length))throw new Error("JSON.stringify");return str("",{"":t})}),"function"!=typeof JSON.parse&&(cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,JSON.parse=function(text,reviver){var j;function walk(t,e){var r,n,o=t[e];if(o&&"object"==typeof o)for(r in o)Object.prototype.hasOwnProperty.call(o,r)&&(void 0!==(n=walk(o,r))?o[r]=n:delete o[r]);return reviver.call(t,e,o)}if(text=String(text),cx.lastIndex=0,cx.test(text)&&(text=text.replace(cx,function(t){return"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})),/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return j=eval("("+text+")"),"function"==typeof reviver?walk({"":j},""):j;throw new SyntaxError("JSON.parse")})}(),Object.prototype.stringify=function(){return JSON.stringify(this)},Object.prototype.parse=function(t){return JSON.parse(t)},Object.prototype.jsonPath=function(t,e,basename){return JSON.jsonPath(this,t,(e==true?{resultType:"PATH"}:e),basename)},Object.prototype.objToString=function(){return JSON.stringify(this)},Object.prototype.strToObject=function(t){return JSON.parse(t)},Object.prototype.dot=function(str,jsStrFun){return"string"==typeof str?eval('"'+protectDoubleQuotes(str)+'".'+jsStrFun):eval(str+"."+jsStrFun)},Object.prototype.toObj=function(literal){return"string"==typeof literal?eval('new oLiteral("'+protectDoubleQuotes(literal)+'")'):eval("new oLiteral("+literal+")")},Object.prototype.jsMethAdd=function(funname,numParams){var x=buildParamlist(numParams);return eval("oLiteral.prototype."+funname+" = function("+x+"){return this.literal."+funname+"("+x+"); }")};Object.prototype.beautify=function(r){return JSON.stringify(this,null,typeof r=='undefined'?4:r)},Object.prototype.prettify=Object.prototype.beautify,Object.prototype.toStr=function(r){if(r<0){return JSON.stringify(this.stringify())}else{return JSON.stringify(this,null,typeof r=='undefined'?null:r)}},Object.prototype.sort=function(){},Object.prototype.reverse=function(){},Object.prototype.min=function(){return Math.min.apply(null,this)},Object.prototype.max=function(){return Math.max.apply(null,this)},JSON.filter=JSON.jsonPath,Object.prototype.filter=Object.prototype.jsonPath,Object.prototype.parseXML=function(t){return JSON.parse(xml2json(t).toStr())},Object.prototype.get=function(jsonPath,obj2str){var val=eval("this"+checkkey(jsonPath).replace(/\.(\d+)\b/g,"[$1]"));if(typeof val=="object"&&"undefined"!=typeof obj2str){val=val.toStr(obj2str)};return val},Object.prototype.set=function(key_name,val){eval("this"+checkkey(key_name).replace(/\.(?:item|index)\((\d+)\)/g,"[$1]").replace(/\.(\d+)\b/g,"[$1]")+"="+val)},Object.prototype.remove=function(key_name){eval("delete this."+key_name)},Object.prototype.values=function(){var oValues=[];for(var key in this){if(this.hasOwnProperty(key)){oValues.push(eval("this."+key))}};return oValues};function search(path,obj,target,regexMode){var aPath=[];var val;function json_search(path,obj,target,regexMode){for(var keyname in obj){if(obj.hasOwnProperty(keyname)){val=obj[keyname];if(regexMode==true&&"string"==typeof val&&val.match(target)){aPath.push(path+(isNaN(keyname)?"."+keyname:'['+keyname+']'))}else if(val===target){aPath.push(path+(isNaN(keyname)?"."+keyname:'['+keyname+']'))}else if(typeof val==="object"){json_search(path+(isNaN(keyname)?"."+keyname:'['+keyname+']'),val,target,regexMode)}}}};json_search(path,obj,target,regexMode);return aPath};Object.prototype.findPath=function(node,regexMode){return search("this",this,node,regexMode)};function checkkey(keyname){if(!isNaN(keyname)){keyname="['"+keyname+"']"}if(keyname.substr(0,1)!=="["){keyname="."+keyname}return keyname}

 

 


This JSON object after calling parse method will accept every method and property names, so obviously it can not be passed through __IDispatch_GetIDsFromNames, so i think maybe i will try to intercept every dot statement, and this is the question i have for this post.

I tried to hook the HTMLFILE object, place it both before and after the ObjCreate statement.

Au3_CallByName_Init(True, 'HTMLFILE')

This time i commented out the "If" statement that indicate that AutoIt didn't find the method name (now __IDispatch_GetIDsFromNames should be triggered on every dot statement), slightly modified CBN_CB_Au3_CallByName to use its own param $sName as method name instead of $Au3_CallByName, and added a trace line in order to track those names.

Func __IDispatch_GetIDsFromNames($pSelf, $riid, $rgszNames, $cNames, $lcid, $rgDispId)
    Local Const $DISP_E_UNKNOWNNAME = 0x80020006, $DISPID_UNKNOWN = -1
    Local Static $pGIFN = __Pointer_GetIDsFromNames()
    Local $hRes

    ;Call the original GetIDsFromNames
    $hRes = DllCallAddress("LRESULT", $pGIFN, "ptr", $pSelf, "ptr", $riid, _
            "struct*", $rgszNames, "dword", $cNames, "dword", $lcid, "ptr", $rgDispId)
    If @error Then
        ConsoleWriteError("Error: GetIDsFromNames: " & @error & @CRLF)
        Return $DISP_E_UNKNOWNNAME
    EndIf

    ; Autoit didnt find the name now its our turn
    ;~ If $DISPID_UNKNOWN = DllStructGetData(DllStructCreate("long[" & $cNames & "]", $rgDispId), 1, 1) Then
        ;$rgszNames is a pointer to an array[$cNames] of names -- Autoit only asks for one member $cNames = 1
        Local $tName = DllStructCreate("wchar[64]", DllStructGetData(DllStructCreate("ptr[" & $cNames & "]", $rgszNames), 1, 1))
        Local $sName = DllStructGetData($tName, 1)
        ConsoleWrite('__IDispatch_GetIDsFromNames triggered: ' & $sName & @CRLF)

        ;We just prepend CBN_CB_ to the function name and try to call it
        $hRes = Call("CBN_CB_" & $sName, $sName, $pGIFN, $pSelf, $riid, $rgszNames, $cNames, $lcid, $rgDispId)
        If Not @error And $hRes <> Default Then Return $hRes         ; User handled the function

        ;Call the original GetIDsFromNames
        $hRes = DllCallAddress("LRESULT", $pGIFN, "ptr", $pSelf, "ptr", $riid, _
                "struct*", $rgszNames, "dword", $cNames, "dword", $lcid, "ptr", $rgDispId)
        If @error Then
            ConsoleWrite("Error: GetIDsFromNames: " & @error & @CRLF)
            Return $DISP_E_UNKNOWNNAME
        EndIf
    ;~ EndIf
    Return $hRes[0]
EndFunc   ;==>__IDispatch_GetIDsFromNames
Func CBN_CB_Au3_CallByName($sName, $pGIFN, $pSelf, $riid, $rgszNames, $cNames, $lcid, $rgDispId)
    Local Const $DISP_E_UNKNOWNNAME = 0x80020006
    ;~ ConsoleWrite(">Call By Name: " & $sName & " -> " & $Au3_CallByName & @CRLF)
    Local Static $tpMember = DllStructCreate("ptr")
    ;~ If $Au3_CallByName Then
        Local $hRes, $tMember

        ;ConsoleWrite("CallByName: " & $Au3_CallByName & @CRLF)
        $tMember = DllStructCreate("wchar[" & StringLen($sName) + 1 & "]")
        DllStructSetData($tMember, 1, $sName)
        DllStructSetData($tpMember, 1, DllStructGetPtr($tMember))
        $rgszNames = $tpMember
        ;~ $Au3_CallByName = 0

        ;Call the original GetIDsFromNames
        $hRes = DllCallAddress("LRESULT", $pGIFN, "ptr", $pSelf, "ptr", $riid, _
                "struct*", $rgszNames, "dword", $cNames, "dword", $lcid, "ptr", $rgDispId)
        If @error Then
            ConsoleWrite("Error: Call By Name: " & @error & @CRLF)
            Return $DISP_E_UNKNOWNNAME
        EndIf
        Return $hRes[0]
    ;~ EndIf
    Return Default     ;Default handler
EndFunc   ;==>CBN_CB_Au3_CallByName


Here are the console outputs:

__IDispatch_GetIDsFromNames triggered: parentwindow
__IDispatch_GetIDsFromNames triggered: parentwindow

Of course i did manually check with IsObj to make sure that every dot statement is being used on a valid object. And according to console, only parentwindow was caught, while execScript, eval, parse, title didn't.

Edited by sylremo
provide more infos, correct grammars
Link to comment
Share on other sites

Sorry you haven't gotten any satisfactory answers so far, I don't have a windows machine to test on ATM so I'm not of much help

Likely whats going on is the object is in a different process 'multithreaded apartment' you could look at the

TLB in a decent object browser Com View https://www.softpedia.com/get/System/System-Info/COMView.shtml

 

 

 

Link to comment
Share on other sites

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
 Share

×
×
  • Create New...