Jump to content

Guess the setup up string of DLLStruct


Ward
 Share

Recommended Posts

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 的白痴作者,不管是誰,去死一死好了

 

Link to comment
Share on other sites

  • 4 weeks later...

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
Link to comment
Share on other sites

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 的白痴作者,不管是誰,去死一死好了

 

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

  • 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
 Share

×
×
  • Create New...