Get the real path of the file through the shortcut lnk

Get the real path of the file through the shortcut .lnk

premise

Recently, in the development of resource management, a large number of resources need to be uploaded in advance. The students who are responsible for organizing resources directly use shortcut keys to organize video resources OTZ because of lack of space, so they can only find a way to obtain the real address of the file through the .lnk file.

All the following content is from the Internet, and the blogger only makes a reference and summary.

.lnk file format parsing

Here is a general introduction to the composition of the lnk file. The purpose is to help understand how to extract the required information from the link file.
A lnk file includes the following modules:

module Remark
File header (lnk file header) Some important file information.
Shell Item Id List 段 The optional structure is determined by the value at the offset 0x14 position in the file header. When the 0 bit value is 1, it means that the lnk file contains this structure.
File location info The optional structure is determined by the value at the offset 0x14 position in the file header. When the value of 1 bit is 1, it means that the lnk file contains this structure.
Description string The optional structure is determined by the value at the offset 0x14 position in the file header. When the 2 bit value is 1, it means that the lnk file contains this structure.
Relative path string The optional structure is determined by the value at the offset 0x14 position in the file header. When the 3 bit value is 1, it means that the lnk file contains this structure.
Working directory string The optional structure is determined by the value at the offset 0x14 position in the file header. When the 4 bit value is 1, it means that the lnk file contains this structure.
Command line string The optional structure is determined by the value at the offset 0x14 position in the file header. When the 5 bit value is 1, it means that the lnk file contains this structure.
Icon filename string The optional structure is determined by the value at the offset 0x14 position in the file header. When the 6 bit value is 1, it means that the lnk file contains this structure.
Extra stuff The specific meaning of the data inside is unknown, and some of them will contain some local machine names.

注意:
不是所有的模块都必须包含在内,但如果存在就要按上述的顺序排列。

Let's learn more about the two modules we need to use:
1. File header (lnk file header)

offset length Types of Remark
0x00 1 dword 总是为0000004CH,相当于字符"L",用于标识是否是个有效的.lnk文件。
0x04 16 bytes GUID, a unique identifier for identifying .lnk, it does not exclude that MS will modify this field in the future.
0x14 1 dword flags标志,用来标识.lnk文件中有哪些可选属性,也就是哪些节是可选的。
0x18 1 dword Target file attributes (whether read-only, hidden, system files, encrypted, temporary...)
0x1c 1 qword file creation time
0x24 1 qword file modification time
0x2c 1 qword file last access time
0x34 1 dword target file length
0x38 1 dword number of custom icons
0x3c 1 dword Window display mode when the target file is executed (1-normal display, 2-minimized, 3-maximized)
0x40 1 dword hotkey
0x44 2 dword This field is unknown, usually 0

0x14The meaning of the hexadecimal number:

Bit When the bit is 1, it means
0 Contains the shell item id list section, which is filtered out by modifying the file, does not affect the .lnk execution target file, but affects other functions.
1 Points to a file or folder, if this bit is 0, it points to something else.
2 description string exists
3 relative path exists
4 working path exists
5 There are command line arguments
6 custom icon exists

0x18The meaning of the hexadecimal number:

Bit When the bit is 1, it means
0 The target file pointed to by the shortcut has the read-only attribute
1 The target file pointed to by the shortcut has hidden attributes
2 The target file pointed to by the shortcut is a system file
3 The shortcut refers to the volume label
4 The shortcut refers to a folder
5 The target file pointed to by the shortcut has been changed since the last time it was archived
6 The target file pointed to by the shortcut is encrypted
7 The attribute of the target file pointed to by the shortcut is General
8 The target file pointed to by the shortcut is temporary
9 The target file pointed to by the shortcut is a sparse file.
10 The target file pointed to by the shortcut has reparse point data.
11 The target file pointed to by the shortcut is compressed
12 The target file pointed to by the shortcut is offline

2. File location info

offset length Types of Remark
0x00 1 dword The total length of this section, and the modification of this value will affect the execution of the .lnk file or the confusion and invalidation of command parameters.
0x04 1 dword Fixed as 0x1c, indicating the length of the section, this value can be modified arbitrarily.
0x08 1 dword flags标志,指示文件在哪些卷有效,例如是本地卷标还是网络卷标。
0x0c 1 dword Fixed to 0x1c, the offset of the local volume information table.
0x10 1 dword Indicates the offset of the target file path relative to the header of this section, but the execution of the target program by the .lnk file does not depend on whether the path pointed to by this value is correct.
0x14 1 dword 网络卷信息表偏移,如果flags标记含有网络卷的话,否则为0。
0x18 1 dword 剩余偏移路径,一般都指向本节的末尾,也就是节总长度减1的值,当该值指向的位置为0时(大多数情况下都是0),该值可任意修改。

0x08偏移flags 具体含义:

  • 如果目标文件是本地文件,那么文件名称 = 本地路径信息+剩余偏移路径
  • 如果目标文件是网络文件,那么文件名称 = 网络卷中共享名称+剩余偏移路径

所以,File location info节之后的数据是,本地卷信息表,及网络卷信息表。
1. 本地卷信息表结构

偏移 长度 类型 备注
0x00 1 dword 本地卷信息表的长度,该值可任意修改。
0x04 1 dword 卷类型,该值可以任意修改。
0x08 1 dword 标识卷序列号,2byte一组,该值可任意修改。
0x0c 1 dword 卷名称的偏移,固定为0x10,该值可以任意修改。
0x10 可变长度 卷名称,本地路径信息,其大小由该表总长度决定。

2. 网络卷信息表结构

偏移 长度 类型 备注
0x00 1 dword 网络卷信息表的长度,该值可任意修改。
0x04 1 dword 固定为0x2
0x08 1 dword 固定为0x14
0x0c 1 dword 固定为0
0x10 可变长度 固定为0x20000
0x10 可变长度 网络共享名

注意:
八个比特(Bit)称为一个字节(Byte),两个字节称为一个字(Word),两个字称为一个双字(Dword),两个双字称为一个四字(Qword)。

代码

private void parseLink(File f) throws FileNotFoundException, IOException {
    FileInputStream fin = new FileInputStream(f); 
    byte[] link = new byte[(int)f.length()]; 
    //读取文件中的内容到link[]数组
    fin.read(link);    
    fin.close(); 

    // 判断当前文件是否为快捷方式
    if(!isLnkFile(link)){
        return;
    }
    // 获得flags信息
    byte flags = link[0x14]; 

    int shell_len = 0;
    // 0000 0000 xxxx xxxx & 0000 0000 0000 0001(判断是否包含shell item id list段)
    if((flags & 0x1) > 0) { 
        // 如果存在,则获取shell item id list段的总长度,加2是为了将link[0x4c]本身的长度计算在内
        shell_len = bytes2short(link,0x4c) + 2; 
    } 
    // 获得文件位置信息段的开始位置=shell item id list段的开始位置+shell item id list段的总长度
    int file_start = 0x4c + shell_len; 
    // 获取本地路径信息的偏移
    int local_sys_off = link[file_start + 0x10] + file_start;
    String real_file = getNullDelimitedString(link, local_sys_off);
    System.out.println(real_file);
} 

private boolean isLnkFile(byte[] link) {
    if (link[0x00]== 0x4c) {// 76,L,0x4c代表lnk文件格式
        return true;
    }
    return false;
}

/**
 * 将两个字节转换为short<br>
 * 注意,因为仅限英特尔操作系统,所以这是小端字节<br>
 */
private int bytes2short(byte[] bytes, int off) {
    return bytes[off] | (bytes[off + 1] << 8);
}

/**
 * 获得从偏移位置off到以‘0’为结尾分割字符串
 * @param bytes 源数组
 * @param off 偏移位置
 * @return 字符串
 */
private String getNullDelimitedString(byte[] bytes, int off) {
    int len = 0;
    // 计算字符串占用数组的真实长度
    while (true) {
        if (bytes[off + len] == 0) {
            break;
        }
        len++;
    }
    byte[] results = new byte[len];
    for (int i = off, j = 0; i < off + len; i++, j++) {
        results[j] = bytes[i];
    }
    try {
        // 因为我是中文系统,所以设置了字符集GBK,否则中文路径会出现乱码
        return new String(bytes, off, len, "GBK");
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return null;
}

后话

GIT上也有一些项目实现了解析.lnk文件的功能,比如:
1. mslinks: 将.lnk封装对象可以通过get方法拿到想要的属性,但中文路径有乱码,如果愿意可以尝试自行修改源码;
2. jshortcut:用到了JNI,需要编译jshortcut.dll文件,没有尝试过,貌似同样存在中文乱码问题;

参考
  1. Windows快捷方式文件格式解析-http://www.cnblogs.com/ahuo/archive/2006/12/01/579503.html
  2. .lnk文件格式解析-http://pope12389.iteye.com/blog/1333585

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325794615&siteId=291194637