[GiM logo] gim.org.pl is down || odświeżony jogger (v.0.4) GiMa

You've probably heard about Microsoft PowerShell. This small note will show you how to analyze (well at least start to analyze) Windows PE executable files with just use of PowerShell.

I suggest that you open these two sites: So first let's open the file, and read it into memory.
  • PS > $file=$(ls axe2.exe)
  • PS > $stream=$file.OpenRead()
  • PS > $x=new-object -TypeName Byte[] -ArgumentList $stream.Length
  • PS > $stream.Read($x, 0, $stream.Length)
Now we declare two helpful functions that will count dword or word value at given address. (I'm typing most of commands in one line, they are splitted for better readabilty).
  • PS > Function dword($x, $b) { $x[$b] + $x[$b+1]*0x100 +
  • >> $x[$b+2]*0x10000 + $x[$b+3]*0x1000000; }
  • >>
  • PS > Function word($x, $b) { $x[$b] + $x[$b+1]*0x100; }
Now offset to PE header is a double word at offset 0x3c starting from MZ header.
  • PS > $PE = (dword $x 0x3c)
  • PS > $ep = (dword $x ($PE + 0x28))
now we should enumerate through sections to get the code... (all offsets mentioned from now-on are counted starting from $PE) so first let's get number od sections (offset 0x6):
  • PS > $sect_no = (word $x ($PE + 0x6))
now in normal files sections usualy start at offset 0xf8 (0xe0 = size of optional header + 0x18 = size of image_file_header) but because I'm analyzing unpacker I will first read opt_hdr_size from PE header and move to proper location. Optional header size is at offset 0x14
  • PS > $opt_hdr_size = (word $x ($PE + 0x14))
so we can skip to image_data_directory entries:
  • PS > $dd_off = ($PE + $opt_hdr_size + 0x18)
that 0x18 is size of image_file_header mentioned earlier

Because section-names (8-bytes long) in packed files are often unreadable, I'll be writing out just hex-value of first four bytes like this:
  • ([long](dword ...)).toString("x8");
Because casting can be time consuming (since we've read whole file to memory) you can use function like this to print something nicer:
  • PS > Function name($x, $b) {
  • >> $n="";
  • >> for ($l=0; $l -lt 8; $l++) {
  • >> $n+=[char]$x[$b+$l];
  • >> }
  • >> $n
  • >> }
  • >>
so first let's try to print just section names to check if this is working:
  • PS > $k=$dd_off; for ($j=0; $j -lt $sect_no; $j++) {
  • >> (name $x $k) + " " + ([long](dword $x $k)).toString("x8");
  • >> $k+=0x28 }
  • >>
Powershell seems not to treat:
  • for ($k=$dd_off, $j=0; $j -lt $sect_no; $j++,$k+=0x28)
as I would like it to, but maybe I've tried wrong way. If you ask why 0x28, the answer is simple it's size of data directory entry.

ok so now the same, but we will print some more useful stuff:
  • PS > $k=$dd_off+0xC; for ($j=0; $j -lt $sect_no; $j++) {
  • >> " [+" + ($j+1) + "] vaddr: " + ([long](dword $x $k)).toString("x8") +
  • >> " EP:" + $EP.toString("x8") +
  • >> " vend: " + ([long](dword $x ($k - 0x4)) + [long](dword $x $k)).toString("x8") +
  • >> " (vsize: " + ([long](dword $x ($k - 0x4))).toString("x8") +")";
  • >> $k+=0x28
  • >> }
  • >>
you can add some if+break or something like that I just prefer take a look at values EP must be between vaddr and vend. I have the following output:
  • [+1] vaddr: 00001000 EP:00001018 vend: 0006d000 (vsize: 0006c000)
  • [+2] vaddr: 0006d000 EP:00001018 vend: 000b5000 (vsize: 00048000)
  • [+3] vaddr: 000b5000 EP:00001018 vend: 000b6000 (vsize: 00001000)
so in my case, EP is in first section, so we will try to get to the code. The easy way would be:
EP - sect_vaddr + physical_offset (0x14 bytes from beginning of each dd entry)
but we've got to remember that physical offset should be file aligned (file alignement in optional header, 0x3c from beginning of PE). Let's call this fal, now phisical EP will be:
EP - sect_vaddr + ((physical_offset/fal)*fal)
there is also object alignment, but we won't bother about that. fal is usually 512 bytes that is 0x200, you can check your value with:
  • PS > (dword $x ($PE + 0x3c))
I'will assume it's 0x200, so first, let's get phys_offset of first section
  • PS > $phys_off = (dword $x ($dd_off + 0x14))
now finaly we can count EP:
  • PS > $phys_ep = $EP - (dword $x ($dd_off + 0xc)) + [int]($phys_off/0x200)*0x200
tadam!

At the end let's read some bytes from the beginning of our ep:
  • $n=""; for ($j = 0; $j -lt 16; $j++) { $n += ([int]$x[$phys_ep + $j]).toString("x2") + " " } $n
I'm leaving you now.

Ok So now I'm waiting until someone will make disasembler for PSH :)
catz: [eng.lish] [kom.puterowe] [micr.osoft]
dnia wtorek, 08 sierpień 2006, 185245 by Michał 'GiM' Spadliński

Komentarze:

Proszę wpisy pisane po angielsku komentować również w tym języku.

wow, didn't know, that guys from Redmond are offering such interesting features in their new toy. Nice.

dnia wtorek, 08 sierpień 2006, 213153 by deely

Very interesting article!

BTW.
Text files can be also read in very simple way:
$var=${C:\file.txt}
They can be also written this way:
${C:\file.txt}=$var
AFAIK full path must be provided.

dnia środa, 09 sierpień 2006, 003112 by grzegorz.net

..tożsamość..:
..meritum..:
..lokum..:
Wpisz kod:code