// Detect It Easy: detection rule file format
// Author: nicholasmckinney


init("shellcode", "Monoxgas sRDI");


// https://github.com/monoxgas/sRDI/blob/9fdd5c44383039519accd1e6bac4acd5a046a92c/Python/ShellcodeRDI.py
function detect(bShowType, bShowVersion, bShowOptions) {
    bDetected = false;

    // 32-bit and 64-bit start out with the same first 5 bytes (relative jump)
    var jumpStartOffset = Binary.findSignature(0, Binary.getSize(), "E800000000");

    if (jumpStartOffset < 0) {
        return result(bShowType, bShowVersion, bShowOptions);
    }

    var currentOffset = jumpStartOffset + 5;

    // Possible 64-bit sRDI
    // https://github.com/monoxgas/sRDI/blob/9fdd5c44383039519accd1e6bac4acd5a046a92c/Python/ShellcodeRDI.py#L76-L80
    if (Binary.readDword(currentOffset) == 0xC8894959) {

        currentOffset += 4;

        // https://github.com/monoxgas/sRDI/blob/9fdd5c44383039519accd1e6bac4acd5a046a92c/Python/ShellcodeRDI.py#L83-L84
        if ((Binary.readDword(currentOffset) & 0xFF) != 0xBA) {
            return result(bShowType, bShowVersion, bShowOptions);
        }

        currentOffset += 5; // 1 byte for MOV EDX, 4 bytes for function hash


        // 4 bytes from rel jump for func hash
        var setupLocation = Binary.readDword(currentOffset);

        if ((setupLocation & 0xFFFFFF) != 0xC08149) {
            return result(bShowType, bShowVersion, bShowOptions);
        }

        currentOffset += 7; // 33 bytes for bytes compared + 4 bytes for user data location

        if ((Binary.readDword(currentOffset) & 0xFFFF) != 0XB941) {
            return result(bShowType, bShowVersion, bShowOptions);
        }

        currentOffset += 6; // 2 bytes for mov r9d, 4 bytes for length of user data

        var nextBytes = "564889E64883E4F04883EC3048894C24284881C1"; // 20 bytes length
        if (!Binary.isSignaturePresent(currentOffset, 20, nextBytes)) {
            return result(bShowType, bShowVersion, bShowOptions);
        }

        // https://github.com/monoxgas/sRDI/blob/9fdd5c44383039519accd1e6bac4acd5a046a92c/Python/ShellcodeRDI.py#L113
        currentOffset += 24; // 20 bytes for continued setup, 4 bytes for offset to DLL

        if (Binary.readDword(currentOffset) != 0x202444C7) {
            return result(bShowType, bShowVersion, bShowOptions);
        }

        currentOffset += 8; // 4 bytes for mov, 4 bytes for flags operand

        if (Binary.readByte(currentOffset) != 0xE8) {
            return result(bShowType, bShowVersion, bShowOptions);
        }

        currentOffset += 5; // 5 bytes for rel jump

        // https://github.com/monoxgas/sRDI/blob/9fdd5c44383039519accd1e6bac4acd5a046a92c/Python/ShellcodeRDI.py#L127-L134
        if (!Binary.isSignaturePresent(currentOffset, 5, "4889F45EC3")) {
            return result(bShowType, bShowVersion, bShowOptions);
        }

        bDetected = true;
        sOptions = "AMD64";
    }
    // Possible 32-bit sRDI
    else if (Binary.readDword(currentOffset) == 0xE5895558) {


        // https://github.com/monoxgas/sRDI/blob/9fdd5c44383039519accd1e6bac4acd5a046a92c/Python/ShellcodeRDI.py#L159-L171
        if (!Binary.isSignaturePresent(currentOffset, 7, "585589E589C268")) {
            return result(bShowType, bShowVersion, bShowOptions);
        }

        currentOffset += 11; // 7 bytes for sig above + 4 bytes for flags

        if ((Binary.readDword(currentOffset) & 0xFFFFFF) != 0xC28150) {
            return result(bShowType, bShowVersion, bShowOptions);
        }

        currentOffset += 7; // 3 bytes for sig above + 4 bytes for user data location

        if (Binary.readByte(currentOffset) != 0x68) {
            return result(bShowType, bShowVersion, bShowOptions);
        }

        currentOffset += 5; // 5 bytes to push length of user data

        if (Binary.readWord(currentOffset) != 0x6852) {
            return result(bShowType, bShowVersion, bShowOptions);
        }

        currentOffset += 6; // 1 byte to push edx, 5 bytes to push hash of function

        if (Binary.readByte(currentOffset) != 0x05) {
            return result(bShowType, bShowVersion, bShowOptions);
        }

        currentOffset += 5; // 5 bytes to add offset of dll to eax

        if (Binary.readWord(currentOffset) != 0xE850) {
            return result(bShowType, bShowVersion, bShowOptions);
        }

        currentOffset += 6; // 1 byte to push eax, 5 bytes to rel jump to reflective loader

        if (!Binary.isSignaturePresent(currentOffset, 5, "83C414C9C3")) {
            return result(bShowType, bShowVersion, bShowOptions);
        }

        bDetected = true;
        sOptions = "x86";
    }

    return result(bShowType, bShowVersion, bShowOptions);
}
