Advertisement
Guest User

Untitled

a guest
Jan 23rd, 2018
4,229
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 9.76 KB | None | 0 0
  1. #---------------------------------------------------------------------
  2. # lslnk.pl
  3. # Perl script to parse a shortcut (LNK) file and retrieve data
  4. #
  5. # Usage:
  6. # C:\Perl>lslnk.pl <filename> [> report.txt]
  7. #
  8. # This script is intended to be used against LNK files extracted from
  9. # from an image, or for LNK files located on a system
  10. #
  11. # Change history
  12. #   20100210
  13. #     [*] Fix MAC reading in the header. Modification and LastAccessTime
  14. #         were flip.
  15. #   20091222
  16. #     [*] Quick fix for a bug in the date/time return by Perl's 'stat', 'lstat'
  17. #         and 'utime' functions under Windows because it may change by an hour
  18. #         as we move into or out of daylight saving time (DST) if the computer
  19. #         is set to "Automatically adjust clock for daylight saving changes"
  20. #         and if the file reside on a NTFS volume.
  21. #         See Win32::UTCFileTime module on CPAN for more details.
  22. #
  23. # References
  24. #   The windows File Format - Jesse Hager
  25. #   MS-SHLLNK - http://msdn.microsoft.com/en-us/library/dd871305(PROT.10).aspx
  26. #
  27. # copyright 2006-2007 H. Carvey, keydet89@yahoo.com
  28. # copyright 2010 J.-F. Gingras
  29. #---------------------------------------------------------------------
  30. use strict;
  31.  
  32. my $file = shift || die "You must enter a filename.\n";
  33. die "$file not found.\n" unless (-e $file);
  34.  
  35. # Setup some variables
  36. my $record;
  37. my $ofs = 0;
  38. my %flags = (0x01 => "Shell Item ID List exists",
  39.                0x02 => "Shortcut points to a file or directory",
  40.                0x04 => "The shortcut has a descriptive string",
  41.                0x08 => "The shortcut has a relative path string",
  42.                0x10 => "The shortcut has working directory",
  43.                0x20 => "The shortcut has command line arguments",
  44.                0x40 => "The shortcut has a custom icon",
  45.                0x80 => "The shortcut use Unicode encoded string");
  46.  
  47. my %fileattr = (0x01 => "Target is read only",
  48.                 0x02 => "Target is hidden",
  49.                 0x04 => "Target is a system file",
  50.                 0x08 => "Target is a volume label [*]", # ??? MS-SHLLNK said it is a reserved bit and MUST be zero
  51.                 0x10 => "Target is a directory",
  52.                 0x20 => "Target was modified since last backup",
  53.                 0x40 => "Target is encrypted [*]",      # ??? MS-SHLLNK said it is a reserved bit and MUST be zero
  54.                 0x80 => "Target is normal",
  55.                 0x100 => "Target is temporary",
  56.                 0x200 => "Target is a sparse file",
  57.                 0x400 => "Target has a reparse point",
  58.                 0x800 => "Target is compressed",
  59.                 0x1000 => "Target is offline",
  60.                 0x4000 => "Target is encrypted");
  61.  
  62. my %showwnd = (0 => "SW_HIDE [*]",
  63.                1 => "SW_NORMAL",
  64.                2 => "SW_SHOWMINIMIZED [*]",
  65.                3 => "SW_SHOWMAXIMIZED",
  66.                4 => "SW_SHOWNOACTIVE [*]",
  67.                5 => "SW_SHOW [*]",
  68.                6 => "SW_MINIMIZE [*]",
  69.                7 => "SW_SHOWMINNOACTIVE",
  70.                8 => "SW_SHOWNA [*]",
  71.                9 => "SW_RESTORE [*]",
  72.                10 => "SHOWDEFAULT [*]");
  73.  
  74. my %vol_type = (0 => "Unknown",
  75.                 1 => "No root directory",
  76.                 2 => "Removable",
  77.                 3 => "Fixed",
  78.                 4 => "Remote",
  79.                 5 => "CD-ROM",
  80.                 6 => "Ram drive");
  81.  
  82. # Get info about the file
  83. my ($size,$atime,$mtime,$ctime) = (stat($file))[7,8,9,10];
  84. print $file." $size bytes\n";
  85. print "Access Time       = ".gmtime(fixWin32StatTime($atime))." (UTC)\n";
  86. print "Creation Date     = ".gmtime(fixWin32StatTime($ctime))." (UTC)\n";
  87. print "Modification Time = ".gmtime(fixWin32StatTime($mtime))." (UTC)\n";
  88. print "\n";
  89. # Open file in binary mode
  90. open(FH,$file) || die "Could not open $file: $!\n";
  91. binmode(FH);
  92. seek(FH,$ofs,0);
  93. read(FH,$record,0x4c);
  94. if (unpack("Vx72",$record) == 0x4c) {
  95.     my %hdr = parseHeader($record);
  96. # print summary info from header
  97.     print "Flags:\n";
  98.     foreach my $i (keys %flags) {
  99.         print $flags{$i}."\n" if ($hdr{flags} & $i);
  100.     }
  101.     print "\n";
  102.     if (scalar keys %fileattr > 0) {
  103.         print "Attributes:\n";
  104.         foreach my $i (keys %fileattr) {
  105.             print $fileattr{$i}."\n" if ($hdr{attr} & $i);
  106.         }
  107.         print "\n";
  108.     }
  109.     print "MAC Times: \n";
  110.     print "Creation Time     = ".gmtime($hdr{ctime})." (UTC)\n";
  111.     print "Modification Time = ".gmtime($hdr{mtime})." (UTC)\n";
  112.     print "Access Time       = ".gmtime($hdr{atime})." (UTC)\n";
  113.     print "\n";
  114.     print "Filesize          = ".$hdr{length}." bytes\n";
  115.     print "\n";
  116.     print "ShowWnd value(s):\n";
  117.     foreach my $i (keys %showwnd) {
  118.         print $showwnd{$i}."\n" if ($hdr{showwnd} & $i);
  119.     }
  120.    
  121.     $ofs += 0x4c;
  122. # Check to see if Shell Item ID List exists.  If so, get the length
  123. # and skip it.
  124.     if ($hdr{flags} & 0x01) {
  125. #        print "Shell Item ID List exists.\n";
  126.         seek(FH,$ofs,0);
  127.         read(FH,$record,2);
  128. # Note: add 2 to the offset as the Shell Item ID list length is not included in the
  129. #       structure itself
  130.         $ofs += unpack("v",$record) + 2;
  131.     }
  132.    
  133. # Check File Location Info
  134.     if ($hdr{flags} & 0x02) {
  135.         seek(FH,$ofs,0);
  136.         read(FH,$record,4);
  137.         my $l = unpack("V",$record);
  138.         if ($l > 0) {
  139.             seek(FH,$ofs,0);
  140.             read(FH,$record,0x1c);
  141.             my %li = fileLocInfo($record);
  142.           print "\n";
  143.            
  144.             if ($li{flags} & 0x1) {
  145. # Get the local volume table
  146.                 print "Shortcut file is on a local volume.\n";
  147.                 my %lvt = localVolTable($ofs + $li{vol_ofs});
  148.                 print  "Volume Name = $lvt{name}\n";
  149.                 print  "Volume Type = ".$vol_type{$lvt{type}}."\n";
  150.                 printf "Volume SN   = 0x%x\n",$lvt{vol_sn};
  151.                 print "\n";
  152.             }
  153.            
  154.             if ($li{flags} & 0x2) {
  155. # Get the network volume table
  156.                 print "File is on a network share.\n";
  157.                 my %nvt = netVolTable($ofs + $li{network_ofs});
  158.                 print "Network Share name = $nvt{name}\n";
  159.             }
  160.            
  161.             if ($li{base_ofs} > 0) {
  162.                 my $basename = getBasePathName($ofs + $li{base_ofs});
  163.                 print "Base = $basename\n";
  164.             }
  165.         }
  166.        
  167.     }
  168.  
  169. }
  170. else {
  171.     die "$file does not have a valid shortcut header.\n"
  172. }
  173.  
  174. close(FH);
  175.  
  176.  
  177. sub parseHeader {
  178.     my $data = $_[0];
  179.     my %hdr;
  180.     my @hd = unpack("Vx16V12x8",$data);
  181.     $hdr{id}       = $hd[0];
  182.     $hdr{flags}    = $hd[1];
  183.     $hdr{attr}     = $hd[2];
  184.     $hdr{ctime}    = getTime($hd[3],$hd[4]);
  185.     $hdr{atime}    = getTime($hd[5],$hd[6]);
  186.     $hdr{mtime}    = getTime($hd[7],$hd[8]);
  187.     $hdr{length}   = $hd[9];
  188.     $hdr{icon_num} = $hd[10];
  189.     $hdr{showwnd}  = $hd[11];
  190.     $hdr{hotkey}   = $hd[12];
  191.     undef @hd;
  192.     return %hdr;
  193. }
  194.  
  195. sub fileLocInfo {
  196.     my $data = $_[0];
  197.     my %fl;
  198.     ($fl{len},$fl{ptr},$fl{flags},$fl{vol_ofs},$fl{base_ofs},$fl{network_ofs},
  199.      $fl{path_ofs}) = unpack("V7",$data);
  200.     return %fl;
  201. }
  202.  
  203. sub localVolTable {
  204.     my $offset = $_[0];
  205.     my $data;
  206.     my %lv;
  207.     seek(FH,$offset,0);
  208.     read(FH,$data,0x10);
  209.     ($lv{len},$lv{type},$lv{vol_sn},$lv{ofs}) = unpack("V4",$data);
  210.     seek(FH,$offset + $lv{ofs},0);
  211.     read(FH,$data, $lv{len} - 0x10);
  212.     $lv{name} = $data;
  213.     return %lv;
  214. }
  215.  
  216. sub getBasePathName {
  217.     my $ofs = $_[0];
  218.     my $data;
  219.     my @char;
  220.     my $len;
  221.     my $tag = 1;
  222.     while($tag) {
  223.         seek(FH,$ofs,0);
  224.         read(FH,$data,2);
  225.         $tag = 0 if (unpack("v",$data) == 0x00);
  226.         push(@char,$data);
  227.         $ofs += 2;
  228.     }
  229.     return join('',@char);
  230. }
  231.  
  232. sub netVolTable {
  233.     my $offset = $_[0];
  234.     my $data;
  235.     my %nv;
  236.     seek(FH,$offset,0);
  237.     read(FH,$data,0x14);
  238.     ($nv{len},$nv{ofs}) = unpack("Vx4Vx8",$data);
  239. #    printf "Length of the network volume table = 0x%x\n",$nv{len};
  240. #    printf "Offset to the network share name   = 0x%x\n",$nv{ofs};
  241.     seek(FH,$offset + $nv{ofs},0);
  242.     read(FH,$data, $nv{len} - 0x14);
  243.     $nv{name} = $data;
  244.     return %nv;
  245. }
  246.  
  247. #---------------------------------------------------------
  248. # fixWin32StatTime()
  249. # Fix the date/time return by 'stat', 'lstat' and 'utime'
  250. # under Windows because it may change by an hour as we move
  251. # into or out of daylight saving time (DST) if the computer
  252. # is set to "Automatically adjust clock for daylight saving
  253. # changes" and if the file reside on a NTFS volume.
  254. # Input : Unix-style date/time
  255. # Output: Unix-style date/time
  256. #
  257. # For more information, see Win32::UTCFileTime
  258. # NOTES: I do assume a few things here :
  259. #   - you are in north america
  260. #   - your daylight bias is 1 hour
  261. #---------------------------------------------------------
  262. sub fixWin32StatTime {
  263.   my $time = shift;
  264.  
  265.   my $i = 0;
  266.   my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
  267.                                               gmtime($time);
  268.   $year += 1900;
  269.   $mon  += 1;
  270.   $wday += 1;
  271.   if ($year >= 1987 && $year < 2007) {
  272.     $i = 1 if ($mon == 4 && ($mday > 7 || ($wday == 1 && $hour >= 2)));
  273.     $i = 1 if ($mon == 10 && ($mday < 25 || ($wday == 1 && $hour < 2)));
  274.     $i = 1 if ($mon > 4 && $mon < 10);
  275.   } elsif ($year >= 2007) {
  276.     $i = 1 if ($mon == 3 && ($mday > 14 || ($mday >= 8 && $wday == 1 && $hour >= 2)));
  277.     $i = 1 if ($mon == 11 && ($mday > 7 || ($wday == 1 && $hour < 2)));
  278.     $i = 1 if ($mon > 3 && $mon < 11);
  279.   }
  280.   $time += ($i * 60 * 60);
  281. }
  282.  
  283. sub getTime {
  284.     my $lo = shift;
  285.     my $hi = shift;
  286.     my $t;
  287.     if ($lo == 0 && $hi == 0) {
  288.         $t = 0;
  289.     } else {
  290.         $lo -= 0xd53e8000;
  291.         $hi -= 0x019db1de;
  292.         $t = int($hi*429.4967296 + $lo/1e7);
  293.     };
  294.     $t = 0 if ($t < 0);
  295.     return $t;
  296. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement