Let's assume you finished the analysis of Blacole's obfuscated Javascript (see my earlier diary today), and you are still left with a code block like this
because they would trip us up in any of the following steps. Once we're left with only the actual unicode (%uxxyy...) , we can turn this into printable characters: $ cat raw.js | perl -pe 's/%u(..)(..)/chr(hex($2)).chr(hex($1))/ge' > decoded.bin 00000000 41 41 41 41 66 83 e4 fc fc eb 10 58 31 c9 66 81 |AAAAf.äüüë.X1Éf.| This doesn't result in anything all that useful yet. Shellcode is in assembly language, so it wouldn't be "readable" in a hex dump anyway. But since most shellcode just downloads and runs an executable .. well, the name of the EXE could have been visible. Not in this case, because the shellcode is .. encoded one more time :). Next step: Disassemble. The quickest way to do so from a Unix command line (that I'm aware of) is to wrap the shell code into a small C program, compile it, and then disassemble it: $ cat decoded.bin | perl -ne 's/(.)/printf "0x%02x,",ord($1)/ge > decoded.c results in 0x41,0x41,0x41,0x41,0x66,0x83,0xe4,0xfc,0xfc,0xeb,0x10,0x58,0x31,0xc9 [...] which is the correct format to turn it into $ cat decoded.c unsigned char shellcode[] = { int main() { } which in turn can be compiled: $ gcc -O0 -fno-inline decoded.c -o decoded.obj which in turn can be disassembled: $ objdump -M intel,i386 -D decoded.obj > decoded.asm and we are left with a file "decoded.asm". This file will contain all the glue logic that this program needs to run on Unix .. but we're not interested in that. The only thing we're after is the disassembled contents of the array "shellcode":
A-Ha! Somebody is XOR-ing something here with 0x28 (line 600853). If we look at this in a bit more detail, we notice an "odd" combination of JMP and CALL. Why would the code JMP to an address only to CALL back to the address that's right behind the original JMP ? Well .. The shell code has no idea where it resides in memory when it runs, and in order to XOR-decode the remainder of the shellcode, it has to determine its current address. A "CALL" is a function call, and pushes a return address onto the CPU stack. Thus, after the "call 60085b" instruction, the stack will contain 600860 as the return address. The instruction at 60084b then "pops" this address from the stack, which means that register EAX now points to 600860 .. and xor [eax], 0x28 / inc eax then cycle over the shellcode, and XOR every byte with 0x28. Let's try the same in Perl: $ cat decoded.bin | perl -pe 's/(.)/chr(ord($1)^0x28)/ge' > de-xored.bin $ hexdump -C de-xored.bin | tail -5 00000190 0e 89 6f 01 bd 33 ca 8a 5b 1b c6 46 79 36 1a 2f |..o.½3Ê.[.ÆFy6./| If you want to reproduce this analysis, you can find the original (raw.js) shellcode file on Pastebin.
|
Daniel 385 Posts ISC Handler Apr 25th 2012 |
Thread locked Subscribe |
Apr 25th 2012 1 decade ago |
Sign Up for Free or Log In to start participating in the conversation!