// Detect It Easy: detection rule file
// Authors: ajax, hypn0, DosX

// https://vmpsoft.com/
meta("protector", "VMProtect");

function detect() {
    if (PE.isNet()) return; // Native files only

    var nNumberOfSections = PE.getNumberOfSections();

    var sVMPSectionName;

    for (var i = nNumberOfSections - 1; i >= 0; i--) {
        if (i == PE.getRelocsSection() || i == PE.getResourceSection()) {
            continue;
        }

        if (PE.getSectionName(i)) {
            sVMPSectionName = PE.getSectionName(i);

            if (i > 0 &&
                sVMPSectionName == ".vmp0") {
                bDetected = true;

                break;
            } else if (i > 1 &&
                (sVMPSectionName.substr(sVMPSectionName.length - 1) == "1")) {
                var sCollision = PE.getSectionNameCollision("0", "1");

                if (PE.isSectionNamePresent(sCollision + "1")) {
                    bDetected = true;

                    break;
                }
            } else if (i > 2 &&
                (sVMPSectionName.substr(sVMPSectionName.length - 1) == "2")) {
                var sCollision = PE.getSectionNameCollision("1", "2");

                if (PE.isSectionNamePresent(sCollision + "1") &&
                    PE.isSectionNamePresent(sCollision + "0")) {
                    bDetected = true;

                    break;
                }
            } else if (i > 3 &&
                (sVMPSectionName.substr(sVMPSectionName.length - 1) == "3")) {
                var sCollision = PE.getSectionNameCollision("2", "3");

                if (PE.isSectionNamePresent(sCollision + "2") &&
                    PE.isSectionNamePresent(sCollision + "1") &&
                    PE.isSectionNamePresent(sCollision + "0")) {
                    bDetected = true;

                    break;
                }
            }
        }

        break;
    }

    if (bDetected) {
        if (PE.is64()) {
            sVersion = "2.XX-3.XX";
        }

        if (sVMPSectionName) {
            if (sVMPSectionName.substr(sVMPSectionName.length - 1) == "0") {
                sOptions = "min protection";
            }
        }

        if (PE.isImportPositionHashPresent(-1, 0x1ff3103f)) {
            sVersion = "1.70";
        } else if (PE.isImportPositionHashPresent(-1, 0x0c16df2d)) {
            sVersion = "1.70";
            sOptions = "max protection";
        } else if (PE.isImportPositionHashPresent(-1, 0x9d12b153)) {
            sVersion = "2.0.3-2.13";
        } else if (PE.isImportPositionHashPresent(-1, 0x1e5500c1)) {
            sVersion = "3.0.0";
        } else if (PE.isImportPositionHashPresent(-1, 0xc5fb6a4b)) {
            sVersion = "3.0.9";
        } else if (PE.isImportPositionHashPresent(-1, 0x5caa99c7)) {
            sVersion = "3.2.0-3.5.0";
        }
    }

    var bEnableNewEngine = true; // Need more researches

    if (bEnableNewEngine && !bDetected && PE.isDeepScan()) {
        var da = "",
            das = "",
            res = 0,
            jmp = 0;

        var ep = PE.OffsetToVA(PE.getEntryPointOffset()),
            count = 0;

        while (das.substr(0, das.indexOf('+')) != "MOV EDX, DWORD PTR [EAX*4 " &&
            das.substr(0, das.indexOf('+')) != "MOV EBX, DWORD PTR [EAX*4 " &&
            das.substr(0, das.indexOf('+')) != "MOV ECX, DWORD PTR [EAX*4 " && count < 1000) {
            count++;

            var byte = PE.readByte(PE.VAToOffset(ep)),
                da = PE.getDisasmString(ep),
                das = da;

            if (da.indexOf(' ') != -1) {
                da = da.substr(0, da.indexOf(' '));
            }

            var fresh = 0;
            if ((byte == 0xFF && da == "JMP") || ((byte == 0xC3 || byte == 0xC2) && da == "RET")) {
                fresh = 1;
                break;
            }

            if (byte == 0xFF && da == "CALL") break;

            if (da.indexOf(' ') != -1)
                da = da.substr(0, da.indexOf(' '));


            if (da == "CLC" || da == "CMC") { res++; }
            if (da == "PUSHFD") { res++; }
            if (da == "PUSHAL") { res++; }
            if (da == "XOR") { res++; }
            if (da == "NEG" || da == "NOT") { res++; }
            if (da == "SAR" || da == "SAL") { res++; }
            if (da == "JMP" || da == "CALL") { jmp++; }
            if (da == "BT" || da == "BTR" || da == "BTS" || da == "BTC") { res++; }
            if (da == "BSF" || da == "BSR" || da == "BSWAP") { res++; }
            if (da == "ROL" || da == "ROR" || da == "RCL" || da == "RCR") { res++; }

            ep = PE.getDisasmNextAddress(ep);
        }

        if (res > 10 && count < 200) {
            if (fresh == 1) { sVersion = "new"; } else { sVersion = "old"; }
            sOptions = "DS";
            bDetected = true;
        }
    }


    // packer detection
    var kernel32Count = 0;
    for (var i = 0; i < PE.getNumberOfImports(); i++) {
        if (PE.getImportLibraryName(i) === "KERNEL32.dll") {
            kernel32Count++;
        }

        if (kernel32Count >= 2) {
            if (PE.is64() && PE.compare("4D 5A ?? 00 ?? 00 00 00 04 00 ?? 00 FF FF 00 00 B8 00 00 00 00 00 00 00 40 00 ?? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 ?? ?? ?? 0E ?? B4 09 CD 21 B8 01 4C CD")) {
                bDetected = true;
                sOptions = sOptions.append("packed");
            }

            break;
        }
    }

    return result();
}

function detectVmp(sSectionName) {
    if (PE.section[sSectionName]) {
        var nCharacteristics = PE.section[sSectionName].Characteristics;
        if (nCharacteristics == 0x60000060 ||
            nCharacteristics == 0xE0000060 ||
            nCharacteristics == 0xE0000040 ||
            nCharacteristics == 0x68000060 ||
            nCharacteristics == 0xe2000060)
            return true;
    }

    return false;
}

function detectVmp2() {
    if (PE.section.length > 7) {
        var nCount = 5,
            nResource = PE.getResourceSection(),
            nRelocs = PE.getRelocsSection();

        if (nResource > PE.section.length - nCount)
            nCount++;

        if (nRelocs > PE.section.length - nCount)
            nCount++;


        var nDetectCount = 0,
            nLastVMPSection = 0;

        for (var nSection = PE.section.length - nCount; nSection < PE.section.length; nSection++) {
            if (nSection == nResource || nSection == nRelocs)
                continue;

            if (PE.section[nSection].FileSize == 0 && PE.section[nSection].FileOffset == 0)
                nDetectCount++;

            if (PE.section[nSection].FileSize != 0 && PE.section[nSection].FileOffset != 0)
                nLastVMPSection = nSection;
        }

        if (nDetectCount >= 3) {
            if (PE.getEntryPointSection() == nLastVMPSection) {
                if (PE.section[nLastVMPSection].Characteristics == 0xE0000060) {
                    if (PE.calculateEntropy(PE.section[nLastVMPSection].FileOffset, PE.section[nLastVMPSection].FileSize) > 7.6) {
                        return true;
                    }
                } else if (PE.section[nLastVMPSection].Characteristics & 0x20000000) { // Fix sent Deniskore
                    var nSectionOffset = PE.section[nLastVMPSection].FileOffset,
                        nSectionSize = PE.section[nLastVMPSection].FileSize,
                        nOffset = nSectionOffset,
                        nSize = nSectionSize,
                        nCount = 0,
                        nSignatureOffset = 0;

                    while (nSize > 0) {
                        nSignatureOffset = PE.findSignature(nOffset, nSize, "9c8d64");
                        if (nSignatureOffset == -1)
                            break;
                        nCount++;
                        nOffset = nSignatureOffset + 3;
                        nSize = nSectionSize - (nSignatureOffset - nSectionOffset);
                        if (nCount >= 2) {
                            return true;
                        }
                    }
                }
            }
        }
    }

    return false;
}

/* function detect_old() {
    if (PE.section[".vmp0"] && (PE.compareEP("68........E9") || PE.compareEP("68........E8"))) {
        sVersion = "1.60-2.05";
        bDetected = true;
    } else if (detectVmp(".vmp0") || detectVmp(".vmp1") || detectVmp(".vmp2")) {
        bDetected = true;
    } else if (PE.compareEP("54c70424........9c60c74424..........c64424....887424..60")) {
        sVersion = "2.06";
        bDetected = true;
    } else if (PE.compareEP("e8$$$$$$$$e9$$$$$$$$880424881c24c70424........9ce8")) {
        sVersion = "2.07";
        bDetected = true;
    } else if (PE.compareEP("9ce8$$$$$$$$e8$$$$$$$$c74424..........e9$$$$$$$$e8$$$$$$$$c74424..........526068")) {
        sVersion = "2.12-13";
        bDetected = true;
    } else if (PE.compareEP("9c9cc74424..........9cc74424..........9c528d6424..e9")) {
        sVersion = "2.12-13";
        bDetected = true;
    } else if (PE.compareEP("68........e8$$$$$$$$41574150448ac350410f96c057415148c7c7")) {
        sVersion = "3.0X";
        bDetected = true;
    } else {
        var collision = PE.getSectionNameCollision("0", "1");

        if (collision) {
            if (PE.compareEP("68........E9") || PE.compareEP("68........E8")) {
                sVersion = "1.X";
                bDetected = true;
            } else if (PE.compareEP("9cE9") || PE.compareEP("9cFF")) {
                sVersion = "2.X";
                bDetected = true;
            } else if (detectVmp(collision + "0") && detectVmp(collision + "1")) {
                bDetected = true;
            }
        }
        if (!bDetected && detectVmp2()) {
            sVersion = "2.X";
            bDetected = true;
        }
    }

    if (bDetected) {
        if (PE.section.length < 3 || (PE.section.length == 3 && PE.section[0].FileSize == 0)) {
            bDetected = false;
        }
    }
} */