// DIE's signature file
// History:
// 1:00 06.10.2013 x64 support (ajax)
//      2014-05-25 rewritten (adoxa)

init("packer","UPX");

function isPatchedUPX()
{
    var nResult=0;
    var nNumberOfFunctions=PE.getNumberOfImportThunks(0);
    if((nNumberOfFunctions>1)&&(nNumberOfFunctions<7))
    {
        if((PE.getSizeOfCode())&&(PE.getSizeOfUninitializedData())&&(PE.section.length>2)&&(PE.section[0].FileSize==0))
        {
            var nCount=0;
            if(PE.getImportFunctionName(0,0)=="LoadLibraryA")
            {
                nCount++;
            }
            if(PE.getImportFunctionName(0,1)=="GetProcAddress")
            {
                nCount++;
            }
            if(nNumberOfFunctions==4)
            {
                if(PE.getImportFunctionName(0,2)=="VirtualProtect")
                {
                    nCount++;
                }
                if(PE.getImportFunctionName(0,3)=="ExitProcess")
                {
                    nCount++;
                }
            }
            if((nNumberOfFunctions>=3)&&(nCount<4))
            {
                if(PE.getImportFunctionName(0,2)=="ExitProcess")
                {
                    nCount++;
                }
                else if(PE.isDll())
                {
                    if(PE.getImportFunctionName(0,2)=="VirtualProtect")
                    {
                        nCount++;
                    }
                }
            }
            if(nNumberOfFunctions==6)
            {
                if(PE.getImportFunctionName(0,2)=="VirtualProtect")
                {
                    nCount++;
                }
                if(PE.getImportFunctionName(0,3)=="VirtualAlloc")
                {
                    nCount++;
                }
                if(PE.getImportFunctionName(0,4)=="VirtualFree")
                {
                    nCount++;
                }
                if(PE.getImportFunctionName(0,5)=="ExitProcess")
                {
                    nCount++;
                }
            }

            if((nCount==2)&&(nNumberOfFunctions==2))
            {
                nResult=1;
            }
            if((nCount==3)&&(nNumberOfFunctions>=3))
            {
                nResult=1;
            }
            if((nCount==4)&&(nNumberOfFunctions==4))
            {
                nResult=1;
            }
            if((nCount==6)&&(nNumberOfFunctions==6))
            {
                nResult=1;
            }

            if(nResult)
            {
                if(PE.getAddressOfEntryPoint()==0x00001018)
                {
                    // (Win)Upack
                    nResult=0;
                }
            }
        }
    }

    return nResult;
}

function getUPXOptions(nOffset)
{
        var nLevel=PE.readByte(nOffset+2);
        var nMethod=PE.readByte(nOffset+3);
        var sCompression="";
        switch(nMethod) // From http://sourceforge.net/p/upx/code/ci/default/tree/src/conf.h
        {
        case 2:
        case 3:
        case 4:
        case 5:
        case 6:
        case 7:
        case 8:
        case 9:
        case 10: sCompression="NRV"; break;
        case 14: sCompression="LZMA"; break;
        case 15: sCompression="zlib"; break;
        }

        if(sCompression!="")
        {
            sOptions=sOptions.append(sCompression);
            if(nLevel==8)
            {
                sOptions=sOptions.append("best");
            }
            else
            {
                sOptions=sOptions.append("brute");
            }
        }
}

function getUPXVersion()
{
    var nOffset1=PE.findString(0,1024,"$Id: UPX ");
    var nOffset2=PE.findString(0,1024,"UPX!");
    if(nOffset2!=-1)
    {
        getUPXOptions(nOffset2+4);
    }

    if(nOffset1!=-1)
    {
        sVersion=PE.getString(nOffset1+9,4);
    }
    if((sVersion=="")&&(nOffset2!=-1))
    {
        sVersion=PE.getString(nOffset2-5,4);
    }
}

function detect(bShowType,bShowVersion,bShowOptions)
{
    if(!PE.isPEPlus())
    {
        var nEP=PE.compareEP("807C")?27:0;
        if(PE.compareEP("60BE........8DBE........57",nEP))
        {
            bDetected=1;
        }
        else if(PE.compareEP("60e8000000005883e8..508db8........578db0........83cd..31db9090909001db75"))
        {
            sVersion="0.70";
            bDetected=1;
        }
    }
    else
    {
        var nEP=PE.compareEP("4889")?24:0;
        if(PE.compareEP("53565755488D35........488DBE........57",nEP))
        {
            bDetected=1;
        }
    }

    getUPXVersion();
    if(sVersion!="")
    {
        bDetected=1;
    }

    if(!bDetected)
    {
        bDetected=isPatchedUPX();
    }

    if((bDetected)&&(sVersion==""))
    {
        if(PE.isPEPlus())
        {
            sVersion="3.91+"; // UPX 3.91 was the first version with a PE+ support.
        }
        sOptions="modified";
    }

    return result(bShowType,bShowVersion,bShowOptions);
}
