// DIE's signature file

/*
Visual Studio                   4.0
Visual Studio 5.0 (1997)        5.0
Visual Studio 6.0 (1998)        6.0
Visual Studio .NET (2002)       7.0
Visual Studio .NET 2003         7.1
Visual Studio 2005              8.0
Visual Studio 2008              9.0
Visual Studio 2010              10.0
Visual Studio 2012              11.0
Visual Studio 2013              12.0
Visual Studio 2015              14.0
*/

includeScript("MFC");
includeScript("Qt");
includeScript("wxWidgets");

init("compiler","Microsoft Visual "+(aMFC||aQt||aWx||PE.isLibraryPresentExp(/^MSVCP/i)?"C++":"C/C++"));

function getVCVersionFromLinkerVersion()
{
    var sResult="";
    switch(PE.getMajorLinkerVersion())
    {
    case 3:  sResult=PE.getCompilerVersion();   break; // MS C++
    case 4:  sResult="4.0";  break;
    case 5:  sResult="5.0";  break;
    case 6:  sResult="6.0";  break;
    case 7:
        if(PE.getMinorLinkerVersion()<10)
        {
            sResult="2002";
        }
        else
        {
            sResult="2003";
        }
        break;
    case 8:  sResult="2005"; break;
    case 9:  sResult="2008"; break;
    case 10: sResult="2010"; break;
    case 11: sResult="2012"; break;
    case 12: sResult="2013"; break;
    case 13: sResult="2015"; break;
    }

    return sResult;
}

function getVersionFromRichSignature()
{
    var sResult="";
    if(PE.getNumberOfRichIDs()>3)
    {
        var nDosStubOffset=PE.getDosStubOffset();
        var nDosStubSize=PE.getDosStubSize();

        var nRichOffset=PE.findString(nDosStubOffset,nDosStubSize,"Rich");
        if(nRichOffset!=-1)
        {
            // Given information presented in issue #4, just take the second last
            // (compiler version, don't worry about anything else).
            // https://github.com/horsicq/Detect-It-Easy/issues/4
            var nXorKey=PE.readDword(nRichOffset+4);
            var nDword=PE.readDword(nRichOffset-16)^nXorKey;
            switch(nDword&0xFFFF)
            {
            /*
            case 9782:  // seen from VC6 SP6, but probably earlier
            case 7299:  // ditto
            case 8168:
                if(!PE.isLibraryPresent("MSVBVM60.DLL")) // VB
                {
                        sResult="6.0";                  // cl.exe 12.00.8168
                }
                break;
            case 8804:  sResult="6.0";           break; // SP 5/6 cl.exe 12.00.8804
            */
            case 9466:  sResult="2002";          break; // cl.exe 13.00.9466
            case 3077:  sResult="2003";          break; // cl.exe 13.10.3077
            case 4035:  sResult="2003";          break; // cl.exe 13.10.4035
            case 6030:  sResult="2003 SP1";      break; // cl.exe 13.10.6030
            case 50727:
                switch(PE.getMajorLinkerVersion())
                {
                case 8: sResult="2005";          break; // cl.exe 14.00.50727.42 14.00.50727.762 SP1?
                case 11:sResult="2012";          break; // cl.exe 17.00.50727
                }
                break;
            case 21022: sResult="2008";          break; // cl.exe 15.00.21022
            case 30729: sResult="2008 SP1";      break; // cl.exe 15.00.30729.01
            case 30319: sResult="2010";          break; // cl.exe 16.00.30319
            case 40219: sResult="2010 SP1";      break; // cl.exe 16.00.40219
            case 51025: sResult="2012";          break; // cl.exe 17.00.51025
            case 51106: sResult="2012 update 1"; break; // cl.exe 17.00.51106
            case 60315: sResult="2012 update 2"; break; // cl.exe 17.00.60315
            case 60610: sResult="2012 update 3"; break; // cl.exe 17.00.60610
            case 61030: sResult="2012 update 4"; break; // cl.exe 17.00.61030
            case 21005: sResult="2013";          break; // cl.exe 18.00.21005
            case 30501: sResult="2013 update 2"; break; // cl.exe 18.00.30501
            case 22215: sResult="2015"; break; // cl.exe 19.00.22215 Preview
            }

            if(sResult=="")
            {
                if(!PE.isLibraryPresent("MSVBVM60.DLL")) // VB
                {
                    if(PE.isRichVersionPresent(8168))
                    {
                        sResult="6.0";                  // cl.exe 12.00.8168
                    }
                    else if(PE.isRichVersionPresent(8804))
                    {
                        sResult="6.0 SP 5/6";      // SP 5/6 cl.exe 12.00.8804
                    }
                }
            }
        }
    }

    return sResult;
}

function detect(bShowType,bShowVersion,bShowOptions)
{
    var bWmain=0;
    var aMSVCRT=PE.isLibraryPresentExp(/^MSVCR/i);
    if(aMSVCRT)
    {
        bWmain=PE.isLibraryFunctionPresent(aMSVCRT[0],"__wgetmainargs");
    }

    if(!PE.isPEPlus())
    {
        if(PE.compareEP("558BEC51C745FC01000000837D0C007510833D"))
        {
            if(PE.compareEP("00",-4))
            {
                sOptions=sOptions.append("libcd");
            }
            else if(PE.compareEP("00",-8))
            {
                sOptions=sOptions.append("libcmtd");
            }
            else
            {
                sOptions=sOptions.append("msvcrtd");
            }
            sVersion="6.0";
            bDetected=1;
        }
        else if(PE.compareEP("558BEC538B5D08568B750C578B7D1085F67509833D"))
        {
            if(PE.compareEP("CA",-1))
            {
                sOptions=sOptions.append("libc");
            }
            else if(PE.compareEP("59",-7))
            {
                sOptions=sOptions.append("libcmt");
            }
            else
            {
                sOptions=sOptions.append("msvcrt");
            }
            sVersion="6.0";
            bDetected=1;
        }
        else if(PE.compareEP("558BEC6AFF68........68........64A100000000506489250000000083"))
        {
            var nOfs;
            switch(PE.readByte(PE.nEP+31))
            {
            case 0x10:
                if(PE.compareEP("83",107))
                {
                    sOptions=sOptions.append("libc");
                    nOfs=116;
                }
                else
                {
                    sOptions=sOptions.append("libcmt");
                    nOfs=133;
                }
                if(PE.compareEP("E8",nOfs))
                {
                    sOptions=sOptions.append("wmain");
                    --nOfs;
                }
                if(PE.compareEP("FF",nOfs+25))
                {
                    sOptions=sOptions.append("glob");
                }
                break;
            case 0x20:
                sOptions=sOptions.append("msvcrt");
                if(bWmain)
                {
                    sOptions=sOptions.append("wmain");
                }
                if(PE.compareEP("FF",109))
                {
                    sOptions=sOptions.append("glob");
                }
                break;
            case 0x58:
                if(PE.compareEP("33",87))
                {
                    sOptions=sOptions.append("libc");
                    nOfs=116;
                }
                else
                {
                    sOptions=sOptions.append("libcmt");
                    nOfs=134;
                }
                if(PE.compareEP("E8",nOfs))
                {
                    sOptions=sOptions.append("wWinMain");
                }
                break;
            case 0x68:
                sOptions=sOptions.append("msvcrt");
                if(PE.compareEP("5F",45))
                {
                    sOptions=sOptions.append("wWinMain");
                }
                break;
            case 0x90:
                sOptions=sOptions.append("libcd");
                if(PE.compareEP("E8",241))
                {
                    sOptions=sOptions.append("wWinMain");
                }
                break;
            case 0x94:
                sOptions=sOptions.append("msvcrtd");
                if(PE.compareEP("83",233))
                {
                    sOptions=sOptions.append("wWinMain");
                }
                break;
            case 0xA4:
                if(PE.compareEP("00",125))
                {
                    sOptions=sOptions.append("libcd");
                    nOfs=160;
                }
                else
                {
                    sOptions=sOptions.append("libcmtd");
                    nOfs=179;
                }
                if(PE.compareEP("E8",nOfs))
                {
                    sOptions=sOptions.append("wWinMain");
                }
                break;
            case 0xE0:
                switch(PE.readByte(PE.nEP+38))
                {
                case 0xB8:
                    sOptions=sOptions.append("libcd");
                    if(PE.compareEP("E8",241))
                    {
                        sOptions=sOptions.append("wmain");
                    }
                    break;
                case 0xC7:
                    sOptions=sOptions.append("msvcrtd");
                    if(bWmain)
                    {
                        sOptions=sOptions.append("wmain");
                    }
                    if(PE.compareEP("FF",121))
                    {
                        sOptions=sOptions.append("glob");
                    }
                    break;
                }
                break;
            case 0xE8:
                sOptions=sOptions.append("libcd");
                break;
            case 0xF0:
                if(PE.compareEP("00",125))
                {
                    sOptions=sOptions.append("libcd");
                    nOfs=160;
                }
                else
                {
                    sOptions=sOptions.append("libcmtd");
                    nOfs=179;
                }
                if(PE.compareEP("E8",nOfs))
                {
                    sOptions=sOptions.append("wmain");
                    --nOfs;
                }
                if(PE.compareEP("FF",nOfs+25))
                {
                    sOptions=sOptions.append("glob");
                }
                break;
            }
            sVersion="5.0-2003";
            bDetected=1;
        }
        else if(PE.compareEP("6A0C68........E8........33C0408945E48B750C33FF3BF7750C393D"))
        {
            switch(PE.readByte(PE.nEP-1))
            {
            case 0xC0: sOptions=sOptions.append("libc");   break;
            case 0x00: sOptions=sOptions.append("libcmt"); break;
            }
            sVersion="2003";
            bDetected=1;
        }
        else if(PE.compareEP("6A..68........E8........66813D"))
        {
            sVersion="2003";
            bDetected=1;
        }
        else if(PE.compareEP("6A..68........E8........BF940000008BC7E8"))
        {
            nOfs=0;
            var sMain;
            switch(PE.readByte(PE.nEP+1))
            {
            case 0x18:
                sMain="wmain";
                nOfs=197;
                break;
            case 0x60:
                sMain="wWinMain";
                nOfs=199;
                break;
            }
            if(nOfs)
            {
                if(PE.compareEP("6A",nOfs))
                {
                    sOptions=sOptions.append("libcmt");
                    nOfs+=62;
                }
                else
                {
                    sOptions=sOptions.append("libc");
                    nOfs+=69;
                }
                if(PE.compareEP("E8",nOfs))
                {
                    sOptions=sOptions.append(sMain);
                }
            }
            sVersion="2003";
            bDetected=1;
        }
        else if(PE.compareEP("8BFF558BEC837D0C017505E8"))
        {
            if(PE.compareEP("8B",16))
            {
                sOptions=sOptions.append(PE.compareEP("E8",74)?"libcmtd":"msvcrtd");
            }
            else
            {
                sOptions=sOptions.append(PE.compareEP("8B",35)?"libcmt":"msvcrt");
            }
            sVersion="2008-2010";
            bDetected=1;
        }
        else if(PE.compareEP("8BFF558BECE8......00E8......005DC3"))
        {
            switch(PE.readByte(PE.nEP+58))
            {
            case 0x88:
                sOptions=sOptions.append("msvcrtd","wWinMain");
                sVersion="2008";
                break;
            case 0x8C:
                sOptions=sOptions.append("msvcrtd");
                sVersion="2008";
                break;
            case 0x90:
                sOptions=sOptions.append("msvcrtd");
                if(bWmain)
                {
                    sOptions=sOptions.append("wWinMain");
                }
                sVersion="2010";
                break;
            case 0x94:
                sOptions=sOptions.append("libcmtd");
                if(PE.compareEP("52",145))
                {
                    sOptions=sOptions.append("wWinMain");
                }
                sVersion="2008";
                break;
            case 0x98:
                sOptions=sOptions.append("libcmtd");
                if(PE.compareEP("6A",645))
                {
                    sOptions=sOptions.append("wWinMain");
                }
                sVersion="2010";
                break;
            case 0xE4:
                sOptions=sOptions.append("msvcrtd");
                if(bWmain)
                {
                    sOptions=sOptions.append("wmain");
                }
                if(PE.compareEP("FF",-0x9B))
                {
                    sOptions=sOptions.append("glob");
                }
                sVersion="2008-2010";
                break;
            case 0xE8:
                sOptions=sOptions.append("libcmtd");
                if(PE.compareEP("E8",92))
                {
                    if(PE.compareEP("E8",184))
                    {
                        sOptions=sOptions.append("wmain");
                        bWmain=1;
                    }
                    sVersion="2008";
                }
                else
                {
                    if(PE.compareEP("E8$$$$$$$$8BFF558BEC83EC10",213))
                    {
                        sOptions=sOptions.append("wmain");
                        bWmain=1;
                    }
                    sVersion="2010";
                }
                if(bWmain)
                {
                    if(PE.compareEP("10",-6))
                    {
                        sOptions=sOptions.append("glob");
                    }
                }
                else
                {
                    if(PE.compareEP("CC",-2))
                    {
                        sOptions=sOptions.append("glob");
                    }
                }
                break;
            }
            bDetected=1;
        }
        else if(PE.compareEP("E8......00E9$$$$$$$$6A..68........E8"))
        {
            var nEP=PE.nEP;
            nEP+=10+~~PE.readDword(nEP+6);
            if(PE.compare("10",nEP+1))
            {
                sOptions=sOptions.append("msvcrt");
                if(bWmain)
                {
                    sOptions=sOptions.append("wmain");
                }
                if(PE.compareEP("FF",-48))
                {
                    sOptions=sOptions.append("glob");
                }
            }
            else if(PE.compare("33DB",nEP+12))
            {
                sOptions=sOptions.append("msvcrt");
                if(PE.compare("89",nEP+53)||PE.compare("E0",nEP+60))
                {
                    sOptions=sOptions.append("wWinMain");
                }
            }
            else if(PE.compare("3935",nEP+14))
            {
                sOptions=sOptions.append("libcmt");
                if(PE.compareEP("E8$$$$$$$$8B",-150))
                {
                    sOptions=sOptions.append("wmain");
                }
                if(PE.compareEP("FF",-0xA3))
                {
                    sOptions=sOptions.append("glob");
                }
            }
            else if(PE.compare("8D4598",nEP+12))
            {
                sOptions=sOptions.append("libcmt");
                if(PE.compareEP("51",15))
                {
                    sOptions=sOptions.append("wWinMain");
                }
            }
            else if(PE.compare("33F68975FC",nEP+12))
            {
                sOptions=sOptions.append("libcmt");
                if(PE.compare("E8",nEP+170))
                {
                    sOptions=sOptions.append("wWinMain");
                }
            }
            else if(PE.compare("B8'MZ'",nEP+12))
            {
                sOptions=sOptions.append("libcmt");
                if(PE.compare("E8",nEP+149))
                {
                    sOptions=sOptions.append("wmain");
                    --nEP;
                }
                if(PE.compare("FF",nEP+174))
                {
                    sOptions=sOptions.append("glob");
                }
            }
            sVersion="2008-2010";
            bDetected=1;
        }
        else if(PE.compareEP("64A100000000558BEC6AFF68"))
        {
            bDetected=1;
        }
        else if(PE.compareEP("64A100000000506489250000000083C4A8535657"))
        {
            sVersion="5.0";
            bDetected=1;
        }
        else if(PE.compareEP("535657BB........8B......553BFB75"))
        {
            sVersion="2.0";
            bDetected=1;
        }
        else if(PE.compareEP("56E8........8BF0E8........68........68........E8........6A..68........56E8"))
        {
            sVersion="2.0";
            bDetected=1;
        }
        else if(PE.compareEP("53B8........8B......565785DB5575"))
        {
            sVersion="4.2";
            bDetected=1;
        }
        else if(PE.compareEP("558BEC83EC4456FF15........6A018BF0FF15"))
        {
            sVersion="6.0";
            bDetected=1;
        }
        else if(PE.compareEP("558BEC83EC4456FF15........8BF08A063C22"))
        {
            sVersion="6.0";
            bDetected=1;
        }
        else if(PE.compareEP("558D6C....81EC........8B45..83F801560F84........85C00F84"))
        {
            sVersion="6.0";
            bDetected=1;
        }
        //else if(PE.compareEP("837C24080175098B442404A3....0010E88BFFFFFF")) // Pure Basic 4.0
        //{
        //    sVersion="6.0";
        //    bDetected=1;
        //}
        else if(PE.compareEP("558BEC538B5D08568B750C85F6578B7D10"))
        {
            sVersion="2002";
            bDetected=1;
        }
        else if(PE.compareEP("833D........00741A68........E8........85C059740BFF742404FF15........59E8........68........68........E8........85C059597554565768........E8........BE........8BC6BF"))
        {
            sVersion="2005";
            bDetected=1;
        }
        else if(PE.compareEP("6A1468........E8........BB94000000536A008B..........FFD750FF..........8BF085F6750A6A12E8........59EB18891E56FF..........5685C0751450FFD750FF..........B8"))
        {
            sVersion="2005";
            bDetected=1;
        }
        else if(PE.compareEP("8BFF558BEC538B5D08568B750C85F6578B7D100F84....000083FE01"))
        {
            sVersion="2005";
            bDetected=1;
        }
        else if(PE.compareEP("8BFF558BEC538B5D08568B750C85F6578B7D107509833D........00EB2683FE01740583FE027522A1........85C07409575653FFD085C0740C575653E8......FF85C0750433C0EB4E575653E8......FF83FE0189450C750C85C07537575053E8......FF85F6740583FE037526575653E8......FF85C0750321450C837D0C007411A1........85C07408575653FFD089450C8B450C5F5E5B5DC20C00"))
        {
            sVersion="2005";
            bDetected=1;
        }
        else if(PE.compareEP("558BEC83EC10A1........8365F8008365FC005357BF4EE640BB3BC7BB0000FFFF740D85C37409F7D0A3........EB60568D45F850FF15........8B75FC3375F8FF15........33F0FF15........33F0FF15........33F08D45F050FF15........8B45F43345F033F03BF77507BE4FE640BBEB0B85F375078BC6C1E0100BF08935........F7D68935........5E5F5BC9C3"))
        {
            sVersion="2005";
            bDetected=1;
        }
        else if(PE.compareEP("558BEC83EC245356578965F8"))
        {
            bDetected=1;
        }
    }
    else
    {
        if(PE.compareEP("4883EC2885D248895C243048896C243848897424408BDA488BE9498BF0751E3915"))
        {
            sVersion="2005";    // DLL
            bDetected=1;
        }
        else if(PE.compareEP("4883EC5848895C247048897C247866813D"))
        {
            sVersion="2005";    // console, msvcrt
            bDetected=1;
        }
        else if(PE.compareEP("4883EC3848895C245048897C2458FF15"))
        {
            sVersion="2005";    // console, static
            bDetected=1;
        }
        else if(PE.compareEP("488BC44881EC........4889581848897820488D4888FF15"))
        {
            sVersion="2005";    // GUI
            bDetected=1;
        }
        else if(PE.compareEP("4883EC28E8........4883C428E9$$$$$$$$48895C24"))
        {
            sVersion="2010";
            bDetected=1;
        }
        else if(PE.compareEP("4883EC28E8........E8........4883C428C3"))
        {
            sVersion="2010";    // debug
            bDetected=1;
        }
        else if(PE.compareEP("48895C24084889742410574883EC20498BF88BDA488BF183FA017505E8"))
        {
            sVersion="2010";    // DLL
            bDetected=1;
        }
        else if(PE.compareEP("4C894424188954241048894C24084883EC28837C2438017505E8"))
        {
            sVersion="2010";    // DLL debug
            bDetected=1;
        }
    }

    // Correct version.
    if(bDetected) // MASM32 has RichSignature too.
    {
        sVersion=getVCVersionFromLinkerVersion();
        if(PE.getMajorLinkerVersion()==3)
        {
            sName="Microsoft C/C++";
        }
    }

    var sRichVersion=getVersionFromRichSignature(); // VC 6.0-2013
    if(sRichVersion!="")
    {
        sVersion=sRichVersion;
        bDetected=1;
    }

    if(!bDetected)
    {
        var sVCVersion=getVCVersionFromLinkerVersion();
        if(sVCVersion!="")
        {
            if(PE.section.length>=3)
            {
                if(PE.isSignatureInSectionPresent(0,"'Microsoft Visual C++ Runtime Library'")||PE.isSignatureInSectionPresent(1,"'Microsoft Visual C++ Runtime Library'")||PE.isSignatureInSectionPresent(2,"'Microsoft Visual C++ Runtime Library'"))
                {
                    sVersion=sVCVersion;
                    bDetected=1;
                }
            }
        }

    }

    return result(bShowType,bShowVersion,bShowOptions);
}
