📜 ⬆️ ⬇️

Parsim proprietary format .lnk under Linux

What started this story: once synchronization between two servers stopped working. On one of the servers (running Windows) in the shared folder were documents, and on the second (running Debian), Apache was raised from the webdav. There were several subfolders in the folder on the first server. In one lay the documents, and in the rest were made labels on the documents, so the documents were sorted into subfolders. And the contents of the folder on the first server were synchronized with the folder on the second server as follows: the contents of the folder were copied, and then the shortcuts were replaced with the files they pointed to. That is, if the label, for example, pointed to the document corporate-template-65178.doc, then the label was deleted, and in its place was placed this very corporate-template-65178.doc

This system worked for three years, and then suddenly stopped working, without any warnings.
And it had to be fixed by all means.

If it is still interesting, welcome under cat.

')
So. The debriefing was conducted, a large number of people were polled, a lot of documentation was re-digged, but nowhere was any information found about who did it and when. When the digging of the servers began, a server was found that was the mail gateway. And it was on it that the scripts on vbs and cmd were found, which were engaged in synchronization. First, the contents were copied from the shared folder by rsync to the local one, then the labels were replaced with documents using a vbs-script, and then via cmd using Windows scp (without a password, with a key) the files were copied to the webdav, and the last changes.
But this system stopped working because the sshd keys changed, respectively, the files stopped being copied to the webdav.

The administrators of the mail gateway were very surprised that on their server, where there should be no more functionality other than sending mail, such strange scripts and tasks were found in the scheduler, performing the specified actions. At the same time, they negatively and without censorship spoke on the use of this server as a staging base.

The scheme really was oddly organized.
From the first server to the second, the third copied the data, which had nothing to do with the first two at all.
Almost immediately the thought came to mind to get rid of the intermediary, thereby simplifying the scheme of the system.

Since there are two servers, synchronization scripts had to be done on one of them.
It was impossible to use the server on Windows due to the fact that there were no administrative rights to it, and the only task that it performed was to function as a file server.

Thus, there is only one option left - to implement a similar functionality on linux.
The task was immediately complicated by the fact that there was no free access to parsing the proprietary format of Windows shortcuts (.lnk format). On the other hand, it made the task interesting.

The task had to be solved urgently, and Google was called upon to help, in which a whole one program was found, and that one was already in binary form. Since it is not known what is inside, it was decided not to use this program, but to write one’s own.

In the same Google, a document obtained by reverse engineering was found, which describes the structure of files of this format.
It was used as a source of information.

The system itself included the following parts:
1) C program that parses shortcuts
2) synchronization and processing scripts
3) task in krone

So,
1) Program
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> struct TLinkHeaderInfo{ //4 bytes Always 4C 00 00 00 This is how windows knows it is a shortcut file unsigned long Signature; //16 bytes GUID for shortcut files The current GUID for shortcuts. //It may change in the future. 01 14 02 00 00 00 00 00 C0 00 00 00 00 00 46 unsigned char GUID[16]; //4 bytes Shortcut flags Shortcut flags are explained below unsigned long ShortcutFlags; //4 bytes Target file flags Flags are explained below unsigned long TargetFileFlags; //8 bytes Creation time unsigned char CreationTime[8]; //8 bytes Last Access time unsigned char LastAccessTime[8]; //8 bytes Modification time unsigned char ModificationTime[8]; //4 bytes File length //The length of the target file. 0 if the target is not a file. //This value is used to find the target when the link is broken. unsigned long FileLength; //4 bytes Icon number //If the file has a custom icon (set by the flags bit 6), //then this long integer indicates the index of the icon to use. Otherwise it is zero. unsigned long IconNumber; //4 bytes Show Window //the ShowWnd value to pass to the target application when starting it. //1:Normal Window 2:Minimized 3:Maximized unsigned long ShowWindow; // 4 bytes Hot Key The hot key assigned for this shortcut unsigned long HotKey; // 4 bytes Reserved Always 0 unsigned long Reserved1; // 4 bytes Reserved Always 0 unsigned long Reserved2; }; void main(int argc, char** argv) { const int HEADER_SIZE=76; const int FILE_ALLOCATION_INFO_HEADER_SIZE=28; char TempString[255]; int i, LinkFileSize; char LinkFileName[255]; char ExtractedFileName[255]; FILE* LinkFile; struct stat FileStatInfo; struct TLinkHeaderInfo HeaderStructure; size_t result; long TempInt=0; char LinkFileContent[10240]; if(strcmp(argv[1],"")==0) { printf("No parameter used.\n"); return; }; printf("FileName: %s\n",argv[1]); LinkFile=fopen(argv[1],"r"); if(LinkFile==NULL) { fclose(LinkFile); printf("No file found.\n"); return; }; // Open LNK File and parse it for file name // Get it size stat(argv[1],&FileStatInfo); printf("Link Filesize: %d\n", FileStatInfo.st_size); LinkFileSize=FileStatInfo.st_size; // read file to array result = fread (LinkFileContent,1,LinkFileSize,LinkFile); if (result != LinkFileSize) { printf ("Reading error\n"); }; fclose(LinkFile); HeaderStructure.Signature=LinkFileContent[0]*65536*256; HeaderStructure.Signature+=LinkFileContent[1]*65536; HeaderStructure.Signature+=LinkFileContent[2]*256+LinkFileContent[3]; printf("Signature: %X\n",HeaderStructure.Signature); printf("GUID: "); for(i=0;i<16;i++) { HeaderStructure.GUID[i]=LinkFileContent[4+i]; printf(" %X",HeaderStructure.GUID[i]); }; printf("\n"); HeaderStructure.ShortcutFlags=LinkFileContent[23]*65536*256; HeaderStructure.ShortcutFlags+=LinkFileContent[22]*65536; HeaderStructure.ShortcutFlags+=LinkFileContent[21]*256+LinkFileContent[20]; printf("Shortcut Flags: %X\n",HeaderStructure.ShortcutFlags); HeaderStructure.TargetFileFlags=LinkFileContent[27]*65536*256; HeaderStructure.TargetFileFlags+=LinkFileContent[26]*65536; HeaderStructure.TargetFileFlags+=LinkFileContent[25]*256+LinkFileContent[24]; printf("Target File Flags: %X\n",HeaderStructure.TargetFileFlags); for(i=0;i<8;i++){HeaderStructure.CreationTime[i]=LinkFileContent[28+i];}; for(i=0;i<8;i++){HeaderStructure.LastAccessTime[i]=LinkFileContent[36+i];}; for(i=0;i<8;i++){HeaderStructure.LastAccessTime[i]=LinkFileContent[44+i];}; HeaderStructure.FileLength=LinkFileContent[55]*65536*256; HeaderStructure.FileLength+=LinkFileContent[54]*65536; HeaderStructure.FileLength+=LinkFileContent[53]*256+LinkFileContent[52]; printf("Target File Size (bytes): %d\n",HeaderStructure.FileLength); HeaderStructure.IconNumber=LinkFileContent[59]*65536*256; HeaderStructure.IconNumber+=LinkFileContent[58]*65536; HeaderStructure.IconNumber+=LinkFileContent[57]*256+LinkFileContent[56]; printf("IconNumber: %X\n",HeaderStructure.IconNumber); HeaderStructure.ShowWindow=LinkFileContent[63]*65536*256; HeaderStructure.ShowWindow+=LinkFileContent[62]*65536; HeaderStructure.ShowWindow+=LinkFileContent[61]*256+LinkFileContent[60]; printf("ShowWindow Attributes: %X\n",HeaderStructure.IconNumber); HeaderStructure.HotKey=LinkFileContent[67]*65536*256; HeaderStructure.HotKey+=LinkFileContent[66]*65536; HeaderStructure.HotKey+=LinkFileContent[65]*256+LinkFileContent[64]; printf("HotKey Attributes: %X\n",HeaderStructure.HotKey); // Now extract file name and path unsigned int OFFSET=76+(unsigned char)LinkFileContent[76]; OFFSET+=(unsigned char)LinkFileContent[77]*256+(unsigned char)LinkFileContent[78]+2; OFFSET+=LinkFileContent[OFFSET]; printf("Share name: "); printf("%s\n",&LinkFileContent[OFFSET]); OFFSET+=strlen(&LinkFileContent[OFFSET]); OFFSET++; printf("File name: "); printf("%s\n",&LinkFileContent[OFFSET]); } 


There is nothing sophisticated in the program.
Compile it
 gcc ./lnkinfo.c -o lnkinfo 


Throw out debug information
 strip ./lnkinfo 


The source code does not include a parsing of the flags of the file location type (network folder, removable disk, etc.), if you wish, you can add to the source code by carefully reading the document referenced above.

The main functionality is ready, now you need to apply it.

2) Scripts.
The first script performs the basic operations.
It is located, say, in the / usr / doc-sync folder

 #!/bin/bash DOMAIN=MYDOMAIN USER=MYUSER PASSWORD=MYPASSWORD mount.cifs "//server/doc" /mnt/doc -o ro,dom=$DOMAIN,user=$USER,pass=$PASSWORD cd /usr/doc-sync WHERE_TO_PUT=/usr/local/webdav/files/docs rm -rf $WHERE_TO_PUT/* rsync -avz /mnt/doc/DocFolder1 $WHERE_TO_PUT rsync -avz /mnt/doc/DocFolder2 $WHERE_TO_PUT rsync -avz /mnt/doc/DocFolder3 $WHERE_TO_PUT umount /mnt/doc #      .lnk,    lnkinfo     #        (,    ) find $WHERE_TO_PUT -name "*.lnk" | sed -e 's/ /@/g' | awk '{printf "./lnkinfo "$1" | grep ile | grep ame:\n"}' \ | sed -e 's/@/ /g' \ | sed -e 's/(/\\(/g' \ | sed -e 's/)/\\)/g' \ | sed -e 's/ /\\ /g' \ | sed -e 's/lnkinfo\\ /lnkinfo /g' \ | sed -e 's/\\ grep/ grep/g'\ | sed -e 's/grep\\/grep/g'\ | sed -e 's/\\ |/ |/g'\ > ./haba-haba.sh && chmod a+x ./haba-haba.sh #      : PARAMETERS=`./haba-haba.sh | sed -e 's/ /@/g'` rm ./haba-haba.sh HABA2_EXIST=`ls | grep haba-haba2.sh` if [ "$HABA2_EXIST" != "" ] then rm ./haba-haba2.sh fi #      lnk   ,    . i="1" for PARAMETER in $PARAMETERS do if [ "$i" == "2" ] then #    ,       cp1251,     #  utf-8,     PARAMETER=`echo $PARAMETER | iconv -f windows-1251 -t utf8` echo $PARAMETER >> ./haba-haba2.sh i="1" continue fi if [ "$i" == "1" ] then i="2" echo $PARAMETER >> ./haba-haba2.sh continue fi done #        - exchange-lnk.sh #     -  -       cat ./haba-haba2.sh \ | sed -e 's/FileName:@/.\/exchange-lnk.sh /'\ | sed -e 's/File@name:@//'\ | sed -e 's/\\/\//g'\ | sed -e 's/\.lnk/\.lnk \\/g'\ | sed -e 's/@/\\ /g'\ | sed -e 's/(/\\(/g'\ | sed -e 's/)/\\)/g'\ >./haba-haba.sh rm ./haba-haba2.sh sh ./haba-haba.sh rm ./haba-haba.sh 


The second script that removes the shortcut and copies the document in its place.

 #!/bin/sh # remove first parameter and copy second parameter to first parameter's path LINK_NAME=`echo $1 | sed -e '{s/ /\\ /g}' | sed -e 's/(/\\(/g'` LINK_PATH=$(dirname "$LINK_NAME") echo $LINK_PATH echo Copy $2 to path of $1 cp "$2" "$LINK_PATH" rm "$1" 


3) cron
Well, the last thing that remains is to add the task to the cron so that the process takes place automatically.
 0 4 * * * root /usr/sync/doc-sync.sh 


If you have questions, write, try to answer or add / correct

Source: https://habr.com/ru/post/125081/


All Articles