Jump to content

Recommended Posts

Posted (edited)

I am trying to serialize all the autoit variable by >msgpack, so that I can used it in ZeroRPC (language-agnostic remote procedure call over internet). Int, string, binary are easy, but DllStruct is not. Before variable serialization become build-in function (I hope so), I have to find out my own way.
 
Here is my attempt to guess the setup string. I am not sure did I deal with all the align and struct/endstruct correctly, please let me know if there is any bug. The output may not be the same with the original string, it is not bug.
 
 

Test()

Func Test()
    Local $Struct
    $Struct = DllStructCreate("align 2;byte;ptr[2]")
    ConsoleWrite(DLLStructAnalyze($Struct) & @LF)

    ; Output: byte;align 2;ptr[2]

    $Struct = DllStructCreate("int;struct;struct;uint64;uint;byte[5];endstruct;byte;endstruct;byte")
    ConsoleWrite(DLLStructAnalyze($Struct) & @LF)

    ; Output: int;struct;struct;uint64;uint;byte[5];endstruct;byte;endstruct;byte

    $Struct = DllStructCreate("int;uint64;struct;struct;uint;byte[5];endstruct;byte;endstruct;byte")
    ConsoleWrite(DLLStructAnalyze($Struct) & @LF)

    ; Output: int;uint64;struct;struct;uint;byte[5];endstruct;byte;endstruct;byte
EndFunc

 

#Include <Array.au3>

Func DLLStructAnalyze(ByRef $DLLStruct)
    Local $Dict = __DLLStructAnalyzeHook(True)
    $Dict.Add($DLLStruct)    
    __DLLStructAnalyzeHook(False)
    Return __DLLStructAnalyzeCallback(0)
EndFunc

Func __DLLStructAnalyzeCallback($Ptr)
    Static $Array[0], $Echo = ConsoleWrite

    If $Ptr = 0 Then
        Local $Ret = ''
        For $i = 0 To UBound($Array) - 1
            Local $Item = $Array[$i]
            $Ret &= ($i ? ";" : "") & $Item[0]
        Next
        Return $Ret
    EndIf

    ReDim $Array[0]
    Local $Buffer = DllStructCreate("ptr", $Ptr)
    $Ptr = DllStructGetData($Buffer, 1)

    Local $Variant = DllStructCreate("word vt;word[3];ptr data;ptr record", $Ptr)
    Local $Type = DllStructGetData($Variant, "vt")
    If $Type = 36 Then
        Local $Record = DllStructGetData($Variant, "record")
        Local $RecordType = DllStructCreate("ptr;uint;uint type;ptr struct", $Record)

        If DllStructGetData($RecordType, "type") = 12 Then
            Local $Struct = DllStructCreate("uint count;ptr define;ptr base;uint size", DllStructGetData($RecordType, "struct"))
            Local $Count = DllStructGetData($Struct, "count")

            Local $Align = 8, $LastEnd = 0, $DefineSize = 0
            For $i = 0 To $Count - 1
                Local $Define = DllStructCreate("uint start;uint size;uint flag;ptr name;ptr;ptr;ptr;uint end", DllStructGetData($Struct, "define") + $i * $DefineSize)
                Local $DefineSize = DllStructGetSize($Define)

                Local $Start = DllStructGetData($Define, "start")
                Local $Size = DllStructGetData($Define, "size")
                Local $Flag = DllStructGetData($Define, "flag")
                Local $End = DllStructGetData($Define, "end")

                Local $Name = DllStructGetData($Define, "name")
                Local $Ret = DllCall("kernel32.dll", "int", "lstrlenW", "ptr", $Name)
                $Name = $Ret[0] ? " " & DllStructGetData(DllStructCreate("wchar[" & $Ret[0] & "]", $Name), 1) : ""

                $Echo("start: " & $Start & @TAB)
                $Echo("size: " & $Size & @TAB)
                $Echo("end: " & $End & @TAB)

                Local $NextAlign = 0
                If $i > 0 Then
                    $Pad = $Start - $LastEnd
                    If Not ((Mod($Start, $Align) = 0 Or Mod($Start, $Size) = 0) And $Pad < $Align) Then
                        $NextAlign = 1
                        $Echo("(pad" & $Pad & ") align 1")

                        If Mod($Start, 2) = 0 And $Pad < 2 Then
                            $Echo(" 2")
                            $NextAlign = 2
                        EndIf
                        If Mod($Start, 4) = 0 And $Pad < 4 Then
                            $Echo(" 4")
                            $NextAlign = 4
                        EndIf
                        If Mod($Start, 8) = 0 And $Pad < 8 Then
                            $Echo(" 8")
                            $NextAlign = 8
                        EndIf
                        $Echo("; ")

                        If $NextAlign <> $Align Then
                            $Align = $NextAlign
                            Local $ItemAlign[] = ["align " & $Align, 0]
                            ArrayAdd($Array, $ItemAlign)
                        EndIf

                    ElseIf $Pad <> 0 And $Pad >= $Size Then
                        $Echo("(pad" & $Pad & ") endstruct; ")

                        Local $ItemStruct[] = ["struct", 0]
                        For $j = UBound($Array) - 1 To 0 Step -1
                            Local $Item = $Array[$j]
                            If $Item[1] > $Pad Then
                                ArrayInsert($Array, $j, $ItemStruct)
                                ExitLoop
                            EndIf
                        Next

                        Local $ItemEndStruct[] = ["endstruct", 0]
                        ArrayAdd($Array, $ItemEndStruct)
                    EndIf
                EndIf
                $LastEnd = $End

                Local $Type = "unknow" & $Name
                Select
                    Case $Size = 1 And $Flag = 18
                        $Type = "byte" & $Name
                    Case $Size = 1 And $Flag = 1
                        $Type = "char" & $Name
                    Case $Size = 2 And $Flag = 32
                        $Type = "wchar" & $Name
                    Case $Size = 2 And $Flag = 0
                        $Type = "short" & $Name
                    Case $Size = 2 And $Flag = 2
                        $Type = "ushort" & $Name
                    Case $Size = 4 And $Flag = 0
                        $Type = "int" & $Name
                    Case $Size = 4 And $Flag = 2
                        $Type = "uint" & $Name
                    Case $Size = 8 And $Flag = 0
                        $Type = "int64" & $Name
                    Case $Size = 8 And $Flag = 2
                        $Type = "uint64" & $Name
                    Case $Size = 4 And $Flag = 64 And Not @AutoItX64
                        $Type = "ptr" & $Name
                    Case $Size = 8 And $Flag = 64 And @AutoItX64
                        $Type = "ptr" & $Name
                    Case $Size = 4 And $Flag = 8
                        $Type = "float" & $Name
                    Case $Size = 8 And $Flag = 8
                        $Type = "double" & $Name
                    Case $Size = 1 And $Flag = 22
                        $Type = "byte" & $Name
                        If $End - $Start = $Size Then $Type &= "[1]"
                    Case $Size = 1 And $Flag = 5
                        $Type = "char" & $Name
                        If $End - $Start = $Size Then $Type &= "[1]"
                    Case $Size = 2 And $Flag = 36
                        $Type = "wchar" & $Name
                        If $End - $Start = $Size Then $Type &= "[1]"
                EndSelect

                If $End - $Start <> $Size Then $Type &= "[" & Int(($End - $Start) / $Size) & "]"
                $Echo($Type & @LF)
                Local $Item[] = [$Type, $Size]
                ArrayAdd($Array, $Item)
            Next
        EndIf
    EndIf
EndFunc

Func __DLLStructAnalyzeHook($IsHook)
    Static $Callback, $CallbackPtr, $VTable, $InvokePtr, $CodeBuffer, $Hook = 0
    Local $Dict = ObjCreate("Scripting.Dictionary")

    If Not $Hook Then
        $Callback = DllCallbackRegister(__DLLStructAnalyzeCallback, "none", "ptr")
        $CallbackPtr = DllCallbackGetPtr($Callback)

        Local $VTablePtr = DllStructCreate("ptr", Ptr($Dict))
        $VTablePtr = DllStructGetData($VTablePtr, 1)

        $VTable = DllStructCreate("ptr[7]", $VTablePtr)
        $InvokePtr = DllStructGetData($VTable, 1, 7)

        Local $Code, $CallPtr, $JmpPtr
        If @AutoItX64 Then
            $Code = '0x41554154555756534883EC38488BB424980000008B9C24900000004889CF8954242C4C8944242044894C2428488BAC24A00000004889F14C8BA424A80000004C8BAC24B000000048B8FFFFFFFFFFFFFFFFFFD0448B4C24284C8B4424200FB7DB8B54242C4889F94C89AC24B00000004C89A424A80000004889AC24A00000004889B42498000000899C24900000004883C4385B5E5F5D415C415D48B8FFFFFFFFFFFFFFFFFFE0'
            $CallPtr = (StringInStr($Code, '48B8FFFFFFFFFFFFFFFFFFD0', 2) + 1) / 2
            $JmpPtr = (StringInStr($Code, '48B8FFFFFFFFFFFFFFFFFFE0', 2) + 1) / 2
        Else
            $Code = '0x5589E557565383EC3C8B45088B5D1C8B55248B4D288B75108B7D148945E48B450C891C248955D4894DD88945E08B45188945DC8B45208945D0B8FFFFFFFFFFD0508B45D08B4DD88B55D4895D1C897D148945200FB745DC897510894D288955248945188B45E089450C8B45E48945088D65F45B5E5F5DB8FFFFFFFFFFE0'
            $CallPtr = (StringInStr($Code, 'B8FFFFFFFFFFD0', 2) - 1) / 2
            $JmpPtr = (StringInStr($Code, 'B8FFFFFFFFFFE0', 2) - 1) / 2
        EndIf

        $Code = Binary($Code)
        $CodeBuffer = DllStructCreate("byte[" & BinaryLen($Code) & "]")
        $Hook = DllStructGetPtr($CodeBuffer)
        DllStructSetData($CodeBuffer, 1, $Code)
        DllCall("kernel32.dll", "bool", "VirtualProtect", "ptr", $Hook, "dword_ptr", BinaryLen($Code), "dword", 64, "dword*", 0)

        DllStructSetData(DllStructCreate("ptr", $Hook + $CallPtr), 1, $CallbackPtr)
        DllStructSetData(DllStructCreate("ptr", $Hook + $JmpPtr), 1, $InvokePtr)
        DllCall("kernel32.dll", "bool", "VirtualProtect", "ptr", $VTablePtr, "dword_ptr", @AutoItX64 ? 56 : 28, "dword", 4, "dword*", 0)
    EndIf

    If $IsHook Then
        DllStructSetData($VTable, 1, $Hook, 7)
        Return $Dict
    Else
        DllStructSetData($VTable, 1, $InvokePtr, 7)
    EndIf
EndFunc

Func ArrayAdd(ByRef $avArray, $vValue)
    If Not IsArray($avArray) Then Return SetError(1, 0, -1)
    If UBound($avArray, 0) <> 1 Then Return SetError(2, 0, -1)

    Local $iUBound = UBound($avArray)
    ReDim $avArray[$iUBound + 1]
    $avArray[$iUBound] = $vValue
    Return $iUBound
EndFunc

Func ArrayInsert(ByRef $avArray, $iElement, $vValue = "")
    If Not IsArray($avArray) Then Return SetError(1, 0, 0)
    If UBound($avArray, 0) <> 1 Then Return SetError(2, 0, 0)

    ; Check element in array bounds + 1
    If $iElement > UBound($avArray) Then Return SetError(3, 0, 0)

    ; Add 1 to the array
    Local $iUBound = UBound($avArray) + 1
    ReDim $avArray[$iUBound]

    ; Move all entries over til the specified element
    For $i = $iUBound - 1 To $iElement + 1 Step -1
        $avArray[$i] = $avArray[$i - 1]
    Next

    ; Add the value in the specified element
    $avArray[$iElement] = $vValue
    Return $iUBound
EndFunc

Edited by Ward

新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了

 

  • 4 weeks later...
Posted (edited)

Hi Ward,

This would be an extremely useful function (to me, at least). However, on my test rig (W7Pro/64) it errors with:

"D:\Autoit\Pool\dllstructAnalyze.au3" (18) : ==> Subscript used on non-accessible variable.:
$Ret &= ($i ? ";" : "") & $Item[0]
$Ret &= ($i ? ";" : "") & $Item^ ERROR

This is when I include the analyzer as a separate file in your test example. If I simply append the analyzer to the test file, AutoIt crashes. Haven't done any detailed diagnostics.

Edited by RTFC
Posted (edited)

Oh, this scrip crash on v3.3.12.0, because I still use v3.3.10.2...

I fixed it. The problem is in the newer Array.au3 UDF.

It did "concatenate" rather than "add" in _ArrayAdd(). (WTF...)

Edited by Ward

新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了

 

Posted

Is this just an oversight?

Func DLLStructAnalyze(ByRef $DLLStruct)
    Local $Dict = __DLLStructAnalyzeHook(True)
    $Dict.Add($DLLStruct)
    Return __DLLStructAnalyzeCallback(0)
    __DLLStructAnalyzeHook(False); In C/++ terms it would mean unreachable code.
EndFunc

Not that I'd know what to do with the code anyway, just seen it.

AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Posted

Thanks JohnOne, It seems I pressed some hotkey that swapped these two lines by accident.

新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了

 

  • 7 years later...

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...