Analyzing old stub.dll of Trojan RAT fruits Pineapple version

It all started one of those times when I was bored as usual, and I ran a .jar apparently any, but not really, it was a server of adwind (a programmer that I thought was quite talented) year 2017 or so in November.

Well, how do I know that? first I tried to decompile it in other absurd ways like for example, con CFF Explorer, without any result, since it does not contain runPE, as I found out later.

What does the CFF explorer show ?

cffExplorerAdwindStub

The stub.dll is actually a .jar (this time as it is not encrypted it would be enough just to rename it to .jar and that’s it) the code to extract the classes from the stub.dll is the following, what it does is to read it completely and save it in a .jar

Reading the stub

public class CrearJar implements ShowData {

    (1)
    private static final Path STUB_PATH =  Paths.get("src/main/resources/stub.dll");
    (2)
    private static final Path DESTINO_STUB = Paths.get("src/main/resources/clasesStub.jar");

    public CrearJar() {
        init();
    }

    /**
    * reads the path where the stub.dll is and dumps the contents into a .jar
     */
    private void init() { (3)

        try(final JarInputStream jarInputStream = new JarInputStream(Files.newInputStream(STUB_PATH ));
        final BufferedOutputStream bos = new BufferedOutputStream(Files.newOutputStream(DESTINO_STUB ));
        final JarOutputStream jarOutputStream = new JarOutputStream(bos, jarInputStream.getManifest())) {

               JarEntry jarEntry;

               while((jarEntry = jarInputStream.getNextJarEntry()) != null) {
                   if(predicate(jarEntry)) {
                       getLogger().info(jarEntry.getName()); (4)
                       jarOutputStream.putNextEntry(jarEntry);
                       jarOutputStream.write(readAllBytes(jarInputStream));
                       jarOutputStream.flush();
                   }
               }
           }catch (IOException ex) {
               getLogger().severe(ex.getMessage(),ex);
           }
        }

    /**
    * Validate jarEntry
    * @param jarEntry TO BE TESTED
    * @return boolean true if they are only classes, and they are not directories, nor do they have $
    */
    private boolean predicate(final JarEntry jarEntry) { (5)
        final Predicate<Boolean> predicate = p -> !jarEntry.isDirectory()
                                                      && jarEntry.getName().endsWith(".class")
                                                      && !jarEntry.getName().contains("$"),
                                                      || jarEntry.getName().contains("_");
        return predicate.test(jarEntry);
    }

    /**
    *
    * @return all bytes from stub
    */
    private byte[] readAllBytes(final InputStream input) {
        try(ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
              final byte[] bytesread = new byte[1024];
              int dataRead;
              while((dataRead = input.read(bytesread)) != -1) {
                  baos.write(bytesread,0,dataRead);
              }
              return baos.toByteArray();
        } catch (IOException ex) {
            getLogger().severe(null,ex);
        }
        return new byte[0];
    }
}
1 Stub path.
2 Path to the final files.
3 Execution of the init() method.
4 A printout is made of all the classes that are contained in the .jar.
5 It is allowed to print only if they are classes, and that they are not directories, nor have $.
19:08:06.783 [main] INFO CrearJar - Desinstala.class
19:08:06.783 [main] INFO CrearJar - Principal.class
19:08:06.783 [main] INFO CrearJar - extra/ClassLoaderMod.class
19:08:06.783 [main] INFO CrearJar - extra/Constante.class
19:08:06.783 [main] INFO CrearJar - extra/Constantes.class
19:08:06.783 [main] INFO CrearJar - extra/RegistryUtils.class
19:08:06.799 [main] INFO CrearJar - opciones/Archivo.class
19:08:06.799 [main] INFO CrearJar - opciones/DesUAC.class
19:08:06.799 [main] INFO CrearJar - opciones/EnviarFile.class
19:08:06.799 [main] INFO CrearJar - opciones/Informacion.class
19:08:06.799 [main] INFO CrearJar - opciones/Instalador.class
19:08:06.799 [main] INFO CrearJar - opciones/Interface_.class
19:08:06.799 [main] INFO CrearJar - opciones/Kille.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion1.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion10.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion12.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion13.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion14.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion2.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion5.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion6.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion7.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion7b.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion8.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion9.class
19:08:06.799 [main] INFO CrearJar - opciones/Opcion9b.class
19:08:06.799 [main] INFO CrearJar - opciones/OrdenCaptura.class
19:08:06.799 [main] INFO CrearJar - opciones/PassAll.class
19:08:06.799 [main] INFO CrearJar - opciones/Pina.class
19:08:06.799 [main] INFO CrearJar - opciones/WebBot.class
19:08:06.799 [main] INFO CrearJar - opciones/a.class
19:08:06.799 [main] INFO CrearJar - opciones/interfaceInfo.class
19:08:06.799 [main] INFO CrearJar - opciones/passFilezilla.class
19:08:06.799 [main] INFO CrearJar - opciones/passIDM.class
19:08:06.799 [main] INFO CrearJar - opciones/passNoip.class

This class is in charge of deciphering the .class with DES

The Constant class

package extra;
import java.io.ByteArrayOutputStream;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

public class Constante {
   public Constante() {
   }

    public static byte[] Constantino(String contrasena, byte[] input) {
        try {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            SecretKeyFactory skf = SecretKeyFactory.getInstance(new String(new char[]{'D', 'E', 'S'}));
            DESKeySpec kspec = new DESKeySpec(contrasena.getBytes());
            SecretKey ks = skf.generateSecret(kspec);
            Cipher c = Cipher.getInstance(new String(new char[]{'D', 'E', 'S'}));
            c.init(2, ks);
            byte[] tmp = c.update(input, 0, input.length);
            out.write(tmp);
            tmp = c.doFinal();
            out.write(tmp);
            out.close();
            return out.toByteArray();
        } catch (Exception var8) {
            return null;
        }
     }
}

The Main class

Here is the main class, the server reads the password contained in an .xml, to decrypt the bytecodes in runtime and load them in memory by means of the custom Classloader, you see other versions of arabs where that password is exposed by an apparently obfuscated endpoint.

adwind classMod

Newer versions of this trojan (Unrecom, Alien spy, JSocket etc), are anti-virtual machine, anti vmware, and more, here I show some .exe that this malware blocks, that actually the code that executes those actions is encrypted in the corresponding .class and obfuscated, the same step of the Classloader above is performed, it seems that the same procedure has been inherited through the versions of these RATs

adwin1

Blocking of .exe

The amount of .exe blocking is somewhat high in passing establish connection via SSL/TLS.

adwin2