;/* ************************************************************************
; * pp20.dll v1.0.9.4
; * by Peace^Testaware / 22-Nov-2008
; * PureBasic example how to decrunch/crack PowerPacker encrypted dataformat
; * ************************************************************************/


;/* PP20 lib error codes */
#PPERR_OK          =     0    ;no error
#PPERR_ARGS        =    -1    ;bad arguments to function
#PPERR_OPEN        =    -2    ;error opening file
#PPERR_READ        =    -3    ;error reading from file
#PPERR_SEEK        =    -4    ;error seeking in file
#PPERR_NOMEMORY    =    -5    ;out of memory
#PPERR_DATAFORMAT  =    -6    ;error in data format
#PPERR_PASSWORD    =    -7    ;bad or missing password
#PPERR_DECRUNCH    =    -8    ;error decrunching data


;/* PP20 lib mode codes */
#PPMODE_PP11    =    $50503131    ;PowerPacker v1.x data
#PPMODE_PP20    =    $50503230    ;PowerPacker v2.x - v4.x data
#PPMODE_PPBK    =    $5050626B    ;AMOS Professional PPbk Bank
#PPMODE_PPLS    =    $50504C53    ;LoadSegement data
#PPMODE_PX20    =    $50583230    ;Encrypted data


;/* PP20 lib functions */
Structure    PP20
    DLL.q
    *GetDecrunchSize   ;(*InBuf, InSize.l)
    *GetCrunchMode     ;(*InBuf)
    *DecrunchMemory    ;(*InBuf, *OutBuf, InSize.l, OutSize.l, @Password.s)
    *EncodeMemory      ;(*InBuf, *OutBuf, InSize.l, OutSize.l, PassKey.l)
    *DecrunchFile      ;(@InFile.s, @OutFile.s, @Password.s)
    *CalcPasskey       ;(@Password.s)
    *CalcChecksum      ;(@Password.s)
EndStructure    :    PP.PP20


;/* PP20 lib open library, must adapt path */
PP\DLL    =    OpenLibrary(#PB_Any, "C:\pp20_dll\dll\pp20.dll")


;/* PP20 lib declare function addresses */
With    PP
    If  \DLL
        \GetDecrunchSize   =    GetFunction(\DLL, "ppGetDecrunchSize")
        \DecrunchMemory    =    GetFunction(\DLL, "ppDecrunchMemory")
        \EncodeMemory      =    GetFunction(\DLL, "ppEncodeMemory")
        \DecrunchFile      =    GetFunction(\DLL, "ppDecrunchFile")
        \CalcPasskey       =    GetFunction(\DLL, "ppCalcPasskey")
        \CalcChecksum      =    GetFunction(\DLL, "ppCalcChecksum")
    Else
        Debug    "Error: cannot access to pp20.dll"
        End
    EndIf
EndWith


;/* Change filenames by your own ones */
InFile.s   =    "test\AgonySea.pp"     ;crunched/encrypted file
OutFile.s  =    "test\AgonySea.mod"    ;decrunched file

Password.s =    "Amiga"                ;change it for error [CkSum = $6ACF / PassKey = $06150436]


;/* Calculate keys for password (not needed, only for info) */
CkSum      =    CallCFunctionFast(PP\CalcChecksum, @Password)   ;calculate 16 bit validate key
PassKey    =    CallCFunctionFast(PP\CalcPasskey, @Password)    ;calculate 32 bit decrypt key


;/* 0 = decrunch file / 1 = decrunch memory / 2 = encrypt memory -> passkey */
#PP20    =    2


CompilerSelect  #PP20


;/* Decrunch file with password */
CompilerCase    0

    Debug    "Decrunch file..."

    err = CallCFunctionFast(PP\DecrunchFile, @InFile, @OutFile, @Password)
    If  err    =    #PPERR_OK
        InSize =    FileSize(InFile)
        OutSize=    FileSize(OutFile)
    EndIf


;/* Decrunch memory with password */
CompilerCase    1

    Debug    "Decrunch memory..."

    hF  =    ReadFile(#PB_Any, InFile)

    If  hF

        InSize    =    Lof(hF)
        *InBuf    =    AllocateMemory(InSize)
        ReadData(hF, *InBuf, InSize)
        CloseFile(hF)

        OutSize    =    CallCFunctionFast(PP\GetDecrunchSize, *InBuf, InSize)    ;get decrunched size

        If  OutSize    >    0
            *OutBuf    =    AllocateMemory(OutSize)
            err        =    CallCFunctionFast(PP\DecrunchMemory, *InBuf, *OutBuf, InSize, OutSize, @Password)
            If  err    =    #PPERR_OK
                hF     =    CreateFile(#PB_Any, OutFile)
                If  hF
                    WriteData(hF, *OutBuf, OutSize)
                    CloseFile(hF)
                Else
                    err =   #PPERR_OPEN
                EndIf
            EndIf
            FreeMemory(*OutBuf)
        Else
            err = OutSize
        EndIf

        FreeMemory(*InBuf)

    Else

        err = #PPERR_OPEN

    EndIf


;/* Encrypt memory with passkey (brute-force), [ESC = Break] /*
CompilerCase    2

    Debug    "Encrypt memory..."

    hF  =    ReadFile(#PB_Any, InFile)

    If  hF

        InSize    =    Lof(hF)
        *InBuf    =    AllocateMemory(InSize)
        ReadData(hF, *InBuf, InSize)
        CloseFile(hF)

        OutSize   =    CallCFunctionFast(PP\GetDecrunchSize, *InBuf, InSize)    ;get decrunched size

        If  OutSize    >    0

            ;startkey ["Amiga" = $06150436] for demonstrate only
            PassKey    =    $610F436

            ;need to restore orginal buffer if wrong passkey (recomended!)
            *TmpBuf    =    AllocateMemory(InSize)
            CopyMemory(*InBuf, *TmpBuf, InSize)

            *OutBuf    =    AllocateMemory(OutSize)

            ;encrypt & decrunch in brute-force
            Repeat

                loop    +    1
                PassKey +    1

                err     =    CallCFunctionFast(PP\EncodeMemory, *InBuf, *OutBuf, InSize, OutSize, PassKey, *TmpBuf)

                ;yeep! we cracked 'em
                If  err    =    #PPERR_OK
                    Debug  "Checked keys: " + Str(loop) + " - Detected passkey: $" + Hex(PassKey)
                    Break
                EndIf

                ;display status every 4048 checked passkey
                If  loop % $FD0 = 0
                    Debug    Str(loop) + ": $" + Hex(PassKey)
                    If  GetAsyncKeyState_(#VK_ESCAPE)
                        Break
                    EndIf
                    Delay(15)
                EndIf

            Until PassKey = $FFFFFFFF

        EndIf

    Else

        err    =    #PPERR_OPEN

    EndIf

CompilerEndSelect


CloseLibrary(PP\DLL)


;/* Show infos in debugwindow /*
Debug "Infile: "      + InFile   + " - Size: "   + Str(InSize)
Debug "OutFile: "     + OutFile  + " - Size: "   + Str(OutSize)
Debug "Password: "    + Password + " - CkSum: $" Hex(CkSum)   + " - PassKey: $" + Hex(PassKey)
Debug "Errorcode: "   + Str(err)


If  err = #PPERR_OK
    Debug "All successful decrunched!"
EndIf


End
; IDE Options = PureBasic 4.20 (Windows - x86)
; Folding = -